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         isGecko = !isSafari && ua.indexOf("gecko") > -1,
60         isBorderBox = isIE && !isStrict,
61         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
62         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
63         isLinux = (ua.indexOf("linux") != -1),
64         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
65         isTouch =  (function() {
66             try {  
67                 document.createEvent("TouchEvent");  
68                 return true;  
69             } catch (e) {  
70                 return false;  
71             } 
72             
73         })();
74     // remove css image flicker
75         if(isIE && !isIE7){
76         try{
77             document.execCommand("BackgroundImageCache", false, true);
78         }catch(e){}
79     }
80     
81     Roo.apply(Roo, {
82         /**
83          * True if the browser is in strict mode
84          * @type Boolean
85          */
86         isStrict : isStrict,
87         /**
88          * True if the page is running over SSL
89          * @type Boolean
90          */
91         isSecure : isSecure,
92         /**
93          * True when the document is fully initialized and ready for action
94          * @type Boolean
95          */
96         isReady : false,
97         /**
98          * Turn on debugging output (currently only the factory uses this)
99          * @type Boolean
100          */
101         
102         debug: false,
103
104         /**
105          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
106          * @type Boolean
107          */
108         enableGarbageCollector : true,
109
110         /**
111          * True to automatically purge event listeners after uncaching an element (defaults to false).
112          * Note: this only happens if enableGarbageCollector is true.
113          * @type Boolean
114          */
115         enableListenerCollection:false,
116
117         /**
118          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
119          * the IE insecure content warning (defaults to javascript:false).
120          * @type String
121          */
122         SSL_SECURE_URL : "javascript:false",
123
124         /**
125          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
126          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
127          * @type String
128          */
129         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
130
131         emptyFn : function(){},
132         
133         /**
134          * Copies all the properties of config to obj if they don't already exist.
135          * @param {Object} obj The receiver of the properties
136          * @param {Object} config The source of the properties
137          * @return {Object} returns obj
138          */
139         applyIf : function(o, c){
140             if(o && c){
141                 for(var p in c){
142                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
143                 }
144             }
145             return o;
146         },
147
148         /**
149          * Applies event listeners to elements by selectors when the document is ready.
150          * The event name is specified with an @ suffix.
151 <pre><code>
152 Roo.addBehaviors({
153    // add a listener for click on all anchors in element with id foo
154    '#foo a@click' : function(e, t){
155        // do something
156    },
157
158    // add the same listener to multiple selectors (separated by comma BEFORE the @)
159    '#foo a, #bar span.some-class@mouseover' : function(){
160        // do something
161    }
162 });
163 </code></pre>
164          * @param {Object} obj The list of behaviors to apply
165          */
166         addBehaviors : function(o){
167             if(!Roo.isReady){
168                 Roo.onReady(function(){
169                     Roo.addBehaviors(o);
170                 });
171                 return;
172             }
173             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
174             for(var b in o){
175                 var parts = b.split('@');
176                 if(parts[1]){ // for Object prototype breakers
177                     var s = parts[0];
178                     if(!cache[s]){
179                         cache[s] = Roo.select(s);
180                     }
181                     cache[s].on(parts[1], o[b]);
182                 }
183             }
184             cache = null;
185         },
186
187         /**
188          * Generates unique ids. If the element already has an id, it is unchanged
189          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
190          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
191          * @return {String} The generated Id.
192          */
193         id : function(el, prefix){
194             prefix = prefix || "roo-gen";
195             el = Roo.getDom(el);
196             var id = prefix + (++idSeed);
197             return el ? (el.id ? el.id : (el.id = id)) : id;
198         },
199          
200        
201         /**
202          * Extends one class with another class and optionally overrides members with the passed literal. This class
203          * also adds the function "override()" to the class that can be used to override
204          * members on an instance.
205          * @param {Object} subclass The class inheriting the functionality
206          * @param {Object} superclass The class being extended
207          * @param {Object} overrides (optional) A literal with members
208          * @method extend
209          */
210         extend : function(){
211             // inline overrides
212             var io = function(o){
213                 for(var m in o){
214                     this[m] = o[m];
215                 }
216             };
217             return function(sb, sp, overrides){
218                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
219                     overrides = sp;
220                     sp = sb;
221                     sb = function(){sp.apply(this, arguments);};
222                 }
223                 var F = function(){}, sbp, spp = sp.prototype;
224                 F.prototype = spp;
225                 sbp = sb.prototype = new F();
226                 sbp.constructor=sb;
227                 sb.superclass=spp;
228                 
229                 if(spp.constructor == Object.prototype.constructor){
230                     spp.constructor=sp;
231                    
232                 }
233                 
234                 sb.override = function(o){
235                     Roo.override(sb, o);
236                 };
237                 sbp.override = io;
238                 Roo.override(sb, overrides);
239                 return sb;
240             };
241         }(),
242
243         /**
244          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
245          * Usage:<pre><code>
246 Roo.override(MyClass, {
247     newMethod1: function(){
248         // etc.
249     },
250     newMethod2: function(foo){
251         // etc.
252     }
253 });
254  </code></pre>
255          * @param {Object} origclass The class to override
256          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
257          * containing one or more methods.
258          * @method override
259          */
260         override : function(origclass, overrides){
261             if(overrides){
262                 var p = origclass.prototype;
263                 for(var method in overrides){
264                     p[method] = overrides[method];
265                 }
266             }
267         },
268         /**
269          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
270          * <pre><code>
271 Roo.namespace('Company', 'Company.data');
272 Company.Widget = function() { ... }
273 Company.data.CustomStore = function(config) { ... }
274 </code></pre>
275          * @param {String} namespace1
276          * @param {String} namespace2
277          * @param {String} etc
278          * @method namespace
279          */
280         namespace : function(){
281             var a=arguments, o=null, i, j, d, rt;
282             for (i=0; i<a.length; ++i) {
283                 d=a[i].split(".");
284                 rt = d[0];
285                 /** eval:var:o */
286                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
287                 for (j=1; j<d.length; ++j) {
288                     o[d[j]]=o[d[j]] || {};
289                     o=o[d[j]];
290                 }
291             }
292         },
293         /**
294          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
295          * <pre><code>
296 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
297 Roo.factory(conf, Roo.data);
298 </code></pre>
299          * @param {String} classname
300          * @param {String} namespace (optional)
301          * @method factory
302          */
303          
304         factory : function(c, ns)
305         {
306             // no xtype, no ns or c.xns - or forced off by c.xns
307             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
308                 return c;
309             }
310             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
311             if (c.constructor == ns[c.xtype]) {// already created...
312                 return c;
313             }
314             if (ns[c.xtype]) {
315                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
316                 var ret = new ns[c.xtype](c);
317                 ret.xns = false;
318                 return ret;
319             }
320             c.xns = false; // prevent recursion..
321             return c;
322         },
323          /**
324          * Logs to console if it can.
325          *
326          * @param {String|Object} string
327          * @method log
328          */
329         log : function(s)
330         {
331             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
332                 return; // alerT?
333             }
334             console.log(s);
335             
336         },
337         /**
338          * 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.
339          * @param {Object} o
340          * @return {String}
341          */
342         urlEncode : function(o){
343             if(!o){
344                 return "";
345             }
346             var buf = [];
347             for(var key in o){
348                 var ov = o[key], k = Roo.encodeURIComponent(key);
349                 var type = typeof ov;
350                 if(type == 'undefined'){
351                     buf.push(k, "=&");
352                 }else if(type != "function" && type != "object"){
353                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
354                 }else if(ov instanceof Array){
355                     if (ov.length) {
356                             for(var i = 0, len = ov.length; i < len; i++) {
357                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
358                             }
359                         } else {
360                             buf.push(k, "=&");
361                         }
362                 }
363             }
364             buf.pop();
365             return buf.join("");
366         },
367          /**
368          * Safe version of encodeURIComponent
369          * @param {String} data 
370          * @return {String} 
371          */
372         
373         encodeURIComponent : function (data)
374         {
375             try {
376                 return encodeURIComponent(data);
377             } catch(e) {} // should be an uri encode error.
378             
379             if (data == '' || data == null){
380                return '';
381             }
382             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
383             function nibble_to_hex(nibble){
384                 var chars = '0123456789ABCDEF';
385                 return chars.charAt(nibble);
386             }
387             data = data.toString();
388             var buffer = '';
389             for(var i=0; i<data.length; i++){
390                 var c = data.charCodeAt(i);
391                 var bs = new Array();
392                 if (c > 0x10000){
393                         // 4 bytes
394                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
395                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
396                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
397                     bs[3] = 0x80 | (c & 0x3F);
398                 }else if (c > 0x800){
399                          // 3 bytes
400                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
401                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
402                     bs[2] = 0x80 | (c & 0x3F);
403                 }else if (c > 0x80){
404                        // 2 bytes
405                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
406                     bs[1] = 0x80 | (c & 0x3F);
407                 }else{
408                         // 1 byte
409                     bs[0] = c;
410                 }
411                 for(var j=0; j<bs.length; j++){
412                     var b = bs[j];
413                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
414                             + nibble_to_hex(b &0x0F);
415                     buffer += '%'+hex;
416                }
417             }
418             return buffer;    
419              
420         },
421
422         /**
423          * 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]}.
424          * @param {String} string
425          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
426          * @return {Object} A literal with members
427          */
428         urlDecode : function(string, overwrite){
429             if(!string || !string.length){
430                 return {};
431             }
432             var obj = {};
433             var pairs = string.split('&');
434             var pair, name, value;
435             for(var i = 0, len = pairs.length; i < len; i++){
436                 pair = pairs[i].split('=');
437                 name = decodeURIComponent(pair[0]);
438                 value = decodeURIComponent(pair[1]);
439                 if(overwrite !== true){
440                     if(typeof obj[name] == "undefined"){
441                         obj[name] = value;
442                     }else if(typeof obj[name] == "string"){
443                         obj[name] = [obj[name]];
444                         obj[name].push(value);
445                     }else{
446                         obj[name].push(value);
447                     }
448                 }else{
449                     obj[name] = value;
450                 }
451             }
452             return obj;
453         },
454
455         /**
456          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
457          * passed array is not really an array, your function is called once with it.
458          * The supplied function is called with (Object item, Number index, Array allItems).
459          * @param {Array/NodeList/Mixed} array
460          * @param {Function} fn
461          * @param {Object} scope
462          */
463         each : function(array, fn, scope){
464             if(typeof array.length == "undefined" || typeof array == "string"){
465                 array = [array];
466             }
467             for(var i = 0, len = array.length; i < len; i++){
468                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
469             }
470         },
471
472         // deprecated
473         combine : function(){
474             var as = arguments, l = as.length, r = [];
475             for(var i = 0; i < l; i++){
476                 var a = as[i];
477                 if(a instanceof Array){
478                     r = r.concat(a);
479                 }else if(a.length !== undefined && !a.substr){
480                     r = r.concat(Array.prototype.slice.call(a, 0));
481                 }else{
482                     r.push(a);
483                 }
484             }
485             return r;
486         },
487
488         /**
489          * Escapes the passed string for use in a regular expression
490          * @param {String} str
491          * @return {String}
492          */
493         escapeRe : function(s) {
494             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
495         },
496
497         // internal
498         callback : function(cb, scope, args, delay){
499             if(typeof cb == "function"){
500                 if(delay){
501                     cb.defer(delay, scope, args || []);
502                 }else{
503                     cb.apply(scope, args || []);
504                 }
505             }
506         },
507
508         /**
509          * Return the dom node for the passed string (id), dom node, or Roo.Element
510          * @param {String/HTMLElement/Roo.Element} el
511          * @return HTMLElement
512          */
513         getDom : function(el){
514             if(!el){
515                 return null;
516             }
517             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
518         },
519
520         /**
521         * Shorthand for {@link Roo.ComponentMgr#get}
522         * @param {String} id
523         * @return Roo.Component
524         */
525         getCmp : function(id){
526             return Roo.ComponentMgr.get(id);
527         },
528          
529         num : function(v, defaultValue){
530             if(typeof v != 'number'){
531                 return defaultValue;
532             }
533             return v;
534         },
535
536         destroy : function(){
537             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
538                 var as = a[i];
539                 if(as){
540                     if(as.dom){
541                         as.removeAllListeners();
542                         as.remove();
543                         continue;
544                     }
545                     if(typeof as.purgeListeners == 'function'){
546                         as.purgeListeners();
547                     }
548                     if(typeof as.destroy == 'function'){
549                         as.destroy();
550                     }
551                 }
552             }
553         },
554
555         // inpired by a similar function in mootools library
556         /**
557          * Returns the type of object that is passed in. If the object passed in is null or undefined it
558          * return false otherwise it returns one of the following values:<ul>
559          * <li><b>string</b>: If the object passed is a string</li>
560          * <li><b>number</b>: If the object passed is a number</li>
561          * <li><b>boolean</b>: If the object passed is a boolean value</li>
562          * <li><b>function</b>: If the object passed is a function reference</li>
563          * <li><b>object</b>: If the object passed is an object</li>
564          * <li><b>array</b>: If the object passed is an array</li>
565          * <li><b>regexp</b>: If the object passed is a regular expression</li>
566          * <li><b>element</b>: If the object passed is a DOM Element</li>
567          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
568          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
569          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
570          * @param {Mixed} object
571          * @return {String}
572          */
573         type : function(o){
574             if(o === undefined || o === null){
575                 return false;
576             }
577             if(o.htmlElement){
578                 return 'element';
579             }
580             var t = typeof o;
581             if(t == 'object' && o.nodeName) {
582                 switch(o.nodeType) {
583                     case 1: return 'element';
584                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
585                 }
586             }
587             if(t == 'object' || t == 'function') {
588                 switch(o.constructor) {
589                     case Array: return 'array';
590                     case RegExp: return 'regexp';
591                 }
592                 if(typeof o.length == 'number' && typeof o.item == 'function') {
593                     return 'nodelist';
594                 }
595             }
596             return t;
597         },
598
599         /**
600          * Returns true if the passed value is null, undefined or an empty string (optional).
601          * @param {Mixed} value The value to test
602          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
603          * @return {Boolean}
604          */
605         isEmpty : function(v, allowBlank){
606             return v === null || v === undefined || (!allowBlank ? v === '' : false);
607         },
608         
609         /** @type Boolean */
610         isOpera : isOpera,
611         /** @type Boolean */
612         isSafari : isSafari,
613         /** @type Boolean */
614         isFirefox : isFirefox,
615         /** @type Boolean */
616         isIE : isIE,
617         /** @type Boolean */
618         isIE7 : isIE7,
619         /** @type Boolean */
620         isGecko : isGecko,
621         /** @type Boolean */
622         isBorderBox : isBorderBox,
623         /** @type Boolean */
624         isWindows : isWindows,
625         /** @type Boolean */
626         isLinux : isLinux,
627         /** @type Boolean */
628         isMac : isMac,
629         /** @type Boolean */
630         isTouch : isTouch,
631
632         /**
633          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
634          * you may want to set this to true.
635          * @type Boolean
636          */
637         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
638         
639         
640                 
641         /**
642          * Selects a single element as a Roo Element
643          * This is about as close as you can get to jQuery's $('do crazy stuff')
644          * @param {String} selector The selector/xpath query
645          * @param {Node} root (optional) The start of the query (defaults to document).
646          * @return {Roo.Element}
647          */
648         selectNode : function(selector, root) 
649         {
650             var node = Roo.DomQuery.selectNode(selector,root);
651             return node ? Roo.get(node) : new Roo.Element(false);
652         }
653         
654     });
655
656
657 })();
658
659 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
660                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
661                 "Roo.app", "Roo.ux",
662                 "Roo.bootstrap",
663                 "Roo.bootstrap.dash");
664 /*
665  * Based on:
666  * Ext JS Library 1.1.1
667  * Copyright(c) 2006-2007, Ext JS, LLC.
668  *
669  * Originally Released Under LGPL - original licence link has changed is not relivant.
670  *
671  * Fork - LGPL
672  * <script type="text/javascript">
673  */
674
675 (function() {    
676     // wrappedn so fnCleanup is not in global scope...
677     if(Roo.isIE) {
678         function fnCleanUp() {
679             var p = Function.prototype;
680             delete p.createSequence;
681             delete p.defer;
682             delete p.createDelegate;
683             delete p.createCallback;
684             delete p.createInterceptor;
685
686             window.detachEvent("onunload", fnCleanUp);
687         }
688         window.attachEvent("onunload", fnCleanUp);
689     }
690 })();
691
692
693 /**
694  * @class Function
695  * These functions are available on every Function object (any JavaScript function).
696  */
697 Roo.apply(Function.prototype, {
698      /**
699      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
700      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
701      * Will create a function that is bound to those 2 args.
702      * @return {Function} The new function
703     */
704     createCallback : function(/*args...*/){
705         // make args available, in function below
706         var args = arguments;
707         var method = this;
708         return function() {
709             return method.apply(window, args);
710         };
711     },
712
713     /**
714      * Creates a delegate (callback) that sets the scope to obj.
715      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
716      * Will create a function that is automatically scoped to this.
717      * @param {Object} obj (optional) The object for which the scope is set
718      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
719      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
720      *                                             if a number the args are inserted at the specified position
721      * @return {Function} The new function
722      */
723     createDelegate : function(obj, args, appendArgs){
724         var method = this;
725         return function() {
726             var callArgs = args || arguments;
727             if(appendArgs === true){
728                 callArgs = Array.prototype.slice.call(arguments, 0);
729                 callArgs = callArgs.concat(args);
730             }else if(typeof appendArgs == "number"){
731                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
732                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
733                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
734             }
735             return method.apply(obj || window, callArgs);
736         };
737     },
738
739     /**
740      * Calls this function after the number of millseconds specified.
741      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
742      * @param {Object} obj (optional) The object for which the scope is set
743      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
744      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
745      *                                             if a number the args are inserted at the specified position
746      * @return {Number} The timeout id that can be used with clearTimeout
747      */
748     defer : function(millis, obj, args, appendArgs){
749         var fn = this.createDelegate(obj, args, appendArgs);
750         if(millis){
751             return setTimeout(fn, millis);
752         }
753         fn();
754         return 0;
755     },
756     /**
757      * Create a combined function call sequence of the original function + the passed function.
758      * The resulting function returns the results of the original function.
759      * The passed fcn is called with the parameters of the original function
760      * @param {Function} fcn The function to sequence
761      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
762      * @return {Function} The new function
763      */
764     createSequence : function(fcn, scope){
765         if(typeof fcn != "function"){
766             return this;
767         }
768         var method = this;
769         return function() {
770             var retval = method.apply(this || window, arguments);
771             fcn.apply(scope || this || window, arguments);
772             return retval;
773         };
774     },
775
776     /**
777      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
778      * The resulting function returns the results of the original function.
779      * The passed fcn is called with the parameters of the original function.
780      * @addon
781      * @param {Function} fcn The function to call before the original
782      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
783      * @return {Function} The new function
784      */
785     createInterceptor : function(fcn, scope){
786         if(typeof fcn != "function"){
787             return this;
788         }
789         var method = this;
790         return function() {
791             fcn.target = this;
792             fcn.method = method;
793             if(fcn.apply(scope || this || window, arguments) === false){
794                 return;
795             }
796             return method.apply(this || window, arguments);
797         };
798     }
799 });
800 /*
801  * Based on:
802  * Ext JS Library 1.1.1
803  * Copyright(c) 2006-2007, Ext JS, LLC.
804  *
805  * Originally Released Under LGPL - original licence link has changed is not relivant.
806  *
807  * Fork - LGPL
808  * <script type="text/javascript">
809  */
810
811 Roo.applyIf(String, {
812     
813     /** @scope String */
814     
815     /**
816      * Escapes the passed string for ' and \
817      * @param {String} string The string to escape
818      * @return {String} The escaped string
819      * @static
820      */
821     escape : function(string) {
822         return string.replace(/('|\\)/g, "\\$1");
823     },
824
825     /**
826      * Pads the left side of a string with a specified character.  This is especially useful
827      * for normalizing number and date strings.  Example usage:
828      * <pre><code>
829 var s = String.leftPad('123', 5, '0');
830 // s now contains the string: '00123'
831 </code></pre>
832      * @param {String} string The original string
833      * @param {Number} size The total length of the output string
834      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
835      * @return {String} The padded string
836      * @static
837      */
838     leftPad : function (val, size, ch) {
839         var result = new String(val);
840         if(ch === null || ch === undefined || ch === '') {
841             ch = " ";
842         }
843         while (result.length < size) {
844             result = ch + result;
845         }
846         return result;
847     },
848
849     /**
850      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
851      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
852      * <pre><code>
853 var cls = 'my-class', text = 'Some text';
854 var s = String.format('<div class="{0}">{1}</div>', cls, text);
855 // s now contains the string: '<div class="my-class">Some text</div>'
856 </code></pre>
857      * @param {String} string The tokenized string to be formatted
858      * @param {String} value1 The value to replace token {0}
859      * @param {String} value2 Etc...
860      * @return {String} The formatted string
861      * @static
862      */
863     format : function(format){
864         var args = Array.prototype.slice.call(arguments, 1);
865         return format.replace(/\{(\d+)\}/g, function(m, i){
866             return Roo.util.Format.htmlEncode(args[i]);
867         });
868     }
869 });
870
871 /**
872  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
873  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
874  * they are already different, the first value passed in is returned.  Note that this method returns the new value
875  * but does not change the current string.
876  * <pre><code>
877 // alternate sort directions
878 sort = sort.toggle('ASC', 'DESC');
879
880 // instead of conditional logic:
881 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
882 </code></pre>
883  * @param {String} value The value to compare to the current string
884  * @param {String} other The new value to use if the string already equals the first value passed in
885  * @return {String} The new value
886  */
887  
888 String.prototype.toggle = function(value, other){
889     return this == value ? other : value;
890 };/*
891  * Based on:
892  * Ext JS Library 1.1.1
893  * Copyright(c) 2006-2007, Ext JS, LLC.
894  *
895  * Originally Released Under LGPL - original licence link has changed is not relivant.
896  *
897  * Fork - LGPL
898  * <script type="text/javascript">
899  */
900
901  /**
902  * @class Number
903  */
904 Roo.applyIf(Number.prototype, {
905     /**
906      * Checks whether or not the current number is within a desired range.  If the number is already within the
907      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
908      * exceeded.  Note that this method returns the constrained value but does not change the current number.
909      * @param {Number} min The minimum number in the range
910      * @param {Number} max The maximum number in the range
911      * @return {Number} The constrained value if outside the range, otherwise the current value
912      */
913     constrain : function(min, max){
914         return Math.min(Math.max(this, min), max);
915     }
916 });/*
917  * Based on:
918  * Ext JS Library 1.1.1
919  * Copyright(c) 2006-2007, Ext JS, LLC.
920  *
921  * Originally Released Under LGPL - original licence link has changed is not relivant.
922  *
923  * Fork - LGPL
924  * <script type="text/javascript">
925  */
926  /**
927  * @class Array
928  */
929 Roo.applyIf(Array.prototype, {
930     /**
931      * 
932      * Checks whether or not the specified object exists in the array.
933      * @param {Object} o The object to check for
934      * @return {Number} The index of o in the array (or -1 if it is not found)
935      */
936     indexOf : function(o){
937        for (var i = 0, len = this.length; i < len; i++){
938               if(this[i] == o) return i;
939        }
940            return -1;
941     },
942
943     /**
944      * Removes the specified object from the array.  If the object is not found nothing happens.
945      * @param {Object} o The object to remove
946      */
947     remove : function(o){
948        var index = this.indexOf(o);
949        if(index != -1){
950            this.splice(index, 1);
951        }
952     },
953     /**
954      * Map (JS 1.6 compatibility)
955      * @param {Function} function  to call
956      */
957     map : function(fun )
958     {
959         var len = this.length >>> 0;
960         if (typeof fun != "function")
961             throw new TypeError();
962
963         var res = new Array(len);
964         var thisp = arguments[1];
965         for (var i = 0; i < len; i++)
966         {
967             if (i in this)
968                 res[i] = fun.call(thisp, this[i], i, this);
969         }
970
971         return res;
972     }
973     
974 });
975
976
977  /*
978  * Based on:
979  * Ext JS Library 1.1.1
980  * Copyright(c) 2006-2007, Ext JS, LLC.
981  *
982  * Originally Released Under LGPL - original licence link has changed is not relivant.
983  *
984  * Fork - LGPL
985  * <script type="text/javascript">
986  */
987
988 /**
989  * @class Date
990  *
991  * The date parsing and format syntax is a subset of
992  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
993  * supported will provide results equivalent to their PHP versions.
994  *
995  * Following is the list of all currently supported formats:
996  *<pre>
997 Sample date:
998 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
999
1000 Format  Output      Description
1001 ------  ----------  --------------------------------------------------------------
1002   d      10         Day of the month, 2 digits with leading zeros
1003   D      Wed        A textual representation of a day, three letters
1004   j      10         Day of the month without leading zeros
1005   l      Wednesday  A full textual representation of the day of the week
1006   S      th         English ordinal day of month suffix, 2 chars (use with j)
1007   w      3          Numeric representation of the day of the week
1008   z      9          The julian date, or day of the year (0-365)
1009   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1010   F      January    A full textual representation of the month
1011   m      01         Numeric representation of a month, with leading zeros
1012   M      Jan        Month name abbreviation, three letters
1013   n      1          Numeric representation of a month, without leading zeros
1014   t      31         Number of days in the given month
1015   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1016   Y      2007       A full numeric representation of a year, 4 digits
1017   y      07         A two digit representation of a year
1018   a      pm         Lowercase Ante meridiem and Post meridiem
1019   A      PM         Uppercase Ante meridiem and Post meridiem
1020   g      3          12-hour format of an hour without leading zeros
1021   G      15         24-hour format of an hour without leading zeros
1022   h      03         12-hour format of an hour with leading zeros
1023   H      15         24-hour format of an hour with leading zeros
1024   i      05         Minutes with leading zeros
1025   s      01         Seconds, with leading zeros
1026   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1027   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1028   T      CST        Timezone setting of the machine running the code
1029   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1030 </pre>
1031  *
1032  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1033  * <pre><code>
1034 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1035 document.write(dt.format('Y-m-d'));                         //2007-01-10
1036 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1037 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
1038  </code></pre>
1039  *
1040  * Here are some standard date/time patterns that you might find helpful.  They
1041  * are not part of the source of Date.js, but to use them you can simply copy this
1042  * block of code into any script that is included after Date.js and they will also become
1043  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1044  * <pre><code>
1045 Date.patterns = {
1046     ISO8601Long:"Y-m-d H:i:s",
1047     ISO8601Short:"Y-m-d",
1048     ShortDate: "n/j/Y",
1049     LongDate: "l, F d, Y",
1050     FullDateTime: "l, F d, Y g:i:s A",
1051     MonthDay: "F d",
1052     ShortTime: "g:i A",
1053     LongTime: "g:i:s A",
1054     SortableDateTime: "Y-m-d\\TH:i:s",
1055     UniversalSortableDateTime: "Y-m-d H:i:sO",
1056     YearMonth: "F, Y"
1057 };
1058 </code></pre>
1059  *
1060  * Example usage:
1061  * <pre><code>
1062 var dt = new Date();
1063 document.write(dt.format(Date.patterns.ShortDate));
1064  </code></pre>
1065  */
1066
1067 /*
1068  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1069  * They generate precompiled functions from date formats instead of parsing and
1070  * processing the pattern every time you format a date.  These functions are available
1071  * on every Date object (any javascript function).
1072  *
1073  * The original article and download are here:
1074  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1075  *
1076  */
1077  
1078  
1079  // was in core
1080 /**
1081  Returns the number of milliseconds between this date and date
1082  @param {Date} date (optional) Defaults to now
1083  @return {Number} The diff in milliseconds
1084  @member Date getElapsed
1085  */
1086 Date.prototype.getElapsed = function(date) {
1087         return Math.abs((date || new Date()).getTime()-this.getTime());
1088 };
1089 // was in date file..
1090
1091
1092 // private
1093 Date.parseFunctions = {count:0};
1094 // private
1095 Date.parseRegexes = [];
1096 // private
1097 Date.formatFunctions = {count:0};
1098
1099 // private
1100 Date.prototype.dateFormat = function(format) {
1101     if (Date.formatFunctions[format] == null) {
1102         Date.createNewFormat(format);
1103     }
1104     var func = Date.formatFunctions[format];
1105     return this[func]();
1106 };
1107
1108
1109 /**
1110  * Formats a date given the supplied format string
1111  * @param {String} format The format string
1112  * @return {String} The formatted date
1113  * @method
1114  */
1115 Date.prototype.format = Date.prototype.dateFormat;
1116
1117 // private
1118 Date.createNewFormat = function(format) {
1119     var funcName = "format" + Date.formatFunctions.count++;
1120     Date.formatFunctions[format] = funcName;
1121     var code = "Date.prototype." + funcName + " = function(){return ";
1122     var special = false;
1123     var ch = '';
1124     for (var i = 0; i < format.length; ++i) {
1125         ch = format.charAt(i);
1126         if (!special && ch == "\\") {
1127             special = true;
1128         }
1129         else if (special) {
1130             special = false;
1131             code += "'" + String.escape(ch) + "' + ";
1132         }
1133         else {
1134             code += Date.getFormatCode(ch);
1135         }
1136     }
1137     /** eval:var:zzzzzzzzzzzzz */
1138     eval(code.substring(0, code.length - 3) + ";}");
1139 };
1140
1141 // private
1142 Date.getFormatCode = function(character) {
1143     switch (character) {
1144     case "d":
1145         return "String.leftPad(this.getDate(), 2, '0') + ";
1146     case "D":
1147         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1148     case "j":
1149         return "this.getDate() + ";
1150     case "l":
1151         return "Date.dayNames[this.getDay()] + ";
1152     case "S":
1153         return "this.getSuffix() + ";
1154     case "w":
1155         return "this.getDay() + ";
1156     case "z":
1157         return "this.getDayOfYear() + ";
1158     case "W":
1159         return "this.getWeekOfYear() + ";
1160     case "F":
1161         return "Date.monthNames[this.getMonth()] + ";
1162     case "m":
1163         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1164     case "M":
1165         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1166     case "n":
1167         return "(this.getMonth() + 1) + ";
1168     case "t":
1169         return "this.getDaysInMonth() + ";
1170     case "L":
1171         return "(this.isLeapYear() ? 1 : 0) + ";
1172     case "Y":
1173         return "this.getFullYear() + ";
1174     case "y":
1175         return "('' + this.getFullYear()).substring(2, 4) + ";
1176     case "a":
1177         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1178     case "A":
1179         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1180     case "g":
1181         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1182     case "G":
1183         return "this.getHours() + ";
1184     case "h":
1185         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1186     case "H":
1187         return "String.leftPad(this.getHours(), 2, '0') + ";
1188     case "i":
1189         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1190     case "s":
1191         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1192     case "O":
1193         return "this.getGMTOffset() + ";
1194     case "P":
1195         return "this.getGMTColonOffset() + ";
1196     case "T":
1197         return "this.getTimezone() + ";
1198     case "Z":
1199         return "(this.getTimezoneOffset() * -60) + ";
1200     default:
1201         return "'" + String.escape(character) + "' + ";
1202     }
1203 };
1204
1205 /**
1206  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1207  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1208  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1209  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1210  * string or the parse operation will fail.
1211  * Example Usage:
1212 <pre><code>
1213 //dt = Fri May 25 2007 (current date)
1214 var dt = new Date();
1215
1216 //dt = Thu May 25 2006 (today's month/day in 2006)
1217 dt = Date.parseDate("2006", "Y");
1218
1219 //dt = Sun Jan 15 2006 (all date parts specified)
1220 dt = Date.parseDate("2006-1-15", "Y-m-d");
1221
1222 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1223 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1224 </code></pre>
1225  * @param {String} input The unparsed date as a string
1226  * @param {String} format The format the date is in
1227  * @return {Date} The parsed date
1228  * @static
1229  */
1230 Date.parseDate = function(input, format) {
1231     if (Date.parseFunctions[format] == null) {
1232         Date.createParser(format);
1233     }
1234     var func = Date.parseFunctions[format];
1235     return Date[func](input);
1236 };
1237 /**
1238  * @private
1239  */
1240
1241 Date.createParser = function(format) {
1242     var funcName = "parse" + Date.parseFunctions.count++;
1243     var regexNum = Date.parseRegexes.length;
1244     var currentGroup = 1;
1245     Date.parseFunctions[format] = funcName;
1246
1247     var code = "Date." + funcName + " = function(input){\n"
1248         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1249         + "var d = new Date();\n"
1250         + "y = d.getFullYear();\n"
1251         + "m = d.getMonth();\n"
1252         + "d = d.getDate();\n"
1253         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1254         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1255         + "if (results && results.length > 0) {";
1256     var regex = "";
1257
1258     var special = false;
1259     var ch = '';
1260     for (var i = 0; i < format.length; ++i) {
1261         ch = format.charAt(i);
1262         if (!special && ch == "\\") {
1263             special = true;
1264         }
1265         else if (special) {
1266             special = false;
1267             regex += String.escape(ch);
1268         }
1269         else {
1270             var obj = Date.formatCodeToRegex(ch, currentGroup);
1271             currentGroup += obj.g;
1272             regex += obj.s;
1273             if (obj.g && obj.c) {
1274                 code += obj.c;
1275             }
1276         }
1277     }
1278
1279     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1280         + "{v = new Date(y, m, d, h, i, s);}\n"
1281         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1282         + "{v = new Date(y, m, d, h, i);}\n"
1283         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1284         + "{v = new Date(y, m, d, h);}\n"
1285         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1286         + "{v = new Date(y, m, d);}\n"
1287         + "else if (y >= 0 && m >= 0)\n"
1288         + "{v = new Date(y, m);}\n"
1289         + "else if (y >= 0)\n"
1290         + "{v = new Date(y);}\n"
1291         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1292         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1293         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1294         + ";}";
1295
1296     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1297     /** eval:var:zzzzzzzzzzzzz */
1298     eval(code);
1299 };
1300
1301 // private
1302 Date.formatCodeToRegex = function(character, currentGroup) {
1303     switch (character) {
1304     case "D":
1305         return {g:0,
1306         c:null,
1307         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1308     case "j":
1309         return {g:1,
1310             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1311             s:"(\\d{1,2})"}; // day of month without leading zeroes
1312     case "d":
1313         return {g:1,
1314             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1315             s:"(\\d{2})"}; // day of month with leading zeroes
1316     case "l":
1317         return {g:0,
1318             c:null,
1319             s:"(?:" + Date.dayNames.join("|") + ")"};
1320     case "S":
1321         return {g:0,
1322             c:null,
1323             s:"(?:st|nd|rd|th)"};
1324     case "w":
1325         return {g:0,
1326             c:null,
1327             s:"\\d"};
1328     case "z":
1329         return {g:0,
1330             c:null,
1331             s:"(?:\\d{1,3})"};
1332     case "W":
1333         return {g:0,
1334             c:null,
1335             s:"(?:\\d{2})"};
1336     case "F":
1337         return {g:1,
1338             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1339             s:"(" + Date.monthNames.join("|") + ")"};
1340     case "M":
1341         return {g:1,
1342             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1343             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1344     case "n":
1345         return {g:1,
1346             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1347             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1348     case "m":
1349         return {g:1,
1350             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1351             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1352     case "t":
1353         return {g:0,
1354             c:null,
1355             s:"\\d{1,2}"};
1356     case "L":
1357         return {g:0,
1358             c:null,
1359             s:"(?:1|0)"};
1360     case "Y":
1361         return {g:1,
1362             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1363             s:"(\\d{4})"};
1364     case "y":
1365         return {g:1,
1366             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1367                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1368             s:"(\\d{1,2})"};
1369     case "a":
1370         return {g:1,
1371             c:"if (results[" + currentGroup + "] == 'am') {\n"
1372                 + "if (h == 12) { h = 0; }\n"
1373                 + "} else { if (h < 12) { h += 12; }}",
1374             s:"(am|pm)"};
1375     case "A":
1376         return {g:1,
1377             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1378                 + "if (h == 12) { h = 0; }\n"
1379                 + "} else { if (h < 12) { h += 12; }}",
1380             s:"(AM|PM)"};
1381     case "g":
1382     case "G":
1383         return {g:1,
1384             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1385             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1386     case "h":
1387     case "H":
1388         return {g:1,
1389             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1390             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1391     case "i":
1392         return {g:1,
1393             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1394             s:"(\\d{2})"};
1395     case "s":
1396         return {g:1,
1397             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1398             s:"(\\d{2})"};
1399     case "O":
1400         return {g:1,
1401             c:[
1402                 "o = results[", currentGroup, "];\n",
1403                 "var sn = o.substring(0,1);\n", // get + / - sign
1404                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1405                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1406                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1407                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1408             ].join(""),
1409             s:"([+\-]\\d{2,4})"};
1410     
1411     
1412     case "P":
1413         return {g:1,
1414                 c:[
1415                    "o = results[", currentGroup, "];\n",
1416                    "var sn = o.substring(0,1);\n",
1417                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1418                    "var mn = o.substring(4,6) % 60;\n",
1419                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1420                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1421             ].join(""),
1422             s:"([+\-]\\d{4})"};
1423     case "T":
1424         return {g:0,
1425             c:null,
1426             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1427     case "Z":
1428         return {g:1,
1429             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1430                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1431             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1432     default:
1433         return {g:0,
1434             c:null,
1435             s:String.escape(character)};
1436     }
1437 };
1438
1439 /**
1440  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1441  * @return {String} The abbreviated timezone name (e.g. 'CST')
1442  */
1443 Date.prototype.getTimezone = function() {
1444     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1445 };
1446
1447 /**
1448  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1449  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1450  */
1451 Date.prototype.getGMTOffset = function() {
1452     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1453         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1454         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1455 };
1456
1457 /**
1458  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1459  * @return {String} 2-characters representing hours and 2-characters representing minutes
1460  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1461  */
1462 Date.prototype.getGMTColonOffset = function() {
1463         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1464                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1465                 + ":"
1466                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1467 }
1468
1469 /**
1470  * Get the numeric day number of the year, adjusted for leap year.
1471  * @return {Number} 0 through 364 (365 in leap years)
1472  */
1473 Date.prototype.getDayOfYear = function() {
1474     var num = 0;
1475     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1476     for (var i = 0; i < this.getMonth(); ++i) {
1477         num += Date.daysInMonth[i];
1478     }
1479     return num + this.getDate() - 1;
1480 };
1481
1482 /**
1483  * Get the string representation of the numeric week number of the year
1484  * (equivalent to the format specifier 'W').
1485  * @return {String} '00' through '52'
1486  */
1487 Date.prototype.getWeekOfYear = function() {
1488     // Skip to Thursday of this week
1489     var now = this.getDayOfYear() + (4 - this.getDay());
1490     // Find the first Thursday of the year
1491     var jan1 = new Date(this.getFullYear(), 0, 1);
1492     var then = (7 - jan1.getDay() + 4);
1493     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1494 };
1495
1496 /**
1497  * Whether or not the current date is in a leap year.
1498  * @return {Boolean} True if the current date is in a leap year, else false
1499  */
1500 Date.prototype.isLeapYear = function() {
1501     var year = this.getFullYear();
1502     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1503 };
1504
1505 /**
1506  * Get the first day of the current month, adjusted for leap year.  The returned value
1507  * is the numeric day index within the week (0-6) which can be used in conjunction with
1508  * the {@link #monthNames} array to retrieve the textual day name.
1509  * Example:
1510  *<pre><code>
1511 var dt = new Date('1/10/2007');
1512 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1513 </code></pre>
1514  * @return {Number} The day number (0-6)
1515  */
1516 Date.prototype.getFirstDayOfMonth = function() {
1517     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1518     return (day < 0) ? (day + 7) : day;
1519 };
1520
1521 /**
1522  * Get the last day of the current month, adjusted for leap year.  The returned value
1523  * is the numeric day index within the week (0-6) which can be used in conjunction with
1524  * the {@link #monthNames} array to retrieve the textual day name.
1525  * Example:
1526  *<pre><code>
1527 var dt = new Date('1/10/2007');
1528 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1529 </code></pre>
1530  * @return {Number} The day number (0-6)
1531  */
1532 Date.prototype.getLastDayOfMonth = function() {
1533     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1534     return (day < 0) ? (day + 7) : day;
1535 };
1536
1537
1538 /**
1539  * Get the first date of this date's month
1540  * @return {Date}
1541  */
1542 Date.prototype.getFirstDateOfMonth = function() {
1543     return new Date(this.getFullYear(), this.getMonth(), 1);
1544 };
1545
1546 /**
1547  * Get the last date of this date's month
1548  * @return {Date}
1549  */
1550 Date.prototype.getLastDateOfMonth = function() {
1551     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1552 };
1553 /**
1554  * Get the number of days in the current month, adjusted for leap year.
1555  * @return {Number} The number of days in the month
1556  */
1557 Date.prototype.getDaysInMonth = function() {
1558     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1559     return Date.daysInMonth[this.getMonth()];
1560 };
1561
1562 /**
1563  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1564  * @return {String} 'st, 'nd', 'rd' or 'th'
1565  */
1566 Date.prototype.getSuffix = function() {
1567     switch (this.getDate()) {
1568         case 1:
1569         case 21:
1570         case 31:
1571             return "st";
1572         case 2:
1573         case 22:
1574             return "nd";
1575         case 3:
1576         case 23:
1577             return "rd";
1578         default:
1579             return "th";
1580     }
1581 };
1582
1583 // private
1584 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1585
1586 /**
1587  * An array of textual month names.
1588  * Override these values for international dates, for example...
1589  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1590  * @type Array
1591  * @static
1592  */
1593 Date.monthNames =
1594    ["January",
1595     "February",
1596     "March",
1597     "April",
1598     "May",
1599     "June",
1600     "July",
1601     "August",
1602     "September",
1603     "October",
1604     "November",
1605     "December"];
1606
1607 /**
1608  * An array of textual day names.
1609  * Override these values for international dates, for example...
1610  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1611  * @type Array
1612  * @static
1613  */
1614 Date.dayNames =
1615    ["Sunday",
1616     "Monday",
1617     "Tuesday",
1618     "Wednesday",
1619     "Thursday",
1620     "Friday",
1621     "Saturday"];
1622
1623 // private
1624 Date.y2kYear = 50;
1625 // private
1626 Date.monthNumbers = {
1627     Jan:0,
1628     Feb:1,
1629     Mar:2,
1630     Apr:3,
1631     May:4,
1632     Jun:5,
1633     Jul:6,
1634     Aug:7,
1635     Sep:8,
1636     Oct:9,
1637     Nov:10,
1638     Dec:11};
1639
1640 /**
1641  * Creates and returns a new Date instance with the exact same date value as the called instance.
1642  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1643  * variable will also be changed.  When the intention is to create a new variable that will not
1644  * modify the original instance, you should create a clone.
1645  *
1646  * Example of correctly cloning a date:
1647  * <pre><code>
1648 //wrong way:
1649 var orig = new Date('10/1/2006');
1650 var copy = orig;
1651 copy.setDate(5);
1652 document.write(orig);  //returns 'Thu Oct 05 2006'!
1653
1654 //correct way:
1655 var orig = new Date('10/1/2006');
1656 var copy = orig.clone();
1657 copy.setDate(5);
1658 document.write(orig);  //returns 'Thu Oct 01 2006'
1659 </code></pre>
1660  * @return {Date} The new Date instance
1661  */
1662 Date.prototype.clone = function() {
1663         return new Date(this.getTime());
1664 };
1665
1666 /**
1667  * Clears any time information from this date
1668  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1669  @return {Date} this or the clone
1670  */
1671 Date.prototype.clearTime = function(clone){
1672     if(clone){
1673         return this.clone().clearTime();
1674     }
1675     this.setHours(0);
1676     this.setMinutes(0);
1677     this.setSeconds(0);
1678     this.setMilliseconds(0);
1679     return this;
1680 };
1681
1682 // private
1683 // safari setMonth is broken
1684 if(Roo.isSafari){
1685     Date.brokenSetMonth = Date.prototype.setMonth;
1686         Date.prototype.setMonth = function(num){
1687                 if(num <= -1){
1688                         var n = Math.ceil(-num);
1689                         var back_year = Math.ceil(n/12);
1690                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1691                         this.setFullYear(this.getFullYear() - back_year);
1692                         return Date.brokenSetMonth.call(this, month);
1693                 } else {
1694                         return Date.brokenSetMonth.apply(this, arguments);
1695                 }
1696         };
1697 }
1698
1699 /** Date interval constant 
1700 * @static 
1701 * @type String */
1702 Date.MILLI = "ms";
1703 /** Date interval constant 
1704 * @static 
1705 * @type String */
1706 Date.SECOND = "s";
1707 /** Date interval constant 
1708 * @static 
1709 * @type String */
1710 Date.MINUTE = "mi";
1711 /** Date interval constant 
1712 * @static 
1713 * @type String */
1714 Date.HOUR = "h";
1715 /** Date interval constant 
1716 * @static 
1717 * @type String */
1718 Date.DAY = "d";
1719 /** Date interval constant 
1720 * @static 
1721 * @type String */
1722 Date.MONTH = "mo";
1723 /** Date interval constant 
1724 * @static 
1725 * @type String */
1726 Date.YEAR = "y";
1727
1728 /**
1729  * Provides a convenient method of performing basic date arithmetic.  This method
1730  * does not modify the Date instance being called - it creates and returns
1731  * a new Date instance containing the resulting date value.
1732  *
1733  * Examples:
1734  * <pre><code>
1735 //Basic usage:
1736 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1737 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1738
1739 //Negative values will subtract correctly:
1740 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1741 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1742
1743 //You can even chain several calls together in one line!
1744 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1745 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1746  </code></pre>
1747  *
1748  * @param {String} interval   A valid date interval enum value
1749  * @param {Number} value      The amount to add to the current date
1750  * @return {Date} The new Date instance
1751  */
1752 Date.prototype.add = function(interval, value){
1753   var d = this.clone();
1754   if (!interval || value === 0) return d;
1755   switch(interval.toLowerCase()){
1756     case Date.MILLI:
1757       d.setMilliseconds(this.getMilliseconds() + value);
1758       break;
1759     case Date.SECOND:
1760       d.setSeconds(this.getSeconds() + value);
1761       break;
1762     case Date.MINUTE:
1763       d.setMinutes(this.getMinutes() + value);
1764       break;
1765     case Date.HOUR:
1766       d.setHours(this.getHours() + value);
1767       break;
1768     case Date.DAY:
1769       d.setDate(this.getDate() + value);
1770       break;
1771     case Date.MONTH:
1772       var day = this.getDate();
1773       if(day > 28){
1774           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1775       }
1776       d.setDate(day);
1777       d.setMonth(this.getMonth() + value);
1778       break;
1779     case Date.YEAR:
1780       d.setFullYear(this.getFullYear() + value);
1781       break;
1782   }
1783   return d;
1784 };
1785 /*
1786  * Based on:
1787  * Ext JS Library 1.1.1
1788  * Copyright(c) 2006-2007, Ext JS, LLC.
1789  *
1790  * Originally Released Under LGPL - original licence link has changed is not relivant.
1791  *
1792  * Fork - LGPL
1793  * <script type="text/javascript">
1794  */
1795
1796 /**
1797  * @class Roo.lib.Dom
1798  * @static
1799  * 
1800  * Dom utils (from YIU afaik)
1801  * 
1802  **/
1803 Roo.lib.Dom = {
1804     /**
1805      * Get the view width
1806      * @param {Boolean} full True will get the full document, otherwise it's the view width
1807      * @return {Number} The width
1808      */
1809      
1810     getViewWidth : function(full) {
1811         return full ? this.getDocumentWidth() : this.getViewportWidth();
1812     },
1813     /**
1814      * Get the view height
1815      * @param {Boolean} full True will get the full document, otherwise it's the view height
1816      * @return {Number} The height
1817      */
1818     getViewHeight : function(full) {
1819         return full ? this.getDocumentHeight() : this.getViewportHeight();
1820     },
1821
1822     getDocumentHeight: function() {
1823         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1824         return Math.max(scrollHeight, this.getViewportHeight());
1825     },
1826
1827     getDocumentWidth: function() {
1828         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1829         return Math.max(scrollWidth, this.getViewportWidth());
1830     },
1831
1832     getViewportHeight: function() {
1833         var height = self.innerHeight;
1834         var mode = document.compatMode;
1835
1836         if ((mode || Roo.isIE) && !Roo.isOpera) {
1837             height = (mode == "CSS1Compat") ?
1838                      document.documentElement.clientHeight :
1839                      document.body.clientHeight;
1840         }
1841
1842         return height;
1843     },
1844
1845     getViewportWidth: function() {
1846         var width = self.innerWidth;
1847         var mode = document.compatMode;
1848
1849         if (mode || Roo.isIE) {
1850             width = (mode == "CSS1Compat") ?
1851                     document.documentElement.clientWidth :
1852                     document.body.clientWidth;
1853         }
1854         return width;
1855     },
1856
1857     isAncestor : function(p, c) {
1858         p = Roo.getDom(p);
1859         c = Roo.getDom(c);
1860         if (!p || !c) {
1861             return false;
1862         }
1863
1864         if (p.contains && !Roo.isSafari) {
1865             return p.contains(c);
1866         } else if (p.compareDocumentPosition) {
1867             return !!(p.compareDocumentPosition(c) & 16);
1868         } else {
1869             var parent = c.parentNode;
1870             while (parent) {
1871                 if (parent == p) {
1872                     return true;
1873                 }
1874                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1875                     return false;
1876                 }
1877                 parent = parent.parentNode;
1878             }
1879             return false;
1880         }
1881     },
1882
1883     getRegion : function(el) {
1884         return Roo.lib.Region.getRegion(el);
1885     },
1886
1887     getY : function(el) {
1888         return this.getXY(el)[1];
1889     },
1890
1891     getX : function(el) {
1892         return this.getXY(el)[0];
1893     },
1894
1895     getXY : function(el) {
1896         var p, pe, b, scroll, bd = document.body;
1897         el = Roo.getDom(el);
1898         var fly = Roo.lib.AnimBase.fly;
1899         if (el.getBoundingClientRect) {
1900             b = el.getBoundingClientRect();
1901             scroll = fly(document).getScroll();
1902             return [b.left + scroll.left, b.top + scroll.top];
1903         }
1904         var x = 0, y = 0;
1905
1906         p = el;
1907
1908         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1909
1910         while (p) {
1911
1912             x += p.offsetLeft;
1913             y += p.offsetTop;
1914
1915             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1916                 hasAbsolute = true;
1917             }
1918
1919             if (Roo.isGecko) {
1920                 pe = fly(p);
1921
1922                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1923                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1924
1925
1926                 x += bl;
1927                 y += bt;
1928
1929
1930                 if (p != el && pe.getStyle('overflow') != 'visible') {
1931                     x += bl;
1932                     y += bt;
1933                 }
1934             }
1935             p = p.offsetParent;
1936         }
1937
1938         if (Roo.isSafari && hasAbsolute) {
1939             x -= bd.offsetLeft;
1940             y -= bd.offsetTop;
1941         }
1942
1943         if (Roo.isGecko && !hasAbsolute) {
1944             var dbd = fly(bd);
1945             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1946             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1947         }
1948
1949         p = el.parentNode;
1950         while (p && p != bd) {
1951             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1952                 x -= p.scrollLeft;
1953                 y -= p.scrollTop;
1954             }
1955             p = p.parentNode;
1956         }
1957         return [x, y];
1958     },
1959  
1960   
1961
1962
1963     setXY : function(el, xy) {
1964         el = Roo.fly(el, '_setXY');
1965         el.position();
1966         var pts = el.translatePoints(xy);
1967         if (xy[0] !== false) {
1968             el.dom.style.left = pts.left + "px";
1969         }
1970         if (xy[1] !== false) {
1971             el.dom.style.top = pts.top + "px";
1972         }
1973     },
1974
1975     setX : function(el, x) {
1976         this.setXY(el, [x, false]);
1977     },
1978
1979     setY : function(el, y) {
1980         this.setXY(el, [false, y]);
1981     }
1982 };
1983 /*
1984  * Portions of this file are based on pieces of Yahoo User Interface Library
1985  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1986  * YUI licensed under the BSD License:
1987  * http://developer.yahoo.net/yui/license.txt
1988  * <script type="text/javascript">
1989  *
1990  */
1991
1992 Roo.lib.Event = function() {
1993     var loadComplete = false;
1994     var listeners = [];
1995     var unloadListeners = [];
1996     var retryCount = 0;
1997     var onAvailStack = [];
1998     var counter = 0;
1999     var lastError = null;
2000
2001     return {
2002         POLL_RETRYS: 200,
2003         POLL_INTERVAL: 20,
2004         EL: 0,
2005         TYPE: 1,
2006         FN: 2,
2007         WFN: 3,
2008         OBJ: 3,
2009         ADJ_SCOPE: 4,
2010         _interval: null,
2011
2012         startInterval: function() {
2013             if (!this._interval) {
2014                 var self = this;
2015                 var callback = function() {
2016                     self._tryPreloadAttach();
2017                 };
2018                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2019
2020             }
2021         },
2022
2023         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2024             onAvailStack.push({ id:         p_id,
2025                 fn:         p_fn,
2026                 obj:        p_obj,
2027                 override:   p_override,
2028                 checkReady: false    });
2029
2030             retryCount = this.POLL_RETRYS;
2031             this.startInterval();
2032         },
2033
2034
2035         addListener: function(el, eventName, fn) {
2036             el = Roo.getDom(el);
2037             if (!el || !fn) {
2038                 return false;
2039             }
2040
2041             if ("unload" == eventName) {
2042                 unloadListeners[unloadListeners.length] =
2043                 [el, eventName, fn];
2044                 return true;
2045             }
2046
2047             var wrappedFn = function(e) {
2048                 return fn(Roo.lib.Event.getEvent(e));
2049             };
2050
2051             var li = [el, eventName, fn, wrappedFn];
2052
2053             var index = listeners.length;
2054             listeners[index] = li;
2055
2056             this.doAdd(el, eventName, wrappedFn, false);
2057             return true;
2058
2059         },
2060
2061
2062         removeListener: function(el, eventName, fn) {
2063             var i, len;
2064
2065             el = Roo.getDom(el);
2066
2067             if(!fn) {
2068                 return this.purgeElement(el, false, eventName);
2069             }
2070
2071
2072             if ("unload" == eventName) {
2073
2074                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2075                     var li = unloadListeners[i];
2076                     if (li &&
2077                         li[0] == el &&
2078                         li[1] == eventName &&
2079                         li[2] == fn) {
2080                         unloadListeners.splice(i, 1);
2081                         return true;
2082                     }
2083                 }
2084
2085                 return false;
2086             }
2087
2088             var cacheItem = null;
2089
2090
2091             var index = arguments[3];
2092
2093             if ("undefined" == typeof index) {
2094                 index = this._getCacheIndex(el, eventName, fn);
2095             }
2096
2097             if (index >= 0) {
2098                 cacheItem = listeners[index];
2099             }
2100
2101             if (!el || !cacheItem) {
2102                 return false;
2103             }
2104
2105             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2106
2107             delete listeners[index][this.WFN];
2108             delete listeners[index][this.FN];
2109             listeners.splice(index, 1);
2110
2111             return true;
2112
2113         },
2114
2115
2116         getTarget: function(ev, resolveTextNode) {
2117             ev = ev.browserEvent || ev;
2118             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2119             var t = ev.target || ev.srcElement;
2120             return this.resolveTextNode(t);
2121         },
2122
2123
2124         resolveTextNode: function(node) {
2125             if (Roo.isSafari && node && 3 == node.nodeType) {
2126                 return node.parentNode;
2127             } else {
2128                 return node;
2129             }
2130         },
2131
2132
2133         getPageX: function(ev) {
2134             ev = ev.browserEvent || ev;
2135             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2136             var x = ev.pageX;
2137             if (!x && 0 !== x) {
2138                 x = ev.clientX || 0;
2139
2140                 if (Roo.isIE) {
2141                     x += this.getScroll()[1];
2142                 }
2143             }
2144
2145             return x;
2146         },
2147
2148
2149         getPageY: function(ev) {
2150             ev = ev.browserEvent || ev;
2151             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2152             var y = ev.pageY;
2153             if (!y && 0 !== y) {
2154                 y = ev.clientY || 0;
2155
2156                 if (Roo.isIE) {
2157                     y += this.getScroll()[0];
2158                 }
2159             }
2160
2161
2162             return y;
2163         },
2164
2165
2166         getXY: function(ev) {
2167             ev = ev.browserEvent || ev;
2168             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2169             return [this.getPageX(ev), this.getPageY(ev)];
2170         },
2171
2172
2173         getRelatedTarget: function(ev) {
2174             ev = ev.browserEvent || ev;
2175             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2176             var t = ev.relatedTarget;
2177             if (!t) {
2178                 if (ev.type == "mouseout") {
2179                     t = ev.toElement;
2180                 } else if (ev.type == "mouseover") {
2181                     t = ev.fromElement;
2182                 }
2183             }
2184
2185             return this.resolveTextNode(t);
2186         },
2187
2188
2189         getTime: function(ev) {
2190             ev = ev.browserEvent || ev;
2191             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2192             if (!ev.time) {
2193                 var t = new Date().getTime();
2194                 try {
2195                     ev.time = t;
2196                 } catch(ex) {
2197                     this.lastError = ex;
2198                     return t;
2199                 }
2200             }
2201
2202             return ev.time;
2203         },
2204
2205
2206         stopEvent: function(ev) {
2207             this.stopPropagation(ev);
2208             this.preventDefault(ev);
2209         },
2210
2211
2212         stopPropagation: function(ev) {
2213             ev = ev.browserEvent || ev;
2214             if (ev.stopPropagation) {
2215                 ev.stopPropagation();
2216             } else {
2217                 ev.cancelBubble = true;
2218             }
2219         },
2220
2221
2222         preventDefault: function(ev) {
2223             ev = ev.browserEvent || ev;
2224             if(ev.preventDefault) {
2225                 ev.preventDefault();
2226             } else {
2227                 ev.returnValue = false;
2228             }
2229         },
2230
2231
2232         getEvent: function(e) {
2233             var ev = e || window.event;
2234             if (!ev) {
2235                 var c = this.getEvent.caller;
2236                 while (c) {
2237                     ev = c.arguments[0];
2238                     if (ev && Event == ev.constructor) {
2239                         break;
2240                     }
2241                     c = c.caller;
2242                 }
2243             }
2244             return ev;
2245         },
2246
2247
2248         getCharCode: function(ev) {
2249             ev = ev.browserEvent || ev;
2250             return ev.charCode || ev.keyCode || 0;
2251         },
2252
2253
2254         _getCacheIndex: function(el, eventName, fn) {
2255             for (var i = 0,len = listeners.length; i < len; ++i) {
2256                 var li = listeners[i];
2257                 if (li &&
2258                     li[this.FN] == fn &&
2259                     li[this.EL] == el &&
2260                     li[this.TYPE] == eventName) {
2261                     return i;
2262                 }
2263             }
2264
2265             return -1;
2266         },
2267
2268
2269         elCache: {},
2270
2271
2272         getEl: function(id) {
2273             return document.getElementById(id);
2274         },
2275
2276
2277         clearCache: function() {
2278         },
2279
2280
2281         _load: function(e) {
2282             loadComplete = true;
2283             var EU = Roo.lib.Event;
2284
2285
2286             if (Roo.isIE) {
2287                 EU.doRemove(window, "load", EU._load);
2288             }
2289         },
2290
2291
2292         _tryPreloadAttach: function() {
2293
2294             if (this.locked) {
2295                 return false;
2296             }
2297
2298             this.locked = true;
2299
2300
2301             var tryAgain = !loadComplete;
2302             if (!tryAgain) {
2303                 tryAgain = (retryCount > 0);
2304             }
2305
2306
2307             var notAvail = [];
2308             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2309                 var item = onAvailStack[i];
2310                 if (item) {
2311                     var el = this.getEl(item.id);
2312
2313                     if (el) {
2314                         if (!item.checkReady ||
2315                             loadComplete ||
2316                             el.nextSibling ||
2317                             (document && document.body)) {
2318
2319                             var scope = el;
2320                             if (item.override) {
2321                                 if (item.override === true) {
2322                                     scope = item.obj;
2323                                 } else {
2324                                     scope = item.override;
2325                                 }
2326                             }
2327                             item.fn.call(scope, item.obj);
2328                             onAvailStack[i] = null;
2329                         }
2330                     } else {
2331                         notAvail.push(item);
2332                     }
2333                 }
2334             }
2335
2336             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2337
2338             if (tryAgain) {
2339
2340                 this.startInterval();
2341             } else {
2342                 clearInterval(this._interval);
2343                 this._interval = null;
2344             }
2345
2346             this.locked = false;
2347
2348             return true;
2349
2350         },
2351
2352
2353         purgeElement: function(el, recurse, eventName) {
2354             var elListeners = this.getListeners(el, eventName);
2355             if (elListeners) {
2356                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2357                     var l = elListeners[i];
2358                     this.removeListener(el, l.type, l.fn);
2359                 }
2360             }
2361
2362             if (recurse && el && el.childNodes) {
2363                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2364                     this.purgeElement(el.childNodes[i], recurse, eventName);
2365                 }
2366             }
2367         },
2368
2369
2370         getListeners: function(el, eventName) {
2371             var results = [], searchLists;
2372             if (!eventName) {
2373                 searchLists = [listeners, unloadListeners];
2374             } else if (eventName == "unload") {
2375                 searchLists = [unloadListeners];
2376             } else {
2377                 searchLists = [listeners];
2378             }
2379
2380             for (var j = 0; j < searchLists.length; ++j) {
2381                 var searchList = searchLists[j];
2382                 if (searchList && searchList.length > 0) {
2383                     for (var i = 0,len = searchList.length; i < len; ++i) {
2384                         var l = searchList[i];
2385                         if (l && l[this.EL] === el &&
2386                             (!eventName || eventName === l[this.TYPE])) {
2387                             results.push({
2388                                 type:   l[this.TYPE],
2389                                 fn:     l[this.FN],
2390                                 obj:    l[this.OBJ],
2391                                 adjust: l[this.ADJ_SCOPE],
2392                                 index:  i
2393                             });
2394                         }
2395                     }
2396                 }
2397             }
2398
2399             return (results.length) ? results : null;
2400         },
2401
2402
2403         _unload: function(e) {
2404
2405             var EU = Roo.lib.Event, i, j, l, len, index;
2406
2407             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2408                 l = unloadListeners[i];
2409                 if (l) {
2410                     var scope = window;
2411                     if (l[EU.ADJ_SCOPE]) {
2412                         if (l[EU.ADJ_SCOPE] === true) {
2413                             scope = l[EU.OBJ];
2414                         } else {
2415                             scope = l[EU.ADJ_SCOPE];
2416                         }
2417                     }
2418                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2419                     unloadListeners[i] = null;
2420                     l = null;
2421                     scope = null;
2422                 }
2423             }
2424
2425             unloadListeners = null;
2426
2427             if (listeners && listeners.length > 0) {
2428                 j = listeners.length;
2429                 while (j) {
2430                     index = j - 1;
2431                     l = listeners[index];
2432                     if (l) {
2433                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2434                                 l[EU.FN], index);
2435                     }
2436                     j = j - 1;
2437                 }
2438                 l = null;
2439
2440                 EU.clearCache();
2441             }
2442
2443             EU.doRemove(window, "unload", EU._unload);
2444
2445         },
2446
2447
2448         getScroll: function() {
2449             var dd = document.documentElement, db = document.body;
2450             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2451                 return [dd.scrollTop, dd.scrollLeft];
2452             } else if (db) {
2453                 return [db.scrollTop, db.scrollLeft];
2454             } else {
2455                 return [0, 0];
2456             }
2457         },
2458
2459
2460         doAdd: function () {
2461             if (window.addEventListener) {
2462                 return function(el, eventName, fn, capture) {
2463                     el.addEventListener(eventName, fn, (capture));
2464                 };
2465             } else if (window.attachEvent) {
2466                 return function(el, eventName, fn, capture) {
2467                     el.attachEvent("on" + eventName, fn);
2468                 };
2469             } else {
2470                 return function() {
2471                 };
2472             }
2473         }(),
2474
2475
2476         doRemove: function() {
2477             if (window.removeEventListener) {
2478                 return function (el, eventName, fn, capture) {
2479                     el.removeEventListener(eventName, fn, (capture));
2480                 };
2481             } else if (window.detachEvent) {
2482                 return function (el, eventName, fn) {
2483                     el.detachEvent("on" + eventName, fn);
2484                 };
2485             } else {
2486                 return function() {
2487                 };
2488             }
2489         }()
2490     };
2491     
2492 }();
2493 (function() {     
2494    
2495     var E = Roo.lib.Event;
2496     E.on = E.addListener;
2497     E.un = E.removeListener;
2498
2499     if (document && document.body) {
2500         E._load();
2501     } else {
2502         E.doAdd(window, "load", E._load);
2503     }
2504     E.doAdd(window, "unload", E._unload);
2505     E._tryPreloadAttach();
2506 })();
2507
2508 /*
2509  * Portions of this file are based on pieces of Yahoo User Interface Library
2510  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2511  * YUI licensed under the BSD License:
2512  * http://developer.yahoo.net/yui/license.txt
2513  * <script type="text/javascript">
2514  *
2515  */
2516
2517 (function() {
2518     /**
2519      * @class Roo.lib.Ajax
2520      *
2521      */
2522     Roo.lib.Ajax = {
2523         /**
2524          * @static 
2525          */
2526         request : function(method, uri, cb, data, options) {
2527             if(options){
2528                 var hs = options.headers;
2529                 if(hs){
2530                     for(var h in hs){
2531                         if(hs.hasOwnProperty(h)){
2532                             this.initHeader(h, hs[h], false);
2533                         }
2534                     }
2535                 }
2536                 if(options.xmlData){
2537                     this.initHeader('Content-Type', 'text/xml', false);
2538                     method = 'POST';
2539                     data = options.xmlData;
2540                 }
2541             }
2542
2543             return this.asyncRequest(method, uri, cb, data);
2544         },
2545
2546         serializeForm : function(form) {
2547             if(typeof form == 'string') {
2548                 form = (document.getElementById(form) || document.forms[form]);
2549             }
2550
2551             var el, name, val, disabled, data = '', hasSubmit = false;
2552             for (var i = 0; i < form.elements.length; i++) {
2553                 el = form.elements[i];
2554                 disabled = form.elements[i].disabled;
2555                 name = form.elements[i].name;
2556                 val = form.elements[i].value;
2557
2558                 if (!disabled && name){
2559                     switch (el.type)
2560                             {
2561                         case 'select-one':
2562                         case 'select-multiple':
2563                             for (var j = 0; j < el.options.length; j++) {
2564                                 if (el.options[j].selected) {
2565                                     if (Roo.isIE) {
2566                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2567                                     }
2568                                     else {
2569                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2570                                     }
2571                                 }
2572                             }
2573                             break;
2574                         case 'radio':
2575                         case 'checkbox':
2576                             if (el.checked) {
2577                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2578                             }
2579                             break;
2580                         case 'file':
2581
2582                         case undefined:
2583
2584                         case 'reset':
2585
2586                         case 'button':
2587
2588                             break;
2589                         case 'submit':
2590                             if(hasSubmit == false) {
2591                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2592                                 hasSubmit = true;
2593                             }
2594                             break;
2595                         default:
2596                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2597                             break;
2598                     }
2599                 }
2600             }
2601             data = data.substr(0, data.length - 1);
2602             return data;
2603         },
2604
2605         headers:{},
2606
2607         hasHeaders:false,
2608
2609         useDefaultHeader:true,
2610
2611         defaultPostHeader:'application/x-www-form-urlencoded',
2612
2613         useDefaultXhrHeader:true,
2614
2615         defaultXhrHeader:'XMLHttpRequest',
2616
2617         hasDefaultHeaders:true,
2618
2619         defaultHeaders:{},
2620
2621         poll:{},
2622
2623         timeout:{},
2624
2625         pollInterval:50,
2626
2627         transactionId:0,
2628
2629         setProgId:function(id)
2630         {
2631             this.activeX.unshift(id);
2632         },
2633
2634         setDefaultPostHeader:function(b)
2635         {
2636             this.useDefaultHeader = b;
2637         },
2638
2639         setDefaultXhrHeader:function(b)
2640         {
2641             this.useDefaultXhrHeader = b;
2642         },
2643
2644         setPollingInterval:function(i)
2645         {
2646             if (typeof i == 'number' && isFinite(i)) {
2647                 this.pollInterval = i;
2648             }
2649         },
2650
2651         createXhrObject:function(transactionId)
2652         {
2653             var obj,http;
2654             try
2655             {
2656
2657                 http = new XMLHttpRequest();
2658
2659                 obj = { conn:http, tId:transactionId };
2660             }
2661             catch(e)
2662             {
2663                 for (var i = 0; i < this.activeX.length; ++i) {
2664                     try
2665                     {
2666
2667                         http = new ActiveXObject(this.activeX[i]);
2668
2669                         obj = { conn:http, tId:transactionId };
2670                         break;
2671                     }
2672                     catch(e) {
2673                     }
2674                 }
2675             }
2676             finally
2677             {
2678                 return obj;
2679             }
2680         },
2681
2682         getConnectionObject:function()
2683         {
2684             var o;
2685             var tId = this.transactionId;
2686
2687             try
2688             {
2689                 o = this.createXhrObject(tId);
2690                 if (o) {
2691                     this.transactionId++;
2692                 }
2693             }
2694             catch(e) {
2695             }
2696             finally
2697             {
2698                 return o;
2699             }
2700         },
2701
2702         asyncRequest:function(method, uri, callback, postData)
2703         {
2704             var o = this.getConnectionObject();
2705
2706             if (!o) {
2707                 return null;
2708             }
2709             else {
2710                 o.conn.open(method, uri, true);
2711
2712                 if (this.useDefaultXhrHeader) {
2713                     if (!this.defaultHeaders['X-Requested-With']) {
2714                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2715                     }
2716                 }
2717
2718                 if(postData && this.useDefaultHeader){
2719                     this.initHeader('Content-Type', this.defaultPostHeader);
2720                 }
2721
2722                  if (this.hasDefaultHeaders || this.hasHeaders) {
2723                     this.setHeader(o);
2724                 }
2725
2726                 this.handleReadyState(o, callback);
2727                 o.conn.send(postData || null);
2728
2729                 return o;
2730             }
2731         },
2732
2733         handleReadyState:function(o, callback)
2734         {
2735             var oConn = this;
2736
2737             if (callback && callback.timeout) {
2738                 
2739                 this.timeout[o.tId] = window.setTimeout(function() {
2740                     oConn.abort(o, callback, true);
2741                 }, callback.timeout);
2742             }
2743
2744             this.poll[o.tId] = window.setInterval(
2745                     function() {
2746                         if (o.conn && o.conn.readyState == 4) {
2747                             window.clearInterval(oConn.poll[o.tId]);
2748                             delete oConn.poll[o.tId];
2749
2750                             if(callback && callback.timeout) {
2751                                 window.clearTimeout(oConn.timeout[o.tId]);
2752                                 delete oConn.timeout[o.tId];
2753                             }
2754
2755                             oConn.handleTransactionResponse(o, callback);
2756                         }
2757                     }
2758                     , this.pollInterval);
2759         },
2760
2761         handleTransactionResponse:function(o, callback, isAbort)
2762         {
2763
2764             if (!callback) {
2765                 this.releaseObject(o);
2766                 return;
2767             }
2768
2769             var httpStatus, responseObject;
2770
2771             try
2772             {
2773                 if (o.conn.status !== undefined && o.conn.status != 0) {
2774                     httpStatus = o.conn.status;
2775                 }
2776                 else {
2777                     httpStatus = 13030;
2778                 }
2779             }
2780             catch(e) {
2781
2782
2783                 httpStatus = 13030;
2784             }
2785
2786             if (httpStatus >= 200 && httpStatus < 300) {
2787                 responseObject = this.createResponseObject(o, callback.argument);
2788                 if (callback.success) {
2789                     if (!callback.scope) {
2790                         callback.success(responseObject);
2791                     }
2792                     else {
2793
2794
2795                         callback.success.apply(callback.scope, [responseObject]);
2796                     }
2797                 }
2798             }
2799             else {
2800                 switch (httpStatus) {
2801
2802                     case 12002:
2803                     case 12029:
2804                     case 12030:
2805                     case 12031:
2806                     case 12152:
2807                     case 13030:
2808                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2809                         if (callback.failure) {
2810                             if (!callback.scope) {
2811                                 callback.failure(responseObject);
2812                             }
2813                             else {
2814                                 callback.failure.apply(callback.scope, [responseObject]);
2815                             }
2816                         }
2817                         break;
2818                     default:
2819                         responseObject = this.createResponseObject(o, callback.argument);
2820                         if (callback.failure) {
2821                             if (!callback.scope) {
2822                                 callback.failure(responseObject);
2823                             }
2824                             else {
2825                                 callback.failure.apply(callback.scope, [responseObject]);
2826                             }
2827                         }
2828                 }
2829             }
2830
2831             this.releaseObject(o);
2832             responseObject = null;
2833         },
2834
2835         createResponseObject:function(o, callbackArg)
2836         {
2837             var obj = {};
2838             var headerObj = {};
2839
2840             try
2841             {
2842                 var headerStr = o.conn.getAllResponseHeaders();
2843                 var header = headerStr.split('\n');
2844                 for (var i = 0; i < header.length; i++) {
2845                     var delimitPos = header[i].indexOf(':');
2846                     if (delimitPos != -1) {
2847                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2848                     }
2849                 }
2850             }
2851             catch(e) {
2852             }
2853
2854             obj.tId = o.tId;
2855             obj.status = o.conn.status;
2856             obj.statusText = o.conn.statusText;
2857             obj.getResponseHeader = headerObj;
2858             obj.getAllResponseHeaders = headerStr;
2859             obj.responseText = o.conn.responseText;
2860             obj.responseXML = o.conn.responseXML;
2861
2862             if (typeof callbackArg !== undefined) {
2863                 obj.argument = callbackArg;
2864             }
2865
2866             return obj;
2867         },
2868
2869         createExceptionObject:function(tId, callbackArg, isAbort)
2870         {
2871             var COMM_CODE = 0;
2872             var COMM_ERROR = 'communication failure';
2873             var ABORT_CODE = -1;
2874             var ABORT_ERROR = 'transaction aborted';
2875
2876             var obj = {};
2877
2878             obj.tId = tId;
2879             if (isAbort) {
2880                 obj.status = ABORT_CODE;
2881                 obj.statusText = ABORT_ERROR;
2882             }
2883             else {
2884                 obj.status = COMM_CODE;
2885                 obj.statusText = COMM_ERROR;
2886             }
2887
2888             if (callbackArg) {
2889                 obj.argument = callbackArg;
2890             }
2891
2892             return obj;
2893         },
2894
2895         initHeader:function(label, value, isDefault)
2896         {
2897             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2898
2899             if (headerObj[label] === undefined) {
2900                 headerObj[label] = value;
2901             }
2902             else {
2903
2904
2905                 headerObj[label] = value + "," + headerObj[label];
2906             }
2907
2908             if (isDefault) {
2909                 this.hasDefaultHeaders = true;
2910             }
2911             else {
2912                 this.hasHeaders = true;
2913             }
2914         },
2915
2916
2917         setHeader:function(o)
2918         {
2919             if (this.hasDefaultHeaders) {
2920                 for (var prop in this.defaultHeaders) {
2921                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2922                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2923                     }
2924                 }
2925             }
2926
2927             if (this.hasHeaders) {
2928                 for (var prop in this.headers) {
2929                     if (this.headers.hasOwnProperty(prop)) {
2930                         o.conn.setRequestHeader(prop, this.headers[prop]);
2931                     }
2932                 }
2933                 this.headers = {};
2934                 this.hasHeaders = false;
2935             }
2936         },
2937
2938         resetDefaultHeaders:function() {
2939             delete this.defaultHeaders;
2940             this.defaultHeaders = {};
2941             this.hasDefaultHeaders = false;
2942         },
2943
2944         abort:function(o, callback, isTimeout)
2945         {
2946             if(this.isCallInProgress(o)) {
2947                 o.conn.abort();
2948                 window.clearInterval(this.poll[o.tId]);
2949                 delete this.poll[o.tId];
2950                 if (isTimeout) {
2951                     delete this.timeout[o.tId];
2952                 }
2953
2954                 this.handleTransactionResponse(o, callback, true);
2955
2956                 return true;
2957             }
2958             else {
2959                 return false;
2960             }
2961         },
2962
2963
2964         isCallInProgress:function(o)
2965         {
2966             if (o && o.conn) {
2967                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2968             }
2969             else {
2970
2971                 return false;
2972             }
2973         },
2974
2975
2976         releaseObject:function(o)
2977         {
2978
2979             o.conn = null;
2980
2981             o = null;
2982         },
2983
2984         activeX:[
2985         'MSXML2.XMLHTTP.3.0',
2986         'MSXML2.XMLHTTP',
2987         'Microsoft.XMLHTTP'
2988         ]
2989
2990
2991     };
2992 })();/*
2993  * Portions of this file are based on pieces of Yahoo User Interface Library
2994  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2995  * YUI licensed under the BSD License:
2996  * http://developer.yahoo.net/yui/license.txt
2997  * <script type="text/javascript">
2998  *
2999  */
3000
3001 Roo.lib.Region = function(t, r, b, l) {
3002     this.top = t;
3003     this[1] = t;
3004     this.right = r;
3005     this.bottom = b;
3006     this.left = l;
3007     this[0] = l;
3008 };
3009
3010
3011 Roo.lib.Region.prototype = {
3012     contains : function(region) {
3013         return ( region.left >= this.left &&
3014                  region.right <= this.right &&
3015                  region.top >= this.top &&
3016                  region.bottom <= this.bottom    );
3017
3018     },
3019
3020     getArea : function() {
3021         return ( (this.bottom - this.top) * (this.right - this.left) );
3022     },
3023
3024     intersect : function(region) {
3025         var t = Math.max(this.top, region.top);
3026         var r = Math.min(this.right, region.right);
3027         var b = Math.min(this.bottom, region.bottom);
3028         var l = Math.max(this.left, region.left);
3029
3030         if (b >= t && r >= l) {
3031             return new Roo.lib.Region(t, r, b, l);
3032         } else {
3033             return null;
3034         }
3035     },
3036     union : function(region) {
3037         var t = Math.min(this.top, region.top);
3038         var r = Math.max(this.right, region.right);
3039         var b = Math.max(this.bottom, region.bottom);
3040         var l = Math.min(this.left, region.left);
3041
3042         return new Roo.lib.Region(t, r, b, l);
3043     },
3044
3045     adjust : function(t, l, b, r) {
3046         this.top += t;
3047         this.left += l;
3048         this.right += r;
3049         this.bottom += b;
3050         return this;
3051     }
3052 };
3053
3054 Roo.lib.Region.getRegion = function(el) {
3055     var p = Roo.lib.Dom.getXY(el);
3056
3057     var t = p[1];
3058     var r = p[0] + el.offsetWidth;
3059     var b = p[1] + el.offsetHeight;
3060     var l = p[0];
3061
3062     return new Roo.lib.Region(t, r, b, l);
3063 };
3064 /*
3065  * Portions of this file are based on pieces of Yahoo User Interface Library
3066  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3067  * YUI licensed under the BSD License:
3068  * http://developer.yahoo.net/yui/license.txt
3069  * <script type="text/javascript">
3070  *
3071  */
3072 //@@dep Roo.lib.Region
3073
3074
3075 Roo.lib.Point = function(x, y) {
3076     if (x instanceof Array) {
3077         y = x[1];
3078         x = x[0];
3079     }
3080     this.x = this.right = this.left = this[0] = x;
3081     this.y = this.top = this.bottom = this[1] = y;
3082 };
3083
3084 Roo.lib.Point.prototype = new Roo.lib.Region();
3085 /*
3086  * Portions of this file are based on pieces of Yahoo User Interface Library
3087  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3088  * YUI licensed under the BSD License:
3089  * http://developer.yahoo.net/yui/license.txt
3090  * <script type="text/javascript">
3091  *
3092  */
3093  
3094 (function() {   
3095
3096     Roo.lib.Anim = {
3097         scroll : function(el, args, duration, easing, cb, scope) {
3098             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3099         },
3100
3101         motion : function(el, args, duration, easing, cb, scope) {
3102             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3103         },
3104
3105         color : function(el, args, duration, easing, cb, scope) {
3106             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3107         },
3108
3109         run : function(el, args, duration, easing, cb, scope, type) {
3110             type = type || Roo.lib.AnimBase;
3111             if (typeof easing == "string") {
3112                 easing = Roo.lib.Easing[easing];
3113             }
3114             var anim = new type(el, args, duration, easing);
3115             anim.animateX(function() {
3116                 Roo.callback(cb, scope);
3117             });
3118             return anim;
3119         }
3120     };
3121 })();/*
3122  * Portions of this file are based on pieces of Yahoo User Interface Library
3123  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3124  * YUI licensed under the BSD License:
3125  * http://developer.yahoo.net/yui/license.txt
3126  * <script type="text/javascript">
3127  *
3128  */
3129
3130 (function() {    
3131     var libFlyweight;
3132     
3133     function fly(el) {
3134         if (!libFlyweight) {
3135             libFlyweight = new Roo.Element.Flyweight();
3136         }
3137         libFlyweight.dom = el;
3138         return libFlyweight;
3139     }
3140
3141     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3142     
3143    
3144     
3145     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3146         if (el) {
3147             this.init(el, attributes, duration, method);
3148         }
3149     };
3150
3151     Roo.lib.AnimBase.fly = fly;
3152     
3153     
3154     
3155     Roo.lib.AnimBase.prototype = {
3156
3157         toString: function() {
3158             var el = this.getEl();
3159             var id = el.id || el.tagName;
3160             return ("Anim " + id);
3161         },
3162
3163         patterns: {
3164             noNegatives:        /width|height|opacity|padding/i,
3165             offsetAttribute:  /^((width|height)|(top|left))$/,
3166             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3167             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3168         },
3169
3170
3171         doMethod: function(attr, start, end) {
3172             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3173         },
3174
3175
3176         setAttribute: function(attr, val, unit) {
3177             if (this.patterns.noNegatives.test(attr)) {
3178                 val = (val > 0) ? val : 0;
3179             }
3180
3181             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3182         },
3183
3184
3185         getAttribute: function(attr) {
3186             var el = this.getEl();
3187             var val = fly(el).getStyle(attr);
3188
3189             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3190                 return parseFloat(val);
3191             }
3192
3193             var a = this.patterns.offsetAttribute.exec(attr) || [];
3194             var pos = !!( a[3] );
3195             var box = !!( a[2] );
3196
3197
3198             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3199                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3200             } else {
3201                 val = 0;
3202             }
3203
3204             return val;
3205         },
3206
3207
3208         getDefaultUnit: function(attr) {
3209             if (this.patterns.defaultUnit.test(attr)) {
3210                 return 'px';
3211             }
3212
3213             return '';
3214         },
3215
3216         animateX : function(callback, scope) {
3217             var f = function() {
3218                 this.onComplete.removeListener(f);
3219                 if (typeof callback == "function") {
3220                     callback.call(scope || this, this);
3221                 }
3222             };
3223             this.onComplete.addListener(f, this);
3224             this.animate();
3225         },
3226
3227
3228         setRuntimeAttribute: function(attr) {
3229             var start;
3230             var end;
3231             var attributes = this.attributes;
3232
3233             this.runtimeAttributes[attr] = {};
3234
3235             var isset = function(prop) {
3236                 return (typeof prop !== 'undefined');
3237             };
3238
3239             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3240                 return false;
3241             }
3242
3243             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3244
3245
3246             if (isset(attributes[attr]['to'])) {
3247                 end = attributes[attr]['to'];
3248             } else if (isset(attributes[attr]['by'])) {
3249                 if (start.constructor == Array) {
3250                     end = [];
3251                     for (var i = 0, len = start.length; i < len; ++i) {
3252                         end[i] = start[i] + attributes[attr]['by'][i];
3253                     }
3254                 } else {
3255                     end = start + attributes[attr]['by'];
3256                 }
3257             }
3258
3259             this.runtimeAttributes[attr].start = start;
3260             this.runtimeAttributes[attr].end = end;
3261
3262
3263             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3264         },
3265
3266
3267         init: function(el, attributes, duration, method) {
3268
3269             var isAnimated = false;
3270
3271
3272             var startTime = null;
3273
3274
3275             var actualFrames = 0;
3276
3277
3278             el = Roo.getDom(el);
3279
3280
3281             this.attributes = attributes || {};
3282
3283
3284             this.duration = duration || 1;
3285
3286
3287             this.method = method || Roo.lib.Easing.easeNone;
3288
3289
3290             this.useSeconds = true;
3291
3292
3293             this.currentFrame = 0;
3294
3295
3296             this.totalFrames = Roo.lib.AnimMgr.fps;
3297
3298
3299             this.getEl = function() {
3300                 return el;
3301             };
3302
3303
3304             this.isAnimated = function() {
3305                 return isAnimated;
3306             };
3307
3308
3309             this.getStartTime = function() {
3310                 return startTime;
3311             };
3312
3313             this.runtimeAttributes = {};
3314
3315
3316             this.animate = function() {
3317                 if (this.isAnimated()) {
3318                     return false;
3319                 }
3320
3321                 this.currentFrame = 0;
3322
3323                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3324
3325                 Roo.lib.AnimMgr.registerElement(this);
3326             };
3327
3328
3329             this.stop = function(finish) {
3330                 if (finish) {
3331                     this.currentFrame = this.totalFrames;
3332                     this._onTween.fire();
3333                 }
3334                 Roo.lib.AnimMgr.stop(this);
3335             };
3336
3337             var onStart = function() {
3338                 this.onStart.fire();
3339
3340                 this.runtimeAttributes = {};
3341                 for (var attr in this.attributes) {
3342                     this.setRuntimeAttribute(attr);
3343                 }
3344
3345                 isAnimated = true;
3346                 actualFrames = 0;
3347                 startTime = new Date();
3348             };
3349
3350
3351             var onTween = function() {
3352                 var data = {
3353                     duration: new Date() - this.getStartTime(),
3354                     currentFrame: this.currentFrame
3355                 };
3356
3357                 data.toString = function() {
3358                     return (
3359                             'duration: ' + data.duration +
3360                             ', currentFrame: ' + data.currentFrame
3361                             );
3362                 };
3363
3364                 this.onTween.fire(data);
3365
3366                 var runtimeAttributes = this.runtimeAttributes;
3367
3368                 for (var attr in runtimeAttributes) {
3369                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3370                 }
3371
3372                 actualFrames += 1;
3373             };
3374
3375             var onComplete = function() {
3376                 var actual_duration = (new Date() - startTime) / 1000 ;
3377
3378                 var data = {
3379                     duration: actual_duration,
3380                     frames: actualFrames,
3381                     fps: actualFrames / actual_duration
3382                 };
3383
3384                 data.toString = function() {
3385                     return (
3386                             'duration: ' + data.duration +
3387                             ', frames: ' + data.frames +
3388                             ', fps: ' + data.fps
3389                             );
3390                 };
3391
3392                 isAnimated = false;
3393                 actualFrames = 0;
3394                 this.onComplete.fire(data);
3395             };
3396
3397
3398             this._onStart = new Roo.util.Event(this);
3399             this.onStart = new Roo.util.Event(this);
3400             this.onTween = new Roo.util.Event(this);
3401             this._onTween = new Roo.util.Event(this);
3402             this.onComplete = new Roo.util.Event(this);
3403             this._onComplete = new Roo.util.Event(this);
3404             this._onStart.addListener(onStart);
3405             this._onTween.addListener(onTween);
3406             this._onComplete.addListener(onComplete);
3407         }
3408     };
3409 })();
3410 /*
3411  * Portions of this file are based on pieces of Yahoo User Interface Library
3412  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3413  * YUI licensed under the BSD License:
3414  * http://developer.yahoo.net/yui/license.txt
3415  * <script type="text/javascript">
3416  *
3417  */
3418
3419 Roo.lib.AnimMgr = new function() {
3420
3421     var thread = null;
3422
3423
3424     var queue = [];
3425
3426
3427     var tweenCount = 0;
3428
3429
3430     this.fps = 1000;
3431
3432
3433     this.delay = 1;
3434
3435
3436     this.registerElement = function(tween) {
3437         queue[queue.length] = tween;
3438         tweenCount += 1;
3439         tween._onStart.fire();
3440         this.start();
3441     };
3442
3443
3444     this.unRegister = function(tween, index) {
3445         tween._onComplete.fire();
3446         index = index || getIndex(tween);
3447         if (index != -1) {
3448             queue.splice(index, 1);
3449         }
3450
3451         tweenCount -= 1;
3452         if (tweenCount <= 0) {
3453             this.stop();
3454         }
3455     };
3456
3457
3458     this.start = function() {
3459         if (thread === null) {
3460             thread = setInterval(this.run, this.delay);
3461         }
3462     };
3463
3464
3465     this.stop = function(tween) {
3466         if (!tween) {
3467             clearInterval(thread);
3468
3469             for (var i = 0, len = queue.length; i < len; ++i) {
3470                 if (queue[0].isAnimated()) {
3471                     this.unRegister(queue[0], 0);
3472                 }
3473             }
3474
3475             queue = [];
3476             thread = null;
3477             tweenCount = 0;
3478         }
3479         else {
3480             this.unRegister(tween);
3481         }
3482     };
3483
3484
3485     this.run = function() {
3486         for (var i = 0, len = queue.length; i < len; ++i) {
3487             var tween = queue[i];
3488             if (!tween || !tween.isAnimated()) {
3489                 continue;
3490             }
3491
3492             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3493             {
3494                 tween.currentFrame += 1;
3495
3496                 if (tween.useSeconds) {
3497                     correctFrame(tween);
3498                 }
3499                 tween._onTween.fire();
3500             }
3501             else {
3502                 Roo.lib.AnimMgr.stop(tween, i);
3503             }
3504         }
3505     };
3506
3507     var getIndex = function(anim) {
3508         for (var i = 0, len = queue.length; i < len; ++i) {
3509             if (queue[i] == anim) {
3510                 return i;
3511             }
3512         }
3513         return -1;
3514     };
3515
3516
3517     var correctFrame = function(tween) {
3518         var frames = tween.totalFrames;
3519         var frame = tween.currentFrame;
3520         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3521         var elapsed = (new Date() - tween.getStartTime());
3522         var tweak = 0;
3523
3524         if (elapsed < tween.duration * 1000) {
3525             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3526         } else {
3527             tweak = frames - (frame + 1);
3528         }
3529         if (tweak > 0 && isFinite(tweak)) {
3530             if (tween.currentFrame + tweak >= frames) {
3531                 tweak = frames - (frame + 1);
3532             }
3533
3534             tween.currentFrame += tweak;
3535         }
3536     };
3537 };
3538
3539     /*
3540  * Portions of this file are based on pieces of Yahoo User Interface Library
3541  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3542  * YUI licensed under the BSD License:
3543  * http://developer.yahoo.net/yui/license.txt
3544  * <script type="text/javascript">
3545  *
3546  */
3547 Roo.lib.Bezier = new function() {
3548
3549         this.getPosition = function(points, t) {
3550             var n = points.length;
3551             var tmp = [];
3552
3553             for (var i = 0; i < n; ++i) {
3554                 tmp[i] = [points[i][0], points[i][1]];
3555             }
3556
3557             for (var j = 1; j < n; ++j) {
3558                 for (i = 0; i < n - j; ++i) {
3559                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3560                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3561                 }
3562             }
3563
3564             return [ tmp[0][0], tmp[0][1] ];
3565
3566         };
3567     };/*
3568  * Portions of this file are based on pieces of Yahoo User Interface Library
3569  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3570  * YUI licensed under the BSD License:
3571  * http://developer.yahoo.net/yui/license.txt
3572  * <script type="text/javascript">
3573  *
3574  */
3575 (function() {
3576
3577     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3578         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3579     };
3580
3581     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3582
3583     var fly = Roo.lib.AnimBase.fly;
3584     var Y = Roo.lib;
3585     var superclass = Y.ColorAnim.superclass;
3586     var proto = Y.ColorAnim.prototype;
3587
3588     proto.toString = function() {
3589         var el = this.getEl();
3590         var id = el.id || el.tagName;
3591         return ("ColorAnim " + id);
3592     };
3593
3594     proto.patterns.color = /color$/i;
3595     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3596     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3597     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3598     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3599
3600
3601     proto.parseColor = function(s) {
3602         if (s.length == 3) {
3603             return s;
3604         }
3605
3606         var c = this.patterns.hex.exec(s);
3607         if (c && c.length == 4) {
3608             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3609         }
3610
3611         c = this.patterns.rgb.exec(s);
3612         if (c && c.length == 4) {
3613             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3614         }
3615
3616         c = this.patterns.hex3.exec(s);
3617         if (c && c.length == 4) {
3618             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3619         }
3620
3621         return null;
3622     };
3623     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3624     proto.getAttribute = function(attr) {
3625         var el = this.getEl();
3626         if (this.patterns.color.test(attr)) {
3627             var val = fly(el).getStyle(attr);
3628
3629             if (this.patterns.transparent.test(val)) {
3630                 var parent = el.parentNode;
3631                 val = fly(parent).getStyle(attr);
3632
3633                 while (parent && this.patterns.transparent.test(val)) {
3634                     parent = parent.parentNode;
3635                     val = fly(parent).getStyle(attr);
3636                     if (parent.tagName.toUpperCase() == 'HTML') {
3637                         val = '#fff';
3638                     }
3639                 }
3640             }
3641         } else {
3642             val = superclass.getAttribute.call(this, attr);
3643         }
3644
3645         return val;
3646     };
3647     proto.getAttribute = function(attr) {
3648         var el = this.getEl();
3649         if (this.patterns.color.test(attr)) {
3650             var val = fly(el).getStyle(attr);
3651
3652             if (this.patterns.transparent.test(val)) {
3653                 var parent = el.parentNode;
3654                 val = fly(parent).getStyle(attr);
3655
3656                 while (parent && this.patterns.transparent.test(val)) {
3657                     parent = parent.parentNode;
3658                     val = fly(parent).getStyle(attr);
3659                     if (parent.tagName.toUpperCase() == 'HTML') {
3660                         val = '#fff';
3661                     }
3662                 }
3663             }
3664         } else {
3665             val = superclass.getAttribute.call(this, attr);
3666         }
3667
3668         return val;
3669     };
3670
3671     proto.doMethod = function(attr, start, end) {
3672         var val;
3673
3674         if (this.patterns.color.test(attr)) {
3675             val = [];
3676             for (var i = 0, len = start.length; i < len; ++i) {
3677                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3678             }
3679
3680             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3681         }
3682         else {
3683             val = superclass.doMethod.call(this, attr, start, end);
3684         }
3685
3686         return val;
3687     };
3688
3689     proto.setRuntimeAttribute = function(attr) {
3690         superclass.setRuntimeAttribute.call(this, attr);
3691
3692         if (this.patterns.color.test(attr)) {
3693             var attributes = this.attributes;
3694             var start = this.parseColor(this.runtimeAttributes[attr].start);
3695             var end = this.parseColor(this.runtimeAttributes[attr].end);
3696
3697             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3698                 end = this.parseColor(attributes[attr].by);
3699
3700                 for (var i = 0, len = start.length; i < len; ++i) {
3701                     end[i] = start[i] + end[i];
3702                 }
3703             }
3704
3705             this.runtimeAttributes[attr].start = start;
3706             this.runtimeAttributes[attr].end = end;
3707         }
3708     };
3709 })();
3710
3711 /*
3712  * Portions of this file are based on pieces of Yahoo User Interface Library
3713  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3714  * YUI licensed under the BSD License:
3715  * http://developer.yahoo.net/yui/license.txt
3716  * <script type="text/javascript">
3717  *
3718  */
3719 Roo.lib.Easing = {
3720
3721
3722     easeNone: function (t, b, c, d) {
3723         return c * t / d + b;
3724     },
3725
3726
3727     easeIn: function (t, b, c, d) {
3728         return c * (t /= d) * t + b;
3729     },
3730
3731
3732     easeOut: function (t, b, c, d) {
3733         return -c * (t /= d) * (t - 2) + b;
3734     },
3735
3736
3737     easeBoth: function (t, b, c, d) {
3738         if ((t /= d / 2) < 1) {
3739             return c / 2 * t * t + b;
3740         }
3741
3742         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3743     },
3744
3745
3746     easeInStrong: function (t, b, c, d) {
3747         return c * (t /= d) * t * t * t + b;
3748     },
3749
3750
3751     easeOutStrong: function (t, b, c, d) {
3752         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3753     },
3754
3755
3756     easeBothStrong: function (t, b, c, d) {
3757         if ((t /= d / 2) < 1) {
3758             return c / 2 * t * t * t * t + b;
3759         }
3760
3761         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3762     },
3763
3764
3765
3766     elasticIn: function (t, b, c, d, a, p) {
3767         if (t == 0) {
3768             return b;
3769         }
3770         if ((t /= d) == 1) {
3771             return b + c;
3772         }
3773         if (!p) {
3774             p = d * .3;
3775         }
3776
3777         if (!a || a < Math.abs(c)) {
3778             a = c;
3779             var s = p / 4;
3780         }
3781         else {
3782             var s = p / (2 * Math.PI) * Math.asin(c / a);
3783         }
3784
3785         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3786     },
3787
3788
3789     elasticOut: function (t, b, c, d, a, p) {
3790         if (t == 0) {
3791             return b;
3792         }
3793         if ((t /= d) == 1) {
3794             return b + c;
3795         }
3796         if (!p) {
3797             p = d * .3;
3798         }
3799
3800         if (!a || a < Math.abs(c)) {
3801             a = c;
3802             var s = p / 4;
3803         }
3804         else {
3805             var s = p / (2 * Math.PI) * Math.asin(c / a);
3806         }
3807
3808         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3809     },
3810
3811
3812     elasticBoth: function (t, b, c, d, a, p) {
3813         if (t == 0) {
3814             return b;
3815         }
3816
3817         if ((t /= d / 2) == 2) {
3818             return b + c;
3819         }
3820
3821         if (!p) {
3822             p = d * (.3 * 1.5);
3823         }
3824
3825         if (!a || a < Math.abs(c)) {
3826             a = c;
3827             var s = p / 4;
3828         }
3829         else {
3830             var s = p / (2 * Math.PI) * Math.asin(c / a);
3831         }
3832
3833         if (t < 1) {
3834             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3835                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3836         }
3837         return a * Math.pow(2, -10 * (t -= 1)) *
3838                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3839     },
3840
3841
3842
3843     backIn: function (t, b, c, d, s) {
3844         if (typeof s == 'undefined') {
3845             s = 1.70158;
3846         }
3847         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3848     },
3849
3850
3851     backOut: function (t, b, c, d, s) {
3852         if (typeof s == 'undefined') {
3853             s = 1.70158;
3854         }
3855         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3856     },
3857
3858
3859     backBoth: function (t, b, c, d, s) {
3860         if (typeof s == 'undefined') {
3861             s = 1.70158;
3862         }
3863
3864         if ((t /= d / 2 ) < 1) {
3865             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3866         }
3867         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3868     },
3869
3870
3871     bounceIn: function (t, b, c, d) {
3872         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3873     },
3874
3875
3876     bounceOut: function (t, b, c, d) {
3877         if ((t /= d) < (1 / 2.75)) {
3878             return c * (7.5625 * t * t) + b;
3879         } else if (t < (2 / 2.75)) {
3880             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3881         } else if (t < (2.5 / 2.75)) {
3882             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3883         }
3884         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3885     },
3886
3887
3888     bounceBoth: function (t, b, c, d) {
3889         if (t < d / 2) {
3890             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3891         }
3892         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3893     }
3894 };/*
3895  * Portions of this file are based on pieces of Yahoo User Interface Library
3896  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3897  * YUI licensed under the BSD License:
3898  * http://developer.yahoo.net/yui/license.txt
3899  * <script type="text/javascript">
3900  *
3901  */
3902     (function() {
3903         Roo.lib.Motion = function(el, attributes, duration, method) {
3904             if (el) {
3905                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3906             }
3907         };
3908
3909         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3910
3911
3912         var Y = Roo.lib;
3913         var superclass = Y.Motion.superclass;
3914         var proto = Y.Motion.prototype;
3915
3916         proto.toString = function() {
3917             var el = this.getEl();
3918             var id = el.id || el.tagName;
3919             return ("Motion " + id);
3920         };
3921
3922         proto.patterns.points = /^points$/i;
3923
3924         proto.setAttribute = function(attr, val, unit) {
3925             if (this.patterns.points.test(attr)) {
3926                 unit = unit || 'px';
3927                 superclass.setAttribute.call(this, 'left', val[0], unit);
3928                 superclass.setAttribute.call(this, 'top', val[1], unit);
3929             } else {
3930                 superclass.setAttribute.call(this, attr, val, unit);
3931             }
3932         };
3933
3934         proto.getAttribute = function(attr) {
3935             if (this.patterns.points.test(attr)) {
3936                 var val = [
3937                         superclass.getAttribute.call(this, 'left'),
3938                         superclass.getAttribute.call(this, 'top')
3939                         ];
3940             } else {
3941                 val = superclass.getAttribute.call(this, attr);
3942             }
3943
3944             return val;
3945         };
3946
3947         proto.doMethod = function(attr, start, end) {
3948             var val = null;
3949
3950             if (this.patterns.points.test(attr)) {
3951                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3952                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3953             } else {
3954                 val = superclass.doMethod.call(this, attr, start, end);
3955             }
3956             return val;
3957         };
3958
3959         proto.setRuntimeAttribute = function(attr) {
3960             if (this.patterns.points.test(attr)) {
3961                 var el = this.getEl();
3962                 var attributes = this.attributes;
3963                 var start;
3964                 var control = attributes['points']['control'] || [];
3965                 var end;
3966                 var i, len;
3967
3968                 if (control.length > 0 && !(control[0] instanceof Array)) {
3969                     control = [control];
3970                 } else {
3971                     var tmp = [];
3972                     for (i = 0,len = control.length; i < len; ++i) {
3973                         tmp[i] = control[i];
3974                     }
3975                     control = tmp;
3976                 }
3977
3978                 Roo.fly(el).position();
3979
3980                 if (isset(attributes['points']['from'])) {
3981                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3982                 }
3983                 else {
3984                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3985                 }
3986
3987                 start = this.getAttribute('points');
3988
3989
3990                 if (isset(attributes['points']['to'])) {
3991                     end = translateValues.call(this, attributes['points']['to'], start);
3992
3993                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3994                     for (i = 0,len = control.length; i < len; ++i) {
3995                         control[i] = translateValues.call(this, control[i], start);
3996                     }
3997
3998
3999                 } else if (isset(attributes['points']['by'])) {
4000                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4001
4002                     for (i = 0,len = control.length; i < len; ++i) {
4003                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4004                     }
4005                 }
4006
4007                 this.runtimeAttributes[attr] = [start];
4008
4009                 if (control.length > 0) {
4010                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4011                 }
4012
4013                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4014             }
4015             else {
4016                 superclass.setRuntimeAttribute.call(this, attr);
4017             }
4018         };
4019
4020         var translateValues = function(val, start) {
4021             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4022             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4023
4024             return val;
4025         };
4026
4027         var isset = function(prop) {
4028             return (typeof prop !== 'undefined');
4029         };
4030     })();
4031 /*
4032  * Portions of this file are based on pieces of Yahoo User Interface Library
4033  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4034  * YUI licensed under the BSD License:
4035  * http://developer.yahoo.net/yui/license.txt
4036  * <script type="text/javascript">
4037  *
4038  */
4039     (function() {
4040         Roo.lib.Scroll = function(el, attributes, duration, method) {
4041             if (el) {
4042                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4043             }
4044         };
4045
4046         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4047
4048
4049         var Y = Roo.lib;
4050         var superclass = Y.Scroll.superclass;
4051         var proto = Y.Scroll.prototype;
4052
4053         proto.toString = function() {
4054             var el = this.getEl();
4055             var id = el.id || el.tagName;
4056             return ("Scroll " + id);
4057         };
4058
4059         proto.doMethod = function(attr, start, end) {
4060             var val = null;
4061
4062             if (attr == 'scroll') {
4063                 val = [
4064                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4065                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4066                         ];
4067
4068             } else {
4069                 val = superclass.doMethod.call(this, attr, start, end);
4070             }
4071             return val;
4072         };
4073
4074         proto.getAttribute = function(attr) {
4075             var val = null;
4076             var el = this.getEl();
4077
4078             if (attr == 'scroll') {
4079                 val = [ el.scrollLeft, el.scrollTop ];
4080             } else {
4081                 val = superclass.getAttribute.call(this, attr);
4082             }
4083
4084             return val;
4085         };
4086
4087         proto.setAttribute = function(attr, val, unit) {
4088             var el = this.getEl();
4089
4090             if (attr == 'scroll') {
4091                 el.scrollLeft = val[0];
4092                 el.scrollTop = val[1];
4093             } else {
4094                 superclass.setAttribute.call(this, attr, val, unit);
4095             }
4096         };
4097     })();
4098 /*
4099  * Based on:
4100  * Ext JS Library 1.1.1
4101  * Copyright(c) 2006-2007, Ext JS, LLC.
4102  *
4103  * Originally Released Under LGPL - original licence link has changed is not relivant.
4104  *
4105  * Fork - LGPL
4106  * <script type="text/javascript">
4107  */
4108
4109
4110 // nasty IE9 hack - what a pile of crap that is..
4111
4112  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4113     Range.prototype.createContextualFragment = function (html) {
4114         var doc = window.document;
4115         var container = doc.createElement("div");
4116         container.innerHTML = html;
4117         var frag = doc.createDocumentFragment(), n;
4118         while ((n = container.firstChild)) {
4119             frag.appendChild(n);
4120         }
4121         return frag;
4122     };
4123 }
4124
4125 /**
4126  * @class Roo.DomHelper
4127  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4128  * 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>.
4129  * @singleton
4130  */
4131 Roo.DomHelper = function(){
4132     var tempTableEl = null;
4133     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4134     var tableRe = /^table|tbody|tr|td$/i;
4135     var xmlns = {};
4136     // build as innerHTML where available
4137     /** @ignore */
4138     var createHtml = function(o){
4139         if(typeof o == 'string'){
4140             return o;
4141         }
4142         var b = "";
4143         if(!o.tag){
4144             o.tag = "div";
4145         }
4146         b += "<" + o.tag;
4147         for(var attr in o){
4148             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4149             if(attr == "style"){
4150                 var s = o["style"];
4151                 if(typeof s == "function"){
4152                     s = s.call();
4153                 }
4154                 if(typeof s == "string"){
4155                     b += ' style="' + s + '"';
4156                 }else if(typeof s == "object"){
4157                     b += ' style="';
4158                     for(var key in s){
4159                         if(typeof s[key] != "function"){
4160                             b += key + ":" + s[key] + ";";
4161                         }
4162                     }
4163                     b += '"';
4164                 }
4165             }else{
4166                 if(attr == "cls"){
4167                     b += ' class="' + o["cls"] + '"';
4168                 }else if(attr == "htmlFor"){
4169                     b += ' for="' + o["htmlFor"] + '"';
4170                 }else{
4171                     b += " " + attr + '="' + o[attr] + '"';
4172                 }
4173             }
4174         }
4175         if(emptyTags.test(o.tag)){
4176             b += "/>";
4177         }else{
4178             b += ">";
4179             var cn = o.children || o.cn;
4180             if(cn){
4181                 //http://bugs.kde.org/show_bug.cgi?id=71506
4182                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4183                     for(var i = 0, len = cn.length; i < len; i++) {
4184                         b += createHtml(cn[i], b);
4185                     }
4186                 }else{
4187                     b += createHtml(cn, b);
4188                 }
4189             }
4190             if(o.html){
4191                 b += o.html;
4192             }
4193             b += "</" + o.tag + ">";
4194         }
4195         return b;
4196     };
4197
4198     // build as dom
4199     /** @ignore */
4200     var createDom = function(o, parentNode){
4201          
4202         // defininition craeted..
4203         var ns = false;
4204         if (o.ns && o.ns != 'html') {
4205                
4206             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4207                 xmlns[o.ns] = o.xmlns;
4208                 ns = o.xmlns;
4209             }
4210             if (typeof(xmlns[o.ns]) == 'undefined') {
4211                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4212             }
4213             ns = xmlns[o.ns];
4214         }
4215         
4216         
4217         if (typeof(o) == 'string') {
4218             return parentNode.appendChild(document.createTextNode(o));
4219         }
4220         o.tag = o.tag || div;
4221         if (o.ns && Roo.isIE) {
4222             ns = false;
4223             o.tag = o.ns + ':' + o.tag;
4224             
4225         }
4226         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4227         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4228         for(var attr in o){
4229             
4230             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4231                     attr == "style" || typeof o[attr] == "function") continue;
4232                     
4233             if(attr=="cls" && Roo.isIE){
4234                 el.className = o["cls"];
4235             }else{
4236                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4237                 else el[attr] = o[attr];
4238             }
4239         }
4240         Roo.DomHelper.applyStyles(el, o.style);
4241         var cn = o.children || o.cn;
4242         if(cn){
4243             //http://bugs.kde.org/show_bug.cgi?id=71506
4244              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4245                 for(var i = 0, len = cn.length; i < len; i++) {
4246                     createDom(cn[i], el);
4247                 }
4248             }else{
4249                 createDom(cn, el);
4250             }
4251         }
4252         if(o.html){
4253             el.innerHTML = o.html;
4254         }
4255         if(parentNode){
4256            parentNode.appendChild(el);
4257         }
4258         return el;
4259     };
4260
4261     var ieTable = function(depth, s, h, e){
4262         tempTableEl.innerHTML = [s, h, e].join('');
4263         var i = -1, el = tempTableEl;
4264         while(++i < depth){
4265             el = el.firstChild;
4266         }
4267         return el;
4268     };
4269
4270     // kill repeat to save bytes
4271     var ts = '<table>',
4272         te = '</table>',
4273         tbs = ts+'<tbody>',
4274         tbe = '</tbody>'+te,
4275         trs = tbs + '<tr>',
4276         tre = '</tr>'+tbe;
4277
4278     /**
4279      * @ignore
4280      * Nasty code for IE's broken table implementation
4281      */
4282     var insertIntoTable = function(tag, where, el, html){
4283         if(!tempTableEl){
4284             tempTableEl = document.createElement('div');
4285         }
4286         var node;
4287         var before = null;
4288         if(tag == 'td'){
4289             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4290                 return;
4291             }
4292             if(where == 'beforebegin'){
4293                 before = el;
4294                 el = el.parentNode;
4295             } else{
4296                 before = el.nextSibling;
4297                 el = el.parentNode;
4298             }
4299             node = ieTable(4, trs, html, tre);
4300         }
4301         else if(tag == 'tr'){
4302             if(where == 'beforebegin'){
4303                 before = el;
4304                 el = el.parentNode;
4305                 node = ieTable(3, tbs, html, tbe);
4306             } else if(where == 'afterend'){
4307                 before = el.nextSibling;
4308                 el = el.parentNode;
4309                 node = ieTable(3, tbs, html, tbe);
4310             } else{ // INTO a TR
4311                 if(where == 'afterbegin'){
4312                     before = el.firstChild;
4313                 }
4314                 node = ieTable(4, trs, html, tre);
4315             }
4316         } else if(tag == 'tbody'){
4317             if(where == 'beforebegin'){
4318                 before = el;
4319                 el = el.parentNode;
4320                 node = ieTable(2, ts, html, te);
4321             } else if(where == 'afterend'){
4322                 before = el.nextSibling;
4323                 el = el.parentNode;
4324                 node = ieTable(2, ts, html, te);
4325             } else{
4326                 if(where == 'afterbegin'){
4327                     before = el.firstChild;
4328                 }
4329                 node = ieTable(3, tbs, html, tbe);
4330             }
4331         } else{ // TABLE
4332             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4333                 return;
4334             }
4335             if(where == 'afterbegin'){
4336                 before = el.firstChild;
4337             }
4338             node = ieTable(2, ts, html, te);
4339         }
4340         el.insertBefore(node, before);
4341         return node;
4342     };
4343
4344     return {
4345     /** True to force the use of DOM instead of html fragments @type Boolean */
4346     useDom : false,
4347
4348     /**
4349      * Returns the markup for the passed Element(s) config
4350      * @param {Object} o The Dom object spec (and children)
4351      * @return {String}
4352      */
4353     markup : function(o){
4354         return createHtml(o);
4355     },
4356
4357     /**
4358      * Applies a style specification to an element
4359      * @param {String/HTMLElement} el The element to apply styles to
4360      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4361      * a function which returns such a specification.
4362      */
4363     applyStyles : function(el, styles){
4364         if(styles){
4365            el = Roo.fly(el);
4366            if(typeof styles == "string"){
4367                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4368                var matches;
4369                while ((matches = re.exec(styles)) != null){
4370                    el.setStyle(matches[1], matches[2]);
4371                }
4372            }else if (typeof styles == "object"){
4373                for (var style in styles){
4374                   el.setStyle(style, styles[style]);
4375                }
4376            }else if (typeof styles == "function"){
4377                 Roo.DomHelper.applyStyles(el, styles.call());
4378            }
4379         }
4380     },
4381
4382     /**
4383      * Inserts an HTML fragment into the Dom
4384      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4385      * @param {HTMLElement} el The context element
4386      * @param {String} html The HTML fragmenet
4387      * @return {HTMLElement} The new node
4388      */
4389     insertHtml : function(where, el, html){
4390         where = where.toLowerCase();
4391         if(el.insertAdjacentHTML){
4392             if(tableRe.test(el.tagName)){
4393                 var rs;
4394                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4395                     return rs;
4396                 }
4397             }
4398             switch(where){
4399                 case "beforebegin":
4400                     el.insertAdjacentHTML('BeforeBegin', html);
4401                     return el.previousSibling;
4402                 case "afterbegin":
4403                     el.insertAdjacentHTML('AfterBegin', html);
4404                     return el.firstChild;
4405                 case "beforeend":
4406                     el.insertAdjacentHTML('BeforeEnd', html);
4407                     return el.lastChild;
4408                 case "afterend":
4409                     el.insertAdjacentHTML('AfterEnd', html);
4410                     return el.nextSibling;
4411             }
4412             throw 'Illegal insertion point -> "' + where + '"';
4413         }
4414         var range = el.ownerDocument.createRange();
4415         var frag;
4416         switch(where){
4417              case "beforebegin":
4418                 range.setStartBefore(el);
4419                 frag = range.createContextualFragment(html);
4420                 el.parentNode.insertBefore(frag, el);
4421                 return el.previousSibling;
4422              case "afterbegin":
4423                 if(el.firstChild){
4424                     range.setStartBefore(el.firstChild);
4425                     frag = range.createContextualFragment(html);
4426                     el.insertBefore(frag, el.firstChild);
4427                     return el.firstChild;
4428                 }else{
4429                     el.innerHTML = html;
4430                     return el.firstChild;
4431                 }
4432             case "beforeend":
4433                 if(el.lastChild){
4434                     range.setStartAfter(el.lastChild);
4435                     frag = range.createContextualFragment(html);
4436                     el.appendChild(frag);
4437                     return el.lastChild;
4438                 }else{
4439                     el.innerHTML = html;
4440                     return el.lastChild;
4441                 }
4442             case "afterend":
4443                 range.setStartAfter(el);
4444                 frag = range.createContextualFragment(html);
4445                 el.parentNode.insertBefore(frag, el.nextSibling);
4446                 return el.nextSibling;
4447             }
4448             throw 'Illegal insertion point -> "' + where + '"';
4449     },
4450
4451     /**
4452      * Creates new Dom element(s) and inserts them before el
4453      * @param {String/HTMLElement/Element} el The context element
4454      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4455      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4456      * @return {HTMLElement/Roo.Element} The new node
4457      */
4458     insertBefore : function(el, o, returnElement){
4459         return this.doInsert(el, o, returnElement, "beforeBegin");
4460     },
4461
4462     /**
4463      * Creates new Dom element(s) and inserts them after el
4464      * @param {String/HTMLElement/Element} el The context element
4465      * @param {Object} o The Dom object spec (and children)
4466      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4467      * @return {HTMLElement/Roo.Element} The new node
4468      */
4469     insertAfter : function(el, o, returnElement){
4470         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4471     },
4472
4473     /**
4474      * Creates new Dom element(s) and inserts them as the first child of el
4475      * @param {String/HTMLElement/Element} el The context element
4476      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4477      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4478      * @return {HTMLElement/Roo.Element} The new node
4479      */
4480     insertFirst : function(el, o, returnElement){
4481         return this.doInsert(el, o, returnElement, "afterBegin");
4482     },
4483
4484     // private
4485     doInsert : function(el, o, returnElement, pos, sibling){
4486         el = Roo.getDom(el);
4487         var newNode;
4488         if(this.useDom || o.ns){
4489             newNode = createDom(o, null);
4490             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4491         }else{
4492             var html = createHtml(o);
4493             newNode = this.insertHtml(pos, el, html);
4494         }
4495         return returnElement ? Roo.get(newNode, true) : newNode;
4496     },
4497
4498     /**
4499      * Creates new Dom element(s) and appends them to el
4500      * @param {String/HTMLElement/Element} el The context element
4501      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4502      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4503      * @return {HTMLElement/Roo.Element} The new node
4504      */
4505     append : function(el, o, returnElement){
4506         el = Roo.getDom(el);
4507         var newNode;
4508         if(this.useDom || o.ns){
4509             newNode = createDom(o, null);
4510             el.appendChild(newNode);
4511         }else{
4512             var html = createHtml(o);
4513             newNode = this.insertHtml("beforeEnd", el, html);
4514         }
4515         return returnElement ? Roo.get(newNode, true) : newNode;
4516     },
4517
4518     /**
4519      * Creates new Dom element(s) and overwrites the contents of el with them
4520      * @param {String/HTMLElement/Element} el The context element
4521      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4522      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4523      * @return {HTMLElement/Roo.Element} The new node
4524      */
4525     overwrite : function(el, o, returnElement){
4526         el = Roo.getDom(el);
4527         if (o.ns) {
4528           
4529             while (el.childNodes.length) {
4530                 el.removeChild(el.firstChild);
4531             }
4532             createDom(o, el);
4533         } else {
4534             el.innerHTML = createHtml(o);   
4535         }
4536         
4537         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4538     },
4539
4540     /**
4541      * Creates a new Roo.DomHelper.Template from the Dom object spec
4542      * @param {Object} o The Dom object spec (and children)
4543      * @return {Roo.DomHelper.Template} The new template
4544      */
4545     createTemplate : function(o){
4546         var html = createHtml(o);
4547         return new Roo.Template(html);
4548     }
4549     };
4550 }();
4551 /*
4552  * Based on:
4553  * Ext JS Library 1.1.1
4554  * Copyright(c) 2006-2007, Ext JS, LLC.
4555  *
4556  * Originally Released Under LGPL - original licence link has changed is not relivant.
4557  *
4558  * Fork - LGPL
4559  * <script type="text/javascript">
4560  */
4561  
4562 /**
4563 * @class Roo.Template
4564 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4565 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4566 * Usage:
4567 <pre><code>
4568 var t = new Roo.Template({
4569     html :  '&lt;div name="{id}"&gt;' + 
4570         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4571         '&lt;/div&gt;',
4572     myformat: function (value, allValues) {
4573         return 'XX' + value;
4574     }
4575 });
4576 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4577 </code></pre>
4578 * For more information see this blog post with examples:
4579 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4580      - Create Elements using DOM, HTML fragments and Templates</a>. 
4581 * @constructor
4582 * @param {Object} cfg - Configuration object.
4583 */
4584 Roo.Template = function(cfg){
4585     // BC!
4586     if(cfg instanceof Array){
4587         cfg = cfg.join("");
4588     }else if(arguments.length > 1){
4589         cfg = Array.prototype.join.call(arguments, "");
4590     }
4591     
4592     
4593     if (typeof(cfg) == 'object') {
4594         Roo.apply(this,cfg)
4595     } else {
4596         // bc
4597         this.html = cfg;
4598     }
4599     if (this.url) {
4600         this.load();
4601     }
4602     
4603 };
4604 Roo.Template.prototype = {
4605     
4606     /**
4607      * @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..
4608      *                    it should be fixed so that template is observable...
4609      */
4610     url : false,
4611     /**
4612      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4613      */
4614     html : '',
4615     /**
4616      * Returns an HTML fragment of this template with the specified values applied.
4617      * @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'})
4618      * @return {String} The HTML fragment
4619      */
4620     applyTemplate : function(values){
4621         try {
4622            
4623             if(this.compiled){
4624                 return this.compiled(values);
4625             }
4626             var useF = this.disableFormats !== true;
4627             var fm = Roo.util.Format, tpl = this;
4628             var fn = function(m, name, format, args){
4629                 if(format && useF){
4630                     if(format.substr(0, 5) == "this."){
4631                         return tpl.call(format.substr(5), values[name], values);
4632                     }else{
4633                         if(args){
4634                             // quoted values are required for strings in compiled templates, 
4635                             // but for non compiled we need to strip them
4636                             // quoted reversed for jsmin
4637                             var re = /^\s*['"](.*)["']\s*$/;
4638                             args = args.split(',');
4639                             for(var i = 0, len = args.length; i < len; i++){
4640                                 args[i] = args[i].replace(re, "$1");
4641                             }
4642                             args = [values[name]].concat(args);
4643                         }else{
4644                             args = [values[name]];
4645                         }
4646                         return fm[format].apply(fm, args);
4647                     }
4648                 }else{
4649                     return values[name] !== undefined ? values[name] : "";
4650                 }
4651             };
4652             return this.html.replace(this.re, fn);
4653         } catch (e) {
4654             Roo.log(e);
4655             throw e;
4656         }
4657          
4658     },
4659     
4660     loading : false,
4661       
4662     load : function ()
4663     {
4664          
4665         if (this.loading) {
4666             return;
4667         }
4668         var _t = this;
4669         
4670         this.loading = true;
4671         this.compiled = false;
4672         
4673         var cx = new Roo.data.Connection();
4674         cx.request({
4675             url : this.url,
4676             method : 'GET',
4677             success : function (response) {
4678                 _t.loading = false;
4679                 _t.html = response.responseText;
4680                 _t.url = false;
4681                 _t.compile();
4682              },
4683             failure : function(response) {
4684                 Roo.log("Template failed to load from " + _t.url);
4685                 _t.loading = false;
4686             }
4687         });
4688     },
4689
4690     /**
4691      * Sets the HTML used as the template and optionally compiles it.
4692      * @param {String} html
4693      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4694      * @return {Roo.Template} this
4695      */
4696     set : function(html, compile){
4697         this.html = html;
4698         this.compiled = null;
4699         if(compile){
4700             this.compile();
4701         }
4702         return this;
4703     },
4704     
4705     /**
4706      * True to disable format functions (defaults to false)
4707      * @type Boolean
4708      */
4709     disableFormats : false,
4710     
4711     /**
4712     * The regular expression used to match template variables 
4713     * @type RegExp
4714     * @property 
4715     */
4716     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4717     
4718     /**
4719      * Compiles the template into an internal function, eliminating the RegEx overhead.
4720      * @return {Roo.Template} this
4721      */
4722     compile : function(){
4723         var fm = Roo.util.Format;
4724         var useF = this.disableFormats !== true;
4725         var sep = Roo.isGecko ? "+" : ",";
4726         var fn = function(m, name, format, args){
4727             if(format && useF){
4728                 args = args ? ',' + args : "";
4729                 if(format.substr(0, 5) != "this."){
4730                     format = "fm." + format + '(';
4731                 }else{
4732                     format = 'this.call("'+ format.substr(5) + '", ';
4733                     args = ", values";
4734                 }
4735             }else{
4736                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4737             }
4738             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4739         };
4740         var body;
4741         // branched to use + in gecko and [].join() in others
4742         if(Roo.isGecko){
4743             body = "this.compiled = function(values){ return '" +
4744                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4745                     "';};";
4746         }else{
4747             body = ["this.compiled = function(values){ return ['"];
4748             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4749             body.push("'].join('');};");
4750             body = body.join('');
4751         }
4752         /**
4753          * eval:var:values
4754          * eval:var:fm
4755          */
4756         eval(body);
4757         return this;
4758     },
4759     
4760     // private function used to call members
4761     call : function(fnName, value, allValues){
4762         return this[fnName](value, allValues);
4763     },
4764     
4765     /**
4766      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4767      * @param {String/HTMLElement/Roo.Element} el The context element
4768      * @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'})
4769      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4770      * @return {HTMLElement/Roo.Element} The new node or Element
4771      */
4772     insertFirst: function(el, values, returnElement){
4773         return this.doInsert('afterBegin', el, values, returnElement);
4774     },
4775
4776     /**
4777      * Applies the supplied values to the template and inserts the new node(s) before el.
4778      * @param {String/HTMLElement/Roo.Element} el The context element
4779      * @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'})
4780      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4781      * @return {HTMLElement/Roo.Element} The new node or Element
4782      */
4783     insertBefore: function(el, values, returnElement){
4784         return this.doInsert('beforeBegin', el, values, returnElement);
4785     },
4786
4787     /**
4788      * Applies the supplied values to the template and inserts the new node(s) after el.
4789      * @param {String/HTMLElement/Roo.Element} el The context element
4790      * @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'})
4791      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4792      * @return {HTMLElement/Roo.Element} The new node or Element
4793      */
4794     insertAfter : function(el, values, returnElement){
4795         return this.doInsert('afterEnd', el, values, returnElement);
4796     },
4797     
4798     /**
4799      * Applies the supplied values to the template and appends the new node(s) to el.
4800      * @param {String/HTMLElement/Roo.Element} el The context element
4801      * @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'})
4802      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4803      * @return {HTMLElement/Roo.Element} The new node or Element
4804      */
4805     append : function(el, values, returnElement){
4806         return this.doInsert('beforeEnd', el, values, returnElement);
4807     },
4808
4809     doInsert : function(where, el, values, returnEl){
4810         el = Roo.getDom(el);
4811         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4812         return returnEl ? Roo.get(newNode, true) : newNode;
4813     },
4814
4815     /**
4816      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4817      * @param {String/HTMLElement/Roo.Element} el The context element
4818      * @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'})
4819      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4820      * @return {HTMLElement/Roo.Element} The new node or Element
4821      */
4822     overwrite : function(el, values, returnElement){
4823         el = Roo.getDom(el);
4824         el.innerHTML = this.applyTemplate(values);
4825         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4826     }
4827 };
4828 /**
4829  * Alias for {@link #applyTemplate}
4830  * @method
4831  */
4832 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4833
4834 // backwards compat
4835 Roo.DomHelper.Template = Roo.Template;
4836
4837 /**
4838  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4839  * @param {String/HTMLElement} el A DOM element or its id
4840  * @returns {Roo.Template} The created template
4841  * @static
4842  */
4843 Roo.Template.from = function(el){
4844     el = Roo.getDom(el);
4845     return new Roo.Template(el.value || el.innerHTML);
4846 };/*
4847  * Based on:
4848  * Ext JS Library 1.1.1
4849  * Copyright(c) 2006-2007, Ext JS, LLC.
4850  *
4851  * Originally Released Under LGPL - original licence link has changed is not relivant.
4852  *
4853  * Fork - LGPL
4854  * <script type="text/javascript">
4855  */
4856  
4857
4858 /*
4859  * This is code is also distributed under MIT license for use
4860  * with jQuery and prototype JavaScript libraries.
4861  */
4862 /**
4863  * @class Roo.DomQuery
4864 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).
4865 <p>
4866 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>
4867
4868 <p>
4869 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.
4870 </p>
4871 <h4>Element Selectors:</h4>
4872 <ul class="list">
4873     <li> <b>*</b> any element</li>
4874     <li> <b>E</b> an element with the tag E</li>
4875     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4876     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4877     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4878     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4879 </ul>
4880 <h4>Attribute Selectors:</h4>
4881 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4882 <ul class="list">
4883     <li> <b>E[foo]</b> has an attribute "foo"</li>
4884     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4885     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4886     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4887     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4888     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4889     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4890 </ul>
4891 <h4>Pseudo Classes:</h4>
4892 <ul class="list">
4893     <li> <b>E:first-child</b> E is the first child of its parent</li>
4894     <li> <b>E:last-child</b> E is the last child of its parent</li>
4895     <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>
4896     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4897     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4898     <li> <b>E:only-child</b> E is the only child of its parent</li>
4899     <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>
4900     <li> <b>E:first</b> the first E in the resultset</li>
4901     <li> <b>E:last</b> the last E in the resultset</li>
4902     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4903     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4904     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4905     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4906     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4907     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4908     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4909     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4910     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4911 </ul>
4912 <h4>CSS Value Selectors:</h4>
4913 <ul class="list">
4914     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4915     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4916     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4917     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4918     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4919     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4920 </ul>
4921  * @singleton
4922  */
4923 Roo.DomQuery = function(){
4924     var cache = {}, simpleCache = {}, valueCache = {};
4925     var nonSpace = /\S/;
4926     var trimRe = /^\s+|\s+$/g;
4927     var tplRe = /\{(\d+)\}/g;
4928     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4929     var tagTokenRe = /^(#)?([\w-\*]+)/;
4930     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4931
4932     function child(p, index){
4933         var i = 0;
4934         var n = p.firstChild;
4935         while(n){
4936             if(n.nodeType == 1){
4937                if(++i == index){
4938                    return n;
4939                }
4940             }
4941             n = n.nextSibling;
4942         }
4943         return null;
4944     };
4945
4946     function next(n){
4947         while((n = n.nextSibling) && n.nodeType != 1);
4948         return n;
4949     };
4950
4951     function prev(n){
4952         while((n = n.previousSibling) && n.nodeType != 1);
4953         return n;
4954     };
4955
4956     function children(d){
4957         var n = d.firstChild, ni = -1;
4958             while(n){
4959                 var nx = n.nextSibling;
4960                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4961                     d.removeChild(n);
4962                 }else{
4963                     n.nodeIndex = ++ni;
4964                 }
4965                 n = nx;
4966             }
4967             return this;
4968         };
4969
4970     function byClassName(c, a, v){
4971         if(!v){
4972             return c;
4973         }
4974         var r = [], ri = -1, cn;
4975         for(var i = 0, ci; ci = c[i]; i++){
4976             if((' '+ci.className+' ').indexOf(v) != -1){
4977                 r[++ri] = ci;
4978             }
4979         }
4980         return r;
4981     };
4982
4983     function attrValue(n, attr){
4984         if(!n.tagName && typeof n.length != "undefined"){
4985             n = n[0];
4986         }
4987         if(!n){
4988             return null;
4989         }
4990         if(attr == "for"){
4991             return n.htmlFor;
4992         }
4993         if(attr == "class" || attr == "className"){
4994             return n.className;
4995         }
4996         return n.getAttribute(attr) || n[attr];
4997
4998     };
4999
5000     function getNodes(ns, mode, tagName){
5001         var result = [], ri = -1, cs;
5002         if(!ns){
5003             return result;
5004         }
5005         tagName = tagName || "*";
5006         if(typeof ns.getElementsByTagName != "undefined"){
5007             ns = [ns];
5008         }
5009         if(!mode){
5010             for(var i = 0, ni; ni = ns[i]; i++){
5011                 cs = ni.getElementsByTagName(tagName);
5012                 for(var j = 0, ci; ci = cs[j]; j++){
5013                     result[++ri] = ci;
5014                 }
5015             }
5016         }else if(mode == "/" || mode == ">"){
5017             var utag = tagName.toUpperCase();
5018             for(var i = 0, ni, cn; ni = ns[i]; i++){
5019                 cn = ni.children || ni.childNodes;
5020                 for(var j = 0, cj; cj = cn[j]; j++){
5021                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5022                         result[++ri] = cj;
5023                     }
5024                 }
5025             }
5026         }else if(mode == "+"){
5027             var utag = tagName.toUpperCase();
5028             for(var i = 0, n; n = ns[i]; i++){
5029                 while((n = n.nextSibling) && n.nodeType != 1);
5030                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5031                     result[++ri] = n;
5032                 }
5033             }
5034         }else if(mode == "~"){
5035             for(var i = 0, n; n = ns[i]; i++){
5036                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5037                 if(n){
5038                     result[++ri] = n;
5039                 }
5040             }
5041         }
5042         return result;
5043     };
5044
5045     function concat(a, b){
5046         if(b.slice){
5047             return a.concat(b);
5048         }
5049         for(var i = 0, l = b.length; i < l; i++){
5050             a[a.length] = b[i];
5051         }
5052         return a;
5053     }
5054
5055     function byTag(cs, tagName){
5056         if(cs.tagName || cs == document){
5057             cs = [cs];
5058         }
5059         if(!tagName){
5060             return cs;
5061         }
5062         var r = [], ri = -1;
5063         tagName = tagName.toLowerCase();
5064         for(var i = 0, ci; ci = cs[i]; i++){
5065             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5066                 r[++ri] = ci;
5067             }
5068         }
5069         return r;
5070     };
5071
5072     function byId(cs, attr, id){
5073         if(cs.tagName || cs == document){
5074             cs = [cs];
5075         }
5076         if(!id){
5077             return cs;
5078         }
5079         var r = [], ri = -1;
5080         for(var i = 0,ci; ci = cs[i]; i++){
5081             if(ci && ci.id == id){
5082                 r[++ri] = ci;
5083                 return r;
5084             }
5085         }
5086         return r;
5087     };
5088
5089     function byAttribute(cs, attr, value, op, custom){
5090         var r = [], ri = -1, st = custom=="{";
5091         var f = Roo.DomQuery.operators[op];
5092         for(var i = 0, ci; ci = cs[i]; i++){
5093             var a;
5094             if(st){
5095                 a = Roo.DomQuery.getStyle(ci, attr);
5096             }
5097             else if(attr == "class" || attr == "className"){
5098                 a = ci.className;
5099             }else if(attr == "for"){
5100                 a = ci.htmlFor;
5101             }else if(attr == "href"){
5102                 a = ci.getAttribute("href", 2);
5103             }else{
5104                 a = ci.getAttribute(attr);
5105             }
5106             if((f && f(a, value)) || (!f && a)){
5107                 r[++ri] = ci;
5108             }
5109         }
5110         return r;
5111     };
5112
5113     function byPseudo(cs, name, value){
5114         return Roo.DomQuery.pseudos[name](cs, value);
5115     };
5116
5117     // This is for IE MSXML which does not support expandos.
5118     // IE runs the same speed using setAttribute, however FF slows way down
5119     // and Safari completely fails so they need to continue to use expandos.
5120     var isIE = window.ActiveXObject ? true : false;
5121
5122     // this eval is stop the compressor from
5123     // renaming the variable to something shorter
5124     
5125     /** eval:var:batch */
5126     var batch = 30803; 
5127
5128     var key = 30803;
5129
5130     function nodupIEXml(cs){
5131         var d = ++key;
5132         cs[0].setAttribute("_nodup", d);
5133         var r = [cs[0]];
5134         for(var i = 1, len = cs.length; i < len; i++){
5135             var c = cs[i];
5136             if(!c.getAttribute("_nodup") != d){
5137                 c.setAttribute("_nodup", d);
5138                 r[r.length] = c;
5139             }
5140         }
5141         for(var i = 0, len = cs.length; i < len; i++){
5142             cs[i].removeAttribute("_nodup");
5143         }
5144         return r;
5145     }
5146
5147     function nodup(cs){
5148         if(!cs){
5149             return [];
5150         }
5151         var len = cs.length, c, i, r = cs, cj, ri = -1;
5152         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5153             return cs;
5154         }
5155         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5156             return nodupIEXml(cs);
5157         }
5158         var d = ++key;
5159         cs[0]._nodup = d;
5160         for(i = 1; c = cs[i]; i++){
5161             if(c._nodup != d){
5162                 c._nodup = d;
5163             }else{
5164                 r = [];
5165                 for(var j = 0; j < i; j++){
5166                     r[++ri] = cs[j];
5167                 }
5168                 for(j = i+1; cj = cs[j]; j++){
5169                     if(cj._nodup != d){
5170                         cj._nodup = d;
5171                         r[++ri] = cj;
5172                     }
5173                 }
5174                 return r;
5175             }
5176         }
5177         return r;
5178     }
5179
5180     function quickDiffIEXml(c1, c2){
5181         var d = ++key;
5182         for(var i = 0, len = c1.length; i < len; i++){
5183             c1[i].setAttribute("_qdiff", d);
5184         }
5185         var r = [];
5186         for(var i = 0, len = c2.length; i < len; i++){
5187             if(c2[i].getAttribute("_qdiff") != d){
5188                 r[r.length] = c2[i];
5189             }
5190         }
5191         for(var i = 0, len = c1.length; i < len; i++){
5192            c1[i].removeAttribute("_qdiff");
5193         }
5194         return r;
5195     }
5196
5197     function quickDiff(c1, c2){
5198         var len1 = c1.length;
5199         if(!len1){
5200             return c2;
5201         }
5202         if(isIE && c1[0].selectSingleNode){
5203             return quickDiffIEXml(c1, c2);
5204         }
5205         var d = ++key;
5206         for(var i = 0; i < len1; i++){
5207             c1[i]._qdiff = d;
5208         }
5209         var r = [];
5210         for(var i = 0, len = c2.length; i < len; i++){
5211             if(c2[i]._qdiff != d){
5212                 r[r.length] = c2[i];
5213             }
5214         }
5215         return r;
5216     }
5217
5218     function quickId(ns, mode, root, id){
5219         if(ns == root){
5220            var d = root.ownerDocument || root;
5221            return d.getElementById(id);
5222         }
5223         ns = getNodes(ns, mode, "*");
5224         return byId(ns, null, id);
5225     }
5226
5227     return {
5228         getStyle : function(el, name){
5229             return Roo.fly(el).getStyle(name);
5230         },
5231         /**
5232          * Compiles a selector/xpath query into a reusable function. The returned function
5233          * takes one parameter "root" (optional), which is the context node from where the query should start.
5234          * @param {String} selector The selector/xpath query
5235          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5236          * @return {Function}
5237          */
5238         compile : function(path, type){
5239             type = type || "select";
5240             
5241             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5242             var q = path, mode, lq;
5243             var tk = Roo.DomQuery.matchers;
5244             var tklen = tk.length;
5245             var mm;
5246
5247             // accept leading mode switch
5248             var lmode = q.match(modeRe);
5249             if(lmode && lmode[1]){
5250                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5251                 q = q.replace(lmode[1], "");
5252             }
5253             // strip leading slashes
5254             while(path.substr(0, 1)=="/"){
5255                 path = path.substr(1);
5256             }
5257
5258             while(q && lq != q){
5259                 lq = q;
5260                 var tm = q.match(tagTokenRe);
5261                 if(type == "select"){
5262                     if(tm){
5263                         if(tm[1] == "#"){
5264                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5265                         }else{
5266                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5267                         }
5268                         q = q.replace(tm[0], "");
5269                     }else if(q.substr(0, 1) != '@'){
5270                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5271                     }
5272                 }else{
5273                     if(tm){
5274                         if(tm[1] == "#"){
5275                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5276                         }else{
5277                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5278                         }
5279                         q = q.replace(tm[0], "");
5280                     }
5281                 }
5282                 while(!(mm = q.match(modeRe))){
5283                     var matched = false;
5284                     for(var j = 0; j < tklen; j++){
5285                         var t = tk[j];
5286                         var m = q.match(t.re);
5287                         if(m){
5288                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5289                                                     return m[i];
5290                                                 });
5291                             q = q.replace(m[0], "");
5292                             matched = true;
5293                             break;
5294                         }
5295                     }
5296                     // prevent infinite loop on bad selector
5297                     if(!matched){
5298                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5299                     }
5300                 }
5301                 if(mm[1]){
5302                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5303                     q = q.replace(mm[1], "");
5304                 }
5305             }
5306             fn[fn.length] = "return nodup(n);\n}";
5307             
5308              /** 
5309               * list of variables that need from compression as they are used by eval.
5310              *  eval:var:batch 
5311              *  eval:var:nodup
5312              *  eval:var:byTag
5313              *  eval:var:ById
5314              *  eval:var:getNodes
5315              *  eval:var:quickId
5316              *  eval:var:mode
5317              *  eval:var:root
5318              *  eval:var:n
5319              *  eval:var:byClassName
5320              *  eval:var:byPseudo
5321              *  eval:var:byAttribute
5322              *  eval:var:attrValue
5323              * 
5324              **/ 
5325             eval(fn.join(""));
5326             return f;
5327         },
5328
5329         /**
5330          * Selects a group of elements.
5331          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5332          * @param {Node} root (optional) The start of the query (defaults to document).
5333          * @return {Array}
5334          */
5335         select : function(path, root, type){
5336             if(!root || root == document){
5337                 root = document;
5338             }
5339             if(typeof root == "string"){
5340                 root = document.getElementById(root);
5341             }
5342             var paths = path.split(",");
5343             var results = [];
5344             for(var i = 0, len = paths.length; i < len; i++){
5345                 var p = paths[i].replace(trimRe, "");
5346                 if(!cache[p]){
5347                     cache[p] = Roo.DomQuery.compile(p);
5348                     if(!cache[p]){
5349                         throw p + " is not a valid selector";
5350                     }
5351                 }
5352                 var result = cache[p](root);
5353                 if(result && result != document){
5354                     results = results.concat(result);
5355                 }
5356             }
5357             if(paths.length > 1){
5358                 return nodup(results);
5359             }
5360             return results;
5361         },
5362
5363         /**
5364          * Selects a single element.
5365          * @param {String} selector The selector/xpath query
5366          * @param {Node} root (optional) The start of the query (defaults to document).
5367          * @return {Element}
5368          */
5369         selectNode : function(path, root){
5370             return Roo.DomQuery.select(path, root)[0];
5371         },
5372
5373         /**
5374          * Selects the value of a node, optionally replacing null with the defaultValue.
5375          * @param {String} selector The selector/xpath query
5376          * @param {Node} root (optional) The start of the query (defaults to document).
5377          * @param {String} defaultValue
5378          */
5379         selectValue : function(path, root, defaultValue){
5380             path = path.replace(trimRe, "");
5381             if(!valueCache[path]){
5382                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5383             }
5384             var n = valueCache[path](root);
5385             n = n[0] ? n[0] : n;
5386             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5387             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5388         },
5389
5390         /**
5391          * Selects the value of a node, parsing integers and floats.
5392          * @param {String} selector The selector/xpath query
5393          * @param {Node} root (optional) The start of the query (defaults to document).
5394          * @param {Number} defaultValue
5395          * @return {Number}
5396          */
5397         selectNumber : function(path, root, defaultValue){
5398             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5399             return parseFloat(v);
5400         },
5401
5402         /**
5403          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5404          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5405          * @param {String} selector The simple selector to test
5406          * @return {Boolean}
5407          */
5408         is : function(el, ss){
5409             if(typeof el == "string"){
5410                 el = document.getElementById(el);
5411             }
5412             var isArray = (el instanceof Array);
5413             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5414             return isArray ? (result.length == el.length) : (result.length > 0);
5415         },
5416
5417         /**
5418          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5419          * @param {Array} el An array of elements to filter
5420          * @param {String} selector The simple selector to test
5421          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5422          * the selector instead of the ones that match
5423          * @return {Array}
5424          */
5425         filter : function(els, ss, nonMatches){
5426             ss = ss.replace(trimRe, "");
5427             if(!simpleCache[ss]){
5428                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5429             }
5430             var result = simpleCache[ss](els);
5431             return nonMatches ? quickDiff(result, els) : result;
5432         },
5433
5434         /**
5435          * Collection of matching regular expressions and code snippets.
5436          */
5437         matchers : [{
5438                 re: /^\.([\w-]+)/,
5439                 select: 'n = byClassName(n, null, " {1} ");'
5440             }, {
5441                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5442                 select: 'n = byPseudo(n, "{1}", "{2}");'
5443             },{
5444                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5445                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5446             }, {
5447                 re: /^#([\w-]+)/,
5448                 select: 'n = byId(n, null, "{1}");'
5449             },{
5450                 re: /^@([\w-]+)/,
5451                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5452             }
5453         ],
5454
5455         /**
5456          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5457          * 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;.
5458          */
5459         operators : {
5460             "=" : function(a, v){
5461                 return a == v;
5462             },
5463             "!=" : function(a, v){
5464                 return a != v;
5465             },
5466             "^=" : function(a, v){
5467                 return a && a.substr(0, v.length) == v;
5468             },
5469             "$=" : function(a, v){
5470                 return a && a.substr(a.length-v.length) == v;
5471             },
5472             "*=" : function(a, v){
5473                 return a && a.indexOf(v) !== -1;
5474             },
5475             "%=" : function(a, v){
5476                 return (a % v) == 0;
5477             },
5478             "|=" : function(a, v){
5479                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5480             },
5481             "~=" : function(a, v){
5482                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5483             }
5484         },
5485
5486         /**
5487          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5488          * and the argument (if any) supplied in the selector.
5489          */
5490         pseudos : {
5491             "first-child" : function(c){
5492                 var r = [], ri = -1, n;
5493                 for(var i = 0, ci; ci = n = c[i]; i++){
5494                     while((n = n.previousSibling) && n.nodeType != 1);
5495                     if(!n){
5496                         r[++ri] = ci;
5497                     }
5498                 }
5499                 return r;
5500             },
5501
5502             "last-child" : function(c){
5503                 var r = [], ri = -1, n;
5504                 for(var i = 0, ci; ci = n = c[i]; i++){
5505                     while((n = n.nextSibling) && n.nodeType != 1);
5506                     if(!n){
5507                         r[++ri] = ci;
5508                     }
5509                 }
5510                 return r;
5511             },
5512
5513             "nth-child" : function(c, a) {
5514                 var r = [], ri = -1;
5515                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5516                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5517                 for(var i = 0, n; n = c[i]; i++){
5518                     var pn = n.parentNode;
5519                     if (batch != pn._batch) {
5520                         var j = 0;
5521                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5522                             if(cn.nodeType == 1){
5523                                cn.nodeIndex = ++j;
5524                             }
5525                         }
5526                         pn._batch = batch;
5527                     }
5528                     if (f == 1) {
5529                         if (l == 0 || n.nodeIndex == l){
5530                             r[++ri] = n;
5531                         }
5532                     } else if ((n.nodeIndex + l) % f == 0){
5533                         r[++ri] = n;
5534                     }
5535                 }
5536
5537                 return r;
5538             },
5539
5540             "only-child" : function(c){
5541                 var r = [], ri = -1;;
5542                 for(var i = 0, ci; ci = c[i]; i++){
5543                     if(!prev(ci) && !next(ci)){
5544                         r[++ri] = ci;
5545                     }
5546                 }
5547                 return r;
5548             },
5549
5550             "empty" : function(c){
5551                 var r = [], ri = -1;
5552                 for(var i = 0, ci; ci = c[i]; i++){
5553                     var cns = ci.childNodes, j = 0, cn, empty = true;
5554                     while(cn = cns[j]){
5555                         ++j;
5556                         if(cn.nodeType == 1 || cn.nodeType == 3){
5557                             empty = false;
5558                             break;
5559                         }
5560                     }
5561                     if(empty){
5562                         r[++ri] = ci;
5563                     }
5564                 }
5565                 return r;
5566             },
5567
5568             "contains" : function(c, v){
5569                 var r = [], ri = -1;
5570                 for(var i = 0, ci; ci = c[i]; i++){
5571                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5572                         r[++ri] = ci;
5573                     }
5574                 }
5575                 return r;
5576             },
5577
5578             "nodeValue" : function(c, v){
5579                 var r = [], ri = -1;
5580                 for(var i = 0, ci; ci = c[i]; i++){
5581                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5582                         r[++ri] = ci;
5583                     }
5584                 }
5585                 return r;
5586             },
5587
5588             "checked" : function(c){
5589                 var r = [], ri = -1;
5590                 for(var i = 0, ci; ci = c[i]; i++){
5591                     if(ci.checked == true){
5592                         r[++ri] = ci;
5593                     }
5594                 }
5595                 return r;
5596             },
5597
5598             "not" : function(c, ss){
5599                 return Roo.DomQuery.filter(c, ss, true);
5600             },
5601
5602             "odd" : function(c){
5603                 return this["nth-child"](c, "odd");
5604             },
5605
5606             "even" : function(c){
5607                 return this["nth-child"](c, "even");
5608             },
5609
5610             "nth" : function(c, a){
5611                 return c[a-1] || [];
5612             },
5613
5614             "first" : function(c){
5615                 return c[0] || [];
5616             },
5617
5618             "last" : function(c){
5619                 return c[c.length-1] || [];
5620             },
5621
5622             "has" : function(c, ss){
5623                 var s = Roo.DomQuery.select;
5624                 var r = [], ri = -1;
5625                 for(var i = 0, ci; ci = c[i]; i++){
5626                     if(s(ss, ci).length > 0){
5627                         r[++ri] = ci;
5628                     }
5629                 }
5630                 return r;
5631             },
5632
5633             "next" : function(c, ss){
5634                 var is = Roo.DomQuery.is;
5635                 var r = [], ri = -1;
5636                 for(var i = 0, ci; ci = c[i]; i++){
5637                     var n = next(ci);
5638                     if(n && is(n, ss)){
5639                         r[++ri] = ci;
5640                     }
5641                 }
5642                 return r;
5643             },
5644
5645             "prev" : function(c, ss){
5646                 var is = Roo.DomQuery.is;
5647                 var r = [], ri = -1;
5648                 for(var i = 0, ci; ci = c[i]; i++){
5649                     var n = prev(ci);
5650                     if(n && is(n, ss)){
5651                         r[++ri] = ci;
5652                     }
5653                 }
5654                 return r;
5655             }
5656         }
5657     };
5658 }();
5659
5660 /**
5661  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5662  * @param {String} path The selector/xpath query
5663  * @param {Node} root (optional) The start of the query (defaults to document).
5664  * @return {Array}
5665  * @member Roo
5666  * @method query
5667  */
5668 Roo.query = Roo.DomQuery.select;
5669 /*
5670  * Based on:
5671  * Ext JS Library 1.1.1
5672  * Copyright(c) 2006-2007, Ext JS, LLC.
5673  *
5674  * Originally Released Under LGPL - original licence link has changed is not relivant.
5675  *
5676  * Fork - LGPL
5677  * <script type="text/javascript">
5678  */
5679
5680 /**
5681  * @class Roo.util.Observable
5682  * Base class that provides a common interface for publishing events. Subclasses are expected to
5683  * to have a property "events" with all the events defined.<br>
5684  * For example:
5685  * <pre><code>
5686  Employee = function(name){
5687     this.name = name;
5688     this.addEvents({
5689         "fired" : true,
5690         "quit" : true
5691     });
5692  }
5693  Roo.extend(Employee, Roo.util.Observable);
5694 </code></pre>
5695  * @param {Object} config properties to use (incuding events / listeners)
5696  */
5697
5698 Roo.util.Observable = function(cfg){
5699     
5700     cfg = cfg|| {};
5701     this.addEvents(cfg.events || {});
5702     if (cfg.events) {
5703         delete cfg.events; // make sure
5704     }
5705      
5706     Roo.apply(this, cfg);
5707     
5708     if(this.listeners){
5709         this.on(this.listeners);
5710         delete this.listeners;
5711     }
5712 };
5713 Roo.util.Observable.prototype = {
5714     /** 
5715  * @cfg {Object} listeners  list of events and functions to call for this object, 
5716  * For example :
5717  * <pre><code>
5718     listeners :  { 
5719        'click' : function(e) {
5720            ..... 
5721         } ,
5722         .... 
5723     } 
5724   </code></pre>
5725  */
5726     
5727     
5728     /**
5729      * Fires the specified event with the passed parameters (minus the event name).
5730      * @param {String} eventName
5731      * @param {Object...} args Variable number of parameters are passed to handlers
5732      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5733      */
5734     fireEvent : function(){
5735         var ce = this.events[arguments[0].toLowerCase()];
5736         if(typeof ce == "object"){
5737             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5738         }else{
5739             return true;
5740         }
5741     },
5742
5743     // private
5744     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5745
5746     /**
5747      * Appends an event handler to this component
5748      * @param {String}   eventName The type of event to listen for
5749      * @param {Function} handler The method the event invokes
5750      * @param {Object}   scope (optional) The scope in which to execute the handler
5751      * function. The handler function's "this" context.
5752      * @param {Object}   options (optional) An object containing handler configuration
5753      * properties. This may contain any of the following properties:<ul>
5754      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5755      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5756      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5757      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5758      * by the specified number of milliseconds. If the event fires again within that time, the original
5759      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5760      * </ul><br>
5761      * <p>
5762      * <b>Combining Options</b><br>
5763      * Using the options argument, it is possible to combine different types of listeners:<br>
5764      * <br>
5765      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5766                 <pre><code>
5767                 el.on('click', this.onClick, this, {
5768                         single: true,
5769                 delay: 100,
5770                 forumId: 4
5771                 });
5772                 </code></pre>
5773      * <p>
5774      * <b>Attaching multiple handlers in 1 call</b><br>
5775      * The method also allows for a single argument to be passed which is a config object containing properties
5776      * which specify multiple handlers.
5777      * <pre><code>
5778                 el.on({
5779                         'click': {
5780                         fn: this.onClick,
5781                         scope: this,
5782                         delay: 100
5783                 }, 
5784                 'mouseover': {
5785                         fn: this.onMouseOver,
5786                         scope: this
5787                 },
5788                 'mouseout': {
5789                         fn: this.onMouseOut,
5790                         scope: this
5791                 }
5792                 });
5793                 </code></pre>
5794      * <p>
5795      * Or a shorthand syntax which passes the same scope object to all handlers:
5796         <pre><code>
5797                 el.on({
5798                         'click': this.onClick,
5799                 'mouseover': this.onMouseOver,
5800                 'mouseout': this.onMouseOut,
5801                 scope: this
5802                 });
5803                 </code></pre>
5804      */
5805     addListener : function(eventName, fn, scope, o){
5806         if(typeof eventName == "object"){
5807             o = eventName;
5808             for(var e in o){
5809                 if(this.filterOptRe.test(e)){
5810                     continue;
5811                 }
5812                 if(typeof o[e] == "function"){
5813                     // shared options
5814                     this.addListener(e, o[e], o.scope,  o);
5815                 }else{
5816                     // individual options
5817                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5818                 }
5819             }
5820             return;
5821         }
5822         o = (!o || typeof o == "boolean") ? {} : o;
5823         eventName = eventName.toLowerCase();
5824         var ce = this.events[eventName] || true;
5825         if(typeof ce == "boolean"){
5826             ce = new Roo.util.Event(this, eventName);
5827             this.events[eventName] = ce;
5828         }
5829         ce.addListener(fn, scope, o);
5830     },
5831
5832     /**
5833      * Removes a listener
5834      * @param {String}   eventName     The type of event to listen for
5835      * @param {Function} handler        The handler to remove
5836      * @param {Object}   scope  (optional) The scope (this object) for the handler
5837      */
5838     removeListener : function(eventName, fn, scope){
5839         var ce = this.events[eventName.toLowerCase()];
5840         if(typeof ce == "object"){
5841             ce.removeListener(fn, scope);
5842         }
5843     },
5844
5845     /**
5846      * Removes all listeners for this object
5847      */
5848     purgeListeners : function(){
5849         for(var evt in this.events){
5850             if(typeof this.events[evt] == "object"){
5851                  this.events[evt].clearListeners();
5852             }
5853         }
5854     },
5855
5856     relayEvents : function(o, events){
5857         var createHandler = function(ename){
5858             return function(){
5859                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5860             };
5861         };
5862         for(var i = 0, len = events.length; i < len; i++){
5863             var ename = events[i];
5864             if(!this.events[ename]){ this.events[ename] = true; };
5865             o.on(ename, createHandler(ename), this);
5866         }
5867     },
5868
5869     /**
5870      * Used to define events on this Observable
5871      * @param {Object} object The object with the events defined
5872      */
5873     addEvents : function(o){
5874         if(!this.events){
5875             this.events = {};
5876         }
5877         Roo.applyIf(this.events, o);
5878     },
5879
5880     /**
5881      * Checks to see if this object has any listeners for a specified event
5882      * @param {String} eventName The name of the event to check for
5883      * @return {Boolean} True if the event is being listened for, else false
5884      */
5885     hasListener : function(eventName){
5886         var e = this.events[eventName];
5887         return typeof e == "object" && e.listeners.length > 0;
5888     }
5889 };
5890 /**
5891  * Appends an event handler to this element (shorthand for addListener)
5892  * @param {String}   eventName     The type of event to listen for
5893  * @param {Function} handler        The method the event invokes
5894  * @param {Object}   scope (optional) The scope in which to execute the handler
5895  * function. The handler function's "this" context.
5896  * @param {Object}   options  (optional)
5897  * @method
5898  */
5899 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5900 /**
5901  * Removes a listener (shorthand for removeListener)
5902  * @param {String}   eventName     The type of event to listen for
5903  * @param {Function} handler        The handler to remove
5904  * @param {Object}   scope  (optional) The scope (this object) for the handler
5905  * @method
5906  */
5907 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5908
5909 /**
5910  * Starts capture on the specified Observable. All events will be passed
5911  * to the supplied function with the event name + standard signature of the event
5912  * <b>before</b> the event is fired. If the supplied function returns false,
5913  * the event will not fire.
5914  * @param {Observable} o The Observable to capture
5915  * @param {Function} fn The function to call
5916  * @param {Object} scope (optional) The scope (this object) for the fn
5917  * @static
5918  */
5919 Roo.util.Observable.capture = function(o, fn, scope){
5920     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5921 };
5922
5923 /**
5924  * Removes <b>all</b> added captures from the Observable.
5925  * @param {Observable} o The Observable to release
5926  * @static
5927  */
5928 Roo.util.Observable.releaseCapture = function(o){
5929     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5930 };
5931
5932 (function(){
5933
5934     var createBuffered = function(h, o, scope){
5935         var task = new Roo.util.DelayedTask();
5936         return function(){
5937             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5938         };
5939     };
5940
5941     var createSingle = function(h, e, fn, scope){
5942         return function(){
5943             e.removeListener(fn, scope);
5944             return h.apply(scope, arguments);
5945         };
5946     };
5947
5948     var createDelayed = function(h, o, scope){
5949         return function(){
5950             var args = Array.prototype.slice.call(arguments, 0);
5951             setTimeout(function(){
5952                 h.apply(scope, args);
5953             }, o.delay || 10);
5954         };
5955     };
5956
5957     Roo.util.Event = function(obj, name){
5958         this.name = name;
5959         this.obj = obj;
5960         this.listeners = [];
5961     };
5962
5963     Roo.util.Event.prototype = {
5964         addListener : function(fn, scope, options){
5965             var o = options || {};
5966             scope = scope || this.obj;
5967             if(!this.isListening(fn, scope)){
5968                 var l = {fn: fn, scope: scope, options: o};
5969                 var h = fn;
5970                 if(o.delay){
5971                     h = createDelayed(h, o, scope);
5972                 }
5973                 if(o.single){
5974                     h = createSingle(h, this, fn, scope);
5975                 }
5976                 if(o.buffer){
5977                     h = createBuffered(h, o, scope);
5978                 }
5979                 l.fireFn = h;
5980                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5981                     this.listeners.push(l);
5982                 }else{
5983                     this.listeners = this.listeners.slice(0);
5984                     this.listeners.push(l);
5985                 }
5986             }
5987         },
5988
5989         findListener : function(fn, scope){
5990             scope = scope || this.obj;
5991             var ls = this.listeners;
5992             for(var i = 0, len = ls.length; i < len; i++){
5993                 var l = ls[i];
5994                 if(l.fn == fn && l.scope == scope){
5995                     return i;
5996                 }
5997             }
5998             return -1;
5999         },
6000
6001         isListening : function(fn, scope){
6002             return this.findListener(fn, scope) != -1;
6003         },
6004
6005         removeListener : function(fn, scope){
6006             var index;
6007             if((index = this.findListener(fn, scope)) != -1){
6008                 if(!this.firing){
6009                     this.listeners.splice(index, 1);
6010                 }else{
6011                     this.listeners = this.listeners.slice(0);
6012                     this.listeners.splice(index, 1);
6013                 }
6014                 return true;
6015             }
6016             return false;
6017         },
6018
6019         clearListeners : function(){
6020             this.listeners = [];
6021         },
6022
6023         fire : function(){
6024             var ls = this.listeners, scope, len = ls.length;
6025             if(len > 0){
6026                 this.firing = true;
6027                 var args = Array.prototype.slice.call(arguments, 0);
6028                 for(var i = 0; i < len; i++){
6029                     var l = ls[i];
6030                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6031                         this.firing = false;
6032                         return false;
6033                     }
6034                 }
6035                 this.firing = false;
6036             }
6037             return true;
6038         }
6039     };
6040 })();/*
6041  * Based on:
6042  * Ext JS Library 1.1.1
6043  * Copyright(c) 2006-2007, Ext JS, LLC.
6044  *
6045  * Originally Released Under LGPL - original licence link has changed is not relivant.
6046  *
6047  * Fork - LGPL
6048  * <script type="text/javascript">
6049  */
6050
6051 /**
6052  * @class Roo.EventManager
6053  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6054  * several useful events directly.
6055  * See {@link Roo.EventObject} for more details on normalized event objects.
6056  * @singleton
6057  */
6058 Roo.EventManager = function(){
6059     var docReadyEvent, docReadyProcId, docReadyState = false;
6060     var resizeEvent, resizeTask, textEvent, textSize;
6061     var E = Roo.lib.Event;
6062     var D = Roo.lib.Dom;
6063
6064     
6065     
6066
6067     var fireDocReady = function(){
6068         if(!docReadyState){
6069             docReadyState = true;
6070             Roo.isReady = true;
6071             if(docReadyProcId){
6072                 clearInterval(docReadyProcId);
6073             }
6074             if(Roo.isGecko || Roo.isOpera) {
6075                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6076             }
6077             if(Roo.isIE){
6078                 var defer = document.getElementById("ie-deferred-loader");
6079                 if(defer){
6080                     defer.onreadystatechange = null;
6081                     defer.parentNode.removeChild(defer);
6082                 }
6083             }
6084             if(docReadyEvent){
6085                 docReadyEvent.fire();
6086                 docReadyEvent.clearListeners();
6087             }
6088         }
6089     };
6090     
6091     var initDocReady = function(){
6092         docReadyEvent = new Roo.util.Event();
6093         if(Roo.isGecko || Roo.isOpera) {
6094             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6095         }else if(Roo.isIE){
6096             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6097             var defer = document.getElementById("ie-deferred-loader");
6098             defer.onreadystatechange = function(){
6099                 if(this.readyState == "complete"){
6100                     fireDocReady();
6101                 }
6102             };
6103         }else if(Roo.isSafari){ 
6104             docReadyProcId = setInterval(function(){
6105                 var rs = document.readyState;
6106                 if(rs == "complete") {
6107                     fireDocReady();     
6108                  }
6109             }, 10);
6110         }
6111         // no matter what, make sure it fires on load
6112         E.on(window, "load", fireDocReady);
6113     };
6114
6115     var createBuffered = function(h, o){
6116         var task = new Roo.util.DelayedTask(h);
6117         return function(e){
6118             // create new event object impl so new events don't wipe out properties
6119             e = new Roo.EventObjectImpl(e);
6120             task.delay(o.buffer, h, null, [e]);
6121         };
6122     };
6123
6124     var createSingle = function(h, el, ename, fn){
6125         return function(e){
6126             Roo.EventManager.removeListener(el, ename, fn);
6127             h(e);
6128         };
6129     };
6130
6131     var createDelayed = function(h, o){
6132         return function(e){
6133             // create new event object impl so new events don't wipe out properties
6134             e = new Roo.EventObjectImpl(e);
6135             setTimeout(function(){
6136                 h(e);
6137             }, o.delay || 10);
6138         };
6139     };
6140     var transitionEndVal = false;
6141     
6142     var transitionEnd = function()
6143     {
6144         if (transitionEndVal) {
6145             return transitionEndVal;
6146         }
6147         var el = document.createElement('div');
6148
6149         var transEndEventNames = {
6150             WebkitTransition : 'webkitTransitionEnd',
6151             MozTransition    : 'transitionend',
6152             OTransition      : 'oTransitionEnd otransitionend',
6153             transition       : 'transitionend'
6154         };
6155     
6156         for (var name in transEndEventNames) {
6157             if (el.style[name] !== undefined) {
6158                 transitionEndVal = transEndEventNames[name];
6159                 return  transitionEndVal ;
6160             }
6161         }
6162     }
6163     
6164
6165     var listen = function(element, ename, opt, fn, scope){
6166         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6167         fn = fn || o.fn; scope = scope || o.scope;
6168         var el = Roo.getDom(element);
6169         
6170         
6171         if(!el){
6172             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6173         }
6174         
6175         if (ename == 'transitionend') {
6176             ename = transitionEnd();
6177         }
6178         var h = function(e){
6179             e = Roo.EventObject.setEvent(e);
6180             var t;
6181             if(o.delegate){
6182                 t = e.getTarget(o.delegate, el);
6183                 if(!t){
6184                     return;
6185                 }
6186             }else{
6187                 t = e.target;
6188             }
6189             if(o.stopEvent === true){
6190                 e.stopEvent();
6191             }
6192             if(o.preventDefault === true){
6193                e.preventDefault();
6194             }
6195             if(o.stopPropagation === true){
6196                 e.stopPropagation();
6197             }
6198
6199             if(o.normalized === false){
6200                 e = e.browserEvent;
6201             }
6202
6203             fn.call(scope || el, e, t, o);
6204         };
6205         if(o.delay){
6206             h = createDelayed(h, o);
6207         }
6208         if(o.single){
6209             h = createSingle(h, el, ename, fn);
6210         }
6211         if(o.buffer){
6212             h = createBuffered(h, o);
6213         }
6214         fn._handlers = fn._handlers || [];
6215         
6216         
6217         fn._handlers.push([Roo.id(el), ename, h]);
6218         
6219         
6220          
6221         E.on(el, ename, h);
6222         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6223             el.addEventListener("DOMMouseScroll", h, false);
6224             E.on(window, 'unload', function(){
6225                 el.removeEventListener("DOMMouseScroll", h, false);
6226             });
6227         }
6228         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6229             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6230         }
6231         return h;
6232     };
6233
6234     var stopListening = function(el, ename, fn){
6235         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6236         if(hds){
6237             for(var i = 0, len = hds.length; i < len; i++){
6238                 var h = hds[i];
6239                 if(h[0] == id && h[1] == ename){
6240                     hd = h[2];
6241                     hds.splice(i, 1);
6242                     break;
6243                 }
6244             }
6245         }
6246         E.un(el, ename, hd);
6247         el = Roo.getDom(el);
6248         if(ename == "mousewheel" && el.addEventListener){
6249             el.removeEventListener("DOMMouseScroll", hd, false);
6250         }
6251         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6252             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6253         }
6254     };
6255
6256     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6257     
6258     var pub = {
6259         
6260         
6261         /** 
6262          * Fix for doc tools
6263          * @scope Roo.EventManager
6264          */
6265         
6266         
6267         /** 
6268          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6269          * object with a Roo.EventObject
6270          * @param {Function} fn        The method the event invokes
6271          * @param {Object}   scope    An object that becomes the scope of the handler
6272          * @param {boolean}  override If true, the obj passed in becomes
6273          *                             the execution scope of the listener
6274          * @return {Function} The wrapped function
6275          * @deprecated
6276          */
6277         wrap : function(fn, scope, override){
6278             return function(e){
6279                 Roo.EventObject.setEvent(e);
6280                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6281             };
6282         },
6283         
6284         /**
6285      * Appends an event handler to an element (shorthand for addListener)
6286      * @param {String/HTMLElement}   element        The html element or id to assign the
6287      * @param {String}   eventName The type of event to listen for
6288      * @param {Function} handler The method the event invokes
6289      * @param {Object}   scope (optional) The scope in which to execute the handler
6290      * function. The handler function's "this" context.
6291      * @param {Object}   options (optional) An object containing handler configuration
6292      * properties. This may contain any of the following properties:<ul>
6293      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6294      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6295      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6296      * <li>preventDefault {Boolean} True to prevent the default action</li>
6297      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6298      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6299      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6300      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6301      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6302      * by the specified number of milliseconds. If the event fires again within that time, the original
6303      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6304      * </ul><br>
6305      * <p>
6306      * <b>Combining Options</b><br>
6307      * Using the options argument, it is possible to combine different types of listeners:<br>
6308      * <br>
6309      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6310      * Code:<pre><code>
6311 el.on('click', this.onClick, this, {
6312     single: true,
6313     delay: 100,
6314     stopEvent : true,
6315     forumId: 4
6316 });</code></pre>
6317      * <p>
6318      * <b>Attaching multiple handlers in 1 call</b><br>
6319       * The method also allows for a single argument to be passed which is a config object containing properties
6320      * which specify multiple handlers.
6321      * <p>
6322      * Code:<pre><code>
6323 el.on({
6324     'click' : {
6325         fn: this.onClick
6326         scope: this,
6327         delay: 100
6328     },
6329     'mouseover' : {
6330         fn: this.onMouseOver
6331         scope: this
6332     },
6333     'mouseout' : {
6334         fn: this.onMouseOut
6335         scope: this
6336     }
6337 });</code></pre>
6338      * <p>
6339      * Or a shorthand syntax:<br>
6340      * Code:<pre><code>
6341 el.on({
6342     'click' : this.onClick,
6343     'mouseover' : this.onMouseOver,
6344     'mouseout' : this.onMouseOut
6345     scope: this
6346 });</code></pre>
6347      */
6348         addListener : function(element, eventName, fn, scope, options){
6349             if(typeof eventName == "object"){
6350                 var o = eventName;
6351                 for(var e in o){
6352                     if(propRe.test(e)){
6353                         continue;
6354                     }
6355                     if(typeof o[e] == "function"){
6356                         // shared options
6357                         listen(element, e, o, o[e], o.scope);
6358                     }else{
6359                         // individual options
6360                         listen(element, e, o[e]);
6361                     }
6362                 }
6363                 return;
6364             }
6365             return listen(element, eventName, options, fn, scope);
6366         },
6367         
6368         /**
6369          * Removes an event handler
6370          *
6371          * @param {String/HTMLElement}   element        The id or html element to remove the 
6372          *                             event from
6373          * @param {String}   eventName     The type of event
6374          * @param {Function} fn
6375          * @return {Boolean} True if a listener was actually removed
6376          */
6377         removeListener : function(element, eventName, fn){
6378             return stopListening(element, eventName, fn);
6379         },
6380         
6381         /**
6382          * Fires when the document is ready (before onload and before images are loaded). Can be 
6383          * accessed shorthanded Roo.onReady().
6384          * @param {Function} fn        The method the event invokes
6385          * @param {Object}   scope    An  object that becomes the scope of the handler
6386          * @param {boolean}  options
6387          */
6388         onDocumentReady : function(fn, scope, options){
6389             if(docReadyState){ // if it already fired
6390                 docReadyEvent.addListener(fn, scope, options);
6391                 docReadyEvent.fire();
6392                 docReadyEvent.clearListeners();
6393                 return;
6394             }
6395             if(!docReadyEvent){
6396                 initDocReady();
6397             }
6398             docReadyEvent.addListener(fn, scope, options);
6399         },
6400         
6401         /**
6402          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6403          * @param {Function} fn        The method the event invokes
6404          * @param {Object}   scope    An object that becomes the scope of the handler
6405          * @param {boolean}  options
6406          */
6407         onWindowResize : function(fn, scope, options){
6408             if(!resizeEvent){
6409                 resizeEvent = new Roo.util.Event();
6410                 resizeTask = new Roo.util.DelayedTask(function(){
6411                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6412                 });
6413                 E.on(window, "resize", function(){
6414                     if(Roo.isIE){
6415                         resizeTask.delay(50);
6416                     }else{
6417                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6418                     }
6419                 });
6420             }
6421             resizeEvent.addListener(fn, scope, options);
6422         },
6423
6424         /**
6425          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6426          * @param {Function} fn        The method the event invokes
6427          * @param {Object}   scope    An object that becomes the scope of the handler
6428          * @param {boolean}  options
6429          */
6430         onTextResize : function(fn, scope, options){
6431             if(!textEvent){
6432                 textEvent = new Roo.util.Event();
6433                 var textEl = new Roo.Element(document.createElement('div'));
6434                 textEl.dom.className = 'x-text-resize';
6435                 textEl.dom.innerHTML = 'X';
6436                 textEl.appendTo(document.body);
6437                 textSize = textEl.dom.offsetHeight;
6438                 setInterval(function(){
6439                     if(textEl.dom.offsetHeight != textSize){
6440                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6441                     }
6442                 }, this.textResizeInterval);
6443             }
6444             textEvent.addListener(fn, scope, options);
6445         },
6446
6447         /**
6448          * Removes the passed window resize listener.
6449          * @param {Function} fn        The method the event invokes
6450          * @param {Object}   scope    The scope of handler
6451          */
6452         removeResizeListener : function(fn, scope){
6453             if(resizeEvent){
6454                 resizeEvent.removeListener(fn, scope);
6455             }
6456         },
6457
6458         // private
6459         fireResize : function(){
6460             if(resizeEvent){
6461                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6462             }   
6463         },
6464         /**
6465          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6466          */
6467         ieDeferSrc : false,
6468         /**
6469          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6470          */
6471         textResizeInterval : 50
6472     };
6473     
6474     /**
6475      * Fix for doc tools
6476      * @scopeAlias pub=Roo.EventManager
6477      */
6478     
6479      /**
6480      * Appends an event handler to an element (shorthand for addListener)
6481      * @param {String/HTMLElement}   element        The html element or id to assign the
6482      * @param {String}   eventName The type of event to listen for
6483      * @param {Function} handler The method the event invokes
6484      * @param {Object}   scope (optional) The scope in which to execute the handler
6485      * function. The handler function's "this" context.
6486      * @param {Object}   options (optional) An object containing handler configuration
6487      * properties. This may contain any of the following properties:<ul>
6488      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6489      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6490      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6491      * <li>preventDefault {Boolean} True to prevent the default action</li>
6492      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6493      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6494      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6495      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6496      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6497      * by the specified number of milliseconds. If the event fires again within that time, the original
6498      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6499      * </ul><br>
6500      * <p>
6501      * <b>Combining Options</b><br>
6502      * Using the options argument, it is possible to combine different types of listeners:<br>
6503      * <br>
6504      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6505      * Code:<pre><code>
6506 el.on('click', this.onClick, this, {
6507     single: true,
6508     delay: 100,
6509     stopEvent : true,
6510     forumId: 4
6511 });</code></pre>
6512      * <p>
6513      * <b>Attaching multiple handlers in 1 call</b><br>
6514       * The method also allows for a single argument to be passed which is a config object containing properties
6515      * which specify multiple handlers.
6516      * <p>
6517      * Code:<pre><code>
6518 el.on({
6519     'click' : {
6520         fn: this.onClick
6521         scope: this,
6522         delay: 100
6523     },
6524     'mouseover' : {
6525         fn: this.onMouseOver
6526         scope: this
6527     },
6528     'mouseout' : {
6529         fn: this.onMouseOut
6530         scope: this
6531     }
6532 });</code></pre>
6533      * <p>
6534      * Or a shorthand syntax:<br>
6535      * Code:<pre><code>
6536 el.on({
6537     'click' : this.onClick,
6538     'mouseover' : this.onMouseOver,
6539     'mouseout' : this.onMouseOut
6540     scope: this
6541 });</code></pre>
6542      */
6543     pub.on = pub.addListener;
6544     pub.un = pub.removeListener;
6545
6546     pub.stoppedMouseDownEvent = new Roo.util.Event();
6547     return pub;
6548 }();
6549 /**
6550   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6551   * @param {Function} fn        The method the event invokes
6552   * @param {Object}   scope    An  object that becomes the scope of the handler
6553   * @param {boolean}  override If true, the obj passed in becomes
6554   *                             the execution scope of the listener
6555   * @member Roo
6556   * @method onReady
6557  */
6558 Roo.onReady = Roo.EventManager.onDocumentReady;
6559
6560 Roo.onReady(function(){
6561     var bd = Roo.get(document.body);
6562     if(!bd){ return; }
6563
6564     var cls = [
6565             Roo.isIE ? "roo-ie"
6566             : Roo.isGecko ? "roo-gecko"
6567             : Roo.isOpera ? "roo-opera"
6568             : Roo.isSafari ? "roo-safari" : ""];
6569
6570     if(Roo.isMac){
6571         cls.push("roo-mac");
6572     }
6573     if(Roo.isLinux){
6574         cls.push("roo-linux");
6575     }
6576     if(Roo.isBorderBox){
6577         cls.push('roo-border-box');
6578     }
6579     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6580         var p = bd.dom.parentNode;
6581         if(p){
6582             p.className += ' roo-strict';
6583         }
6584     }
6585     bd.addClass(cls.join(' '));
6586 });
6587
6588 /**
6589  * @class Roo.EventObject
6590  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6591  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6592  * Example:
6593  * <pre><code>
6594  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6595     e.preventDefault();
6596     var target = e.getTarget();
6597     ...
6598  }
6599  var myDiv = Roo.get("myDiv");
6600  myDiv.on("click", handleClick);
6601  //or
6602  Roo.EventManager.on("myDiv", 'click', handleClick);
6603  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6604  </code></pre>
6605  * @singleton
6606  */
6607 Roo.EventObject = function(){
6608     
6609     var E = Roo.lib.Event;
6610     
6611     // safari keypress events for special keys return bad keycodes
6612     var safariKeys = {
6613         63234 : 37, // left
6614         63235 : 39, // right
6615         63232 : 38, // up
6616         63233 : 40, // down
6617         63276 : 33, // page up
6618         63277 : 34, // page down
6619         63272 : 46, // delete
6620         63273 : 36, // home
6621         63275 : 35  // end
6622     };
6623
6624     // normalize button clicks
6625     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6626                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6627
6628     Roo.EventObjectImpl = function(e){
6629         if(e){
6630             this.setEvent(e.browserEvent || e);
6631         }
6632     };
6633     Roo.EventObjectImpl.prototype = {
6634         /**
6635          * Used to fix doc tools.
6636          * @scope Roo.EventObject.prototype
6637          */
6638             
6639
6640         
6641         
6642         /** The normal browser event */
6643         browserEvent : null,
6644         /** The button pressed in a mouse event */
6645         button : -1,
6646         /** True if the shift key was down during the event */
6647         shiftKey : false,
6648         /** True if the control key was down during the event */
6649         ctrlKey : false,
6650         /** True if the alt key was down during the event */
6651         altKey : false,
6652
6653         /** Key constant 
6654         * @type Number */
6655         BACKSPACE : 8,
6656         /** Key constant 
6657         * @type Number */
6658         TAB : 9,
6659         /** Key constant 
6660         * @type Number */
6661         RETURN : 13,
6662         /** Key constant 
6663         * @type Number */
6664         ENTER : 13,
6665         /** Key constant 
6666         * @type Number */
6667         SHIFT : 16,
6668         /** Key constant 
6669         * @type Number */
6670         CONTROL : 17,
6671         /** Key constant 
6672         * @type Number */
6673         ESC : 27,
6674         /** Key constant 
6675         * @type Number */
6676         SPACE : 32,
6677         /** Key constant 
6678         * @type Number */
6679         PAGEUP : 33,
6680         /** Key constant 
6681         * @type Number */
6682         PAGEDOWN : 34,
6683         /** Key constant 
6684         * @type Number */
6685         END : 35,
6686         /** Key constant 
6687         * @type Number */
6688         HOME : 36,
6689         /** Key constant 
6690         * @type Number */
6691         LEFT : 37,
6692         /** Key constant 
6693         * @type Number */
6694         UP : 38,
6695         /** Key constant 
6696         * @type Number */
6697         RIGHT : 39,
6698         /** Key constant 
6699         * @type Number */
6700         DOWN : 40,
6701         /** Key constant 
6702         * @type Number */
6703         DELETE : 46,
6704         /** Key constant 
6705         * @type Number */
6706         F5 : 116,
6707
6708            /** @private */
6709         setEvent : function(e){
6710             if(e == this || (e && e.browserEvent)){ // already wrapped
6711                 return e;
6712             }
6713             this.browserEvent = e;
6714             if(e){
6715                 // normalize buttons
6716                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6717                 if(e.type == 'click' && this.button == -1){
6718                     this.button = 0;
6719                 }
6720                 this.type = e.type;
6721                 this.shiftKey = e.shiftKey;
6722                 // mac metaKey behaves like ctrlKey
6723                 this.ctrlKey = e.ctrlKey || e.metaKey;
6724                 this.altKey = e.altKey;
6725                 // in getKey these will be normalized for the mac
6726                 this.keyCode = e.keyCode;
6727                 // keyup warnings on firefox.
6728                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6729                 // cache the target for the delayed and or buffered events
6730                 this.target = E.getTarget(e);
6731                 // same for XY
6732                 this.xy = E.getXY(e);
6733             }else{
6734                 this.button = -1;
6735                 this.shiftKey = false;
6736                 this.ctrlKey = false;
6737                 this.altKey = false;
6738                 this.keyCode = 0;
6739                 this.charCode =0;
6740                 this.target = null;
6741                 this.xy = [0, 0];
6742             }
6743             return this;
6744         },
6745
6746         /**
6747          * Stop the event (preventDefault and stopPropagation)
6748          */
6749         stopEvent : function(){
6750             if(this.browserEvent){
6751                 if(this.browserEvent.type == 'mousedown'){
6752                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6753                 }
6754                 E.stopEvent(this.browserEvent);
6755             }
6756         },
6757
6758         /**
6759          * Prevents the browsers default handling of the event.
6760          */
6761         preventDefault : function(){
6762             if(this.browserEvent){
6763                 E.preventDefault(this.browserEvent);
6764             }
6765         },
6766
6767         /** @private */
6768         isNavKeyPress : function(){
6769             var k = this.keyCode;
6770             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6771             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6772         },
6773
6774         isSpecialKey : function(){
6775             var k = this.keyCode;
6776             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6777             (k == 16) || (k == 17) ||
6778             (k >= 18 && k <= 20) ||
6779             (k >= 33 && k <= 35) ||
6780             (k >= 36 && k <= 39) ||
6781             (k >= 44 && k <= 45);
6782         },
6783         /**
6784          * Cancels bubbling of the event.
6785          */
6786         stopPropagation : function(){
6787             if(this.browserEvent){
6788                 if(this.type == 'mousedown'){
6789                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6790                 }
6791                 E.stopPropagation(this.browserEvent);
6792             }
6793         },
6794
6795         /**
6796          * Gets the key code for the event.
6797          * @return {Number}
6798          */
6799         getCharCode : function(){
6800             return this.charCode || this.keyCode;
6801         },
6802
6803         /**
6804          * Returns a normalized keyCode for the event.
6805          * @return {Number} The key code
6806          */
6807         getKey : function(){
6808             var k = this.keyCode || this.charCode;
6809             return Roo.isSafari ? (safariKeys[k] || k) : k;
6810         },
6811
6812         /**
6813          * Gets the x coordinate of the event.
6814          * @return {Number}
6815          */
6816         getPageX : function(){
6817             return this.xy[0];
6818         },
6819
6820         /**
6821          * Gets the y coordinate of the event.
6822          * @return {Number}
6823          */
6824         getPageY : function(){
6825             return this.xy[1];
6826         },
6827
6828         /**
6829          * Gets the time of the event.
6830          * @return {Number}
6831          */
6832         getTime : function(){
6833             if(this.browserEvent){
6834                 return E.getTime(this.browserEvent);
6835             }
6836             return null;
6837         },
6838
6839         /**
6840          * Gets the page coordinates of the event.
6841          * @return {Array} The xy values like [x, y]
6842          */
6843         getXY : function(){
6844             return this.xy;
6845         },
6846
6847         /**
6848          * Gets the target for the event.
6849          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6850          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6851                 search as a number or element (defaults to 10 || document.body)
6852          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6853          * @return {HTMLelement}
6854          */
6855         getTarget : function(selector, maxDepth, returnEl){
6856             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6857         },
6858         /**
6859          * Gets the related target.
6860          * @return {HTMLElement}
6861          */
6862         getRelatedTarget : function(){
6863             if(this.browserEvent){
6864                 return E.getRelatedTarget(this.browserEvent);
6865             }
6866             return null;
6867         },
6868
6869         /**
6870          * Normalizes mouse wheel delta across browsers
6871          * @return {Number} The delta
6872          */
6873         getWheelDelta : function(){
6874             var e = this.browserEvent;
6875             var delta = 0;
6876             if(e.wheelDelta){ /* IE/Opera. */
6877                 delta = e.wheelDelta/120;
6878             }else if(e.detail){ /* Mozilla case. */
6879                 delta = -e.detail/3;
6880             }
6881             return delta;
6882         },
6883
6884         /**
6885          * Returns true if the control, meta, shift or alt key was pressed during this event.
6886          * @return {Boolean}
6887          */
6888         hasModifier : function(){
6889             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6890         },
6891
6892         /**
6893          * Returns true if the target of this event equals el or is a child of el
6894          * @param {String/HTMLElement/Element} el
6895          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6896          * @return {Boolean}
6897          */
6898         within : function(el, related){
6899             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6900             return t && Roo.fly(el).contains(t);
6901         },
6902
6903         getPoint : function(){
6904             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6905         }
6906     };
6907
6908     return new Roo.EventObjectImpl();
6909 }();
6910             
6911     /*
6912  * Based on:
6913  * Ext JS Library 1.1.1
6914  * Copyright(c) 2006-2007, Ext JS, LLC.
6915  *
6916  * Originally Released Under LGPL - original licence link has changed is not relivant.
6917  *
6918  * Fork - LGPL
6919  * <script type="text/javascript">
6920  */
6921
6922  
6923 // was in Composite Element!??!?!
6924  
6925 (function(){
6926     var D = Roo.lib.Dom;
6927     var E = Roo.lib.Event;
6928     var A = Roo.lib.Anim;
6929
6930     // local style camelizing for speed
6931     var propCache = {};
6932     var camelRe = /(-[a-z])/gi;
6933     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6934     var view = document.defaultView;
6935
6936 /**
6937  * @class Roo.Element
6938  * Represents an Element in the DOM.<br><br>
6939  * Usage:<br>
6940 <pre><code>
6941 var el = Roo.get("my-div");
6942
6943 // or with getEl
6944 var el = getEl("my-div");
6945
6946 // or with a DOM element
6947 var el = Roo.get(myDivElement);
6948 </code></pre>
6949  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6950  * each call instead of constructing a new one.<br><br>
6951  * <b>Animations</b><br />
6952  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6953  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6954 <pre>
6955 Option    Default   Description
6956 --------- --------  ---------------------------------------------
6957 duration  .35       The duration of the animation in seconds
6958 easing    easeOut   The YUI easing method
6959 callback  none      A function to execute when the anim completes
6960 scope     this      The scope (this) of the callback function
6961 </pre>
6962 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6963 * manipulate the animation. Here's an example:
6964 <pre><code>
6965 var el = Roo.get("my-div");
6966
6967 // no animation
6968 el.setWidth(100);
6969
6970 // default animation
6971 el.setWidth(100, true);
6972
6973 // animation with some options set
6974 el.setWidth(100, {
6975     duration: 1,
6976     callback: this.foo,
6977     scope: this
6978 });
6979
6980 // using the "anim" property to get the Anim object
6981 var opt = {
6982     duration: 1,
6983     callback: this.foo,
6984     scope: this
6985 };
6986 el.setWidth(100, opt);
6987 ...
6988 if(opt.anim.isAnimated()){
6989     opt.anim.stop();
6990 }
6991 </code></pre>
6992 * <b> Composite (Collections of) Elements</b><br />
6993  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6994  * @constructor Create a new Element directly.
6995  * @param {String/HTMLElement} element
6996  * @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).
6997  */
6998     Roo.Element = function(element, forceNew){
6999         var dom = typeof element == "string" ?
7000                 document.getElementById(element) : element;
7001         if(!dom){ // invalid id/element
7002             return null;
7003         }
7004         var id = dom.id;
7005         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7006             return Roo.Element.cache[id];
7007         }
7008
7009         /**
7010          * The DOM element
7011          * @type HTMLElement
7012          */
7013         this.dom = dom;
7014
7015         /**
7016          * The DOM element ID
7017          * @type String
7018          */
7019         this.id = id || Roo.id(dom);
7020     };
7021
7022     var El = Roo.Element;
7023
7024     El.prototype = {
7025         /**
7026          * The element's default display mode  (defaults to "")
7027          * @type String
7028          */
7029         originalDisplay : "",
7030
7031         visibilityMode : 1,
7032         /**
7033          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7034          * @type String
7035          */
7036         defaultUnit : "px",
7037         /**
7038          * Sets the element's visibility mode. When setVisible() is called it
7039          * will use this to determine whether to set the visibility or the display property.
7040          * @param visMode Element.VISIBILITY or Element.DISPLAY
7041          * @return {Roo.Element} this
7042          */
7043         setVisibilityMode : function(visMode){
7044             this.visibilityMode = visMode;
7045             return this;
7046         },
7047         /**
7048          * Convenience method for setVisibilityMode(Element.DISPLAY)
7049          * @param {String} display (optional) What to set display to when visible
7050          * @return {Roo.Element} this
7051          */
7052         enableDisplayMode : function(display){
7053             this.setVisibilityMode(El.DISPLAY);
7054             if(typeof display != "undefined") this.originalDisplay = display;
7055             return this;
7056         },
7057
7058         /**
7059          * 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)
7060          * @param {String} selector The simple selector to test
7061          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7062                 search as a number or element (defaults to 10 || document.body)
7063          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7064          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7065          */
7066         findParent : function(simpleSelector, maxDepth, returnEl){
7067             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7068             maxDepth = maxDepth || 50;
7069             if(typeof maxDepth != "number"){
7070                 stopEl = Roo.getDom(maxDepth);
7071                 maxDepth = 10;
7072             }
7073             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7074                 if(dq.is(p, simpleSelector)){
7075                     return returnEl ? Roo.get(p) : p;
7076                 }
7077                 depth++;
7078                 p = p.parentNode;
7079             }
7080             return null;
7081         },
7082
7083
7084         /**
7085          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7086          * @param {String} selector The simple selector to test
7087          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7088                 search as a number or element (defaults to 10 || document.body)
7089          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7090          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7091          */
7092         findParentNode : function(simpleSelector, maxDepth, returnEl){
7093             var p = Roo.fly(this.dom.parentNode, '_internal');
7094             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7095         },
7096
7097         /**
7098          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7099          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7100          * @param {String} selector The simple selector to test
7101          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7102                 search as a number or element (defaults to 10 || document.body)
7103          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7104          */
7105         up : function(simpleSelector, maxDepth){
7106             return this.findParentNode(simpleSelector, maxDepth, true);
7107         },
7108
7109
7110
7111         /**
7112          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7113          * @param {String} selector The simple selector to test
7114          * @return {Boolean} True if this element matches the selector, else false
7115          */
7116         is : function(simpleSelector){
7117             return Roo.DomQuery.is(this.dom, simpleSelector);
7118         },
7119
7120         /**
7121          * Perform animation on this element.
7122          * @param {Object} args The YUI animation control args
7123          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7124          * @param {Function} onComplete (optional) Function to call when animation completes
7125          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7126          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7127          * @return {Roo.Element} this
7128          */
7129         animate : function(args, duration, onComplete, easing, animType){
7130             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7131             return this;
7132         },
7133
7134         /*
7135          * @private Internal animation call
7136          */
7137         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7138             animType = animType || 'run';
7139             opt = opt || {};
7140             var anim = Roo.lib.Anim[animType](
7141                 this.dom, args,
7142                 (opt.duration || defaultDur) || .35,
7143                 (opt.easing || defaultEase) || 'easeOut',
7144                 function(){
7145                     Roo.callback(cb, this);
7146                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7147                 },
7148                 this
7149             );
7150             opt.anim = anim;
7151             return anim;
7152         },
7153
7154         // private legacy anim prep
7155         preanim : function(a, i){
7156             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7157         },
7158
7159         /**
7160          * Removes worthless text nodes
7161          * @param {Boolean} forceReclean (optional) By default the element
7162          * keeps track if it has been cleaned already so
7163          * you can call this over and over. However, if you update the element and
7164          * need to force a reclean, you can pass true.
7165          */
7166         clean : function(forceReclean){
7167             if(this.isCleaned && forceReclean !== true){
7168                 return this;
7169             }
7170             var ns = /\S/;
7171             var d = this.dom, n = d.firstChild, ni = -1;
7172             while(n){
7173                 var nx = n.nextSibling;
7174                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7175                     d.removeChild(n);
7176                 }else{
7177                     n.nodeIndex = ++ni;
7178                 }
7179                 n = nx;
7180             }
7181             this.isCleaned = true;
7182             return this;
7183         },
7184
7185         // private
7186         calcOffsetsTo : function(el){
7187             el = Roo.get(el);
7188             var d = el.dom;
7189             var restorePos = false;
7190             if(el.getStyle('position') == 'static'){
7191                 el.position('relative');
7192                 restorePos = true;
7193             }
7194             var x = 0, y =0;
7195             var op = this.dom;
7196             while(op && op != d && op.tagName != 'HTML'){
7197                 x+= op.offsetLeft;
7198                 y+= op.offsetTop;
7199                 op = op.offsetParent;
7200             }
7201             if(restorePos){
7202                 el.position('static');
7203             }
7204             return [x, y];
7205         },
7206
7207         /**
7208          * Scrolls this element into view within the passed container.
7209          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7210          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7211          * @return {Roo.Element} this
7212          */
7213         scrollIntoView : function(container, hscroll){
7214             var c = Roo.getDom(container) || document.body;
7215             var el = this.dom;
7216
7217             var o = this.calcOffsetsTo(c),
7218                 l = o[0],
7219                 t = o[1],
7220                 b = t+el.offsetHeight,
7221                 r = l+el.offsetWidth;
7222
7223             var ch = c.clientHeight;
7224             var ct = parseInt(c.scrollTop, 10);
7225             var cl = parseInt(c.scrollLeft, 10);
7226             var cb = ct + ch;
7227             var cr = cl + c.clientWidth;
7228
7229             if(t < ct){
7230                 c.scrollTop = t;
7231             }else if(b > cb){
7232                 c.scrollTop = b-ch;
7233             }
7234
7235             if(hscroll !== false){
7236                 if(l < cl){
7237                     c.scrollLeft = l;
7238                 }else if(r > cr){
7239                     c.scrollLeft = r-c.clientWidth;
7240                 }
7241             }
7242             return this;
7243         },
7244
7245         // private
7246         scrollChildIntoView : function(child, hscroll){
7247             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7248         },
7249
7250         /**
7251          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7252          * the new height may not be available immediately.
7253          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7254          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7255          * @param {Function} onComplete (optional) Function to call when animation completes
7256          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7257          * @return {Roo.Element} this
7258          */
7259         autoHeight : function(animate, duration, onComplete, easing){
7260             var oldHeight = this.getHeight();
7261             this.clip();
7262             this.setHeight(1); // force clipping
7263             setTimeout(function(){
7264                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7265                 if(!animate){
7266                     this.setHeight(height);
7267                     this.unclip();
7268                     if(typeof onComplete == "function"){
7269                         onComplete();
7270                     }
7271                 }else{
7272                     this.setHeight(oldHeight); // restore original height
7273                     this.setHeight(height, animate, duration, function(){
7274                         this.unclip();
7275                         if(typeof onComplete == "function") onComplete();
7276                     }.createDelegate(this), easing);
7277                 }
7278             }.createDelegate(this), 0);
7279             return this;
7280         },
7281
7282         /**
7283          * Returns true if this element is an ancestor of the passed element
7284          * @param {HTMLElement/String} el The element to check
7285          * @return {Boolean} True if this element is an ancestor of el, else false
7286          */
7287         contains : function(el){
7288             if(!el){return false;}
7289             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7290         },
7291
7292         /**
7293          * Checks whether the element is currently visible using both visibility and display properties.
7294          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7295          * @return {Boolean} True if the element is currently visible, else false
7296          */
7297         isVisible : function(deep) {
7298             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7299             if(deep !== true || !vis){
7300                 return vis;
7301             }
7302             var p = this.dom.parentNode;
7303             while(p && p.tagName.toLowerCase() != "body"){
7304                 if(!Roo.fly(p, '_isVisible').isVisible()){
7305                     return false;
7306                 }
7307                 p = p.parentNode;
7308             }
7309             return true;
7310         },
7311
7312         /**
7313          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7314          * @param {String} selector The CSS selector
7315          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7316          * @return {CompositeElement/CompositeElementLite} The composite element
7317          */
7318         select : function(selector, unique){
7319             return El.select(selector, unique, this.dom);
7320         },
7321
7322         /**
7323          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7324          * @param {String} selector The CSS selector
7325          * @return {Array} An array of the matched nodes
7326          */
7327         query : function(selector, unique){
7328             return Roo.DomQuery.select(selector, this.dom);
7329         },
7330
7331         /**
7332          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7333          * @param {String} selector The CSS selector
7334          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7335          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7336          */
7337         child : function(selector, returnDom){
7338             var n = Roo.DomQuery.selectNode(selector, this.dom);
7339             return returnDom ? n : Roo.get(n);
7340         },
7341
7342         /**
7343          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7344          * @param {String} selector The CSS selector
7345          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7346          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7347          */
7348         down : function(selector, returnDom){
7349             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7350             return returnDom ? n : Roo.get(n);
7351         },
7352
7353         /**
7354          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7355          * @param {String} group The group the DD object is member of
7356          * @param {Object} config The DD config object
7357          * @param {Object} overrides An object containing methods to override/implement on the DD object
7358          * @return {Roo.dd.DD} The DD object
7359          */
7360         initDD : function(group, config, overrides){
7361             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7362             return Roo.apply(dd, overrides);
7363         },
7364
7365         /**
7366          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7367          * @param {String} group The group the DDProxy object is member of
7368          * @param {Object} config The DDProxy config object
7369          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7370          * @return {Roo.dd.DDProxy} The DDProxy object
7371          */
7372         initDDProxy : function(group, config, overrides){
7373             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7374             return Roo.apply(dd, overrides);
7375         },
7376
7377         /**
7378          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7379          * @param {String} group The group the DDTarget object is member of
7380          * @param {Object} config The DDTarget config object
7381          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7382          * @return {Roo.dd.DDTarget} The DDTarget object
7383          */
7384         initDDTarget : function(group, config, overrides){
7385             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7386             return Roo.apply(dd, overrides);
7387         },
7388
7389         /**
7390          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7391          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7392          * @param {Boolean} visible Whether the element is visible
7393          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7394          * @return {Roo.Element} this
7395          */
7396          setVisible : function(visible, animate){
7397             if(!animate || !A){
7398                 if(this.visibilityMode == El.DISPLAY){
7399                     this.setDisplayed(visible);
7400                 }else{
7401                     this.fixDisplay();
7402                     this.dom.style.visibility = visible ? "visible" : "hidden";
7403                 }
7404             }else{
7405                 // closure for composites
7406                 var dom = this.dom;
7407                 var visMode = this.visibilityMode;
7408                 if(visible){
7409                     this.setOpacity(.01);
7410                     this.setVisible(true);
7411                 }
7412                 this.anim({opacity: { to: (visible?1:0) }},
7413                       this.preanim(arguments, 1),
7414                       null, .35, 'easeIn', function(){
7415                          if(!visible){
7416                              if(visMode == El.DISPLAY){
7417                                  dom.style.display = "none";
7418                              }else{
7419                                  dom.style.visibility = "hidden";
7420                              }
7421                              Roo.get(dom).setOpacity(1);
7422                          }
7423                      });
7424             }
7425             return this;
7426         },
7427
7428         /**
7429          * Returns true if display is not "none"
7430          * @return {Boolean}
7431          */
7432         isDisplayed : function() {
7433             return this.getStyle("display") != "none";
7434         },
7435
7436         /**
7437          * Toggles the element's visibility or display, depending on visibility mode.
7438          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7439          * @return {Roo.Element} this
7440          */
7441         toggle : function(animate){
7442             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7443             return this;
7444         },
7445
7446         /**
7447          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7448          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7449          * @return {Roo.Element} this
7450          */
7451         setDisplayed : function(value) {
7452             if(typeof value == "boolean"){
7453                value = value ? this.originalDisplay : "none";
7454             }
7455             this.setStyle("display", value);
7456             return this;
7457         },
7458
7459         /**
7460          * Tries to focus the element. Any exceptions are caught and ignored.
7461          * @return {Roo.Element} this
7462          */
7463         focus : function() {
7464             try{
7465                 this.dom.focus();
7466             }catch(e){}
7467             return this;
7468         },
7469
7470         /**
7471          * Tries to blur the element. Any exceptions are caught and ignored.
7472          * @return {Roo.Element} this
7473          */
7474         blur : function() {
7475             try{
7476                 this.dom.blur();
7477             }catch(e){}
7478             return this;
7479         },
7480
7481         /**
7482          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7483          * @param {String/Array} className The CSS class to add, or an array of classes
7484          * @return {Roo.Element} this
7485          */
7486         addClass : function(className){
7487             if(className instanceof Array){
7488                 for(var i = 0, len = className.length; i < len; i++) {
7489                     this.addClass(className[i]);
7490                 }
7491             }else{
7492                 if(className && !this.hasClass(className)){
7493                     this.dom.className = this.dom.className + " " + className;
7494                 }
7495             }
7496             return this;
7497         },
7498
7499         /**
7500          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7501          * @param {String/Array} className The CSS class to add, or an array of classes
7502          * @return {Roo.Element} this
7503          */
7504         radioClass : function(className){
7505             var siblings = this.dom.parentNode.childNodes;
7506             for(var i = 0; i < siblings.length; i++) {
7507                 var s = siblings[i];
7508                 if(s.nodeType == 1){
7509                     Roo.get(s).removeClass(className);
7510                 }
7511             }
7512             this.addClass(className);
7513             return this;
7514         },
7515
7516         /**
7517          * Removes one or more CSS classes from the element.
7518          * @param {String/Array} className The CSS class to remove, or an array of classes
7519          * @return {Roo.Element} this
7520          */
7521         removeClass : function(className){
7522             if(!className || !this.dom.className){
7523                 return this;
7524             }
7525             if(className instanceof Array){
7526                 for(var i = 0, len = className.length; i < len; i++) {
7527                     this.removeClass(className[i]);
7528                 }
7529             }else{
7530                 if(this.hasClass(className)){
7531                     var re = this.classReCache[className];
7532                     if (!re) {
7533                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7534                        this.classReCache[className] = re;
7535                     }
7536                     this.dom.className =
7537                         this.dom.className.replace(re, " ");
7538                 }
7539             }
7540             return this;
7541         },
7542
7543         // private
7544         classReCache: {},
7545
7546         /**
7547          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7548          * @param {String} className The CSS class to toggle
7549          * @return {Roo.Element} this
7550          */
7551         toggleClass : function(className){
7552             if(this.hasClass(className)){
7553                 this.removeClass(className);
7554             }else{
7555                 this.addClass(className);
7556             }
7557             return this;
7558         },
7559
7560         /**
7561          * Checks if the specified CSS class exists on this element's DOM node.
7562          * @param {String} className The CSS class to check for
7563          * @return {Boolean} True if the class exists, else false
7564          */
7565         hasClass : function(className){
7566             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7567         },
7568
7569         /**
7570          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7571          * @param {String} oldClassName The CSS class to replace
7572          * @param {String} newClassName The replacement CSS class
7573          * @return {Roo.Element} this
7574          */
7575         replaceClass : function(oldClassName, newClassName){
7576             this.removeClass(oldClassName);
7577             this.addClass(newClassName);
7578             return this;
7579         },
7580
7581         /**
7582          * Returns an object with properties matching the styles requested.
7583          * For example, el.getStyles('color', 'font-size', 'width') might return
7584          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7585          * @param {String} style1 A style name
7586          * @param {String} style2 A style name
7587          * @param {String} etc.
7588          * @return {Object} The style object
7589          */
7590         getStyles : function(){
7591             var a = arguments, len = a.length, r = {};
7592             for(var i = 0; i < len; i++){
7593                 r[a[i]] = this.getStyle(a[i]);
7594             }
7595             return r;
7596         },
7597
7598         /**
7599          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7600          * @param {String} property The style property whose value is returned.
7601          * @return {String} The current value of the style property for this element.
7602          */
7603         getStyle : function(){
7604             return view && view.getComputedStyle ?
7605                 function(prop){
7606                     var el = this.dom, v, cs, camel;
7607                     if(prop == 'float'){
7608                         prop = "cssFloat";
7609                     }
7610                     if(el.style && (v = el.style[prop])){
7611                         return v;
7612                     }
7613                     if(cs = view.getComputedStyle(el, "")){
7614                         if(!(camel = propCache[prop])){
7615                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7616                         }
7617                         return cs[camel];
7618                     }
7619                     return null;
7620                 } :
7621                 function(prop){
7622                     var el = this.dom, v, cs, camel;
7623                     if(prop == 'opacity'){
7624                         if(typeof el.style.filter == 'string'){
7625                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7626                             if(m){
7627                                 var fv = parseFloat(m[1]);
7628                                 if(!isNaN(fv)){
7629                                     return fv ? fv / 100 : 0;
7630                                 }
7631                             }
7632                         }
7633                         return 1;
7634                     }else if(prop == 'float'){
7635                         prop = "styleFloat";
7636                     }
7637                     if(!(camel = propCache[prop])){
7638                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7639                     }
7640                     if(v = el.style[camel]){
7641                         return v;
7642                     }
7643                     if(cs = el.currentStyle){
7644                         return cs[camel];
7645                     }
7646                     return null;
7647                 };
7648         }(),
7649
7650         /**
7651          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7652          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7653          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7654          * @return {Roo.Element} this
7655          */
7656         setStyle : function(prop, value){
7657             if(typeof prop == "string"){
7658                 
7659                 if (prop == 'float') {
7660                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7661                     return this;
7662                 }
7663                 
7664                 var camel;
7665                 if(!(camel = propCache[prop])){
7666                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7667                 }
7668                 
7669                 if(camel == 'opacity') {
7670                     this.setOpacity(value);
7671                 }else{
7672                     this.dom.style[camel] = value;
7673                 }
7674             }else{
7675                 for(var style in prop){
7676                     if(typeof prop[style] != "function"){
7677                        this.setStyle(style, prop[style]);
7678                     }
7679                 }
7680             }
7681             return this;
7682         },
7683
7684         /**
7685          * More flexible version of {@link #setStyle} for setting style properties.
7686          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7687          * a function which returns such a specification.
7688          * @return {Roo.Element} this
7689          */
7690         applyStyles : function(style){
7691             Roo.DomHelper.applyStyles(this.dom, style);
7692             return this;
7693         },
7694
7695         /**
7696           * 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).
7697           * @return {Number} The X position of the element
7698           */
7699         getX : function(){
7700             return D.getX(this.dom);
7701         },
7702
7703         /**
7704           * 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).
7705           * @return {Number} The Y position of the element
7706           */
7707         getY : function(){
7708             return D.getY(this.dom);
7709         },
7710
7711         /**
7712           * 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).
7713           * @return {Array} The XY position of the element
7714           */
7715         getXY : function(){
7716             return D.getXY(this.dom);
7717         },
7718
7719         /**
7720          * 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).
7721          * @param {Number} The X position of the element
7722          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7723          * @return {Roo.Element} this
7724          */
7725         setX : function(x, animate){
7726             if(!animate || !A){
7727                 D.setX(this.dom, x);
7728             }else{
7729                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7730             }
7731             return this;
7732         },
7733
7734         /**
7735          * 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).
7736          * @param {Number} The Y position of the element
7737          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7738          * @return {Roo.Element} this
7739          */
7740         setY : function(y, animate){
7741             if(!animate || !A){
7742                 D.setY(this.dom, y);
7743             }else{
7744                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7745             }
7746             return this;
7747         },
7748
7749         /**
7750          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7751          * @param {String} left The left CSS property value
7752          * @return {Roo.Element} this
7753          */
7754         setLeft : function(left){
7755             this.setStyle("left", this.addUnits(left));
7756             return this;
7757         },
7758
7759         /**
7760          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7761          * @param {String} top The top CSS property value
7762          * @return {Roo.Element} this
7763          */
7764         setTop : function(top){
7765             this.setStyle("top", this.addUnits(top));
7766             return this;
7767         },
7768
7769         /**
7770          * Sets the element's CSS right style.
7771          * @param {String} right The right CSS property value
7772          * @return {Roo.Element} this
7773          */
7774         setRight : function(right){
7775             this.setStyle("right", this.addUnits(right));
7776             return this;
7777         },
7778
7779         /**
7780          * Sets the element's CSS bottom style.
7781          * @param {String} bottom The bottom CSS property value
7782          * @return {Roo.Element} this
7783          */
7784         setBottom : function(bottom){
7785             this.setStyle("bottom", this.addUnits(bottom));
7786             return this;
7787         },
7788
7789         /**
7790          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7791          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7792          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7793          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7794          * @return {Roo.Element} this
7795          */
7796         setXY : function(pos, animate){
7797             if(!animate || !A){
7798                 D.setXY(this.dom, pos);
7799             }else{
7800                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7801             }
7802             return this;
7803         },
7804
7805         /**
7806          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7807          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7808          * @param {Number} x X value for new position (coordinates are page-based)
7809          * @param {Number} y Y value for new position (coordinates are page-based)
7810          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7811          * @return {Roo.Element} this
7812          */
7813         setLocation : function(x, y, animate){
7814             this.setXY([x, y], this.preanim(arguments, 2));
7815             return this;
7816         },
7817
7818         /**
7819          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7820          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7821          * @param {Number} x X value for new position (coordinates are page-based)
7822          * @param {Number} y Y value for new position (coordinates are page-based)
7823          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7824          * @return {Roo.Element} this
7825          */
7826         moveTo : function(x, y, animate){
7827             this.setXY([x, y], this.preanim(arguments, 2));
7828             return this;
7829         },
7830
7831         /**
7832          * Returns the region of the given element.
7833          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7834          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7835          */
7836         getRegion : function(){
7837             return D.getRegion(this.dom);
7838         },
7839
7840         /**
7841          * Returns the offset height of the element
7842          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7843          * @return {Number} The element's height
7844          */
7845         getHeight : function(contentHeight){
7846             var h = this.dom.offsetHeight || 0;
7847             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7848         },
7849
7850         /**
7851          * Returns the offset width of the element
7852          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7853          * @return {Number} The element's width
7854          */
7855         getWidth : function(contentWidth){
7856             var w = this.dom.offsetWidth || 0;
7857             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7858         },
7859
7860         /**
7861          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7862          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7863          * if a height has not been set using CSS.
7864          * @return {Number}
7865          */
7866         getComputedHeight : function(){
7867             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7868             if(!h){
7869                 h = parseInt(this.getStyle('height'), 10) || 0;
7870                 if(!this.isBorderBox()){
7871                     h += this.getFrameWidth('tb');
7872                 }
7873             }
7874             return h;
7875         },
7876
7877         /**
7878          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7879          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7880          * if a width has not been set using CSS.
7881          * @return {Number}
7882          */
7883         getComputedWidth : function(){
7884             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7885             if(!w){
7886                 w = parseInt(this.getStyle('width'), 10) || 0;
7887                 if(!this.isBorderBox()){
7888                     w += this.getFrameWidth('lr');
7889                 }
7890             }
7891             return w;
7892         },
7893
7894         /**
7895          * Returns the size of the element.
7896          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7897          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7898          */
7899         getSize : function(contentSize){
7900             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7901         },
7902
7903         /**
7904          * Returns the width and height of the viewport.
7905          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7906          */
7907         getViewSize : function(){
7908             var d = this.dom, doc = document, aw = 0, ah = 0;
7909             if(d == doc || d == doc.body){
7910                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7911             }else{
7912                 return {
7913                     width : d.clientWidth,
7914                     height: d.clientHeight
7915                 };
7916             }
7917         },
7918
7919         /**
7920          * Returns the value of the "value" attribute
7921          * @param {Boolean} asNumber true to parse the value as a number
7922          * @return {String/Number}
7923          */
7924         getValue : function(asNumber){
7925             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7926         },
7927
7928         // private
7929         adjustWidth : function(width){
7930             if(typeof width == "number"){
7931                 if(this.autoBoxAdjust && !this.isBorderBox()){
7932                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7933                 }
7934                 if(width < 0){
7935                     width = 0;
7936                 }
7937             }
7938             return width;
7939         },
7940
7941         // private
7942         adjustHeight : function(height){
7943             if(typeof height == "number"){
7944                if(this.autoBoxAdjust && !this.isBorderBox()){
7945                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7946                }
7947                if(height < 0){
7948                    height = 0;
7949                }
7950             }
7951             return height;
7952         },
7953
7954         /**
7955          * Set the width of the element
7956          * @param {Number} width The new width
7957          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7958          * @return {Roo.Element} this
7959          */
7960         setWidth : function(width, animate){
7961             width = this.adjustWidth(width);
7962             if(!animate || !A){
7963                 this.dom.style.width = this.addUnits(width);
7964             }else{
7965                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7966             }
7967             return this;
7968         },
7969
7970         /**
7971          * Set the height of the element
7972          * @param {Number} height The new height
7973          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7974          * @return {Roo.Element} this
7975          */
7976          setHeight : function(height, animate){
7977             height = this.adjustHeight(height);
7978             if(!animate || !A){
7979                 this.dom.style.height = this.addUnits(height);
7980             }else{
7981                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7982             }
7983             return this;
7984         },
7985
7986         /**
7987          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7988          * @param {Number} width The new width
7989          * @param {Number} height The new height
7990          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7991          * @return {Roo.Element} this
7992          */
7993          setSize : function(width, height, animate){
7994             if(typeof width == "object"){ // in case of object from getSize()
7995                 height = width.height; width = width.width;
7996             }
7997             width = this.adjustWidth(width); height = this.adjustHeight(height);
7998             if(!animate || !A){
7999                 this.dom.style.width = this.addUnits(width);
8000                 this.dom.style.height = this.addUnits(height);
8001             }else{
8002                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8003             }
8004             return this;
8005         },
8006
8007         /**
8008          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8009          * @param {Number} x X value for new position (coordinates are page-based)
8010          * @param {Number} y Y value for new position (coordinates are page-based)
8011          * @param {Number} width The new width
8012          * @param {Number} height The new height
8013          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8014          * @return {Roo.Element} this
8015          */
8016         setBounds : function(x, y, width, height, animate){
8017             if(!animate || !A){
8018                 this.setSize(width, height);
8019                 this.setLocation(x, y);
8020             }else{
8021                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8022                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8023                               this.preanim(arguments, 4), 'motion');
8024             }
8025             return this;
8026         },
8027
8028         /**
8029          * 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.
8030          * @param {Roo.lib.Region} region The region to fill
8031          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8032          * @return {Roo.Element} this
8033          */
8034         setRegion : function(region, animate){
8035             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8036             return this;
8037         },
8038
8039         /**
8040          * Appends an event handler
8041          *
8042          * @param {String}   eventName     The type of event to append
8043          * @param {Function} fn        The method the event invokes
8044          * @param {Object} scope       (optional) The scope (this object) of the fn
8045          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8046          */
8047         addListener : function(eventName, fn, scope, options){
8048             if (this.dom) {
8049                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8050             }
8051         },
8052
8053         /**
8054          * Removes an event handler from this element
8055          * @param {String} eventName the type of event to remove
8056          * @param {Function} fn the method the event invokes
8057          * @return {Roo.Element} this
8058          */
8059         removeListener : function(eventName, fn){
8060             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8061             return this;
8062         },
8063
8064         /**
8065          * Removes all previous added listeners from this element
8066          * @return {Roo.Element} this
8067          */
8068         removeAllListeners : function(){
8069             E.purgeElement(this.dom);
8070             return this;
8071         },
8072
8073         relayEvent : function(eventName, observable){
8074             this.on(eventName, function(e){
8075                 observable.fireEvent(eventName, e);
8076             });
8077         },
8078
8079         /**
8080          * Set the opacity of the element
8081          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8082          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8083          * @return {Roo.Element} this
8084          */
8085          setOpacity : function(opacity, animate){
8086             if(!animate || !A){
8087                 var s = this.dom.style;
8088                 if(Roo.isIE){
8089                     s.zoom = 1;
8090                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8091                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8092                 }else{
8093                     s.opacity = opacity;
8094                 }
8095             }else{
8096                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8097             }
8098             return this;
8099         },
8100
8101         /**
8102          * Gets the left X coordinate
8103          * @param {Boolean} local True to get the local css position instead of page coordinate
8104          * @return {Number}
8105          */
8106         getLeft : function(local){
8107             if(!local){
8108                 return this.getX();
8109             }else{
8110                 return parseInt(this.getStyle("left"), 10) || 0;
8111             }
8112         },
8113
8114         /**
8115          * Gets the right X coordinate of the element (element X position + element width)
8116          * @param {Boolean} local True to get the local css position instead of page coordinate
8117          * @return {Number}
8118          */
8119         getRight : function(local){
8120             if(!local){
8121                 return this.getX() + this.getWidth();
8122             }else{
8123                 return (this.getLeft(true) + this.getWidth()) || 0;
8124             }
8125         },
8126
8127         /**
8128          * Gets the top Y coordinate
8129          * @param {Boolean} local True to get the local css position instead of page coordinate
8130          * @return {Number}
8131          */
8132         getTop : function(local) {
8133             if(!local){
8134                 return this.getY();
8135             }else{
8136                 return parseInt(this.getStyle("top"), 10) || 0;
8137             }
8138         },
8139
8140         /**
8141          * Gets the bottom Y coordinate of the element (element Y position + element height)
8142          * @param {Boolean} local True to get the local css position instead of page coordinate
8143          * @return {Number}
8144          */
8145         getBottom : function(local){
8146             if(!local){
8147                 return this.getY() + this.getHeight();
8148             }else{
8149                 return (this.getTop(true) + this.getHeight()) || 0;
8150             }
8151         },
8152
8153         /**
8154         * Initializes positioning on this element. If a desired position is not passed, it will make the
8155         * the element positioned relative IF it is not already positioned.
8156         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8157         * @param {Number} zIndex (optional) The zIndex to apply
8158         * @param {Number} x (optional) Set the page X position
8159         * @param {Number} y (optional) Set the page Y position
8160         */
8161         position : function(pos, zIndex, x, y){
8162             if(!pos){
8163                if(this.getStyle('position') == 'static'){
8164                    this.setStyle('position', 'relative');
8165                }
8166             }else{
8167                 this.setStyle("position", pos);
8168             }
8169             if(zIndex){
8170                 this.setStyle("z-index", zIndex);
8171             }
8172             if(x !== undefined && y !== undefined){
8173                 this.setXY([x, y]);
8174             }else if(x !== undefined){
8175                 this.setX(x);
8176             }else if(y !== undefined){
8177                 this.setY(y);
8178             }
8179         },
8180
8181         /**
8182         * Clear positioning back to the default when the document was loaded
8183         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8184         * @return {Roo.Element} this
8185          */
8186         clearPositioning : function(value){
8187             value = value ||'';
8188             this.setStyle({
8189                 "left": value,
8190                 "right": value,
8191                 "top": value,
8192                 "bottom": value,
8193                 "z-index": "",
8194                 "position" : "static"
8195             });
8196             return this;
8197         },
8198
8199         /**
8200         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8201         * snapshot before performing an update and then restoring the element.
8202         * @return {Object}
8203         */
8204         getPositioning : function(){
8205             var l = this.getStyle("left");
8206             var t = this.getStyle("top");
8207             return {
8208                 "position" : this.getStyle("position"),
8209                 "left" : l,
8210                 "right" : l ? "" : this.getStyle("right"),
8211                 "top" : t,
8212                 "bottom" : t ? "" : this.getStyle("bottom"),
8213                 "z-index" : this.getStyle("z-index")
8214             };
8215         },
8216
8217         /**
8218          * Gets the width of the border(s) for the specified side(s)
8219          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8220          * passing lr would get the border (l)eft width + the border (r)ight width.
8221          * @return {Number} The width of the sides passed added together
8222          */
8223         getBorderWidth : function(side){
8224             return this.addStyles(side, El.borders);
8225         },
8226
8227         /**
8228          * Gets the width of the padding(s) for the specified side(s)
8229          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8230          * passing lr would get the padding (l)eft + the padding (r)ight.
8231          * @return {Number} The padding of the sides passed added together
8232          */
8233         getPadding : function(side){
8234             return this.addStyles(side, El.paddings);
8235         },
8236
8237         /**
8238         * Set positioning with an object returned by getPositioning().
8239         * @param {Object} posCfg
8240         * @return {Roo.Element} this
8241          */
8242         setPositioning : function(pc){
8243             this.applyStyles(pc);
8244             if(pc.right == "auto"){
8245                 this.dom.style.right = "";
8246             }
8247             if(pc.bottom == "auto"){
8248                 this.dom.style.bottom = "";
8249             }
8250             return this;
8251         },
8252
8253         // private
8254         fixDisplay : function(){
8255             if(this.getStyle("display") == "none"){
8256                 this.setStyle("visibility", "hidden");
8257                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8258                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8259                     this.setStyle("display", "block");
8260                 }
8261             }
8262         },
8263
8264         /**
8265          * Quick set left and top adding default units
8266          * @param {String} left The left CSS property value
8267          * @param {String} top The top CSS property value
8268          * @return {Roo.Element} this
8269          */
8270          setLeftTop : function(left, top){
8271             this.dom.style.left = this.addUnits(left);
8272             this.dom.style.top = this.addUnits(top);
8273             return this;
8274         },
8275
8276         /**
8277          * Move this element relative to its current position.
8278          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8279          * @param {Number} distance How far to move the element in pixels
8280          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8281          * @return {Roo.Element} this
8282          */
8283          move : function(direction, distance, animate){
8284             var xy = this.getXY();
8285             direction = direction.toLowerCase();
8286             switch(direction){
8287                 case "l":
8288                 case "left":
8289                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8290                     break;
8291                case "r":
8292                case "right":
8293                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8294                     break;
8295                case "t":
8296                case "top":
8297                case "up":
8298                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8299                     break;
8300                case "b":
8301                case "bottom":
8302                case "down":
8303                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8304                     break;
8305             }
8306             return this;
8307         },
8308
8309         /**
8310          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8311          * @return {Roo.Element} this
8312          */
8313         clip : function(){
8314             if(!this.isClipped){
8315                this.isClipped = true;
8316                this.originalClip = {
8317                    "o": this.getStyle("overflow"),
8318                    "x": this.getStyle("overflow-x"),
8319                    "y": this.getStyle("overflow-y")
8320                };
8321                this.setStyle("overflow", "hidden");
8322                this.setStyle("overflow-x", "hidden");
8323                this.setStyle("overflow-y", "hidden");
8324             }
8325             return this;
8326         },
8327
8328         /**
8329          *  Return clipping (overflow) to original clipping before clip() was called
8330          * @return {Roo.Element} this
8331          */
8332         unclip : function(){
8333             if(this.isClipped){
8334                 this.isClipped = false;
8335                 var o = this.originalClip;
8336                 if(o.o){this.setStyle("overflow", o.o);}
8337                 if(o.x){this.setStyle("overflow-x", o.x);}
8338                 if(o.y){this.setStyle("overflow-y", o.y);}
8339             }
8340             return this;
8341         },
8342
8343
8344         /**
8345          * Gets the x,y coordinates specified by the anchor position on the element.
8346          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8347          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8348          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8349          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8350          * @return {Array} [x, y] An array containing the element's x and y coordinates
8351          */
8352         getAnchorXY : function(anchor, local, s){
8353             //Passing a different size is useful for pre-calculating anchors,
8354             //especially for anchored animations that change the el size.
8355
8356             var w, h, vp = false;
8357             if(!s){
8358                 var d = this.dom;
8359                 if(d == document.body || d == document){
8360                     vp = true;
8361                     w = D.getViewWidth(); h = D.getViewHeight();
8362                 }else{
8363                     w = this.getWidth(); h = this.getHeight();
8364                 }
8365             }else{
8366                 w = s.width;  h = s.height;
8367             }
8368             var x = 0, y = 0, r = Math.round;
8369             switch((anchor || "tl").toLowerCase()){
8370                 case "c":
8371                     x = r(w*.5);
8372                     y = r(h*.5);
8373                 break;
8374                 case "t":
8375                     x = r(w*.5);
8376                     y = 0;
8377                 break;
8378                 case "l":
8379                     x = 0;
8380                     y = r(h*.5);
8381                 break;
8382                 case "r":
8383                     x = w;
8384                     y = r(h*.5);
8385                 break;
8386                 case "b":
8387                     x = r(w*.5);
8388                     y = h;
8389                 break;
8390                 case "tl":
8391                     x = 0;
8392                     y = 0;
8393                 break;
8394                 case "bl":
8395                     x = 0;
8396                     y = h;
8397                 break;
8398                 case "br":
8399                     x = w;
8400                     y = h;
8401                 break;
8402                 case "tr":
8403                     x = w;
8404                     y = 0;
8405                 break;
8406             }
8407             if(local === true){
8408                 return [x, y];
8409             }
8410             if(vp){
8411                 var sc = this.getScroll();
8412                 return [x + sc.left, y + sc.top];
8413             }
8414             //Add the element's offset xy
8415             var o = this.getXY();
8416             return [x+o[0], y+o[1]];
8417         },
8418
8419         /**
8420          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8421          * supported position values.
8422          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8423          * @param {String} position The position to align to.
8424          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8425          * @return {Array} [x, y]
8426          */
8427         getAlignToXY : function(el, p, o){
8428             el = Roo.get(el);
8429             var d = this.dom;
8430             if(!el.dom){
8431                 throw "Element.alignTo with an element that doesn't exist";
8432             }
8433             var c = false; //constrain to viewport
8434             var p1 = "", p2 = "";
8435             o = o || [0,0];
8436
8437             if(!p){
8438                 p = "tl-bl";
8439             }else if(p == "?"){
8440                 p = "tl-bl?";
8441             }else if(p.indexOf("-") == -1){
8442                 p = "tl-" + p;
8443             }
8444             p = p.toLowerCase();
8445             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8446             if(!m){
8447                throw "Element.alignTo with an invalid alignment " + p;
8448             }
8449             p1 = m[1]; p2 = m[2]; c = !!m[3];
8450
8451             //Subtract the aligned el's internal xy from the target's offset xy
8452             //plus custom offset to get the aligned el's new offset xy
8453             var a1 = this.getAnchorXY(p1, true);
8454             var a2 = el.getAnchorXY(p2, false);
8455             var x = a2[0] - a1[0] + o[0];
8456             var y = a2[1] - a1[1] + o[1];
8457             if(c){
8458                 //constrain the aligned el to viewport if necessary
8459                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8460                 // 5px of margin for ie
8461                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8462
8463                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8464                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8465                 //otherwise swap the aligned el to the opposite border of the target.
8466                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8467                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8468                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8469                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8470
8471                var doc = document;
8472                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8473                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8474
8475                if((x+w) > dw + scrollX){
8476                     x = swapX ? r.left-w : dw+scrollX-w;
8477                 }
8478                if(x < scrollX){
8479                    x = swapX ? r.right : scrollX;
8480                }
8481                if((y+h) > dh + scrollY){
8482                     y = swapY ? r.top-h : dh+scrollY-h;
8483                 }
8484                if (y < scrollY){
8485                    y = swapY ? r.bottom : scrollY;
8486                }
8487             }
8488             return [x,y];
8489         },
8490
8491         // private
8492         getConstrainToXY : function(){
8493             var os = {top:0, left:0, bottom:0, right: 0};
8494
8495             return function(el, local, offsets, proposedXY){
8496                 el = Roo.get(el);
8497                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8498
8499                 var vw, vh, vx = 0, vy = 0;
8500                 if(el.dom == document.body || el.dom == document){
8501                     vw = Roo.lib.Dom.getViewWidth();
8502                     vh = Roo.lib.Dom.getViewHeight();
8503                 }else{
8504                     vw = el.dom.clientWidth;
8505                     vh = el.dom.clientHeight;
8506                     if(!local){
8507                         var vxy = el.getXY();
8508                         vx = vxy[0];
8509                         vy = vxy[1];
8510                     }
8511                 }
8512
8513                 var s = el.getScroll();
8514
8515                 vx += offsets.left + s.left;
8516                 vy += offsets.top + s.top;
8517
8518                 vw -= offsets.right;
8519                 vh -= offsets.bottom;
8520
8521                 var vr = vx+vw;
8522                 var vb = vy+vh;
8523
8524                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8525                 var x = xy[0], y = xy[1];
8526                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8527
8528                 // only move it if it needs it
8529                 var moved = false;
8530
8531                 // first validate right/bottom
8532                 if((x + w) > vr){
8533                     x = vr - w;
8534                     moved = true;
8535                 }
8536                 if((y + h) > vb){
8537                     y = vb - h;
8538                     moved = true;
8539                 }
8540                 // then make sure top/left isn't negative
8541                 if(x < vx){
8542                     x = vx;
8543                     moved = true;
8544                 }
8545                 if(y < vy){
8546                     y = vy;
8547                     moved = true;
8548                 }
8549                 return moved ? [x, y] : false;
8550             };
8551         }(),
8552
8553         // private
8554         adjustForConstraints : function(xy, parent, offsets){
8555             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8556         },
8557
8558         /**
8559          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8560          * document it aligns it to the viewport.
8561          * The position parameter is optional, and can be specified in any one of the following formats:
8562          * <ul>
8563          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8564          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8565          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8566          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8567          *   <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
8568          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8569          * </ul>
8570          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8571          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8572          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8573          * that specified in order to enforce the viewport constraints.
8574          * Following are all of the supported anchor positions:
8575     <pre>
8576     Value  Description
8577     -----  -----------------------------
8578     tl     The top left corner (default)
8579     t      The center of the top edge
8580     tr     The top right corner
8581     l      The center of the left edge
8582     c      In the center of the element
8583     r      The center of the right edge
8584     bl     The bottom left corner
8585     b      The center of the bottom edge
8586     br     The bottom right corner
8587     </pre>
8588     Example Usage:
8589     <pre><code>
8590     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8591     el.alignTo("other-el");
8592
8593     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8594     el.alignTo("other-el", "tr?");
8595
8596     // align the bottom right corner of el with the center left edge of other-el
8597     el.alignTo("other-el", "br-l?");
8598
8599     // align the center of el with the bottom left corner of other-el and
8600     // adjust the x position by -6 pixels (and the y position by 0)
8601     el.alignTo("other-el", "c-bl", [-6, 0]);
8602     </code></pre>
8603          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8604          * @param {String} position The position to align to.
8605          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8606          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8607          * @return {Roo.Element} this
8608          */
8609         alignTo : function(element, position, offsets, animate){
8610             var xy = this.getAlignToXY(element, position, offsets);
8611             this.setXY(xy, this.preanim(arguments, 3));
8612             return this;
8613         },
8614
8615         /**
8616          * Anchors an element to another element and realigns it when the window is resized.
8617          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8618          * @param {String} position The position to align to.
8619          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8620          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8621          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8622          * is a number, it is used as the buffer delay (defaults to 50ms).
8623          * @param {Function} callback The function to call after the animation finishes
8624          * @return {Roo.Element} this
8625          */
8626         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8627             var action = function(){
8628                 this.alignTo(el, alignment, offsets, animate);
8629                 Roo.callback(callback, this);
8630             };
8631             Roo.EventManager.onWindowResize(action, this);
8632             var tm = typeof monitorScroll;
8633             if(tm != 'undefined'){
8634                 Roo.EventManager.on(window, 'scroll', action, this,
8635                     {buffer: tm == 'number' ? monitorScroll : 50});
8636             }
8637             action.call(this); // align immediately
8638             return this;
8639         },
8640         /**
8641          * Clears any opacity settings from this element. Required in some cases for IE.
8642          * @return {Roo.Element} this
8643          */
8644         clearOpacity : function(){
8645             if (window.ActiveXObject) {
8646                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8647                     this.dom.style.filter = "";
8648                 }
8649             } else {
8650                 this.dom.style.opacity = "";
8651                 this.dom.style["-moz-opacity"] = "";
8652                 this.dom.style["-khtml-opacity"] = "";
8653             }
8654             return this;
8655         },
8656
8657         /**
8658          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8659          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8660          * @return {Roo.Element} this
8661          */
8662         hide : function(animate){
8663             this.setVisible(false, this.preanim(arguments, 0));
8664             return this;
8665         },
8666
8667         /**
8668         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8669         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8670          * @return {Roo.Element} this
8671          */
8672         show : function(animate){
8673             this.setVisible(true, this.preanim(arguments, 0));
8674             return this;
8675         },
8676
8677         /**
8678          * @private Test if size has a unit, otherwise appends the default
8679          */
8680         addUnits : function(size){
8681             return Roo.Element.addUnits(size, this.defaultUnit);
8682         },
8683
8684         /**
8685          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8686          * @return {Roo.Element} this
8687          */
8688         beginMeasure : function(){
8689             var el = this.dom;
8690             if(el.offsetWidth || el.offsetHeight){
8691                 return this; // offsets work already
8692             }
8693             var changed = [];
8694             var p = this.dom, b = document.body; // start with this element
8695             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8696                 var pe = Roo.get(p);
8697                 if(pe.getStyle('display') == 'none'){
8698                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8699                     p.style.visibility = "hidden";
8700                     p.style.display = "block";
8701                 }
8702                 p = p.parentNode;
8703             }
8704             this._measureChanged = changed;
8705             return this;
8706
8707         },
8708
8709         /**
8710          * Restores displays to before beginMeasure was called
8711          * @return {Roo.Element} this
8712          */
8713         endMeasure : function(){
8714             var changed = this._measureChanged;
8715             if(changed){
8716                 for(var i = 0, len = changed.length; i < len; i++) {
8717                     var r = changed[i];
8718                     r.el.style.visibility = r.visibility;
8719                     r.el.style.display = "none";
8720                 }
8721                 this._measureChanged = null;
8722             }
8723             return this;
8724         },
8725
8726         /**
8727         * Update the innerHTML of this element, optionally searching for and processing scripts
8728         * @param {String} html The new HTML
8729         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8730         * @param {Function} callback For async script loading you can be noticed when the update completes
8731         * @return {Roo.Element} this
8732          */
8733         update : function(html, loadScripts, callback){
8734             if(typeof html == "undefined"){
8735                 html = "";
8736             }
8737             if(loadScripts !== true){
8738                 this.dom.innerHTML = html;
8739                 if(typeof callback == "function"){
8740                     callback();
8741                 }
8742                 return this;
8743             }
8744             var id = Roo.id();
8745             var dom = this.dom;
8746
8747             html += '<span id="' + id + '"></span>';
8748
8749             E.onAvailable(id, function(){
8750                 var hd = document.getElementsByTagName("head")[0];
8751                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8752                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8753                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8754
8755                 var match;
8756                 while(match = re.exec(html)){
8757                     var attrs = match[1];
8758                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8759                     if(srcMatch && srcMatch[2]){
8760                        var s = document.createElement("script");
8761                        s.src = srcMatch[2];
8762                        var typeMatch = attrs.match(typeRe);
8763                        if(typeMatch && typeMatch[2]){
8764                            s.type = typeMatch[2];
8765                        }
8766                        hd.appendChild(s);
8767                     }else if(match[2] && match[2].length > 0){
8768                         if(window.execScript) {
8769                            window.execScript(match[2]);
8770                         } else {
8771                             /**
8772                              * eval:var:id
8773                              * eval:var:dom
8774                              * eval:var:html
8775                              * 
8776                              */
8777                            window.eval(match[2]);
8778                         }
8779                     }
8780                 }
8781                 var el = document.getElementById(id);
8782                 if(el){el.parentNode.removeChild(el);}
8783                 if(typeof callback == "function"){
8784                     callback();
8785                 }
8786             });
8787             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8788             return this;
8789         },
8790
8791         /**
8792          * Direct access to the UpdateManager update() method (takes the same parameters).
8793          * @param {String/Function} url The url for this request or a function to call to get the url
8794          * @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}
8795          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8796          * @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.
8797          * @return {Roo.Element} this
8798          */
8799         load : function(){
8800             var um = this.getUpdateManager();
8801             um.update.apply(um, arguments);
8802             return this;
8803         },
8804
8805         /**
8806         * Gets this element's UpdateManager
8807         * @return {Roo.UpdateManager} The UpdateManager
8808         */
8809         getUpdateManager : function(){
8810             if(!this.updateManager){
8811                 this.updateManager = new Roo.UpdateManager(this);
8812             }
8813             return this.updateManager;
8814         },
8815
8816         /**
8817          * Disables text selection for this element (normalized across browsers)
8818          * @return {Roo.Element} this
8819          */
8820         unselectable : function(){
8821             this.dom.unselectable = "on";
8822             this.swallowEvent("selectstart", true);
8823             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8824             this.addClass("x-unselectable");
8825             return this;
8826         },
8827
8828         /**
8829         * Calculates the x, y to center this element on the screen
8830         * @return {Array} The x, y values [x, y]
8831         */
8832         getCenterXY : function(){
8833             return this.getAlignToXY(document, 'c-c');
8834         },
8835
8836         /**
8837         * Centers the Element in either the viewport, or another Element.
8838         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8839         */
8840         center : function(centerIn){
8841             this.alignTo(centerIn || document, 'c-c');
8842             return this;
8843         },
8844
8845         /**
8846          * Tests various css rules/browsers to determine if this element uses a border box
8847          * @return {Boolean}
8848          */
8849         isBorderBox : function(){
8850             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8851         },
8852
8853         /**
8854          * Return a box {x, y, width, height} that can be used to set another elements
8855          * size/location to match this element.
8856          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8857          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8858          * @return {Object} box An object in the format {x, y, width, height}
8859          */
8860         getBox : function(contentBox, local){
8861             var xy;
8862             if(!local){
8863                 xy = this.getXY();
8864             }else{
8865                 var left = parseInt(this.getStyle("left"), 10) || 0;
8866                 var top = parseInt(this.getStyle("top"), 10) || 0;
8867                 xy = [left, top];
8868             }
8869             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8870             if(!contentBox){
8871                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8872             }else{
8873                 var l = this.getBorderWidth("l")+this.getPadding("l");
8874                 var r = this.getBorderWidth("r")+this.getPadding("r");
8875                 var t = this.getBorderWidth("t")+this.getPadding("t");
8876                 var b = this.getBorderWidth("b")+this.getPadding("b");
8877                 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)};
8878             }
8879             bx.right = bx.x + bx.width;
8880             bx.bottom = bx.y + bx.height;
8881             return bx;
8882         },
8883
8884         /**
8885          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8886          for more information about the sides.
8887          * @param {String} sides
8888          * @return {Number}
8889          */
8890         getFrameWidth : function(sides, onlyContentBox){
8891             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8892         },
8893
8894         /**
8895          * 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.
8896          * @param {Object} box The box to fill {x, y, width, height}
8897          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8898          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8899          * @return {Roo.Element} this
8900          */
8901         setBox : function(box, adjust, animate){
8902             var w = box.width, h = box.height;
8903             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8904                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8905                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8906             }
8907             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8908             return this;
8909         },
8910
8911         /**
8912          * Forces the browser to repaint this element
8913          * @return {Roo.Element} this
8914          */
8915          repaint : function(){
8916             var dom = this.dom;
8917             this.addClass("x-repaint");
8918             setTimeout(function(){
8919                 Roo.get(dom).removeClass("x-repaint");
8920             }, 1);
8921             return this;
8922         },
8923
8924         /**
8925          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8926          * then it returns the calculated width of the sides (see getPadding)
8927          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8928          * @return {Object/Number}
8929          */
8930         getMargins : function(side){
8931             if(!side){
8932                 return {
8933                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8934                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8935                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8936                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8937                 };
8938             }else{
8939                 return this.addStyles(side, El.margins);
8940              }
8941         },
8942
8943         // private
8944         addStyles : function(sides, styles){
8945             var val = 0, v, w;
8946             for(var i = 0, len = sides.length; i < len; i++){
8947                 v = this.getStyle(styles[sides.charAt(i)]);
8948                 if(v){
8949                      w = parseInt(v, 10);
8950                      if(w){ val += w; }
8951                 }
8952             }
8953             return val;
8954         },
8955
8956         /**
8957          * Creates a proxy element of this element
8958          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8959          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8960          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8961          * @return {Roo.Element} The new proxy element
8962          */
8963         createProxy : function(config, renderTo, matchBox){
8964             if(renderTo){
8965                 renderTo = Roo.getDom(renderTo);
8966             }else{
8967                 renderTo = document.body;
8968             }
8969             config = typeof config == "object" ?
8970                 config : {tag : "div", cls: config};
8971             var proxy = Roo.DomHelper.append(renderTo, config, true);
8972             if(matchBox){
8973                proxy.setBox(this.getBox());
8974             }
8975             return proxy;
8976         },
8977
8978         /**
8979          * Puts a mask over this element to disable user interaction. Requires core.css.
8980          * This method can only be applied to elements which accept child nodes.
8981          * @param {String} msg (optional) A message to display in the mask
8982          * @param {String} msgCls (optional) A css class to apply to the msg element
8983          * @return {Element} The mask  element
8984          */
8985         mask : function(msg, msgCls)
8986         {
8987             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8988                 this.setStyle("position", "relative");
8989             }
8990             if(!this._mask){
8991                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8992             }
8993             this.addClass("x-masked");
8994             this._mask.setDisplayed(true);
8995             
8996             // we wander
8997             var z = 0;
8998             var dom = this.dom
8999             while (dom && dom.style) {
9000                 if (!isNaN(parseInt(dom.style.zIndex))) {
9001                     z = Math.max(z, parseInt(dom.style.zIndex));
9002                 }
9003                 dom = dom.parentNode;
9004             }
9005             // if we are masking the body - then it hides everything..
9006             if (this.dom == document.body) {
9007                 z = 1000000;
9008                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9009                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9010             }
9011            
9012             if(typeof msg == 'string'){
9013                 if(!this._maskMsg){
9014                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9015                 }
9016                 var mm = this._maskMsg;
9017                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9018                 if (mm.dom.firstChild) { // weird IE issue?
9019                     mm.dom.firstChild.innerHTML = msg;
9020                 }
9021                 mm.setDisplayed(true);
9022                 mm.center(this);
9023                 mm.setStyle('z-index', z + 102);
9024             }
9025             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9026                 this._mask.setHeight(this.getHeight());
9027             }
9028             this._mask.setStyle('z-index', z + 100);
9029             
9030             return this._mask;
9031         },
9032
9033         /**
9034          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9035          * it is cached for reuse.
9036          */
9037         unmask : function(removeEl){
9038             if(this._mask){
9039                 if(removeEl === true){
9040                     this._mask.remove();
9041                     delete this._mask;
9042                     if(this._maskMsg){
9043                         this._maskMsg.remove();
9044                         delete this._maskMsg;
9045                     }
9046                 }else{
9047                     this._mask.setDisplayed(false);
9048                     if(this._maskMsg){
9049                         this._maskMsg.setDisplayed(false);
9050                     }
9051                 }
9052             }
9053             this.removeClass("x-masked");
9054         },
9055
9056         /**
9057          * Returns true if this element is masked
9058          * @return {Boolean}
9059          */
9060         isMasked : function(){
9061             return this._mask && this._mask.isVisible();
9062         },
9063
9064         /**
9065          * Creates an iframe shim for this element to keep selects and other windowed objects from
9066          * showing through.
9067          * @return {Roo.Element} The new shim element
9068          */
9069         createShim : function(){
9070             var el = document.createElement('iframe');
9071             el.frameBorder = 'no';
9072             el.className = 'roo-shim';
9073             if(Roo.isIE && Roo.isSecure){
9074                 el.src = Roo.SSL_SECURE_URL;
9075             }
9076             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9077             shim.autoBoxAdjust = false;
9078             return shim;
9079         },
9080
9081         /**
9082          * Removes this element from the DOM and deletes it from the cache
9083          */
9084         remove : function(){
9085             if(this.dom.parentNode){
9086                 this.dom.parentNode.removeChild(this.dom);
9087             }
9088             delete El.cache[this.dom.id];
9089         },
9090
9091         /**
9092          * Sets up event handlers to add and remove a css class when the mouse is over this element
9093          * @param {String} className
9094          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9095          * mouseout events for children elements
9096          * @return {Roo.Element} this
9097          */
9098         addClassOnOver : function(className, preventFlicker){
9099             this.on("mouseover", function(){
9100                 Roo.fly(this, '_internal').addClass(className);
9101             }, this.dom);
9102             var removeFn = function(e){
9103                 if(preventFlicker !== true || !e.within(this, true)){
9104                     Roo.fly(this, '_internal').removeClass(className);
9105                 }
9106             };
9107             this.on("mouseout", removeFn, this.dom);
9108             return this;
9109         },
9110
9111         /**
9112          * Sets up event handlers to add and remove a css class when this element has the focus
9113          * @param {String} className
9114          * @return {Roo.Element} this
9115          */
9116         addClassOnFocus : function(className){
9117             this.on("focus", function(){
9118                 Roo.fly(this, '_internal').addClass(className);
9119             }, this.dom);
9120             this.on("blur", function(){
9121                 Roo.fly(this, '_internal').removeClass(className);
9122             }, this.dom);
9123             return this;
9124         },
9125         /**
9126          * 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)
9127          * @param {String} className
9128          * @return {Roo.Element} this
9129          */
9130         addClassOnClick : function(className){
9131             var dom = this.dom;
9132             this.on("mousedown", function(){
9133                 Roo.fly(dom, '_internal').addClass(className);
9134                 var d = Roo.get(document);
9135                 var fn = function(){
9136                     Roo.fly(dom, '_internal').removeClass(className);
9137                     d.removeListener("mouseup", fn);
9138                 };
9139                 d.on("mouseup", fn);
9140             });
9141             return this;
9142         },
9143
9144         /**
9145          * Stops the specified event from bubbling and optionally prevents the default action
9146          * @param {String} eventName
9147          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9148          * @return {Roo.Element} this
9149          */
9150         swallowEvent : function(eventName, preventDefault){
9151             var fn = function(e){
9152                 e.stopPropagation();
9153                 if(preventDefault){
9154                     e.preventDefault();
9155                 }
9156             };
9157             if(eventName instanceof Array){
9158                 for(var i = 0, len = eventName.length; i < len; i++){
9159                      this.on(eventName[i], fn);
9160                 }
9161                 return this;
9162             }
9163             this.on(eventName, fn);
9164             return this;
9165         },
9166
9167         /**
9168          * @private
9169          */
9170       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9171
9172         /**
9173          * Sizes this element to its parent element's dimensions performing
9174          * neccessary box adjustments.
9175          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9176          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9177          * @return {Roo.Element} this
9178          */
9179         fitToParent : function(monitorResize, targetParent) {
9180           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9181           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9182           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9183             return;
9184           }
9185           var p = Roo.get(targetParent || this.dom.parentNode);
9186           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9187           if (monitorResize === true) {
9188             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9189             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9190           }
9191           return this;
9192         },
9193
9194         /**
9195          * Gets the next sibling, skipping text nodes
9196          * @return {HTMLElement} The next sibling or null
9197          */
9198         getNextSibling : function(){
9199             var n = this.dom.nextSibling;
9200             while(n && n.nodeType != 1){
9201                 n = n.nextSibling;
9202             }
9203             return n;
9204         },
9205
9206         /**
9207          * Gets the previous sibling, skipping text nodes
9208          * @return {HTMLElement} The previous sibling or null
9209          */
9210         getPrevSibling : function(){
9211             var n = this.dom.previousSibling;
9212             while(n && n.nodeType != 1){
9213                 n = n.previousSibling;
9214             }
9215             return n;
9216         },
9217
9218
9219         /**
9220          * Appends the passed element(s) to this element
9221          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9222          * @return {Roo.Element} this
9223          */
9224         appendChild: function(el){
9225             el = Roo.get(el);
9226             el.appendTo(this);
9227             return this;
9228         },
9229
9230         /**
9231          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9232          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9233          * automatically generated with the specified attributes.
9234          * @param {HTMLElement} insertBefore (optional) a child element of this element
9235          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9236          * @return {Roo.Element} The new child element
9237          */
9238         createChild: function(config, insertBefore, returnDom){
9239             config = config || {tag:'div'};
9240             if(insertBefore){
9241                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9242             }
9243             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9244         },
9245
9246         /**
9247          * Appends this element to the passed element
9248          * @param {String/HTMLElement/Element} el The new parent element
9249          * @return {Roo.Element} this
9250          */
9251         appendTo: function(el){
9252             el = Roo.getDom(el);
9253             el.appendChild(this.dom);
9254             return this;
9255         },
9256
9257         /**
9258          * Inserts this element before the passed element in the DOM
9259          * @param {String/HTMLElement/Element} el The element to insert before
9260          * @return {Roo.Element} this
9261          */
9262         insertBefore: function(el){
9263             el = Roo.getDom(el);
9264             el.parentNode.insertBefore(this.dom, el);
9265             return this;
9266         },
9267
9268         /**
9269          * Inserts this element after the passed element in the DOM
9270          * @param {String/HTMLElement/Element} el The element to insert after
9271          * @return {Roo.Element} this
9272          */
9273         insertAfter: function(el){
9274             el = Roo.getDom(el);
9275             el.parentNode.insertBefore(this.dom, el.nextSibling);
9276             return this;
9277         },
9278
9279         /**
9280          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9281          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9282          * @return {Roo.Element} The new child
9283          */
9284         insertFirst: function(el, returnDom){
9285             el = el || {};
9286             if(typeof el == 'object' && !el.nodeType){ // dh config
9287                 return this.createChild(el, this.dom.firstChild, returnDom);
9288             }else{
9289                 el = Roo.getDom(el);
9290                 this.dom.insertBefore(el, this.dom.firstChild);
9291                 return !returnDom ? Roo.get(el) : el;
9292             }
9293         },
9294
9295         /**
9296          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9297          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9298          * @param {String} where (optional) 'before' or 'after' defaults to before
9299          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9300          * @return {Roo.Element} the inserted Element
9301          */
9302         insertSibling: function(el, where, returnDom){
9303             where = where ? where.toLowerCase() : 'before';
9304             el = el || {};
9305             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9306
9307             if(typeof el == 'object' && !el.nodeType){ // dh config
9308                 if(where == 'after' && !this.dom.nextSibling){
9309                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9310                 }else{
9311                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9312                 }
9313
9314             }else{
9315                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9316                             where == 'before' ? this.dom : this.dom.nextSibling);
9317                 if(!returnDom){
9318                     rt = Roo.get(rt);
9319                 }
9320             }
9321             return rt;
9322         },
9323
9324         /**
9325          * Creates and wraps this element with another element
9326          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9327          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9328          * @return {HTMLElement/Element} The newly created wrapper element
9329          */
9330         wrap: function(config, returnDom){
9331             if(!config){
9332                 config = {tag: "div"};
9333             }
9334             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9335             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9336             return newEl;
9337         },
9338
9339         /**
9340          * Replaces the passed element with this element
9341          * @param {String/HTMLElement/Element} el The element to replace
9342          * @return {Roo.Element} this
9343          */
9344         replace: function(el){
9345             el = Roo.get(el);
9346             this.insertBefore(el);
9347             el.remove();
9348             return this;
9349         },
9350
9351         /**
9352          * Inserts an html fragment into this element
9353          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9354          * @param {String} html The HTML fragment
9355          * @param {Boolean} returnEl True to return an Roo.Element
9356          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9357          */
9358         insertHtml : function(where, html, returnEl){
9359             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9360             return returnEl ? Roo.get(el) : el;
9361         },
9362
9363         /**
9364          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9365          * @param {Object} o The object with the attributes
9366          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9367          * @return {Roo.Element} this
9368          */
9369         set : function(o, useSet){
9370             var el = this.dom;
9371             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9372             for(var attr in o){
9373                 if(attr == "style" || typeof o[attr] == "function") continue;
9374                 if(attr=="cls"){
9375                     el.className = o["cls"];
9376                 }else{
9377                     if(useSet) el.setAttribute(attr, o[attr]);
9378                     else el[attr] = o[attr];
9379                 }
9380             }
9381             if(o.style){
9382                 Roo.DomHelper.applyStyles(el, o.style);
9383             }
9384             return this;
9385         },
9386
9387         /**
9388          * Convenience method for constructing a KeyMap
9389          * @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:
9390          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9391          * @param {Function} fn The function to call
9392          * @param {Object} scope (optional) The scope of the function
9393          * @return {Roo.KeyMap} The KeyMap created
9394          */
9395         addKeyListener : function(key, fn, scope){
9396             var config;
9397             if(typeof key != "object" || key instanceof Array){
9398                 config = {
9399                     key: key,
9400                     fn: fn,
9401                     scope: scope
9402                 };
9403             }else{
9404                 config = {
9405                     key : key.key,
9406                     shift : key.shift,
9407                     ctrl : key.ctrl,
9408                     alt : key.alt,
9409                     fn: fn,
9410                     scope: scope
9411                 };
9412             }
9413             return new Roo.KeyMap(this, config);
9414         },
9415
9416         /**
9417          * Creates a KeyMap for this element
9418          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9419          * @return {Roo.KeyMap} The KeyMap created
9420          */
9421         addKeyMap : function(config){
9422             return new Roo.KeyMap(this, config);
9423         },
9424
9425         /**
9426          * Returns true if this element is scrollable.
9427          * @return {Boolean}
9428          */
9429          isScrollable : function(){
9430             var dom = this.dom;
9431             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9432         },
9433
9434         /**
9435          * 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().
9436          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9437          * @param {Number} value The new scroll value
9438          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9439          * @return {Element} this
9440          */
9441
9442         scrollTo : function(side, value, animate){
9443             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9444             if(!animate || !A){
9445                 this.dom[prop] = value;
9446             }else{
9447                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9448                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9449             }
9450             return this;
9451         },
9452
9453         /**
9454          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9455          * within this element's scrollable range.
9456          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9457          * @param {Number} distance How far to scroll the element in pixels
9458          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9459          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9460          * was scrolled as far as it could go.
9461          */
9462          scroll : function(direction, distance, animate){
9463              if(!this.isScrollable()){
9464                  return;
9465              }
9466              var el = this.dom;
9467              var l = el.scrollLeft, t = el.scrollTop;
9468              var w = el.scrollWidth, h = el.scrollHeight;
9469              var cw = el.clientWidth, ch = el.clientHeight;
9470              direction = direction.toLowerCase();
9471              var scrolled = false;
9472              var a = this.preanim(arguments, 2);
9473              switch(direction){
9474                  case "l":
9475                  case "left":
9476                      if(w - l > cw){
9477                          var v = Math.min(l + distance, w-cw);
9478                          this.scrollTo("left", v, a);
9479                          scrolled = true;
9480                      }
9481                      break;
9482                 case "r":
9483                 case "right":
9484                      if(l > 0){
9485                          var v = Math.max(l - distance, 0);
9486                          this.scrollTo("left", v, a);
9487                          scrolled = true;
9488                      }
9489                      break;
9490                 case "t":
9491                 case "top":
9492                 case "up":
9493                      if(t > 0){
9494                          var v = Math.max(t - distance, 0);
9495                          this.scrollTo("top", v, a);
9496                          scrolled = true;
9497                      }
9498                      break;
9499                 case "b":
9500                 case "bottom":
9501                 case "down":
9502                      if(h - t > ch){
9503                          var v = Math.min(t + distance, h-ch);
9504                          this.scrollTo("top", v, a);
9505                          scrolled = true;
9506                      }
9507                      break;
9508              }
9509              return scrolled;
9510         },
9511
9512         /**
9513          * Translates the passed page coordinates into left/top css values for this element
9514          * @param {Number/Array} x The page x or an array containing [x, y]
9515          * @param {Number} y The page y
9516          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9517          */
9518         translatePoints : function(x, y){
9519             if(typeof x == 'object' || x instanceof Array){
9520                 y = x[1]; x = x[0];
9521             }
9522             var p = this.getStyle('position');
9523             var o = this.getXY();
9524
9525             var l = parseInt(this.getStyle('left'), 10);
9526             var t = parseInt(this.getStyle('top'), 10);
9527
9528             if(isNaN(l)){
9529                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9530             }
9531             if(isNaN(t)){
9532                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9533             }
9534
9535             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9536         },
9537
9538         /**
9539          * Returns the current scroll position of the element.
9540          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9541          */
9542         getScroll : function(){
9543             var d = this.dom, doc = document;
9544             if(d == doc || d == doc.body){
9545                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9546                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9547                 return {left: l, top: t};
9548             }else{
9549                 return {left: d.scrollLeft, top: d.scrollTop};
9550             }
9551         },
9552
9553         /**
9554          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9555          * are convert to standard 6 digit hex color.
9556          * @param {String} attr The css attribute
9557          * @param {String} defaultValue The default value to use when a valid color isn't found
9558          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9559          * YUI color anims.
9560          */
9561         getColor : function(attr, defaultValue, prefix){
9562             var v = this.getStyle(attr);
9563             if(!v || v == "transparent" || v == "inherit") {
9564                 return defaultValue;
9565             }
9566             var color = typeof prefix == "undefined" ? "#" : prefix;
9567             if(v.substr(0, 4) == "rgb("){
9568                 var rvs = v.slice(4, v.length -1).split(",");
9569                 for(var i = 0; i < 3; i++){
9570                     var h = parseInt(rvs[i]).toString(16);
9571                     if(h < 16){
9572                         h = "0" + h;
9573                     }
9574                     color += h;
9575                 }
9576             } else {
9577                 if(v.substr(0, 1) == "#"){
9578                     if(v.length == 4) {
9579                         for(var i = 1; i < 4; i++){
9580                             var c = v.charAt(i);
9581                             color +=  c + c;
9582                         }
9583                     }else if(v.length == 7){
9584                         color += v.substr(1);
9585                     }
9586                 }
9587             }
9588             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9589         },
9590
9591         /**
9592          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9593          * gradient background, rounded corners and a 4-way shadow.
9594          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9595          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9596          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9597          * @return {Roo.Element} this
9598          */
9599         boxWrap : function(cls){
9600             cls = cls || 'x-box';
9601             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9602             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9603             return el;
9604         },
9605
9606         /**
9607          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9608          * @param {String} namespace The namespace in which to look for the attribute
9609          * @param {String} name The attribute name
9610          * @return {String} The attribute value
9611          */
9612         getAttributeNS : Roo.isIE ? function(ns, name){
9613             var d = this.dom;
9614             var type = typeof d[ns+":"+name];
9615             if(type != 'undefined' && type != 'unknown'){
9616                 return d[ns+":"+name];
9617             }
9618             return d[name];
9619         } : function(ns, name){
9620             var d = this.dom;
9621             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9622         },
9623         
9624         
9625         /**
9626          * Sets or Returns the value the dom attribute value
9627          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9628          * @param {String} value (optional) The value to set the attribute to
9629          * @return {String} The attribute value
9630          */
9631         attr : function(name){
9632             if (arguments.length > 1) {
9633                 this.dom.setAttribute(name, arguments[1]);
9634                 return arguments[1];
9635             }
9636             if (typeof(name) == 'object') {
9637                 for(var i in name) {
9638                     this.attr(i, name[i]);
9639                 }
9640                 return name;
9641             }
9642             
9643             
9644             if (!this.dom.hasAttribute(name)) {
9645                 return undefined;
9646             }
9647             return this.dom.getAttribute(name);
9648         }
9649         
9650         
9651         
9652     };
9653
9654     var ep = El.prototype;
9655
9656     /**
9657      * Appends an event handler (Shorthand for addListener)
9658      * @param {String}   eventName     The type of event to append
9659      * @param {Function} fn        The method the event invokes
9660      * @param {Object} scope       (optional) The scope (this object) of the fn
9661      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9662      * @method
9663      */
9664     ep.on = ep.addListener;
9665         // backwards compat
9666     ep.mon = ep.addListener;
9667
9668     /**
9669      * Removes an event handler from this element (shorthand for removeListener)
9670      * @param {String} eventName the type of event to remove
9671      * @param {Function} fn the method the event invokes
9672      * @return {Roo.Element} this
9673      * @method
9674      */
9675     ep.un = ep.removeListener;
9676
9677     /**
9678      * true to automatically adjust width and height settings for box-model issues (default to true)
9679      */
9680     ep.autoBoxAdjust = true;
9681
9682     // private
9683     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9684
9685     // private
9686     El.addUnits = function(v, defaultUnit){
9687         if(v === "" || v == "auto"){
9688             return v;
9689         }
9690         if(v === undefined){
9691             return '';
9692         }
9693         if(typeof v == "number" || !El.unitPattern.test(v)){
9694             return v + (defaultUnit || 'px');
9695         }
9696         return v;
9697     };
9698
9699     // special markup used throughout Roo when box wrapping elements
9700     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>';
9701     /**
9702      * Visibility mode constant - Use visibility to hide element
9703      * @static
9704      * @type Number
9705      */
9706     El.VISIBILITY = 1;
9707     /**
9708      * Visibility mode constant - Use display to hide element
9709      * @static
9710      * @type Number
9711      */
9712     El.DISPLAY = 2;
9713
9714     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9715     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9716     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9717
9718
9719
9720     /**
9721      * @private
9722      */
9723     El.cache = {};
9724
9725     var docEl;
9726
9727     /**
9728      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9729      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9730      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9731      * @return {Element} The Element object
9732      * @static
9733      */
9734     El.get = function(el){
9735         var ex, elm, id;
9736         if(!el){ return null; }
9737         if(typeof el == "string"){ // element id
9738             if(!(elm = document.getElementById(el))){
9739                 return null;
9740             }
9741             if(ex = El.cache[el]){
9742                 ex.dom = elm;
9743             }else{
9744                 ex = El.cache[el] = new El(elm);
9745             }
9746             return ex;
9747         }else if(el.tagName){ // dom element
9748             if(!(id = el.id)){
9749                 id = Roo.id(el);
9750             }
9751             if(ex = El.cache[id]){
9752                 ex.dom = el;
9753             }else{
9754                 ex = El.cache[id] = new El(el);
9755             }
9756             return ex;
9757         }else if(el instanceof El){
9758             if(el != docEl){
9759                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9760                                                               // catch case where it hasn't been appended
9761                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9762             }
9763             return el;
9764         }else if(el.isComposite){
9765             return el;
9766         }else if(el instanceof Array){
9767             return El.select(el);
9768         }else if(el == document){
9769             // create a bogus element object representing the document object
9770             if(!docEl){
9771                 var f = function(){};
9772                 f.prototype = El.prototype;
9773                 docEl = new f();
9774                 docEl.dom = document;
9775             }
9776             return docEl;
9777         }
9778         return null;
9779     };
9780
9781     // private
9782     El.uncache = function(el){
9783         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9784             if(a[i]){
9785                 delete El.cache[a[i].id || a[i]];
9786             }
9787         }
9788     };
9789
9790     // private
9791     // Garbage collection - uncache elements/purge listeners on orphaned elements
9792     // so we don't hold a reference and cause the browser to retain them
9793     El.garbageCollect = function(){
9794         if(!Roo.enableGarbageCollector){
9795             clearInterval(El.collectorThread);
9796             return;
9797         }
9798         for(var eid in El.cache){
9799             var el = El.cache[eid], d = el.dom;
9800             // -------------------------------------------------------
9801             // Determining what is garbage:
9802             // -------------------------------------------------------
9803             // !d
9804             // dom node is null, definitely garbage
9805             // -------------------------------------------------------
9806             // !d.parentNode
9807             // no parentNode == direct orphan, definitely garbage
9808             // -------------------------------------------------------
9809             // !d.offsetParent && !document.getElementById(eid)
9810             // display none elements have no offsetParent so we will
9811             // also try to look it up by it's id. However, check
9812             // offsetParent first so we don't do unneeded lookups.
9813             // This enables collection of elements that are not orphans
9814             // directly, but somewhere up the line they have an orphan
9815             // parent.
9816             // -------------------------------------------------------
9817             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9818                 delete El.cache[eid];
9819                 if(d && Roo.enableListenerCollection){
9820                     E.purgeElement(d);
9821                 }
9822             }
9823         }
9824     }
9825     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9826
9827
9828     // dom is optional
9829     El.Flyweight = function(dom){
9830         this.dom = dom;
9831     };
9832     El.Flyweight.prototype = El.prototype;
9833
9834     El._flyweights = {};
9835     /**
9836      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9837      * the dom node can be overwritten by other code.
9838      * @param {String/HTMLElement} el The dom node or id
9839      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9840      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9841      * @static
9842      * @return {Element} The shared Element object
9843      */
9844     El.fly = function(el, named){
9845         named = named || '_global';
9846         el = Roo.getDom(el);
9847         if(!el){
9848             return null;
9849         }
9850         if(!El._flyweights[named]){
9851             El._flyweights[named] = new El.Flyweight();
9852         }
9853         El._flyweights[named].dom = el;
9854         return El._flyweights[named];
9855     };
9856
9857     /**
9858      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9859      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9860      * Shorthand of {@link Roo.Element#get}
9861      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9862      * @return {Element} The Element object
9863      * @member Roo
9864      * @method get
9865      */
9866     Roo.get = El.get;
9867     /**
9868      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9869      * the dom node can be overwritten by other code.
9870      * Shorthand of {@link Roo.Element#fly}
9871      * @param {String/HTMLElement} el The dom node or id
9872      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9873      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9874      * @static
9875      * @return {Element} The shared Element object
9876      * @member Roo
9877      * @method fly
9878      */
9879     Roo.fly = El.fly;
9880
9881     // speedy lookup for elements never to box adjust
9882     var noBoxAdjust = Roo.isStrict ? {
9883         select:1
9884     } : {
9885         input:1, select:1, textarea:1
9886     };
9887     if(Roo.isIE || Roo.isGecko){
9888         noBoxAdjust['button'] = 1;
9889     }
9890
9891
9892     Roo.EventManager.on(window, 'unload', function(){
9893         delete El.cache;
9894         delete El._flyweights;
9895     });
9896 })();
9897
9898
9899
9900
9901 if(Roo.DomQuery){
9902     Roo.Element.selectorFunction = Roo.DomQuery.select;
9903 }
9904
9905 Roo.Element.select = function(selector, unique, root){
9906     var els;
9907     if(typeof selector == "string"){
9908         els = Roo.Element.selectorFunction(selector, root);
9909     }else if(selector.length !== undefined){
9910         els = selector;
9911     }else{
9912         throw "Invalid selector";
9913     }
9914     if(unique === true){
9915         return new Roo.CompositeElement(els);
9916     }else{
9917         return new Roo.CompositeElementLite(els);
9918     }
9919 };
9920 /**
9921  * Selects elements based on the passed CSS selector to enable working on them as 1.
9922  * @param {String/Array} selector The CSS selector or an array of elements
9923  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9924  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9925  * @return {CompositeElementLite/CompositeElement}
9926  * @member Roo
9927  * @method select
9928  */
9929 Roo.select = Roo.Element.select;
9930
9931
9932
9933
9934
9935
9936
9937
9938
9939
9940
9941
9942
9943
9944 /*
9945  * Based on:
9946  * Ext JS Library 1.1.1
9947  * Copyright(c) 2006-2007, Ext JS, LLC.
9948  *
9949  * Originally Released Under LGPL - original licence link has changed is not relivant.
9950  *
9951  * Fork - LGPL
9952  * <script type="text/javascript">
9953  */
9954
9955
9956
9957 //Notifies Element that fx methods are available
9958 Roo.enableFx = true;
9959
9960 /**
9961  * @class Roo.Fx
9962  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9963  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9964  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9965  * Element effects to work.</p><br/>
9966  *
9967  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9968  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9969  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9970  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9971  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9972  * expected results and should be done with care.</p><br/>
9973  *
9974  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9975  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9976 <pre>
9977 Value  Description
9978 -----  -----------------------------
9979 tl     The top left corner
9980 t      The center of the top edge
9981 tr     The top right corner
9982 l      The center of the left edge
9983 r      The center of the right edge
9984 bl     The bottom left corner
9985 b      The center of the bottom edge
9986 br     The bottom right corner
9987 </pre>
9988  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9989  * below are common options that can be passed to any Fx method.</b>
9990  * @cfg {Function} callback A function called when the effect is finished
9991  * @cfg {Object} scope The scope of the effect function
9992  * @cfg {String} easing A valid Easing value for the effect
9993  * @cfg {String} afterCls A css class to apply after the effect
9994  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9995  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9996  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9997  * effects that end with the element being visually hidden, ignored otherwise)
9998  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9999  * a function which returns such a specification that will be applied to the Element after the effect finishes
10000  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10001  * @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
10002  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10003  */
10004 Roo.Fx = {
10005         /**
10006          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10007          * origin for the slide effect.  This function automatically handles wrapping the element with
10008          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10009          * Usage:
10010          *<pre><code>
10011 // default: slide the element in from the top
10012 el.slideIn();
10013
10014 // custom: slide the element in from the right with a 2-second duration
10015 el.slideIn('r', { duration: 2 });
10016
10017 // common config options shown with default values
10018 el.slideIn('t', {
10019     easing: 'easeOut',
10020     duration: .5
10021 });
10022 </code></pre>
10023          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10024          * @param {Object} options (optional) Object literal with any of the Fx config options
10025          * @return {Roo.Element} The Element
10026          */
10027     slideIn : function(anchor, o){
10028         var el = this.getFxEl();
10029         o = o || {};
10030
10031         el.queueFx(o, function(){
10032
10033             anchor = anchor || "t";
10034
10035             // fix display to visibility
10036             this.fixDisplay();
10037
10038             // restore values after effect
10039             var r = this.getFxRestore();
10040             var b = this.getBox();
10041             // fixed size for slide
10042             this.setSize(b);
10043
10044             // wrap if needed
10045             var wrap = this.fxWrap(r.pos, o, "hidden");
10046
10047             var st = this.dom.style;
10048             st.visibility = "visible";
10049             st.position = "absolute";
10050
10051             // clear out temp styles after slide and unwrap
10052             var after = function(){
10053                 el.fxUnwrap(wrap, r.pos, o);
10054                 st.width = r.width;
10055                 st.height = r.height;
10056                 el.afterFx(o);
10057             };
10058             // time to calc the positions
10059             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10060
10061             switch(anchor.toLowerCase()){
10062                 case "t":
10063                     wrap.setSize(b.width, 0);
10064                     st.left = st.bottom = "0";
10065                     a = {height: bh};
10066                 break;
10067                 case "l":
10068                     wrap.setSize(0, b.height);
10069                     st.right = st.top = "0";
10070                     a = {width: bw};
10071                 break;
10072                 case "r":
10073                     wrap.setSize(0, b.height);
10074                     wrap.setX(b.right);
10075                     st.left = st.top = "0";
10076                     a = {width: bw, points: pt};
10077                 break;
10078                 case "b":
10079                     wrap.setSize(b.width, 0);
10080                     wrap.setY(b.bottom);
10081                     st.left = st.top = "0";
10082                     a = {height: bh, points: pt};
10083                 break;
10084                 case "tl":
10085                     wrap.setSize(0, 0);
10086                     st.right = st.bottom = "0";
10087                     a = {width: bw, height: bh};
10088                 break;
10089                 case "bl":
10090                     wrap.setSize(0, 0);
10091                     wrap.setY(b.y+b.height);
10092                     st.right = st.top = "0";
10093                     a = {width: bw, height: bh, points: pt};
10094                 break;
10095                 case "br":
10096                     wrap.setSize(0, 0);
10097                     wrap.setXY([b.right, b.bottom]);
10098                     st.left = st.top = "0";
10099                     a = {width: bw, height: bh, points: pt};
10100                 break;
10101                 case "tr":
10102                     wrap.setSize(0, 0);
10103                     wrap.setX(b.x+b.width);
10104                     st.left = st.bottom = "0";
10105                     a = {width: bw, height: bh, points: pt};
10106                 break;
10107             }
10108             this.dom.style.visibility = "visible";
10109             wrap.show();
10110
10111             arguments.callee.anim = wrap.fxanim(a,
10112                 o,
10113                 'motion',
10114                 .5,
10115                 'easeOut', after);
10116         });
10117         return this;
10118     },
10119     
10120         /**
10121          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10122          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10123          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10124          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10125          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10126          * Usage:
10127          *<pre><code>
10128 // default: slide the element out to the top
10129 el.slideOut();
10130
10131 // custom: slide the element out to the right with a 2-second duration
10132 el.slideOut('r', { duration: 2 });
10133
10134 // common config options shown with default values
10135 el.slideOut('t', {
10136     easing: 'easeOut',
10137     duration: .5,
10138     remove: false,
10139     useDisplay: false
10140 });
10141 </code></pre>
10142          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10143          * @param {Object} options (optional) Object literal with any of the Fx config options
10144          * @return {Roo.Element} The Element
10145          */
10146     slideOut : function(anchor, o){
10147         var el = this.getFxEl();
10148         o = o || {};
10149
10150         el.queueFx(o, function(){
10151
10152             anchor = anchor || "t";
10153
10154             // restore values after effect
10155             var r = this.getFxRestore();
10156             
10157             var b = this.getBox();
10158             // fixed size for slide
10159             this.setSize(b);
10160
10161             // wrap if needed
10162             var wrap = this.fxWrap(r.pos, o, "visible");
10163
10164             var st = this.dom.style;
10165             st.visibility = "visible";
10166             st.position = "absolute";
10167
10168             wrap.setSize(b);
10169
10170             var after = function(){
10171                 if(o.useDisplay){
10172                     el.setDisplayed(false);
10173                 }else{
10174                     el.hide();
10175                 }
10176
10177                 el.fxUnwrap(wrap, r.pos, o);
10178
10179                 st.width = r.width;
10180                 st.height = r.height;
10181
10182                 el.afterFx(o);
10183             };
10184
10185             var a, zero = {to: 0};
10186             switch(anchor.toLowerCase()){
10187                 case "t":
10188                     st.left = st.bottom = "0";
10189                     a = {height: zero};
10190                 break;
10191                 case "l":
10192                     st.right = st.top = "0";
10193                     a = {width: zero};
10194                 break;
10195                 case "r":
10196                     st.left = st.top = "0";
10197                     a = {width: zero, points: {to:[b.right, b.y]}};
10198                 break;
10199                 case "b":
10200                     st.left = st.top = "0";
10201                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10202                 break;
10203                 case "tl":
10204                     st.right = st.bottom = "0";
10205                     a = {width: zero, height: zero};
10206                 break;
10207                 case "bl":
10208                     st.right = st.top = "0";
10209                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10210                 break;
10211                 case "br":
10212                     st.left = st.top = "0";
10213                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10214                 break;
10215                 case "tr":
10216                     st.left = st.bottom = "0";
10217                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10218                 break;
10219             }
10220
10221             arguments.callee.anim = wrap.fxanim(a,
10222                 o,
10223                 'motion',
10224                 .5,
10225                 "easeOut", after);
10226         });
10227         return this;
10228     },
10229
10230         /**
10231          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10232          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10233          * The element must be removed from the DOM using the 'remove' config option if desired.
10234          * Usage:
10235          *<pre><code>
10236 // default
10237 el.puff();
10238
10239 // common config options shown with default values
10240 el.puff({
10241     easing: 'easeOut',
10242     duration: .5,
10243     remove: false,
10244     useDisplay: false
10245 });
10246 </code></pre>
10247          * @param {Object} options (optional) Object literal with any of the Fx config options
10248          * @return {Roo.Element} The Element
10249          */
10250     puff : function(o){
10251         var el = this.getFxEl();
10252         o = o || {};
10253
10254         el.queueFx(o, function(){
10255             this.clearOpacity();
10256             this.show();
10257
10258             // restore values after effect
10259             var r = this.getFxRestore();
10260             var st = this.dom.style;
10261
10262             var after = function(){
10263                 if(o.useDisplay){
10264                     el.setDisplayed(false);
10265                 }else{
10266                     el.hide();
10267                 }
10268
10269                 el.clearOpacity();
10270
10271                 el.setPositioning(r.pos);
10272                 st.width = r.width;
10273                 st.height = r.height;
10274                 st.fontSize = '';
10275                 el.afterFx(o);
10276             };
10277
10278             var width = this.getWidth();
10279             var height = this.getHeight();
10280
10281             arguments.callee.anim = this.fxanim({
10282                     width : {to: this.adjustWidth(width * 2)},
10283                     height : {to: this.adjustHeight(height * 2)},
10284                     points : {by: [-(width * .5), -(height * .5)]},
10285                     opacity : {to: 0},
10286                     fontSize: {to:200, unit: "%"}
10287                 },
10288                 o,
10289                 'motion',
10290                 .5,
10291                 "easeOut", after);
10292         });
10293         return this;
10294     },
10295
10296         /**
10297          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10298          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10299          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10300          * Usage:
10301          *<pre><code>
10302 // default
10303 el.switchOff();
10304
10305 // all config options shown with default values
10306 el.switchOff({
10307     easing: 'easeIn',
10308     duration: .3,
10309     remove: false,
10310     useDisplay: false
10311 });
10312 </code></pre>
10313          * @param {Object} options (optional) Object literal with any of the Fx config options
10314          * @return {Roo.Element} The Element
10315          */
10316     switchOff : function(o){
10317         var el = this.getFxEl();
10318         o = o || {};
10319
10320         el.queueFx(o, function(){
10321             this.clearOpacity();
10322             this.clip();
10323
10324             // restore values after effect
10325             var r = this.getFxRestore();
10326             var st = this.dom.style;
10327
10328             var after = function(){
10329                 if(o.useDisplay){
10330                     el.setDisplayed(false);
10331                 }else{
10332                     el.hide();
10333                 }
10334
10335                 el.clearOpacity();
10336                 el.setPositioning(r.pos);
10337                 st.width = r.width;
10338                 st.height = r.height;
10339
10340                 el.afterFx(o);
10341             };
10342
10343             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10344                 this.clearOpacity();
10345                 (function(){
10346                     this.fxanim({
10347                         height:{to:1},
10348                         points:{by:[0, this.getHeight() * .5]}
10349                     }, o, 'motion', 0.3, 'easeIn', after);
10350                 }).defer(100, this);
10351             });
10352         });
10353         return this;
10354     },
10355
10356     /**
10357      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10358      * changed using the "attr" config option) and then fading back to the original color. If no original
10359      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10360      * Usage:
10361 <pre><code>
10362 // default: highlight background to yellow
10363 el.highlight();
10364
10365 // custom: highlight foreground text to blue for 2 seconds
10366 el.highlight("0000ff", { attr: 'color', duration: 2 });
10367
10368 // common config options shown with default values
10369 el.highlight("ffff9c", {
10370     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10371     endColor: (current color) or "ffffff",
10372     easing: 'easeIn',
10373     duration: 1
10374 });
10375 </code></pre>
10376      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10377      * @param {Object} options (optional) Object literal with any of the Fx config options
10378      * @return {Roo.Element} The Element
10379      */ 
10380     highlight : function(color, o){
10381         var el = this.getFxEl();
10382         o = o || {};
10383
10384         el.queueFx(o, function(){
10385             color = color || "ffff9c";
10386             attr = o.attr || "backgroundColor";
10387
10388             this.clearOpacity();
10389             this.show();
10390
10391             var origColor = this.getColor(attr);
10392             var restoreColor = this.dom.style[attr];
10393             endColor = (o.endColor || origColor) || "ffffff";
10394
10395             var after = function(){
10396                 el.dom.style[attr] = restoreColor;
10397                 el.afterFx(o);
10398             };
10399
10400             var a = {};
10401             a[attr] = {from: color, to: endColor};
10402             arguments.callee.anim = this.fxanim(a,
10403                 o,
10404                 'color',
10405                 1,
10406                 'easeIn', after);
10407         });
10408         return this;
10409     },
10410
10411    /**
10412     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10413     * Usage:
10414 <pre><code>
10415 // default: a single light blue ripple
10416 el.frame();
10417
10418 // custom: 3 red ripples lasting 3 seconds total
10419 el.frame("ff0000", 3, { duration: 3 });
10420
10421 // common config options shown with default values
10422 el.frame("C3DAF9", 1, {
10423     duration: 1 //duration of entire animation (not each individual ripple)
10424     // Note: Easing is not configurable and will be ignored if included
10425 });
10426 </code></pre>
10427     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10428     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10429     * @param {Object} options (optional) Object literal with any of the Fx config options
10430     * @return {Roo.Element} The Element
10431     */
10432     frame : function(color, count, o){
10433         var el = this.getFxEl();
10434         o = o || {};
10435
10436         el.queueFx(o, function(){
10437             color = color || "#C3DAF9";
10438             if(color.length == 6){
10439                 color = "#" + color;
10440             }
10441             count = count || 1;
10442             duration = o.duration || 1;
10443             this.show();
10444
10445             var b = this.getBox();
10446             var animFn = function(){
10447                 var proxy = this.createProxy({
10448
10449                      style:{
10450                         visbility:"hidden",
10451                         position:"absolute",
10452                         "z-index":"35000", // yee haw
10453                         border:"0px solid " + color
10454                      }
10455                   });
10456                 var scale = Roo.isBorderBox ? 2 : 1;
10457                 proxy.animate({
10458                     top:{from:b.y, to:b.y - 20},
10459                     left:{from:b.x, to:b.x - 20},
10460                     borderWidth:{from:0, to:10},
10461                     opacity:{from:1, to:0},
10462                     height:{from:b.height, to:(b.height + (20*scale))},
10463                     width:{from:b.width, to:(b.width + (20*scale))}
10464                 }, duration, function(){
10465                     proxy.remove();
10466                 });
10467                 if(--count > 0){
10468                      animFn.defer((duration/2)*1000, this);
10469                 }else{
10470                     el.afterFx(o);
10471                 }
10472             };
10473             animFn.call(this);
10474         });
10475         return this;
10476     },
10477
10478    /**
10479     * Creates a pause before any subsequent queued effects begin.  If there are
10480     * no effects queued after the pause it will have no effect.
10481     * Usage:
10482 <pre><code>
10483 el.pause(1);
10484 </code></pre>
10485     * @param {Number} seconds The length of time to pause (in seconds)
10486     * @return {Roo.Element} The Element
10487     */
10488     pause : function(seconds){
10489         var el = this.getFxEl();
10490         var o = {};
10491
10492         el.queueFx(o, function(){
10493             setTimeout(function(){
10494                 el.afterFx(o);
10495             }, seconds * 1000);
10496         });
10497         return this;
10498     },
10499
10500    /**
10501     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10502     * using the "endOpacity" config option.
10503     * Usage:
10504 <pre><code>
10505 // default: fade in from opacity 0 to 100%
10506 el.fadeIn();
10507
10508 // custom: fade in from opacity 0 to 75% over 2 seconds
10509 el.fadeIn({ endOpacity: .75, duration: 2});
10510
10511 // common config options shown with default values
10512 el.fadeIn({
10513     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10514     easing: 'easeOut',
10515     duration: .5
10516 });
10517 </code></pre>
10518     * @param {Object} options (optional) Object literal with any of the Fx config options
10519     * @return {Roo.Element} The Element
10520     */
10521     fadeIn : function(o){
10522         var el = this.getFxEl();
10523         o = o || {};
10524         el.queueFx(o, function(){
10525             this.setOpacity(0);
10526             this.fixDisplay();
10527             this.dom.style.visibility = 'visible';
10528             var to = o.endOpacity || 1;
10529             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10530                 o, null, .5, "easeOut", function(){
10531                 if(to == 1){
10532                     this.clearOpacity();
10533                 }
10534                 el.afterFx(o);
10535             });
10536         });
10537         return this;
10538     },
10539
10540    /**
10541     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10542     * using the "endOpacity" config option.
10543     * Usage:
10544 <pre><code>
10545 // default: fade out from the element's current opacity to 0
10546 el.fadeOut();
10547
10548 // custom: fade out from the element's current opacity to 25% over 2 seconds
10549 el.fadeOut({ endOpacity: .25, duration: 2});
10550
10551 // common config options shown with default values
10552 el.fadeOut({
10553     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10554     easing: 'easeOut',
10555     duration: .5
10556     remove: false,
10557     useDisplay: false
10558 });
10559 </code></pre>
10560     * @param {Object} options (optional) Object literal with any of the Fx config options
10561     * @return {Roo.Element} The Element
10562     */
10563     fadeOut : function(o){
10564         var el = this.getFxEl();
10565         o = o || {};
10566         el.queueFx(o, function(){
10567             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10568                 o, null, .5, "easeOut", function(){
10569                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10570                      this.dom.style.display = "none";
10571                 }else{
10572                      this.dom.style.visibility = "hidden";
10573                 }
10574                 this.clearOpacity();
10575                 el.afterFx(o);
10576             });
10577         });
10578         return this;
10579     },
10580
10581    /**
10582     * Animates the transition of an element's dimensions from a starting height/width
10583     * to an ending height/width.
10584     * Usage:
10585 <pre><code>
10586 // change height and width to 100x100 pixels
10587 el.scale(100, 100);
10588
10589 // common config options shown with default values.  The height and width will default to
10590 // the element's existing values if passed as null.
10591 el.scale(
10592     [element's width],
10593     [element's height], {
10594     easing: 'easeOut',
10595     duration: .35
10596 });
10597 </code></pre>
10598     * @param {Number} width  The new width (pass undefined to keep the original width)
10599     * @param {Number} height  The new height (pass undefined to keep the original height)
10600     * @param {Object} options (optional) Object literal with any of the Fx config options
10601     * @return {Roo.Element} The Element
10602     */
10603     scale : function(w, h, o){
10604         this.shift(Roo.apply({}, o, {
10605             width: w,
10606             height: h
10607         }));
10608         return this;
10609     },
10610
10611    /**
10612     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10613     * Any of these properties not specified in the config object will not be changed.  This effect 
10614     * requires that at least one new dimension, position or opacity setting must be passed in on
10615     * the config object in order for the function to have any effect.
10616     * Usage:
10617 <pre><code>
10618 // slide the element horizontally to x position 200 while changing the height and opacity
10619 el.shift({ x: 200, height: 50, opacity: .8 });
10620
10621 // common config options shown with default values.
10622 el.shift({
10623     width: [element's width],
10624     height: [element's height],
10625     x: [element's x position],
10626     y: [element's y position],
10627     opacity: [element's opacity],
10628     easing: 'easeOut',
10629     duration: .35
10630 });
10631 </code></pre>
10632     * @param {Object} options  Object literal with any of the Fx config options
10633     * @return {Roo.Element} The Element
10634     */
10635     shift : function(o){
10636         var el = this.getFxEl();
10637         o = o || {};
10638         el.queueFx(o, function(){
10639             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10640             if(w !== undefined){
10641                 a.width = {to: this.adjustWidth(w)};
10642             }
10643             if(h !== undefined){
10644                 a.height = {to: this.adjustHeight(h)};
10645             }
10646             if(x !== undefined || y !== undefined){
10647                 a.points = {to: [
10648                     x !== undefined ? x : this.getX(),
10649                     y !== undefined ? y : this.getY()
10650                 ]};
10651             }
10652             if(op !== undefined){
10653                 a.opacity = {to: op};
10654             }
10655             if(o.xy !== undefined){
10656                 a.points = {to: o.xy};
10657             }
10658             arguments.callee.anim = this.fxanim(a,
10659                 o, 'motion', .35, "easeOut", function(){
10660                 el.afterFx(o);
10661             });
10662         });
10663         return this;
10664     },
10665
10666         /**
10667          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10668          * ending point of the effect.
10669          * Usage:
10670          *<pre><code>
10671 // default: slide the element downward while fading out
10672 el.ghost();
10673
10674 // custom: slide the element out to the right with a 2-second duration
10675 el.ghost('r', { duration: 2 });
10676
10677 // common config options shown with default values
10678 el.ghost('b', {
10679     easing: 'easeOut',
10680     duration: .5
10681     remove: false,
10682     useDisplay: false
10683 });
10684 </code></pre>
10685          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10686          * @param {Object} options (optional) Object literal with any of the Fx config options
10687          * @return {Roo.Element} The Element
10688          */
10689     ghost : function(anchor, o){
10690         var el = this.getFxEl();
10691         o = o || {};
10692
10693         el.queueFx(o, function(){
10694             anchor = anchor || "b";
10695
10696             // restore values after effect
10697             var r = this.getFxRestore();
10698             var w = this.getWidth(),
10699                 h = this.getHeight();
10700
10701             var st = this.dom.style;
10702
10703             var after = function(){
10704                 if(o.useDisplay){
10705                     el.setDisplayed(false);
10706                 }else{
10707                     el.hide();
10708                 }
10709
10710                 el.clearOpacity();
10711                 el.setPositioning(r.pos);
10712                 st.width = r.width;
10713                 st.height = r.height;
10714
10715                 el.afterFx(o);
10716             };
10717
10718             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10719             switch(anchor.toLowerCase()){
10720                 case "t":
10721                     pt.by = [0, -h];
10722                 break;
10723                 case "l":
10724                     pt.by = [-w, 0];
10725                 break;
10726                 case "r":
10727                     pt.by = [w, 0];
10728                 break;
10729                 case "b":
10730                     pt.by = [0, h];
10731                 break;
10732                 case "tl":
10733                     pt.by = [-w, -h];
10734                 break;
10735                 case "bl":
10736                     pt.by = [-w, h];
10737                 break;
10738                 case "br":
10739                     pt.by = [w, h];
10740                 break;
10741                 case "tr":
10742                     pt.by = [w, -h];
10743                 break;
10744             }
10745
10746             arguments.callee.anim = this.fxanim(a,
10747                 o,
10748                 'motion',
10749                 .5,
10750                 "easeOut", after);
10751         });
10752         return this;
10753     },
10754
10755         /**
10756          * Ensures that all effects queued after syncFx is called on the element are
10757          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10758          * @return {Roo.Element} The Element
10759          */
10760     syncFx : function(){
10761         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10762             block : false,
10763             concurrent : true,
10764             stopFx : false
10765         });
10766         return this;
10767     },
10768
10769         /**
10770          * Ensures that all effects queued after sequenceFx is called on the element are
10771          * run in sequence.  This is the opposite of {@link #syncFx}.
10772          * @return {Roo.Element} The Element
10773          */
10774     sequenceFx : function(){
10775         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10776             block : false,
10777             concurrent : false,
10778             stopFx : false
10779         });
10780         return this;
10781     },
10782
10783         /* @private */
10784     nextFx : function(){
10785         var ef = this.fxQueue[0];
10786         if(ef){
10787             ef.call(this);
10788         }
10789     },
10790
10791         /**
10792          * Returns true if the element has any effects actively running or queued, else returns false.
10793          * @return {Boolean} True if element has active effects, else false
10794          */
10795     hasActiveFx : function(){
10796         return this.fxQueue && this.fxQueue[0];
10797     },
10798
10799         /**
10800          * Stops any running effects and clears the element's internal effects queue if it contains
10801          * any additional effects that haven't started yet.
10802          * @return {Roo.Element} The Element
10803          */
10804     stopFx : function(){
10805         if(this.hasActiveFx()){
10806             var cur = this.fxQueue[0];
10807             if(cur && cur.anim && cur.anim.isAnimated()){
10808                 this.fxQueue = [cur]; // clear out others
10809                 cur.anim.stop(true);
10810             }
10811         }
10812         return this;
10813     },
10814
10815         /* @private */
10816     beforeFx : function(o){
10817         if(this.hasActiveFx() && !o.concurrent){
10818            if(o.stopFx){
10819                this.stopFx();
10820                return true;
10821            }
10822            return false;
10823         }
10824         return true;
10825     },
10826
10827         /**
10828          * Returns true if the element is currently blocking so that no other effect can be queued
10829          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10830          * used to ensure that an effect initiated by a user action runs to completion prior to the
10831          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10832          * @return {Boolean} True if blocking, else false
10833          */
10834     hasFxBlock : function(){
10835         var q = this.fxQueue;
10836         return q && q[0] && q[0].block;
10837     },
10838
10839         /* @private */
10840     queueFx : function(o, fn){
10841         if(!this.fxQueue){
10842             this.fxQueue = [];
10843         }
10844         if(!this.hasFxBlock()){
10845             Roo.applyIf(o, this.fxDefaults);
10846             if(!o.concurrent){
10847                 var run = this.beforeFx(o);
10848                 fn.block = o.block;
10849                 this.fxQueue.push(fn);
10850                 if(run){
10851                     this.nextFx();
10852                 }
10853             }else{
10854                 fn.call(this);
10855             }
10856         }
10857         return this;
10858     },
10859
10860         /* @private */
10861     fxWrap : function(pos, o, vis){
10862         var wrap;
10863         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10864             var wrapXY;
10865             if(o.fixPosition){
10866                 wrapXY = this.getXY();
10867             }
10868             var div = document.createElement("div");
10869             div.style.visibility = vis;
10870             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10871             wrap.setPositioning(pos);
10872             if(wrap.getStyle("position") == "static"){
10873                 wrap.position("relative");
10874             }
10875             this.clearPositioning('auto');
10876             wrap.clip();
10877             wrap.dom.appendChild(this.dom);
10878             if(wrapXY){
10879                 wrap.setXY(wrapXY);
10880             }
10881         }
10882         return wrap;
10883     },
10884
10885         /* @private */
10886     fxUnwrap : function(wrap, pos, o){
10887         this.clearPositioning();
10888         this.setPositioning(pos);
10889         if(!o.wrap){
10890             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10891             wrap.remove();
10892         }
10893     },
10894
10895         /* @private */
10896     getFxRestore : function(){
10897         var st = this.dom.style;
10898         return {pos: this.getPositioning(), width: st.width, height : st.height};
10899     },
10900
10901         /* @private */
10902     afterFx : function(o){
10903         if(o.afterStyle){
10904             this.applyStyles(o.afterStyle);
10905         }
10906         if(o.afterCls){
10907             this.addClass(o.afterCls);
10908         }
10909         if(o.remove === true){
10910             this.remove();
10911         }
10912         Roo.callback(o.callback, o.scope, [this]);
10913         if(!o.concurrent){
10914             this.fxQueue.shift();
10915             this.nextFx();
10916         }
10917     },
10918
10919         /* @private */
10920     getFxEl : function(){ // support for composite element fx
10921         return Roo.get(this.dom);
10922     },
10923
10924         /* @private */
10925     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10926         animType = animType || 'run';
10927         opt = opt || {};
10928         var anim = Roo.lib.Anim[animType](
10929             this.dom, args,
10930             (opt.duration || defaultDur) || .35,
10931             (opt.easing || defaultEase) || 'easeOut',
10932             function(){
10933                 Roo.callback(cb, this);
10934             },
10935             this
10936         );
10937         opt.anim = anim;
10938         return anim;
10939     }
10940 };
10941
10942 // backwords compat
10943 Roo.Fx.resize = Roo.Fx.scale;
10944
10945 //When included, Roo.Fx is automatically applied to Element so that all basic
10946 //effects are available directly via the Element API
10947 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10948  * Based on:
10949  * Ext JS Library 1.1.1
10950  * Copyright(c) 2006-2007, Ext JS, LLC.
10951  *
10952  * Originally Released Under LGPL - original licence link has changed is not relivant.
10953  *
10954  * Fork - LGPL
10955  * <script type="text/javascript">
10956  */
10957
10958
10959 /**
10960  * @class Roo.CompositeElement
10961  * Standard composite class. Creates a Roo.Element for every element in the collection.
10962  * <br><br>
10963  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10964  * actions will be performed on all the elements in this collection.</b>
10965  * <br><br>
10966  * All methods return <i>this</i> and can be chained.
10967  <pre><code>
10968  var els = Roo.select("#some-el div.some-class", true);
10969  // or select directly from an existing element
10970  var el = Roo.get('some-el');
10971  el.select('div.some-class', true);
10972
10973  els.setWidth(100); // all elements become 100 width
10974  els.hide(true); // all elements fade out and hide
10975  // or
10976  els.setWidth(100).hide(true);
10977  </code></pre>
10978  */
10979 Roo.CompositeElement = function(els){
10980     this.elements = [];
10981     this.addElements(els);
10982 };
10983 Roo.CompositeElement.prototype = {
10984     isComposite: true,
10985     addElements : function(els){
10986         if(!els) return this;
10987         if(typeof els == "string"){
10988             els = Roo.Element.selectorFunction(els);
10989         }
10990         var yels = this.elements;
10991         var index = yels.length-1;
10992         for(var i = 0, len = els.length; i < len; i++) {
10993                 yels[++index] = Roo.get(els[i]);
10994         }
10995         return this;
10996     },
10997
10998     /**
10999     * Clears this composite and adds the elements returned by the passed selector.
11000     * @param {String/Array} els A string CSS selector, an array of elements or an element
11001     * @return {CompositeElement} this
11002     */
11003     fill : function(els){
11004         this.elements = [];
11005         this.add(els);
11006         return this;
11007     },
11008
11009     /**
11010     * Filters this composite to only elements that match the passed selector.
11011     * @param {String} selector A string CSS selector
11012     * @param {Boolean} inverse return inverse filter (not matches)
11013     * @return {CompositeElement} this
11014     */
11015     filter : function(selector, inverse){
11016         var els = [];
11017         inverse = inverse || false;
11018         this.each(function(el){
11019             var match = inverse ? !el.is(selector) : el.is(selector);
11020             if(match){
11021                 els[els.length] = el.dom;
11022             }
11023         });
11024         this.fill(els);
11025         return this;
11026     },
11027
11028     invoke : function(fn, args){
11029         var els = this.elements;
11030         for(var i = 0, len = els.length; i < len; i++) {
11031                 Roo.Element.prototype[fn].apply(els[i], args);
11032         }
11033         return this;
11034     },
11035     /**
11036     * Adds elements to this composite.
11037     * @param {String/Array} els A string CSS selector, an array of elements or an element
11038     * @return {CompositeElement} this
11039     */
11040     add : function(els){
11041         if(typeof els == "string"){
11042             this.addElements(Roo.Element.selectorFunction(els));
11043         }else if(els.length !== undefined){
11044             this.addElements(els);
11045         }else{
11046             this.addElements([els]);
11047         }
11048         return this;
11049     },
11050     /**
11051     * Calls the passed function passing (el, this, index) for each element in this composite.
11052     * @param {Function} fn The function to call
11053     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11054     * @return {CompositeElement} this
11055     */
11056     each : function(fn, scope){
11057         var els = this.elements;
11058         for(var i = 0, len = els.length; i < len; i++){
11059             if(fn.call(scope || els[i], els[i], this, i) === false) {
11060                 break;
11061             }
11062         }
11063         return this;
11064     },
11065
11066     /**
11067      * Returns the Element object at the specified index
11068      * @param {Number} index
11069      * @return {Roo.Element}
11070      */
11071     item : function(index){
11072         return this.elements[index] || null;
11073     },
11074
11075     /**
11076      * Returns the first Element
11077      * @return {Roo.Element}
11078      */
11079     first : function(){
11080         return this.item(0);
11081     },
11082
11083     /**
11084      * Returns the last Element
11085      * @return {Roo.Element}
11086      */
11087     last : function(){
11088         return this.item(this.elements.length-1);
11089     },
11090
11091     /**
11092      * Returns the number of elements in this composite
11093      * @return Number
11094      */
11095     getCount : function(){
11096         return this.elements.length;
11097     },
11098
11099     /**
11100      * Returns true if this composite contains the passed element
11101      * @return Boolean
11102      */
11103     contains : function(el){
11104         return this.indexOf(el) !== -1;
11105     },
11106
11107     /**
11108      * Returns true if this composite contains the passed element
11109      * @return Boolean
11110      */
11111     indexOf : function(el){
11112         return this.elements.indexOf(Roo.get(el));
11113     },
11114
11115
11116     /**
11117     * Removes the specified element(s).
11118     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11119     * or an array of any of those.
11120     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11121     * @return {CompositeElement} this
11122     */
11123     removeElement : function(el, removeDom){
11124         if(el instanceof Array){
11125             for(var i = 0, len = el.length; i < len; i++){
11126                 this.removeElement(el[i]);
11127             }
11128             return this;
11129         }
11130         var index = typeof el == 'number' ? el : this.indexOf(el);
11131         if(index !== -1){
11132             if(removeDom){
11133                 var d = this.elements[index];
11134                 if(d.dom){
11135                     d.remove();
11136                 }else{
11137                     d.parentNode.removeChild(d);
11138                 }
11139             }
11140             this.elements.splice(index, 1);
11141         }
11142         return this;
11143     },
11144
11145     /**
11146     * Replaces the specified element with the passed element.
11147     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11148     * to replace.
11149     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11150     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11151     * @return {CompositeElement} this
11152     */
11153     replaceElement : function(el, replacement, domReplace){
11154         var index = typeof el == 'number' ? el : this.indexOf(el);
11155         if(index !== -1){
11156             if(domReplace){
11157                 this.elements[index].replaceWith(replacement);
11158             }else{
11159                 this.elements.splice(index, 1, Roo.get(replacement))
11160             }
11161         }
11162         return this;
11163     },
11164
11165     /**
11166      * Removes all elements.
11167      */
11168     clear : function(){
11169         this.elements = [];
11170     }
11171 };
11172 (function(){
11173     Roo.CompositeElement.createCall = function(proto, fnName){
11174         if(!proto[fnName]){
11175             proto[fnName] = function(){
11176                 return this.invoke(fnName, arguments);
11177             };
11178         }
11179     };
11180     for(var fnName in Roo.Element.prototype){
11181         if(typeof Roo.Element.prototype[fnName] == "function"){
11182             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11183         }
11184     };
11185 })();
11186 /*
11187  * Based on:
11188  * Ext JS Library 1.1.1
11189  * Copyright(c) 2006-2007, Ext JS, LLC.
11190  *
11191  * Originally Released Under LGPL - original licence link has changed is not relivant.
11192  *
11193  * Fork - LGPL
11194  * <script type="text/javascript">
11195  */
11196
11197 /**
11198  * @class Roo.CompositeElementLite
11199  * @extends Roo.CompositeElement
11200  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11201  <pre><code>
11202  var els = Roo.select("#some-el div.some-class");
11203  // or select directly from an existing element
11204  var el = Roo.get('some-el');
11205  el.select('div.some-class');
11206
11207  els.setWidth(100); // all elements become 100 width
11208  els.hide(true); // all elements fade out and hide
11209  // or
11210  els.setWidth(100).hide(true);
11211  </code></pre><br><br>
11212  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11213  * actions will be performed on all the elements in this collection.</b>
11214  */
11215 Roo.CompositeElementLite = function(els){
11216     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11217     this.el = new Roo.Element.Flyweight();
11218 };
11219 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11220     addElements : function(els){
11221         if(els){
11222             if(els instanceof Array){
11223                 this.elements = this.elements.concat(els);
11224             }else{
11225                 var yels = this.elements;
11226                 var index = yels.length-1;
11227                 for(var i = 0, len = els.length; i < len; i++) {
11228                     yels[++index] = els[i];
11229                 }
11230             }
11231         }
11232         return this;
11233     },
11234     invoke : function(fn, args){
11235         var els = this.elements;
11236         var el = this.el;
11237         for(var i = 0, len = els.length; i < len; i++) {
11238             el.dom = els[i];
11239                 Roo.Element.prototype[fn].apply(el, args);
11240         }
11241         return this;
11242     },
11243     /**
11244      * Returns a flyweight Element of the dom element object at the specified index
11245      * @param {Number} index
11246      * @return {Roo.Element}
11247      */
11248     item : function(index){
11249         if(!this.elements[index]){
11250             return null;
11251         }
11252         this.el.dom = this.elements[index];
11253         return this.el;
11254     },
11255
11256     // fixes scope with flyweight
11257     addListener : function(eventName, handler, scope, opt){
11258         var els = this.elements;
11259         for(var i = 0, len = els.length; i < len; i++) {
11260             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11261         }
11262         return this;
11263     },
11264
11265     /**
11266     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11267     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11268     * a reference to the dom node, use el.dom.</b>
11269     * @param {Function} fn The function to call
11270     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11271     * @return {CompositeElement} this
11272     */
11273     each : function(fn, scope){
11274         var els = this.elements;
11275         var el = this.el;
11276         for(var i = 0, len = els.length; i < len; i++){
11277             el.dom = els[i];
11278                 if(fn.call(scope || el, el, this, i) === false){
11279                 break;
11280             }
11281         }
11282         return this;
11283     },
11284
11285     indexOf : function(el){
11286         return this.elements.indexOf(Roo.getDom(el));
11287     },
11288
11289     replaceElement : function(el, replacement, domReplace){
11290         var index = typeof el == 'number' ? el : this.indexOf(el);
11291         if(index !== -1){
11292             replacement = Roo.getDom(replacement);
11293             if(domReplace){
11294                 var d = this.elements[index];
11295                 d.parentNode.insertBefore(replacement, d);
11296                 d.parentNode.removeChild(d);
11297             }
11298             this.elements.splice(index, 1, replacement);
11299         }
11300         return this;
11301     }
11302 });
11303 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11304
11305 /*
11306  * Based on:
11307  * Ext JS Library 1.1.1
11308  * Copyright(c) 2006-2007, Ext JS, LLC.
11309  *
11310  * Originally Released Under LGPL - original licence link has changed is not relivant.
11311  *
11312  * Fork - LGPL
11313  * <script type="text/javascript">
11314  */
11315
11316  
11317
11318 /**
11319  * @class Roo.data.Connection
11320  * @extends Roo.util.Observable
11321  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11322  * either to a configured URL, or to a URL specified at request time.<br><br>
11323  * <p>
11324  * Requests made by this class are asynchronous, and will return immediately. No data from
11325  * the server will be available to the statement immediately following the {@link #request} call.
11326  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11327  * <p>
11328  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11329  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11330  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11331  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11332  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11333  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11334  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11335  * standard DOM methods.
11336  * @constructor
11337  * @param {Object} config a configuration object.
11338  */
11339 Roo.data.Connection = function(config){
11340     Roo.apply(this, config);
11341     this.addEvents({
11342         /**
11343          * @event beforerequest
11344          * Fires before a network request is made to retrieve a data object.
11345          * @param {Connection} conn This Connection object.
11346          * @param {Object} options The options config object passed to the {@link #request} method.
11347          */
11348         "beforerequest" : true,
11349         /**
11350          * @event requestcomplete
11351          * Fires if the request was successfully completed.
11352          * @param {Connection} conn This Connection object.
11353          * @param {Object} response The XHR object containing the response data.
11354          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11355          * @param {Object} options The options config object passed to the {@link #request} method.
11356          */
11357         "requestcomplete" : true,
11358         /**
11359          * @event requestexception
11360          * Fires if an error HTTP status was returned from the server.
11361          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11362          * @param {Connection} conn This Connection object.
11363          * @param {Object} response The XHR object containing the response data.
11364          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11365          * @param {Object} options The options config object passed to the {@link #request} method.
11366          */
11367         "requestexception" : true
11368     });
11369     Roo.data.Connection.superclass.constructor.call(this);
11370 };
11371
11372 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11373     /**
11374      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11375      */
11376     /**
11377      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11378      * extra parameters to each request made by this object. (defaults to undefined)
11379      */
11380     /**
11381      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11382      *  to each request made by this object. (defaults to undefined)
11383      */
11384     /**
11385      * @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)
11386      */
11387     /**
11388      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11389      */
11390     timeout : 30000,
11391     /**
11392      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11393      * @type Boolean
11394      */
11395     autoAbort:false,
11396
11397     /**
11398      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11399      * @type Boolean
11400      */
11401     disableCaching: true,
11402
11403     /**
11404      * Sends an HTTP request to a remote server.
11405      * @param {Object} options An object which may contain the following properties:<ul>
11406      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11407      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11408      * request, a url encoded string or a function to call to get either.</li>
11409      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11410      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11411      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11412      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11413      * <li>options {Object} The parameter to the request call.</li>
11414      * <li>success {Boolean} True if the request succeeded.</li>
11415      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11416      * </ul></li>
11417      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11418      * The callback is passed the following parameters:<ul>
11419      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11420      * <li>options {Object} The parameter to the request call.</li>
11421      * </ul></li>
11422      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11423      * The callback is passed the following parameters:<ul>
11424      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11425      * <li>options {Object} The parameter to the request call.</li>
11426      * </ul></li>
11427      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11428      * for the callback function. Defaults to the browser window.</li>
11429      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11430      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11431      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11432      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11433      * params for the post data. Any params will be appended to the URL.</li>
11434      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11435      * </ul>
11436      * @return {Number} transactionId
11437      */
11438     request : function(o){
11439         if(this.fireEvent("beforerequest", this, o) !== false){
11440             var p = o.params;
11441
11442             if(typeof p == "function"){
11443                 p = p.call(o.scope||window, o);
11444             }
11445             if(typeof p == "object"){
11446                 p = Roo.urlEncode(o.params);
11447             }
11448             if(this.extraParams){
11449                 var extras = Roo.urlEncode(this.extraParams);
11450                 p = p ? (p + '&' + extras) : extras;
11451             }
11452
11453             var url = o.url || this.url;
11454             if(typeof url == 'function'){
11455                 url = url.call(o.scope||window, o);
11456             }
11457
11458             if(o.form){
11459                 var form = Roo.getDom(o.form);
11460                 url = url || form.action;
11461
11462                 var enctype = form.getAttribute("enctype");
11463                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11464                     return this.doFormUpload(o, p, url);
11465                 }
11466                 var f = Roo.lib.Ajax.serializeForm(form);
11467                 p = p ? (p + '&' + f) : f;
11468             }
11469
11470             var hs = o.headers;
11471             if(this.defaultHeaders){
11472                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11473                 if(!o.headers){
11474                     o.headers = hs;
11475                 }
11476             }
11477
11478             var cb = {
11479                 success: this.handleResponse,
11480                 failure: this.handleFailure,
11481                 scope: this,
11482                 argument: {options: o},
11483                 timeout : o.timeout || this.timeout
11484             };
11485
11486             var method = o.method||this.method||(p ? "POST" : "GET");
11487
11488             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11489                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11490             }
11491
11492             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11493                 if(o.autoAbort){
11494                     this.abort();
11495                 }
11496             }else if(this.autoAbort !== false){
11497                 this.abort();
11498             }
11499
11500             if((method == 'GET' && p) || o.xmlData){
11501                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11502                 p = '';
11503             }
11504             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11505             return this.transId;
11506         }else{
11507             Roo.callback(o.callback, o.scope, [o, null, null]);
11508             return null;
11509         }
11510     },
11511
11512     /**
11513      * Determine whether this object has a request outstanding.
11514      * @param {Number} transactionId (Optional) defaults to the last transaction
11515      * @return {Boolean} True if there is an outstanding request.
11516      */
11517     isLoading : function(transId){
11518         if(transId){
11519             return Roo.lib.Ajax.isCallInProgress(transId);
11520         }else{
11521             return this.transId ? true : false;
11522         }
11523     },
11524
11525     /**
11526      * Aborts any outstanding request.
11527      * @param {Number} transactionId (Optional) defaults to the last transaction
11528      */
11529     abort : function(transId){
11530         if(transId || this.isLoading()){
11531             Roo.lib.Ajax.abort(transId || this.transId);
11532         }
11533     },
11534
11535     // private
11536     handleResponse : function(response){
11537         this.transId = false;
11538         var options = response.argument.options;
11539         response.argument = options ? options.argument : null;
11540         this.fireEvent("requestcomplete", this, response, options);
11541         Roo.callback(options.success, options.scope, [response, options]);
11542         Roo.callback(options.callback, options.scope, [options, true, response]);
11543     },
11544
11545     // private
11546     handleFailure : function(response, e){
11547         this.transId = false;
11548         var options = response.argument.options;
11549         response.argument = options ? options.argument : null;
11550         this.fireEvent("requestexception", this, response, options, e);
11551         Roo.callback(options.failure, options.scope, [response, options]);
11552         Roo.callback(options.callback, options.scope, [options, false, response]);
11553     },
11554
11555     // private
11556     doFormUpload : function(o, ps, url){
11557         var id = Roo.id();
11558         var frame = document.createElement('iframe');
11559         frame.id = id;
11560         frame.name = id;
11561         frame.className = 'x-hidden';
11562         if(Roo.isIE){
11563             frame.src = Roo.SSL_SECURE_URL;
11564         }
11565         document.body.appendChild(frame);
11566
11567         if(Roo.isIE){
11568            document.frames[id].name = id;
11569         }
11570
11571         var form = Roo.getDom(o.form);
11572         form.target = id;
11573         form.method = 'POST';
11574         form.enctype = form.encoding = 'multipart/form-data';
11575         if(url){
11576             form.action = url;
11577         }
11578
11579         var hiddens, hd;
11580         if(ps){ // add dynamic params
11581             hiddens = [];
11582             ps = Roo.urlDecode(ps, false);
11583             for(var k in ps){
11584                 if(ps.hasOwnProperty(k)){
11585                     hd = document.createElement('input');
11586                     hd.type = 'hidden';
11587                     hd.name = k;
11588                     hd.value = ps[k];
11589                     form.appendChild(hd);
11590                     hiddens.push(hd);
11591                 }
11592             }
11593         }
11594
11595         function cb(){
11596             var r = {  // bogus response object
11597                 responseText : '',
11598                 responseXML : null
11599             };
11600
11601             r.argument = o ? o.argument : null;
11602
11603             try { //
11604                 var doc;
11605                 if(Roo.isIE){
11606                     doc = frame.contentWindow.document;
11607                 }else {
11608                     doc = (frame.contentDocument || window.frames[id].document);
11609                 }
11610                 if(doc && doc.body){
11611                     r.responseText = doc.body.innerHTML;
11612                 }
11613                 if(doc && doc.XMLDocument){
11614                     r.responseXML = doc.XMLDocument;
11615                 }else {
11616                     r.responseXML = doc;
11617                 }
11618             }
11619             catch(e) {
11620                 // ignore
11621             }
11622
11623             Roo.EventManager.removeListener(frame, 'load', cb, this);
11624
11625             this.fireEvent("requestcomplete", this, r, o);
11626             Roo.callback(o.success, o.scope, [r, o]);
11627             Roo.callback(o.callback, o.scope, [o, true, r]);
11628
11629             setTimeout(function(){document.body.removeChild(frame);}, 100);
11630         }
11631
11632         Roo.EventManager.on(frame, 'load', cb, this);
11633         form.submit();
11634
11635         if(hiddens){ // remove dynamic params
11636             for(var i = 0, len = hiddens.length; i < len; i++){
11637                 form.removeChild(hiddens[i]);
11638             }
11639         }
11640     }
11641 });
11642 /*
11643  * Based on:
11644  * Ext JS Library 1.1.1
11645  * Copyright(c) 2006-2007, Ext JS, LLC.
11646  *
11647  * Originally Released Under LGPL - original licence link has changed is not relivant.
11648  *
11649  * Fork - LGPL
11650  * <script type="text/javascript">
11651  */
11652  
11653 /**
11654  * Global Ajax request class.
11655  * 
11656  * @class Roo.Ajax
11657  * @extends Roo.data.Connection
11658  * @static
11659  * 
11660  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11661  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11662  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11663  * @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)
11664  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11665  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11666  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11667  */
11668 Roo.Ajax = new Roo.data.Connection({
11669     // fix up the docs
11670     /**
11671      * @scope Roo.Ajax
11672      * @type {Boolear} 
11673      */
11674     autoAbort : false,
11675
11676     /**
11677      * Serialize the passed form into a url encoded string
11678      * @scope Roo.Ajax
11679      * @param {String/HTMLElement} form
11680      * @return {String}
11681      */
11682     serializeForm : function(form){
11683         return Roo.lib.Ajax.serializeForm(form);
11684     }
11685 });/*
11686  * Based on:
11687  * Ext JS Library 1.1.1
11688  * Copyright(c) 2006-2007, Ext JS, LLC.
11689  *
11690  * Originally Released Under LGPL - original licence link has changed is not relivant.
11691  *
11692  * Fork - LGPL
11693  * <script type="text/javascript">
11694  */
11695
11696  
11697 /**
11698  * @class Roo.UpdateManager
11699  * @extends Roo.util.Observable
11700  * Provides AJAX-style update for Element object.<br><br>
11701  * Usage:<br>
11702  * <pre><code>
11703  * // Get it from a Roo.Element object
11704  * var el = Roo.get("foo");
11705  * var mgr = el.getUpdateManager();
11706  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11707  * ...
11708  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11709  * <br>
11710  * // or directly (returns the same UpdateManager instance)
11711  * var mgr = new Roo.UpdateManager("myElementId");
11712  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11713  * mgr.on("update", myFcnNeedsToKnow);
11714  * <br>
11715    // short handed call directly from the element object
11716    Roo.get("foo").load({
11717         url: "bar.php",
11718         scripts:true,
11719         params: "for=bar",
11720         text: "Loading Foo..."
11721    });
11722  * </code></pre>
11723  * @constructor
11724  * Create new UpdateManager directly.
11725  * @param {String/HTMLElement/Roo.Element} el The element to update
11726  * @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).
11727  */
11728 Roo.UpdateManager = function(el, forceNew){
11729     el = Roo.get(el);
11730     if(!forceNew && el.updateManager){
11731         return el.updateManager;
11732     }
11733     /**
11734      * The Element object
11735      * @type Roo.Element
11736      */
11737     this.el = el;
11738     /**
11739      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11740      * @type String
11741      */
11742     this.defaultUrl = null;
11743
11744     this.addEvents({
11745         /**
11746          * @event beforeupdate
11747          * Fired before an update is made, return false from your handler and the update is cancelled.
11748          * @param {Roo.Element} el
11749          * @param {String/Object/Function} url
11750          * @param {String/Object} params
11751          */
11752         "beforeupdate": true,
11753         /**
11754          * @event update
11755          * Fired after successful update is made.
11756          * @param {Roo.Element} el
11757          * @param {Object} oResponseObject The response Object
11758          */
11759         "update": true,
11760         /**
11761          * @event failure
11762          * Fired on update failure.
11763          * @param {Roo.Element} el
11764          * @param {Object} oResponseObject The response Object
11765          */
11766         "failure": true
11767     });
11768     var d = Roo.UpdateManager.defaults;
11769     /**
11770      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11771      * @type String
11772      */
11773     this.sslBlankUrl = d.sslBlankUrl;
11774     /**
11775      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11776      * @type Boolean
11777      */
11778     this.disableCaching = d.disableCaching;
11779     /**
11780      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11781      * @type String
11782      */
11783     this.indicatorText = d.indicatorText;
11784     /**
11785      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11786      * @type String
11787      */
11788     this.showLoadIndicator = d.showLoadIndicator;
11789     /**
11790      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11791      * @type Number
11792      */
11793     this.timeout = d.timeout;
11794
11795     /**
11796      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11797      * @type Boolean
11798      */
11799     this.loadScripts = d.loadScripts;
11800
11801     /**
11802      * Transaction object of current executing transaction
11803      */
11804     this.transaction = null;
11805
11806     /**
11807      * @private
11808      */
11809     this.autoRefreshProcId = null;
11810     /**
11811      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11812      * @type Function
11813      */
11814     this.refreshDelegate = this.refresh.createDelegate(this);
11815     /**
11816      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11817      * @type Function
11818      */
11819     this.updateDelegate = this.update.createDelegate(this);
11820     /**
11821      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11822      * @type Function
11823      */
11824     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11825     /**
11826      * @private
11827      */
11828     this.successDelegate = this.processSuccess.createDelegate(this);
11829     /**
11830      * @private
11831      */
11832     this.failureDelegate = this.processFailure.createDelegate(this);
11833
11834     if(!this.renderer){
11835      /**
11836       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11837       */
11838     this.renderer = new Roo.UpdateManager.BasicRenderer();
11839     }
11840     
11841     Roo.UpdateManager.superclass.constructor.call(this);
11842 };
11843
11844 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11845     /**
11846      * Get the Element this UpdateManager is bound to
11847      * @return {Roo.Element} The element
11848      */
11849     getEl : function(){
11850         return this.el;
11851     },
11852     /**
11853      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11854      * @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:
11855 <pre><code>
11856 um.update({<br/>
11857     url: "your-url.php",<br/>
11858     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11859     callback: yourFunction,<br/>
11860     scope: yourObject, //(optional scope)  <br/>
11861     discardUrl: false, <br/>
11862     nocache: false,<br/>
11863     text: "Loading...",<br/>
11864     timeout: 30,<br/>
11865     scripts: false<br/>
11866 });
11867 </code></pre>
11868      * The only required property is url. The optional properties nocache, text and scripts
11869      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11870      * @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}
11871      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11872      * @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.
11873      */
11874     update : function(url, params, callback, discardUrl){
11875         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11876             var method = this.method,
11877                 cfg;
11878             if(typeof url == "object"){ // must be config object
11879                 cfg = url;
11880                 url = cfg.url;
11881                 params = params || cfg.params;
11882                 callback = callback || cfg.callback;
11883                 discardUrl = discardUrl || cfg.discardUrl;
11884                 if(callback && cfg.scope){
11885                     callback = callback.createDelegate(cfg.scope);
11886                 }
11887                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11888                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11889                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11890                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11891                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11892             }
11893             this.showLoading();
11894             if(!discardUrl){
11895                 this.defaultUrl = url;
11896             }
11897             if(typeof url == "function"){
11898                 url = url.call(this);
11899             }
11900
11901             method = method || (params ? "POST" : "GET");
11902             if(method == "GET"){
11903                 url = this.prepareUrl(url);
11904             }
11905
11906             var o = Roo.apply(cfg ||{}, {
11907                 url : url,
11908                 params: params,
11909                 success: this.successDelegate,
11910                 failure: this.failureDelegate,
11911                 callback: undefined,
11912                 timeout: (this.timeout*1000),
11913                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11914             });
11915             Roo.log("updated manager called with timeout of " + o.timeout);
11916             this.transaction = Roo.Ajax.request(o);
11917         }
11918     },
11919
11920     /**
11921      * 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.
11922      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11923      * @param {String/HTMLElement} form The form Id or form element
11924      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11925      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11926      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11927      */
11928     formUpdate : function(form, url, reset, callback){
11929         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11930             if(typeof url == "function"){
11931                 url = url.call(this);
11932             }
11933             form = Roo.getDom(form);
11934             this.transaction = Roo.Ajax.request({
11935                 form: form,
11936                 url:url,
11937                 success: this.successDelegate,
11938                 failure: this.failureDelegate,
11939                 timeout: (this.timeout*1000),
11940                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11941             });
11942             this.showLoading.defer(1, this);
11943         }
11944     },
11945
11946     /**
11947      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11948      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11949      */
11950     refresh : function(callback){
11951         if(this.defaultUrl == null){
11952             return;
11953         }
11954         this.update(this.defaultUrl, null, callback, true);
11955     },
11956
11957     /**
11958      * Set this element to auto refresh.
11959      * @param {Number} interval How often to update (in seconds).
11960      * @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)
11961      * @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}
11962      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11963      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11964      */
11965     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11966         if(refreshNow){
11967             this.update(url || this.defaultUrl, params, callback, true);
11968         }
11969         if(this.autoRefreshProcId){
11970             clearInterval(this.autoRefreshProcId);
11971         }
11972         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11973     },
11974
11975     /**
11976      * Stop auto refresh on this element.
11977      */
11978      stopAutoRefresh : function(){
11979         if(this.autoRefreshProcId){
11980             clearInterval(this.autoRefreshProcId);
11981             delete this.autoRefreshProcId;
11982         }
11983     },
11984
11985     isAutoRefreshing : function(){
11986        return this.autoRefreshProcId ? true : false;
11987     },
11988     /**
11989      * Called to update the element to "Loading" state. Override to perform custom action.
11990      */
11991     showLoading : function(){
11992         if(this.showLoadIndicator){
11993             this.el.update(this.indicatorText);
11994         }
11995     },
11996
11997     /**
11998      * Adds unique parameter to query string if disableCaching = true
11999      * @private
12000      */
12001     prepareUrl : function(url){
12002         if(this.disableCaching){
12003             var append = "_dc=" + (new Date().getTime());
12004             if(url.indexOf("?") !== -1){
12005                 url += "&" + append;
12006             }else{
12007                 url += "?" + append;
12008             }
12009         }
12010         return url;
12011     },
12012
12013     /**
12014      * @private
12015      */
12016     processSuccess : function(response){
12017         this.transaction = null;
12018         if(response.argument.form && response.argument.reset){
12019             try{ // put in try/catch since some older FF releases had problems with this
12020                 response.argument.form.reset();
12021             }catch(e){}
12022         }
12023         if(this.loadScripts){
12024             this.renderer.render(this.el, response, this,
12025                 this.updateComplete.createDelegate(this, [response]));
12026         }else{
12027             this.renderer.render(this.el, response, this);
12028             this.updateComplete(response);
12029         }
12030     },
12031
12032     updateComplete : function(response){
12033         this.fireEvent("update", this.el, response);
12034         if(typeof response.argument.callback == "function"){
12035             response.argument.callback(this.el, true, response);
12036         }
12037     },
12038
12039     /**
12040      * @private
12041      */
12042     processFailure : function(response){
12043         this.transaction = null;
12044         this.fireEvent("failure", this.el, response);
12045         if(typeof response.argument.callback == "function"){
12046             response.argument.callback(this.el, false, response);
12047         }
12048     },
12049
12050     /**
12051      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12052      * @param {Object} renderer The object implementing the render() method
12053      */
12054     setRenderer : function(renderer){
12055         this.renderer = renderer;
12056     },
12057
12058     getRenderer : function(){
12059        return this.renderer;
12060     },
12061
12062     /**
12063      * Set the defaultUrl used for updates
12064      * @param {String/Function} defaultUrl The url or a function to call to get the url
12065      */
12066     setDefaultUrl : function(defaultUrl){
12067         this.defaultUrl = defaultUrl;
12068     },
12069
12070     /**
12071      * Aborts the executing transaction
12072      */
12073     abort : function(){
12074         if(this.transaction){
12075             Roo.Ajax.abort(this.transaction);
12076         }
12077     },
12078
12079     /**
12080      * Returns true if an update is in progress
12081      * @return {Boolean}
12082      */
12083     isUpdating : function(){
12084         if(this.transaction){
12085             return Roo.Ajax.isLoading(this.transaction);
12086         }
12087         return false;
12088     }
12089 });
12090
12091 /**
12092  * @class Roo.UpdateManager.defaults
12093  * @static (not really - but it helps the doc tool)
12094  * The defaults collection enables customizing the default properties of UpdateManager
12095  */
12096    Roo.UpdateManager.defaults = {
12097        /**
12098          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12099          * @type Number
12100          */
12101          timeout : 30,
12102
12103          /**
12104          * True to process scripts by default (Defaults to false).
12105          * @type Boolean
12106          */
12107         loadScripts : false,
12108
12109         /**
12110         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12111         * @type String
12112         */
12113         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12114         /**
12115          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12116          * @type Boolean
12117          */
12118         disableCaching : false,
12119         /**
12120          * Whether to show indicatorText when loading (Defaults to true).
12121          * @type Boolean
12122          */
12123         showLoadIndicator : true,
12124         /**
12125          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12126          * @type String
12127          */
12128         indicatorText : '<div class="loading-indicator">Loading...</div>'
12129    };
12130
12131 /**
12132  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12133  *Usage:
12134  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12135  * @param {String/HTMLElement/Roo.Element} el The element to update
12136  * @param {String} url The url
12137  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12138  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12139  * @static
12140  * @deprecated
12141  * @member Roo.UpdateManager
12142  */
12143 Roo.UpdateManager.updateElement = function(el, url, params, options){
12144     var um = Roo.get(el, true).getUpdateManager();
12145     Roo.apply(um, options);
12146     um.update(url, params, options ? options.callback : null);
12147 };
12148 // alias for backwards compat
12149 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12150 /**
12151  * @class Roo.UpdateManager.BasicRenderer
12152  * Default Content renderer. Updates the elements innerHTML with the responseText.
12153  */
12154 Roo.UpdateManager.BasicRenderer = function(){};
12155
12156 Roo.UpdateManager.BasicRenderer.prototype = {
12157     /**
12158      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12159      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12160      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12161      * @param {Roo.Element} el The element being rendered
12162      * @param {Object} response The YUI Connect response object
12163      * @param {UpdateManager} updateManager The calling update manager
12164      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12165      */
12166      render : function(el, response, updateManager, callback){
12167         el.update(response.responseText, updateManager.loadScripts, callback);
12168     }
12169 };
12170 /*
12171  * Based on:
12172  * Roo JS
12173  * (c)) Alan Knowles
12174  * Licence : LGPL
12175  */
12176
12177
12178 /**
12179  * @class Roo.DomTemplate
12180  * @extends Roo.Template
12181  * An effort at a dom based template engine..
12182  *
12183  * Similar to XTemplate, except it uses dom parsing to create the template..
12184  *
12185  * Supported features:
12186  *
12187  *  Tags:
12188
12189 <pre><code>
12190       {a_variable} - output encoded.
12191       {a_variable.format:("Y-m-d")} - call a method on the variable
12192       {a_variable:raw} - unencoded output
12193       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12194       {a_variable:this.method_on_template(...)} - call a method on the template object.
12195  
12196 </code></pre>
12197  *  The tpl tag:
12198 <pre><code>
12199         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12200         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12201         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12202         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12203   
12204 </code></pre>
12205  *      
12206  */
12207 Roo.DomTemplate = function()
12208 {
12209      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12210      if (this.html) {
12211         this.compile();
12212      }
12213 };
12214
12215
12216 Roo.extend(Roo.DomTemplate, Roo.Template, {
12217     /**
12218      * id counter for sub templates.
12219      */
12220     id : 0,
12221     /**
12222      * flag to indicate if dom parser is inside a pre,
12223      * it will strip whitespace if not.
12224      */
12225     inPre : false,
12226     
12227     /**
12228      * The various sub templates
12229      */
12230     tpls : false,
12231     
12232     
12233     
12234     /**
12235      *
12236      * basic tag replacing syntax
12237      * WORD:WORD()
12238      *
12239      * // you can fake an object call by doing this
12240      *  x.t:(test,tesT) 
12241      * 
12242      */
12243     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12244     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12245     
12246     iterChild : function (node, method) {
12247         
12248         var oldPre = this.inPre;
12249         if (node.tagName == 'PRE') {
12250             this.inPre = true;
12251         }
12252         for( var i = 0; i < node.childNodes.length; i++) {
12253             method.call(this, node.childNodes[i]);
12254         }
12255         this.inPre = oldPre;
12256     },
12257     
12258     
12259     
12260     /**
12261      * compile the template
12262      *
12263      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12264      *
12265      */
12266     compile: function()
12267     {
12268         var s = this.html;
12269         
12270         // covert the html into DOM...
12271         var doc = false;
12272         var div =false;
12273         try {
12274             doc = document.implementation.createHTMLDocument("");
12275             doc.documentElement.innerHTML =   this.html  ;
12276             div = doc.documentElement;
12277         } catch (e) {
12278             // old IE... - nasty -- it causes all sorts of issues.. with
12279             // images getting pulled from server..
12280             div = document.createElement('div');
12281             div.innerHTML = this.html;
12282         }
12283         //doc.documentElement.innerHTML = htmlBody
12284          
12285         
12286         
12287         this.tpls = [];
12288         var _t = this;
12289         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12290         
12291         var tpls = this.tpls;
12292         
12293         // create a top level template from the snippet..
12294         
12295         //Roo.log(div.innerHTML);
12296         
12297         var tpl = {
12298             uid : 'master',
12299             id : this.id++,
12300             attr : false,
12301             value : false,
12302             body : div.innerHTML,
12303             
12304             forCall : false,
12305             execCall : false,
12306             dom : div,
12307             isTop : true
12308             
12309         };
12310         tpls.unshift(tpl);
12311         
12312         
12313         // compile them...
12314         this.tpls = [];
12315         Roo.each(tpls, function(tp){
12316             this.compileTpl(tp);
12317             this.tpls[tp.id] = tp;
12318         }, this);
12319         
12320         this.master = tpls[0];
12321         return this;
12322         
12323         
12324     },
12325     
12326     compileNode : function(node, istop) {
12327         // test for
12328         //Roo.log(node);
12329         
12330         
12331         // skip anything not a tag..
12332         if (node.nodeType != 1) {
12333             if (node.nodeType == 3 && !this.inPre) {
12334                 // reduce white space..
12335                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12336                 
12337             }
12338             return;
12339         }
12340         
12341         var tpl = {
12342             uid : false,
12343             id : false,
12344             attr : false,
12345             value : false,
12346             body : '',
12347             
12348             forCall : false,
12349             execCall : false,
12350             dom : false,
12351             isTop : istop
12352             
12353             
12354         };
12355         
12356         
12357         switch(true) {
12358             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12359             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12360             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12361             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12362             // no default..
12363         }
12364         
12365         
12366         if (!tpl.attr) {
12367             // just itterate children..
12368             this.iterChild(node,this.compileNode);
12369             return;
12370         }
12371         tpl.uid = this.id++;
12372         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12373         node.removeAttribute('roo-'+ tpl.attr);
12374         if (tpl.attr != 'name') {
12375             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12376             node.parentNode.replaceChild(placeholder,  node);
12377         } else {
12378             
12379             var placeholder =  document.createElement('span');
12380             placeholder.className = 'roo-tpl-' + tpl.value;
12381             node.parentNode.replaceChild(placeholder,  node);
12382         }
12383         
12384         // parent now sees '{domtplXXXX}
12385         this.iterChild(node,this.compileNode);
12386         
12387         // we should now have node body...
12388         var div = document.createElement('div');
12389         div.appendChild(node);
12390         tpl.dom = node;
12391         // this has the unfortunate side effect of converting tagged attributes
12392         // eg. href="{...}" into %7C...%7D
12393         // this has been fixed by searching for those combo's although it's a bit hacky..
12394         
12395         
12396         tpl.body = div.innerHTML;
12397         
12398         
12399          
12400         tpl.id = tpl.uid;
12401         switch(tpl.attr) {
12402             case 'for' :
12403                 switch (tpl.value) {
12404                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12405                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12406                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12407                 }
12408                 break;
12409             
12410             case 'exec':
12411                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12412                 break;
12413             
12414             case 'if':     
12415                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12416                 break;
12417             
12418             case 'name':
12419                 tpl.id  = tpl.value; // replace non characters???
12420                 break;
12421             
12422         }
12423         
12424         
12425         this.tpls.push(tpl);
12426         
12427         
12428         
12429     },
12430     
12431     
12432     
12433     
12434     /**
12435      * Compile a segment of the template into a 'sub-template'
12436      *
12437      * 
12438      * 
12439      *
12440      */
12441     compileTpl : function(tpl)
12442     {
12443         var fm = Roo.util.Format;
12444         var useF = this.disableFormats !== true;
12445         
12446         var sep = Roo.isGecko ? "+\n" : ",\n";
12447         
12448         var undef = function(str) {
12449             Roo.debug && Roo.log("Property not found :"  + str);
12450             return '';
12451         };
12452           
12453         //Roo.log(tpl.body);
12454         
12455         
12456         
12457         var fn = function(m, lbrace, name, format, args)
12458         {
12459             //Roo.log("ARGS");
12460             //Roo.log(arguments);
12461             args = args ? args.replace(/\\'/g,"'") : args;
12462             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12463             if (typeof(format) == 'undefined') {
12464                 format =  'htmlEncode'; 
12465             }
12466             if (format == 'raw' ) {
12467                 format = false;
12468             }
12469             
12470             if(name.substr(0, 6) == 'domtpl'){
12471                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12472             }
12473             
12474             // build an array of options to determine if value is undefined..
12475             
12476             // basically get 'xxxx.yyyy' then do
12477             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12478             //    (function () { Roo.log("Property not found"); return ''; })() :
12479             //    ......
12480             
12481             var udef_ar = [];
12482             var lookfor = '';
12483             Roo.each(name.split('.'), function(st) {
12484                 lookfor += (lookfor.length ? '.': '') + st;
12485                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12486             });
12487             
12488             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12489             
12490             
12491             if(format && useF){
12492                 
12493                 args = args ? ',' + args : "";
12494                  
12495                 if(format.substr(0, 5) != "this."){
12496                     format = "fm." + format + '(';
12497                 }else{
12498                     format = 'this.call("'+ format.substr(5) + '", ';
12499                     args = ", values";
12500                 }
12501                 
12502                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12503             }
12504              
12505             if (args && args.length) {
12506                 // called with xxyx.yuu:(test,test)
12507                 // change to ()
12508                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12509             }
12510             // raw.. - :raw modifier..
12511             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12512             
12513         };
12514         var body;
12515         // branched to use + in gecko and [].join() in others
12516         if(Roo.isGecko){
12517             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12518                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12519                     "';};};";
12520         }else{
12521             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12522             body.push(tpl.body.replace(/(\r\n|\n)/g,
12523                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12524             body.push("'].join('');};};");
12525             body = body.join('');
12526         }
12527         
12528         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12529        
12530         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12531         eval(body);
12532         
12533         return this;
12534     },
12535      
12536     /**
12537      * same as applyTemplate, except it's done to one of the subTemplates
12538      * when using named templates, you can do:
12539      *
12540      * var str = pl.applySubTemplate('your-name', values);
12541      *
12542      * 
12543      * @param {Number} id of the template
12544      * @param {Object} values to apply to template
12545      * @param {Object} parent (normaly the instance of this object)
12546      */
12547     applySubTemplate : function(id, values, parent)
12548     {
12549         
12550         
12551         var t = this.tpls[id];
12552         
12553         
12554         try { 
12555             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12556                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12557                 return '';
12558             }
12559         } catch(e) {
12560             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12561             Roo.log(values);
12562           
12563             return '';
12564         }
12565         try { 
12566             
12567             if(t.execCall && t.execCall.call(this, values, parent)){
12568                 return '';
12569             }
12570         } catch(e) {
12571             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12572             Roo.log(values);
12573             return '';
12574         }
12575         
12576         try {
12577             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12578             parent = t.target ? values : parent;
12579             if(t.forCall && vs instanceof Array){
12580                 var buf = [];
12581                 for(var i = 0, len = vs.length; i < len; i++){
12582                     try {
12583                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12584                     } catch (e) {
12585                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12586                         Roo.log(e.body);
12587                         //Roo.log(t.compiled);
12588                         Roo.log(vs[i]);
12589                     }   
12590                 }
12591                 return buf.join('');
12592             }
12593         } catch (e) {
12594             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12595             Roo.log(values);
12596             return '';
12597         }
12598         try {
12599             return t.compiled.call(this, vs, parent);
12600         } catch (e) {
12601             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12602             Roo.log(e.body);
12603             //Roo.log(t.compiled);
12604             Roo.log(values);
12605             return '';
12606         }
12607     },
12608
12609    
12610
12611     applyTemplate : function(values){
12612         return this.master.compiled.call(this, values, {});
12613         //var s = this.subs;
12614     },
12615
12616     apply : function(){
12617         return this.applyTemplate.apply(this, arguments);
12618     }
12619
12620  });
12621
12622 Roo.DomTemplate.from = function(el){
12623     el = Roo.getDom(el);
12624     return new Roo.Domtemplate(el.value || el.innerHTML);
12625 };/*
12626  * Based on:
12627  * Ext JS Library 1.1.1
12628  * Copyright(c) 2006-2007, Ext JS, LLC.
12629  *
12630  * Originally Released Under LGPL - original licence link has changed is not relivant.
12631  *
12632  * Fork - LGPL
12633  * <script type="text/javascript">
12634  */
12635
12636 /**
12637  * @class Roo.util.DelayedTask
12638  * Provides a convenient method of performing setTimeout where a new
12639  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12640  * You can use this class to buffer
12641  * the keypress events for a certain number of milliseconds, and perform only if they stop
12642  * for that amount of time.
12643  * @constructor The parameters to this constructor serve as defaults and are not required.
12644  * @param {Function} fn (optional) The default function to timeout
12645  * @param {Object} scope (optional) The default scope of that timeout
12646  * @param {Array} args (optional) The default Array of arguments
12647  */
12648 Roo.util.DelayedTask = function(fn, scope, args){
12649     var id = null, d, t;
12650
12651     var call = function(){
12652         var now = new Date().getTime();
12653         if(now - t >= d){
12654             clearInterval(id);
12655             id = null;
12656             fn.apply(scope, args || []);
12657         }
12658     };
12659     /**
12660      * Cancels any pending timeout and queues a new one
12661      * @param {Number} delay The milliseconds to delay
12662      * @param {Function} newFn (optional) Overrides function passed to constructor
12663      * @param {Object} newScope (optional) Overrides scope passed to constructor
12664      * @param {Array} newArgs (optional) Overrides args passed to constructor
12665      */
12666     this.delay = function(delay, newFn, newScope, newArgs){
12667         if(id && delay != d){
12668             this.cancel();
12669         }
12670         d = delay;
12671         t = new Date().getTime();
12672         fn = newFn || fn;
12673         scope = newScope || scope;
12674         args = newArgs || args;
12675         if(!id){
12676             id = setInterval(call, d);
12677         }
12678     };
12679
12680     /**
12681      * Cancel the last queued timeout
12682      */
12683     this.cancel = function(){
12684         if(id){
12685             clearInterval(id);
12686             id = null;
12687         }
12688     };
12689 };/*
12690  * Based on:
12691  * Ext JS Library 1.1.1
12692  * Copyright(c) 2006-2007, Ext JS, LLC.
12693  *
12694  * Originally Released Under LGPL - original licence link has changed is not relivant.
12695  *
12696  * Fork - LGPL
12697  * <script type="text/javascript">
12698  */
12699  
12700  
12701 Roo.util.TaskRunner = function(interval){
12702     interval = interval || 10;
12703     var tasks = [], removeQueue = [];
12704     var id = 0;
12705     var running = false;
12706
12707     var stopThread = function(){
12708         running = false;
12709         clearInterval(id);
12710         id = 0;
12711     };
12712
12713     var startThread = function(){
12714         if(!running){
12715             running = true;
12716             id = setInterval(runTasks, interval);
12717         }
12718     };
12719
12720     var removeTask = function(task){
12721         removeQueue.push(task);
12722         if(task.onStop){
12723             task.onStop();
12724         }
12725     };
12726
12727     var runTasks = function(){
12728         if(removeQueue.length > 0){
12729             for(var i = 0, len = removeQueue.length; i < len; i++){
12730                 tasks.remove(removeQueue[i]);
12731             }
12732             removeQueue = [];
12733             if(tasks.length < 1){
12734                 stopThread();
12735                 return;
12736             }
12737         }
12738         var now = new Date().getTime();
12739         for(var i = 0, len = tasks.length; i < len; ++i){
12740             var t = tasks[i];
12741             var itime = now - t.taskRunTime;
12742             if(t.interval <= itime){
12743                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12744                 t.taskRunTime = now;
12745                 if(rt === false || t.taskRunCount === t.repeat){
12746                     removeTask(t);
12747                     return;
12748                 }
12749             }
12750             if(t.duration && t.duration <= (now - t.taskStartTime)){
12751                 removeTask(t);
12752             }
12753         }
12754     };
12755
12756     /**
12757      * Queues a new task.
12758      * @param {Object} task
12759      */
12760     this.start = function(task){
12761         tasks.push(task);
12762         task.taskStartTime = new Date().getTime();
12763         task.taskRunTime = 0;
12764         task.taskRunCount = 0;
12765         startThread();
12766         return task;
12767     };
12768
12769     this.stop = function(task){
12770         removeTask(task);
12771         return task;
12772     };
12773
12774     this.stopAll = function(){
12775         stopThread();
12776         for(var i = 0, len = tasks.length; i < len; i++){
12777             if(tasks[i].onStop){
12778                 tasks[i].onStop();
12779             }
12780         }
12781         tasks = [];
12782         removeQueue = [];
12783     };
12784 };
12785
12786 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12787  * Based on:
12788  * Ext JS Library 1.1.1
12789  * Copyright(c) 2006-2007, Ext JS, LLC.
12790  *
12791  * Originally Released Under LGPL - original licence link has changed is not relivant.
12792  *
12793  * Fork - LGPL
12794  * <script type="text/javascript">
12795  */
12796
12797  
12798 /**
12799  * @class Roo.util.MixedCollection
12800  * @extends Roo.util.Observable
12801  * A Collection class that maintains both numeric indexes and keys and exposes events.
12802  * @constructor
12803  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12804  * collection (defaults to false)
12805  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12806  * and return the key value for that item.  This is used when available to look up the key on items that
12807  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12808  * equivalent to providing an implementation for the {@link #getKey} method.
12809  */
12810 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12811     this.items = [];
12812     this.map = {};
12813     this.keys = [];
12814     this.length = 0;
12815     this.addEvents({
12816         /**
12817          * @event clear
12818          * Fires when the collection is cleared.
12819          */
12820         "clear" : true,
12821         /**
12822          * @event add
12823          * Fires when an item is added to the collection.
12824          * @param {Number} index The index at which the item was added.
12825          * @param {Object} o The item added.
12826          * @param {String} key The key associated with the added item.
12827          */
12828         "add" : true,
12829         /**
12830          * @event replace
12831          * Fires when an item is replaced in the collection.
12832          * @param {String} key he key associated with the new added.
12833          * @param {Object} old The item being replaced.
12834          * @param {Object} new The new item.
12835          */
12836         "replace" : true,
12837         /**
12838          * @event remove
12839          * Fires when an item is removed from the collection.
12840          * @param {Object} o The item being removed.
12841          * @param {String} key (optional) The key associated with the removed item.
12842          */
12843         "remove" : true,
12844         "sort" : true
12845     });
12846     this.allowFunctions = allowFunctions === true;
12847     if(keyFn){
12848         this.getKey = keyFn;
12849     }
12850     Roo.util.MixedCollection.superclass.constructor.call(this);
12851 };
12852
12853 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12854     allowFunctions : false,
12855     
12856 /**
12857  * Adds an item to the collection.
12858  * @param {String} key The key to associate with the item
12859  * @param {Object} o The item to add.
12860  * @return {Object} The item added.
12861  */
12862     add : function(key, o){
12863         if(arguments.length == 1){
12864             o = arguments[0];
12865             key = this.getKey(o);
12866         }
12867         if(typeof key == "undefined" || key === null){
12868             this.length++;
12869             this.items.push(o);
12870             this.keys.push(null);
12871         }else{
12872             var old = this.map[key];
12873             if(old){
12874                 return this.replace(key, o);
12875             }
12876             this.length++;
12877             this.items.push(o);
12878             this.map[key] = o;
12879             this.keys.push(key);
12880         }
12881         this.fireEvent("add", this.length-1, o, key);
12882         return o;
12883     },
12884        
12885 /**
12886   * MixedCollection has a generic way to fetch keys if you implement getKey.
12887 <pre><code>
12888 // normal way
12889 var mc = new Roo.util.MixedCollection();
12890 mc.add(someEl.dom.id, someEl);
12891 mc.add(otherEl.dom.id, otherEl);
12892 //and so on
12893
12894 // using getKey
12895 var mc = new Roo.util.MixedCollection();
12896 mc.getKey = function(el){
12897    return el.dom.id;
12898 };
12899 mc.add(someEl);
12900 mc.add(otherEl);
12901
12902 // or via the constructor
12903 var mc = new Roo.util.MixedCollection(false, function(el){
12904    return el.dom.id;
12905 });
12906 mc.add(someEl);
12907 mc.add(otherEl);
12908 </code></pre>
12909  * @param o {Object} The item for which to find the key.
12910  * @return {Object} The key for the passed item.
12911  */
12912     getKey : function(o){
12913          return o.id; 
12914     },
12915    
12916 /**
12917  * Replaces an item in the collection.
12918  * @param {String} key The key associated with the item to replace, or the item to replace.
12919  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12920  * @return {Object}  The new item.
12921  */
12922     replace : function(key, o){
12923         if(arguments.length == 1){
12924             o = arguments[0];
12925             key = this.getKey(o);
12926         }
12927         var old = this.item(key);
12928         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12929              return this.add(key, o);
12930         }
12931         var index = this.indexOfKey(key);
12932         this.items[index] = o;
12933         this.map[key] = o;
12934         this.fireEvent("replace", key, old, o);
12935         return o;
12936     },
12937    
12938 /**
12939  * Adds all elements of an Array or an Object to the collection.
12940  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12941  * an Array of values, each of which are added to the collection.
12942  */
12943     addAll : function(objs){
12944         if(arguments.length > 1 || objs instanceof Array){
12945             var args = arguments.length > 1 ? arguments : objs;
12946             for(var i = 0, len = args.length; i < len; i++){
12947                 this.add(args[i]);
12948             }
12949         }else{
12950             for(var key in objs){
12951                 if(this.allowFunctions || typeof objs[key] != "function"){
12952                     this.add(key, objs[key]);
12953                 }
12954             }
12955         }
12956     },
12957    
12958 /**
12959  * Executes the specified function once for every item in the collection, passing each
12960  * item as the first and only parameter. returning false from the function will stop the iteration.
12961  * @param {Function} fn The function to execute for each item.
12962  * @param {Object} scope (optional) The scope in which to execute the function.
12963  */
12964     each : function(fn, scope){
12965         var items = [].concat(this.items); // each safe for removal
12966         for(var i = 0, len = items.length; i < len; i++){
12967             if(fn.call(scope || items[i], items[i], i, len) === false){
12968                 break;
12969             }
12970         }
12971     },
12972    
12973 /**
12974  * Executes the specified function once for every key in the collection, passing each
12975  * key, and its associated item as the first two parameters.
12976  * @param {Function} fn The function to execute for each item.
12977  * @param {Object} scope (optional) The scope in which to execute the function.
12978  */
12979     eachKey : function(fn, scope){
12980         for(var i = 0, len = this.keys.length; i < len; i++){
12981             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12982         }
12983     },
12984    
12985 /**
12986  * Returns the first item in the collection which elicits a true return value from the
12987  * passed selection function.
12988  * @param {Function} fn The selection function to execute for each item.
12989  * @param {Object} scope (optional) The scope in which to execute the function.
12990  * @return {Object} The first item in the collection which returned true from the selection function.
12991  */
12992     find : function(fn, scope){
12993         for(var i = 0, len = this.items.length; i < len; i++){
12994             if(fn.call(scope || window, this.items[i], this.keys[i])){
12995                 return this.items[i];
12996             }
12997         }
12998         return null;
12999     },
13000    
13001 /**
13002  * Inserts an item at the specified index in the collection.
13003  * @param {Number} index The index to insert the item at.
13004  * @param {String} key The key to associate with the new item, or the item itself.
13005  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13006  * @return {Object} The item inserted.
13007  */
13008     insert : function(index, key, o){
13009         if(arguments.length == 2){
13010             o = arguments[1];
13011             key = this.getKey(o);
13012         }
13013         if(index >= this.length){
13014             return this.add(key, o);
13015         }
13016         this.length++;
13017         this.items.splice(index, 0, o);
13018         if(typeof key != "undefined" && key != null){
13019             this.map[key] = o;
13020         }
13021         this.keys.splice(index, 0, key);
13022         this.fireEvent("add", index, o, key);
13023         return o;
13024     },
13025    
13026 /**
13027  * Removed an item from the collection.
13028  * @param {Object} o The item to remove.
13029  * @return {Object} The item removed.
13030  */
13031     remove : function(o){
13032         return this.removeAt(this.indexOf(o));
13033     },
13034    
13035 /**
13036  * Remove an item from a specified index in the collection.
13037  * @param {Number} index The index within the collection of the item to remove.
13038  */
13039     removeAt : function(index){
13040         if(index < this.length && index >= 0){
13041             this.length--;
13042             var o = this.items[index];
13043             this.items.splice(index, 1);
13044             var key = this.keys[index];
13045             if(typeof key != "undefined"){
13046                 delete this.map[key];
13047             }
13048             this.keys.splice(index, 1);
13049             this.fireEvent("remove", o, key);
13050         }
13051     },
13052    
13053 /**
13054  * Removed an item associated with the passed key fom the collection.
13055  * @param {String} key The key of the item to remove.
13056  */
13057     removeKey : function(key){
13058         return this.removeAt(this.indexOfKey(key));
13059     },
13060    
13061 /**
13062  * Returns the number of items in the collection.
13063  * @return {Number} the number of items in the collection.
13064  */
13065     getCount : function(){
13066         return this.length; 
13067     },
13068    
13069 /**
13070  * Returns index within the collection of the passed Object.
13071  * @param {Object} o The item to find the index of.
13072  * @return {Number} index of the item.
13073  */
13074     indexOf : function(o){
13075         if(!this.items.indexOf){
13076             for(var i = 0, len = this.items.length; i < len; i++){
13077                 if(this.items[i] == o) return i;
13078             }
13079             return -1;
13080         }else{
13081             return this.items.indexOf(o);
13082         }
13083     },
13084    
13085 /**
13086  * Returns index within the collection of the passed key.
13087  * @param {String} key The key to find the index of.
13088  * @return {Number} index of the key.
13089  */
13090     indexOfKey : function(key){
13091         if(!this.keys.indexOf){
13092             for(var i = 0, len = this.keys.length; i < len; i++){
13093                 if(this.keys[i] == key) return i;
13094             }
13095             return -1;
13096         }else{
13097             return this.keys.indexOf(key);
13098         }
13099     },
13100    
13101 /**
13102  * Returns the item associated with the passed key OR index. Key has priority over index.
13103  * @param {String/Number} key The key or index of the item.
13104  * @return {Object} The item associated with the passed key.
13105  */
13106     item : function(key){
13107         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13108         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13109     },
13110     
13111 /**
13112  * Returns the item at the specified index.
13113  * @param {Number} index The index of the item.
13114  * @return {Object}
13115  */
13116     itemAt : function(index){
13117         return this.items[index];
13118     },
13119     
13120 /**
13121  * Returns the item associated with the passed key.
13122  * @param {String/Number} key The key of the item.
13123  * @return {Object} The item associated with the passed key.
13124  */
13125     key : function(key){
13126         return this.map[key];
13127     },
13128    
13129 /**
13130  * Returns true if the collection contains the passed Object as an item.
13131  * @param {Object} o  The Object to look for in the collection.
13132  * @return {Boolean} True if the collection contains the Object as an item.
13133  */
13134     contains : function(o){
13135         return this.indexOf(o) != -1;
13136     },
13137    
13138 /**
13139  * Returns true if the collection contains the passed Object as a key.
13140  * @param {String} key The key to look for in the collection.
13141  * @return {Boolean} True if the collection contains the Object as a key.
13142  */
13143     containsKey : function(key){
13144         return typeof this.map[key] != "undefined";
13145     },
13146    
13147 /**
13148  * Removes all items from the collection.
13149  */
13150     clear : function(){
13151         this.length = 0;
13152         this.items = [];
13153         this.keys = [];
13154         this.map = {};
13155         this.fireEvent("clear");
13156     },
13157    
13158 /**
13159  * Returns the first item in the collection.
13160  * @return {Object} the first item in the collection..
13161  */
13162     first : function(){
13163         return this.items[0]; 
13164     },
13165    
13166 /**
13167  * Returns the last item in the collection.
13168  * @return {Object} the last item in the collection..
13169  */
13170     last : function(){
13171         return this.items[this.length-1];   
13172     },
13173     
13174     _sort : function(property, dir, fn){
13175         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13176         fn = fn || function(a, b){
13177             return a-b;
13178         };
13179         var c = [], k = this.keys, items = this.items;
13180         for(var i = 0, len = items.length; i < len; i++){
13181             c[c.length] = {key: k[i], value: items[i], index: i};
13182         }
13183         c.sort(function(a, b){
13184             var v = fn(a[property], b[property]) * dsc;
13185             if(v == 0){
13186                 v = (a.index < b.index ? -1 : 1);
13187             }
13188             return v;
13189         });
13190         for(var i = 0, len = c.length; i < len; i++){
13191             items[i] = c[i].value;
13192             k[i] = c[i].key;
13193         }
13194         this.fireEvent("sort", this);
13195     },
13196     
13197     /**
13198      * Sorts this collection with the passed comparison function
13199      * @param {String} direction (optional) "ASC" or "DESC"
13200      * @param {Function} fn (optional) comparison function
13201      */
13202     sort : function(dir, fn){
13203         this._sort("value", dir, fn);
13204     },
13205     
13206     /**
13207      * Sorts this collection by keys
13208      * @param {String} direction (optional) "ASC" or "DESC"
13209      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13210      */
13211     keySort : function(dir, fn){
13212         this._sort("key", dir, fn || function(a, b){
13213             return String(a).toUpperCase()-String(b).toUpperCase();
13214         });
13215     },
13216     
13217     /**
13218      * Returns a range of items in this collection
13219      * @param {Number} startIndex (optional) defaults to 0
13220      * @param {Number} endIndex (optional) default to the last item
13221      * @return {Array} An array of items
13222      */
13223     getRange : function(start, end){
13224         var items = this.items;
13225         if(items.length < 1){
13226             return [];
13227         }
13228         start = start || 0;
13229         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13230         var r = [];
13231         if(start <= end){
13232             for(var i = start; i <= end; i++) {
13233                     r[r.length] = items[i];
13234             }
13235         }else{
13236             for(var i = start; i >= end; i--) {
13237                     r[r.length] = items[i];
13238             }
13239         }
13240         return r;
13241     },
13242         
13243     /**
13244      * Filter the <i>objects</i> in this collection by a specific property. 
13245      * Returns a new collection that has been filtered.
13246      * @param {String} property A property on your objects
13247      * @param {String/RegExp} value Either string that the property values 
13248      * should start with or a RegExp to test against the property
13249      * @return {MixedCollection} The new filtered collection
13250      */
13251     filter : function(property, value){
13252         if(!value.exec){ // not a regex
13253             value = String(value);
13254             if(value.length == 0){
13255                 return this.clone();
13256             }
13257             value = new RegExp("^" + Roo.escapeRe(value), "i");
13258         }
13259         return this.filterBy(function(o){
13260             return o && value.test(o[property]);
13261         });
13262         },
13263     
13264     /**
13265      * Filter by a function. * Returns a new collection that has been filtered.
13266      * The passed function will be called with each 
13267      * object in the collection. If the function returns true, the value is included 
13268      * otherwise it is filtered.
13269      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13270      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13271      * @return {MixedCollection} The new filtered collection
13272      */
13273     filterBy : function(fn, scope){
13274         var r = new Roo.util.MixedCollection();
13275         r.getKey = this.getKey;
13276         var k = this.keys, it = this.items;
13277         for(var i = 0, len = it.length; i < len; i++){
13278             if(fn.call(scope||this, it[i], k[i])){
13279                                 r.add(k[i], it[i]);
13280                         }
13281         }
13282         return r;
13283     },
13284     
13285     /**
13286      * Creates a duplicate of this collection
13287      * @return {MixedCollection}
13288      */
13289     clone : function(){
13290         var r = new Roo.util.MixedCollection();
13291         var k = this.keys, it = this.items;
13292         for(var i = 0, len = it.length; i < len; i++){
13293             r.add(k[i], it[i]);
13294         }
13295         r.getKey = this.getKey;
13296         return r;
13297     }
13298 });
13299 /**
13300  * Returns the item associated with the passed key or index.
13301  * @method
13302  * @param {String/Number} key The key or index of the item.
13303  * @return {Object} The item associated with the passed key.
13304  */
13305 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13306  * Based on:
13307  * Ext JS Library 1.1.1
13308  * Copyright(c) 2006-2007, Ext JS, LLC.
13309  *
13310  * Originally Released Under LGPL - original licence link has changed is not relivant.
13311  *
13312  * Fork - LGPL
13313  * <script type="text/javascript">
13314  */
13315 /**
13316  * @class Roo.util.JSON
13317  * Modified version of Douglas Crockford"s json.js that doesn"t
13318  * mess with the Object prototype 
13319  * http://www.json.org/js.html
13320  * @singleton
13321  */
13322 Roo.util.JSON = new (function(){
13323     var useHasOwn = {}.hasOwnProperty ? true : false;
13324     
13325     // crashes Safari in some instances
13326     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13327     
13328     var pad = function(n) {
13329         return n < 10 ? "0" + n : n;
13330     };
13331     
13332     var m = {
13333         "\b": '\\b',
13334         "\t": '\\t',
13335         "\n": '\\n',
13336         "\f": '\\f',
13337         "\r": '\\r',
13338         '"' : '\\"',
13339         "\\": '\\\\'
13340     };
13341
13342     var encodeString = function(s){
13343         if (/["\\\x00-\x1f]/.test(s)) {
13344             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13345                 var c = m[b];
13346                 if(c){
13347                     return c;
13348                 }
13349                 c = b.charCodeAt();
13350                 return "\\u00" +
13351                     Math.floor(c / 16).toString(16) +
13352                     (c % 16).toString(16);
13353             }) + '"';
13354         }
13355         return '"' + s + '"';
13356     };
13357     
13358     var encodeArray = function(o){
13359         var a = ["["], b, i, l = o.length, v;
13360             for (i = 0; i < l; i += 1) {
13361                 v = o[i];
13362                 switch (typeof v) {
13363                     case "undefined":
13364                     case "function":
13365                     case "unknown":
13366                         break;
13367                     default:
13368                         if (b) {
13369                             a.push(',');
13370                         }
13371                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13372                         b = true;
13373                 }
13374             }
13375             a.push("]");
13376             return a.join("");
13377     };
13378     
13379     var encodeDate = function(o){
13380         return '"' + o.getFullYear() + "-" +
13381                 pad(o.getMonth() + 1) + "-" +
13382                 pad(o.getDate()) + "T" +
13383                 pad(o.getHours()) + ":" +
13384                 pad(o.getMinutes()) + ":" +
13385                 pad(o.getSeconds()) + '"';
13386     };
13387     
13388     /**
13389      * Encodes an Object, Array or other value
13390      * @param {Mixed} o The variable to encode
13391      * @return {String} The JSON string
13392      */
13393     this.encode = function(o)
13394     {
13395         // should this be extended to fully wrap stringify..
13396         
13397         if(typeof o == "undefined" || o === null){
13398             return "null";
13399         }else if(o instanceof Array){
13400             return encodeArray(o);
13401         }else if(o instanceof Date){
13402             return encodeDate(o);
13403         }else if(typeof o == "string"){
13404             return encodeString(o);
13405         }else if(typeof o == "number"){
13406             return isFinite(o) ? String(o) : "null";
13407         }else if(typeof o == "boolean"){
13408             return String(o);
13409         }else {
13410             var a = ["{"], b, i, v;
13411             for (i in o) {
13412                 if(!useHasOwn || o.hasOwnProperty(i)) {
13413                     v = o[i];
13414                     switch (typeof v) {
13415                     case "undefined":
13416                     case "function":
13417                     case "unknown":
13418                         break;
13419                     default:
13420                         if(b){
13421                             a.push(',');
13422                         }
13423                         a.push(this.encode(i), ":",
13424                                 v === null ? "null" : this.encode(v));
13425                         b = true;
13426                     }
13427                 }
13428             }
13429             a.push("}");
13430             return a.join("");
13431         }
13432     };
13433     
13434     /**
13435      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13436      * @param {String} json The JSON string
13437      * @return {Object} The resulting object
13438      */
13439     this.decode = function(json){
13440         
13441         return  /** eval:var:json */ eval("(" + json + ')');
13442     };
13443 })();
13444 /** 
13445  * Shorthand for {@link Roo.util.JSON#encode}
13446  * @member Roo encode 
13447  * @method */
13448 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13449 /** 
13450  * Shorthand for {@link Roo.util.JSON#decode}
13451  * @member Roo decode 
13452  * @method */
13453 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13454 /*
13455  * Based on:
13456  * Ext JS Library 1.1.1
13457  * Copyright(c) 2006-2007, Ext JS, LLC.
13458  *
13459  * Originally Released Under LGPL - original licence link has changed is not relivant.
13460  *
13461  * Fork - LGPL
13462  * <script type="text/javascript">
13463  */
13464  
13465 /**
13466  * @class Roo.util.Format
13467  * Reusable data formatting functions
13468  * @singleton
13469  */
13470 Roo.util.Format = function(){
13471     var trimRe = /^\s+|\s+$/g;
13472     return {
13473         /**
13474          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13475          * @param {String} value The string to truncate
13476          * @param {Number} length The maximum length to allow before truncating
13477          * @return {String} The converted text
13478          */
13479         ellipsis : function(value, len){
13480             if(value && value.length > len){
13481                 return value.substr(0, len-3)+"...";
13482             }
13483             return value;
13484         },
13485
13486         /**
13487          * Checks a reference and converts it to empty string if it is undefined
13488          * @param {Mixed} value Reference to check
13489          * @return {Mixed} Empty string if converted, otherwise the original value
13490          */
13491         undef : function(value){
13492             return typeof value != "undefined" ? value : "";
13493         },
13494
13495         /**
13496          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13497          * @param {String} value The string to encode
13498          * @return {String} The encoded text
13499          */
13500         htmlEncode : function(value){
13501             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13502         },
13503
13504         /**
13505          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13506          * @param {String} value The string to decode
13507          * @return {String} The decoded text
13508          */
13509         htmlDecode : function(value){
13510             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13511         },
13512
13513         /**
13514          * Trims any whitespace from either side of a string
13515          * @param {String} value The text to trim
13516          * @return {String} The trimmed text
13517          */
13518         trim : function(value){
13519             return String(value).replace(trimRe, "");
13520         },
13521
13522         /**
13523          * Returns a substring from within an original string
13524          * @param {String} value The original text
13525          * @param {Number} start The start index of the substring
13526          * @param {Number} length The length of the substring
13527          * @return {String} The substring
13528          */
13529         substr : function(value, start, length){
13530             return String(value).substr(start, length);
13531         },
13532
13533         /**
13534          * Converts a string to all lower case letters
13535          * @param {String} value The text to convert
13536          * @return {String} The converted text
13537          */
13538         lowercase : function(value){
13539             return String(value).toLowerCase();
13540         },
13541
13542         /**
13543          * Converts a string to all upper case letters
13544          * @param {String} value The text to convert
13545          * @return {String} The converted text
13546          */
13547         uppercase : function(value){
13548             return String(value).toUpperCase();
13549         },
13550
13551         /**
13552          * Converts the first character only of a string to upper case
13553          * @param {String} value The text to convert
13554          * @return {String} The converted text
13555          */
13556         capitalize : function(value){
13557             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13558         },
13559
13560         // private
13561         call : function(value, fn){
13562             if(arguments.length > 2){
13563                 var args = Array.prototype.slice.call(arguments, 2);
13564                 args.unshift(value);
13565                  
13566                 return /** eval:var:value */  eval(fn).apply(window, args);
13567             }else{
13568                 /** eval:var:value */
13569                 return /** eval:var:value */ eval(fn).call(window, value);
13570             }
13571         },
13572
13573        
13574         /**
13575          * safer version of Math.toFixed..??/
13576          * @param {Number/String} value The numeric value to format
13577          * @param {Number/String} value Decimal places 
13578          * @return {String} The formatted currency string
13579          */
13580         toFixed : function(v, n)
13581         {
13582             // why not use to fixed - precision is buggered???
13583             if (!n) {
13584                 return Math.round(v-0);
13585             }
13586             var fact = Math.pow(10,n+1);
13587             v = (Math.round((v-0)*fact))/fact;
13588             var z = (''+fact).substring(2);
13589             if (v == Math.floor(v)) {
13590                 return Math.floor(v) + '.' + z;
13591             }
13592             
13593             // now just padd decimals..
13594             var ps = String(v).split('.');
13595             var fd = (ps[1] + z);
13596             var r = fd.substring(0,n); 
13597             var rm = fd.substring(n); 
13598             if (rm < 5) {
13599                 return ps[0] + '.' + r;
13600             }
13601             r*=1; // turn it into a number;
13602             r++;
13603             if (String(r).length != n) {
13604                 ps[0]*=1;
13605                 ps[0]++;
13606                 r = String(r).substring(1); // chop the end off.
13607             }
13608             
13609             return ps[0] + '.' + r;
13610              
13611         },
13612         
13613         /**
13614          * Format a number as US currency
13615          * @param {Number/String} value The numeric value to format
13616          * @return {String} The formatted currency string
13617          */
13618         usMoney : function(v){
13619             return '$' + Roo.util.Format.number(v);
13620         },
13621         
13622         /**
13623          * Format a number
13624          * eventually this should probably emulate php's number_format
13625          * @param {Number/String} value The numeric value to format
13626          * @param {Number} decimals number of decimal places
13627          * @return {String} The formatted currency string
13628          */
13629         number : function(v,decimals)
13630         {
13631             // multiply and round.
13632             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13633             var mul = Math.pow(10, decimals);
13634             var zero = String(mul).substring(1);
13635             v = (Math.round((v-0)*mul))/mul;
13636             
13637             // if it's '0' number.. then
13638             
13639             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13640             v = String(v);
13641             var ps = v.split('.');
13642             var whole = ps[0];
13643             
13644             
13645             var r = /(\d+)(\d{3})/;
13646             // add comma's
13647             while (r.test(whole)) {
13648                 whole = whole.replace(r, '$1' + ',' + '$2');
13649             }
13650             
13651             
13652             var sub = ps[1] ?
13653                     // has decimals..
13654                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13655                     // does not have decimals
13656                     (decimals ? ('.' + zero) : '');
13657             
13658             
13659             return whole + sub ;
13660         },
13661         
13662         /**
13663          * Parse a value into a formatted date using the specified format pattern.
13664          * @param {Mixed} value The value to format
13665          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13666          * @return {String} The formatted date string
13667          */
13668         date : function(v, format){
13669             if(!v){
13670                 return "";
13671             }
13672             if(!(v instanceof Date)){
13673                 v = new Date(Date.parse(v));
13674             }
13675             return v.dateFormat(format || Roo.util.Format.defaults.date);
13676         },
13677
13678         /**
13679          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13680          * @param {String} format Any valid date format string
13681          * @return {Function} The date formatting function
13682          */
13683         dateRenderer : function(format){
13684             return function(v){
13685                 return Roo.util.Format.date(v, format);  
13686             };
13687         },
13688
13689         // private
13690         stripTagsRE : /<\/?[^>]+>/gi,
13691         
13692         /**
13693          * Strips all HTML tags
13694          * @param {Mixed} value The text from which to strip tags
13695          * @return {String} The stripped text
13696          */
13697         stripTags : function(v){
13698             return !v ? v : String(v).replace(this.stripTagsRE, "");
13699         }
13700     };
13701 }();
13702 Roo.util.Format.defaults = {
13703     date : 'd/M/Y'
13704 };/*
13705  * Based on:
13706  * Ext JS Library 1.1.1
13707  * Copyright(c) 2006-2007, Ext JS, LLC.
13708  *
13709  * Originally Released Under LGPL - original licence link has changed is not relivant.
13710  *
13711  * Fork - LGPL
13712  * <script type="text/javascript">
13713  */
13714
13715
13716  
13717
13718 /**
13719  * @class Roo.MasterTemplate
13720  * @extends Roo.Template
13721  * Provides a template that can have child templates. The syntax is:
13722 <pre><code>
13723 var t = new Roo.MasterTemplate(
13724         '&lt;select name="{name}"&gt;',
13725                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13726         '&lt;/select&gt;'
13727 );
13728 t.add('options', {value: 'foo', text: 'bar'});
13729 // or you can add multiple child elements in one shot
13730 t.addAll('options', [
13731     {value: 'foo', text: 'bar'},
13732     {value: 'foo2', text: 'bar2'},
13733     {value: 'foo3', text: 'bar3'}
13734 ]);
13735 // then append, applying the master template values
13736 t.append('my-form', {name: 'my-select'});
13737 </code></pre>
13738 * A name attribute for the child template is not required if you have only one child
13739 * template or you want to refer to them by index.
13740  */
13741 Roo.MasterTemplate = function(){
13742     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13743     this.originalHtml = this.html;
13744     var st = {};
13745     var m, re = this.subTemplateRe;
13746     re.lastIndex = 0;
13747     var subIndex = 0;
13748     while(m = re.exec(this.html)){
13749         var name = m[1], content = m[2];
13750         st[subIndex] = {
13751             name: name,
13752             index: subIndex,
13753             buffer: [],
13754             tpl : new Roo.Template(content)
13755         };
13756         if(name){
13757             st[name] = st[subIndex];
13758         }
13759         st[subIndex].tpl.compile();
13760         st[subIndex].tpl.call = this.call.createDelegate(this);
13761         subIndex++;
13762     }
13763     this.subCount = subIndex;
13764     this.subs = st;
13765 };
13766 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13767     /**
13768     * The regular expression used to match sub templates
13769     * @type RegExp
13770     * @property
13771     */
13772     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13773
13774     /**
13775      * Applies the passed values to a child template.
13776      * @param {String/Number} name (optional) The name or index of the child template
13777      * @param {Array/Object} values The values to be applied to the template
13778      * @return {MasterTemplate} this
13779      */
13780      add : function(name, values){
13781         if(arguments.length == 1){
13782             values = arguments[0];
13783             name = 0;
13784         }
13785         var s = this.subs[name];
13786         s.buffer[s.buffer.length] = s.tpl.apply(values);
13787         return this;
13788     },
13789
13790     /**
13791      * Applies all the passed values to a child template.
13792      * @param {String/Number} name (optional) The name or index of the child template
13793      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13794      * @param {Boolean} reset (optional) True to reset the template first
13795      * @return {MasterTemplate} this
13796      */
13797     fill : function(name, values, reset){
13798         var a = arguments;
13799         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13800             values = a[0];
13801             name = 0;
13802             reset = a[1];
13803         }
13804         if(reset){
13805             this.reset();
13806         }
13807         for(var i = 0, len = values.length; i < len; i++){
13808             this.add(name, values[i]);
13809         }
13810         return this;
13811     },
13812
13813     /**
13814      * Resets the template for reuse
13815      * @return {MasterTemplate} this
13816      */
13817      reset : function(){
13818         var s = this.subs;
13819         for(var i = 0; i < this.subCount; i++){
13820             s[i].buffer = [];
13821         }
13822         return this;
13823     },
13824
13825     applyTemplate : function(values){
13826         var s = this.subs;
13827         var replaceIndex = -1;
13828         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13829             return s[++replaceIndex].buffer.join("");
13830         });
13831         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13832     },
13833
13834     apply : function(){
13835         return this.applyTemplate.apply(this, arguments);
13836     },
13837
13838     compile : function(){return this;}
13839 });
13840
13841 /**
13842  * Alias for fill().
13843  * @method
13844  */
13845 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13846  /**
13847  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13848  * var tpl = Roo.MasterTemplate.from('element-id');
13849  * @param {String/HTMLElement} el
13850  * @param {Object} config
13851  * @static
13852  */
13853 Roo.MasterTemplate.from = function(el, config){
13854     el = Roo.getDom(el);
13855     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13856 };/*
13857  * Based on:
13858  * Ext JS Library 1.1.1
13859  * Copyright(c) 2006-2007, Ext JS, LLC.
13860  *
13861  * Originally Released Under LGPL - original licence link has changed is not relivant.
13862  *
13863  * Fork - LGPL
13864  * <script type="text/javascript">
13865  */
13866
13867  
13868 /**
13869  * @class Roo.util.CSS
13870  * Utility class for manipulating CSS rules
13871  * @singleton
13872  */
13873 Roo.util.CSS = function(){
13874         var rules = null;
13875         var doc = document;
13876
13877     var camelRe = /(-[a-z])/gi;
13878     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13879
13880    return {
13881    /**
13882     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13883     * tag and appended to the HEAD of the document.
13884     * @param {String|Object} cssText The text containing the css rules
13885     * @param {String} id An id to add to the stylesheet for later removal
13886     * @return {StyleSheet}
13887     */
13888     createStyleSheet : function(cssText, id){
13889         var ss;
13890         var head = doc.getElementsByTagName("head")[0];
13891         var nrules = doc.createElement("style");
13892         nrules.setAttribute("type", "text/css");
13893         if(id){
13894             nrules.setAttribute("id", id);
13895         }
13896         if (typeof(cssText) != 'string') {
13897             // support object maps..
13898             // not sure if this a good idea.. 
13899             // perhaps it should be merged with the general css handling
13900             // and handle js style props.
13901             var cssTextNew = [];
13902             for(var n in cssText) {
13903                 var citems = [];
13904                 for(var k in cssText[n]) {
13905                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13906                 }
13907                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13908                 
13909             }
13910             cssText = cssTextNew.join("\n");
13911             
13912         }
13913        
13914        
13915        if(Roo.isIE){
13916            head.appendChild(nrules);
13917            ss = nrules.styleSheet;
13918            ss.cssText = cssText;
13919        }else{
13920            try{
13921                 nrules.appendChild(doc.createTextNode(cssText));
13922            }catch(e){
13923                nrules.cssText = cssText; 
13924            }
13925            head.appendChild(nrules);
13926            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13927        }
13928        this.cacheStyleSheet(ss);
13929        return ss;
13930    },
13931
13932    /**
13933     * Removes a style or link tag by id
13934     * @param {String} id The id of the tag
13935     */
13936    removeStyleSheet : function(id){
13937        var existing = doc.getElementById(id);
13938        if(existing){
13939            existing.parentNode.removeChild(existing);
13940        }
13941    },
13942
13943    /**
13944     * Dynamically swaps an existing stylesheet reference for a new one
13945     * @param {String} id The id of an existing link tag to remove
13946     * @param {String} url The href of the new stylesheet to include
13947     */
13948    swapStyleSheet : function(id, url){
13949        this.removeStyleSheet(id);
13950        var ss = doc.createElement("link");
13951        ss.setAttribute("rel", "stylesheet");
13952        ss.setAttribute("type", "text/css");
13953        ss.setAttribute("id", id);
13954        ss.setAttribute("href", url);
13955        doc.getElementsByTagName("head")[0].appendChild(ss);
13956    },
13957    
13958    /**
13959     * Refresh the rule cache if you have dynamically added stylesheets
13960     * @return {Object} An object (hash) of rules indexed by selector
13961     */
13962    refreshCache : function(){
13963        return this.getRules(true);
13964    },
13965
13966    // private
13967    cacheStyleSheet : function(stylesheet){
13968        if(!rules){
13969            rules = {};
13970        }
13971        try{// try catch for cross domain access issue
13972            var ssRules = stylesheet.cssRules || stylesheet.rules;
13973            for(var j = ssRules.length-1; j >= 0; --j){
13974                rules[ssRules[j].selectorText] = ssRules[j];
13975            }
13976        }catch(e){}
13977    },
13978    
13979    /**
13980     * Gets all css rules for the document
13981     * @param {Boolean} refreshCache true to refresh the internal cache
13982     * @return {Object} An object (hash) of rules indexed by selector
13983     */
13984    getRules : function(refreshCache){
13985                 if(rules == null || refreshCache){
13986                         rules = {};
13987                         var ds = doc.styleSheets;
13988                         for(var i =0, len = ds.length; i < len; i++){
13989                             try{
13990                         this.cacheStyleSheet(ds[i]);
13991                     }catch(e){} 
13992                 }
13993                 }
13994                 return rules;
13995         },
13996         
13997         /**
13998     * Gets an an individual CSS rule by selector(s)
13999     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14000     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14001     * @return {CSSRule} The CSS rule or null if one is not found
14002     */
14003    getRule : function(selector, refreshCache){
14004                 var rs = this.getRules(refreshCache);
14005                 if(!(selector instanceof Array)){
14006                     return rs[selector];
14007                 }
14008                 for(var i = 0; i < selector.length; i++){
14009                         if(rs[selector[i]]){
14010                                 return rs[selector[i]];
14011                         }
14012                 }
14013                 return null;
14014         },
14015         
14016         
14017         /**
14018     * Updates a rule property
14019     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14020     * @param {String} property The css property
14021     * @param {String} value The new value for the property
14022     * @return {Boolean} true If a rule was found and updated
14023     */
14024    updateRule : function(selector, property, value){
14025                 if(!(selector instanceof Array)){
14026                         var rule = this.getRule(selector);
14027                         if(rule){
14028                                 rule.style[property.replace(camelRe, camelFn)] = value;
14029                                 return true;
14030                         }
14031                 }else{
14032                         for(var i = 0; i < selector.length; i++){
14033                                 if(this.updateRule(selector[i], property, value)){
14034                                         return true;
14035                                 }
14036                         }
14037                 }
14038                 return false;
14039         }
14040    };   
14041 }();/*
14042  * Based on:
14043  * Ext JS Library 1.1.1
14044  * Copyright(c) 2006-2007, Ext JS, LLC.
14045  *
14046  * Originally Released Under LGPL - original licence link has changed is not relivant.
14047  *
14048  * Fork - LGPL
14049  * <script type="text/javascript">
14050  */
14051
14052  
14053
14054 /**
14055  * @class Roo.util.ClickRepeater
14056  * @extends Roo.util.Observable
14057  * 
14058  * A wrapper class which can be applied to any element. Fires a "click" event while the
14059  * mouse is pressed. The interval between firings may be specified in the config but
14060  * defaults to 10 milliseconds.
14061  * 
14062  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14063  * 
14064  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14065  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14066  * Similar to an autorepeat key delay.
14067  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14068  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14069  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14070  *           "interval" and "delay" are ignored. "immediate" is honored.
14071  * @cfg {Boolean} preventDefault True to prevent the default click event
14072  * @cfg {Boolean} stopDefault True to stop the default click event
14073  * 
14074  * @history
14075  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14076  *     2007-02-02 jvs Renamed to ClickRepeater
14077  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14078  *
14079  *  @constructor
14080  * @param {String/HTMLElement/Element} el The element to listen on
14081  * @param {Object} config
14082  **/
14083 Roo.util.ClickRepeater = function(el, config)
14084 {
14085     this.el = Roo.get(el);
14086     this.el.unselectable();
14087
14088     Roo.apply(this, config);
14089
14090     this.addEvents({
14091     /**
14092      * @event mousedown
14093      * Fires when the mouse button is depressed.
14094      * @param {Roo.util.ClickRepeater} this
14095      */
14096         "mousedown" : true,
14097     /**
14098      * @event click
14099      * Fires on a specified interval during the time the element is pressed.
14100      * @param {Roo.util.ClickRepeater} this
14101      */
14102         "click" : true,
14103     /**
14104      * @event mouseup
14105      * Fires when the mouse key is released.
14106      * @param {Roo.util.ClickRepeater} this
14107      */
14108         "mouseup" : true
14109     });
14110
14111     this.el.on("mousedown", this.handleMouseDown, this);
14112     if(this.preventDefault || this.stopDefault){
14113         this.el.on("click", function(e){
14114             if(this.preventDefault){
14115                 e.preventDefault();
14116             }
14117             if(this.stopDefault){
14118                 e.stopEvent();
14119             }
14120         }, this);
14121     }
14122
14123     // allow inline handler
14124     if(this.handler){
14125         this.on("click", this.handler,  this.scope || this);
14126     }
14127
14128     Roo.util.ClickRepeater.superclass.constructor.call(this);
14129 };
14130
14131 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14132     interval : 20,
14133     delay: 250,
14134     preventDefault : true,
14135     stopDefault : false,
14136     timer : 0,
14137
14138     // private
14139     handleMouseDown : function(){
14140         clearTimeout(this.timer);
14141         this.el.blur();
14142         if(this.pressClass){
14143             this.el.addClass(this.pressClass);
14144         }
14145         this.mousedownTime = new Date();
14146
14147         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14148         this.el.on("mouseout", this.handleMouseOut, this);
14149
14150         this.fireEvent("mousedown", this);
14151         this.fireEvent("click", this);
14152         
14153         this.timer = this.click.defer(this.delay || this.interval, this);
14154     },
14155
14156     // private
14157     click : function(){
14158         this.fireEvent("click", this);
14159         this.timer = this.click.defer(this.getInterval(), this);
14160     },
14161
14162     // private
14163     getInterval: function(){
14164         if(!this.accelerate){
14165             return this.interval;
14166         }
14167         var pressTime = this.mousedownTime.getElapsed();
14168         if(pressTime < 500){
14169             return 400;
14170         }else if(pressTime < 1700){
14171             return 320;
14172         }else if(pressTime < 2600){
14173             return 250;
14174         }else if(pressTime < 3500){
14175             return 180;
14176         }else if(pressTime < 4400){
14177             return 140;
14178         }else if(pressTime < 5300){
14179             return 80;
14180         }else if(pressTime < 6200){
14181             return 50;
14182         }else{
14183             return 10;
14184         }
14185     },
14186
14187     // private
14188     handleMouseOut : function(){
14189         clearTimeout(this.timer);
14190         if(this.pressClass){
14191             this.el.removeClass(this.pressClass);
14192         }
14193         this.el.on("mouseover", this.handleMouseReturn, this);
14194     },
14195
14196     // private
14197     handleMouseReturn : function(){
14198         this.el.un("mouseover", this.handleMouseReturn);
14199         if(this.pressClass){
14200             this.el.addClass(this.pressClass);
14201         }
14202         this.click();
14203     },
14204
14205     // private
14206     handleMouseUp : function(){
14207         clearTimeout(this.timer);
14208         this.el.un("mouseover", this.handleMouseReturn);
14209         this.el.un("mouseout", this.handleMouseOut);
14210         Roo.get(document).un("mouseup", this.handleMouseUp);
14211         this.el.removeClass(this.pressClass);
14212         this.fireEvent("mouseup", this);
14213     }
14214 });/*
14215  * Based on:
14216  * Ext JS Library 1.1.1
14217  * Copyright(c) 2006-2007, Ext JS, LLC.
14218  *
14219  * Originally Released Under LGPL - original licence link has changed is not relivant.
14220  *
14221  * Fork - LGPL
14222  * <script type="text/javascript">
14223  */
14224
14225  
14226 /**
14227  * @class Roo.KeyNav
14228  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14229  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14230  * way to implement custom navigation schemes for any UI component.</p>
14231  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14232  * pageUp, pageDown, del, home, end.  Usage:</p>
14233  <pre><code>
14234 var nav = new Roo.KeyNav("my-element", {
14235     "left" : function(e){
14236         this.moveLeft(e.ctrlKey);
14237     },
14238     "right" : function(e){
14239         this.moveRight(e.ctrlKey);
14240     },
14241     "enter" : function(e){
14242         this.save();
14243     },
14244     scope : this
14245 });
14246 </code></pre>
14247  * @constructor
14248  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14249  * @param {Object} config The config
14250  */
14251 Roo.KeyNav = function(el, config){
14252     this.el = Roo.get(el);
14253     Roo.apply(this, config);
14254     if(!this.disabled){
14255         this.disabled = true;
14256         this.enable();
14257     }
14258 };
14259
14260 Roo.KeyNav.prototype = {
14261     /**
14262      * @cfg {Boolean} disabled
14263      * True to disable this KeyNav instance (defaults to false)
14264      */
14265     disabled : false,
14266     /**
14267      * @cfg {String} defaultEventAction
14268      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14269      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14270      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14271      */
14272     defaultEventAction: "stopEvent",
14273     /**
14274      * @cfg {Boolean} forceKeyDown
14275      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14276      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14277      * handle keydown instead of keypress.
14278      */
14279     forceKeyDown : false,
14280
14281     // private
14282     prepareEvent : function(e){
14283         var k = e.getKey();
14284         var h = this.keyToHandler[k];
14285         //if(h && this[h]){
14286         //    e.stopPropagation();
14287         //}
14288         if(Roo.isSafari && h && k >= 37 && k <= 40){
14289             e.stopEvent();
14290         }
14291     },
14292
14293     // private
14294     relay : function(e){
14295         var k = e.getKey();
14296         var h = this.keyToHandler[k];
14297         if(h && this[h]){
14298             if(this.doRelay(e, this[h], h) !== true){
14299                 e[this.defaultEventAction]();
14300             }
14301         }
14302     },
14303
14304     // private
14305     doRelay : function(e, h, hname){
14306         return h.call(this.scope || this, e);
14307     },
14308
14309     // possible handlers
14310     enter : false,
14311     left : false,
14312     right : false,
14313     up : false,
14314     down : false,
14315     tab : false,
14316     esc : false,
14317     pageUp : false,
14318     pageDown : false,
14319     del : false,
14320     home : false,
14321     end : false,
14322
14323     // quick lookup hash
14324     keyToHandler : {
14325         37 : "left",
14326         39 : "right",
14327         38 : "up",
14328         40 : "down",
14329         33 : "pageUp",
14330         34 : "pageDown",
14331         46 : "del",
14332         36 : "home",
14333         35 : "end",
14334         13 : "enter",
14335         27 : "esc",
14336         9  : "tab"
14337     },
14338
14339         /**
14340          * Enable this KeyNav
14341          */
14342         enable: function(){
14343                 if(this.disabled){
14344             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14345             // the EventObject will normalize Safari automatically
14346             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14347                 this.el.on("keydown", this.relay,  this);
14348             }else{
14349                 this.el.on("keydown", this.prepareEvent,  this);
14350                 this.el.on("keypress", this.relay,  this);
14351             }
14352                     this.disabled = false;
14353                 }
14354         },
14355
14356         /**
14357          * Disable this KeyNav
14358          */
14359         disable: function(){
14360                 if(!this.disabled){
14361                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14362                 this.el.un("keydown", this.relay);
14363             }else{
14364                 this.el.un("keydown", this.prepareEvent);
14365                 this.el.un("keypress", this.relay);
14366             }
14367                     this.disabled = true;
14368                 }
14369         }
14370 };/*
14371  * Based on:
14372  * Ext JS Library 1.1.1
14373  * Copyright(c) 2006-2007, Ext JS, LLC.
14374  *
14375  * Originally Released Under LGPL - original licence link has changed is not relivant.
14376  *
14377  * Fork - LGPL
14378  * <script type="text/javascript">
14379  */
14380
14381  
14382 /**
14383  * @class Roo.KeyMap
14384  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14385  * The constructor accepts the same config object as defined by {@link #addBinding}.
14386  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14387  * combination it will call the function with this signature (if the match is a multi-key
14388  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14389  * A KeyMap can also handle a string representation of keys.<br />
14390  * Usage:
14391  <pre><code>
14392 // map one key by key code
14393 var map = new Roo.KeyMap("my-element", {
14394     key: 13, // or Roo.EventObject.ENTER
14395     fn: myHandler,
14396     scope: myObject
14397 });
14398
14399 // map multiple keys to one action by string
14400 var map = new Roo.KeyMap("my-element", {
14401     key: "a\r\n\t",
14402     fn: myHandler,
14403     scope: myObject
14404 });
14405
14406 // map multiple keys to multiple actions by strings and array of codes
14407 var map = new Roo.KeyMap("my-element", [
14408     {
14409         key: [10,13],
14410         fn: function(){ alert("Return was pressed"); }
14411     }, {
14412         key: "abc",
14413         fn: function(){ alert('a, b or c was pressed'); }
14414     }, {
14415         key: "\t",
14416         ctrl:true,
14417         shift:true,
14418         fn: function(){ alert('Control + shift + tab was pressed.'); }
14419     }
14420 ]);
14421 </code></pre>
14422  * <b>Note: A KeyMap starts enabled</b>
14423  * @constructor
14424  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14425  * @param {Object} config The config (see {@link #addBinding})
14426  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14427  */
14428 Roo.KeyMap = function(el, config, eventName){
14429     this.el  = Roo.get(el);
14430     this.eventName = eventName || "keydown";
14431     this.bindings = [];
14432     if(config){
14433         this.addBinding(config);
14434     }
14435     this.enable();
14436 };
14437
14438 Roo.KeyMap.prototype = {
14439     /**
14440      * True to stop the event from bubbling and prevent the default browser action if the
14441      * key was handled by the KeyMap (defaults to false)
14442      * @type Boolean
14443      */
14444     stopEvent : false,
14445
14446     /**
14447      * Add a new binding to this KeyMap. The following config object properties are supported:
14448      * <pre>
14449 Property    Type             Description
14450 ----------  ---------------  ----------------------------------------------------------------------
14451 key         String/Array     A single keycode or an array of keycodes to handle
14452 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14453 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14454 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14455 fn          Function         The function to call when KeyMap finds the expected key combination
14456 scope       Object           The scope of the callback function
14457 </pre>
14458      *
14459      * Usage:
14460      * <pre><code>
14461 // Create a KeyMap
14462 var map = new Roo.KeyMap(document, {
14463     key: Roo.EventObject.ENTER,
14464     fn: handleKey,
14465     scope: this
14466 });
14467
14468 //Add a new binding to the existing KeyMap later
14469 map.addBinding({
14470     key: 'abc',
14471     shift: true,
14472     fn: handleKey,
14473     scope: this
14474 });
14475 </code></pre>
14476      * @param {Object/Array} config A single KeyMap config or an array of configs
14477      */
14478         addBinding : function(config){
14479         if(config instanceof Array){
14480             for(var i = 0, len = config.length; i < len; i++){
14481                 this.addBinding(config[i]);
14482             }
14483             return;
14484         }
14485         var keyCode = config.key,
14486             shift = config.shift, 
14487             ctrl = config.ctrl, 
14488             alt = config.alt,
14489             fn = config.fn,
14490             scope = config.scope;
14491         if(typeof keyCode == "string"){
14492             var ks = [];
14493             var keyString = keyCode.toUpperCase();
14494             for(var j = 0, len = keyString.length; j < len; j++){
14495                 ks.push(keyString.charCodeAt(j));
14496             }
14497             keyCode = ks;
14498         }
14499         var keyArray = keyCode instanceof Array;
14500         var handler = function(e){
14501             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14502                 var k = e.getKey();
14503                 if(keyArray){
14504                     for(var i = 0, len = keyCode.length; i < len; i++){
14505                         if(keyCode[i] == k){
14506                           if(this.stopEvent){
14507                               e.stopEvent();
14508                           }
14509                           fn.call(scope || window, k, e);
14510                           return;
14511                         }
14512                     }
14513                 }else{
14514                     if(k == keyCode){
14515                         if(this.stopEvent){
14516                            e.stopEvent();
14517                         }
14518                         fn.call(scope || window, k, e);
14519                     }
14520                 }
14521             }
14522         };
14523         this.bindings.push(handler);  
14524         },
14525
14526     /**
14527      * Shorthand for adding a single key listener
14528      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14529      * following options:
14530      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14531      * @param {Function} fn The function to call
14532      * @param {Object} scope (optional) The scope of the function
14533      */
14534     on : function(key, fn, scope){
14535         var keyCode, shift, ctrl, alt;
14536         if(typeof key == "object" && !(key instanceof Array)){
14537             keyCode = key.key;
14538             shift = key.shift;
14539             ctrl = key.ctrl;
14540             alt = key.alt;
14541         }else{
14542             keyCode = key;
14543         }
14544         this.addBinding({
14545             key: keyCode,
14546             shift: shift,
14547             ctrl: ctrl,
14548             alt: alt,
14549             fn: fn,
14550             scope: scope
14551         })
14552     },
14553
14554     // private
14555     handleKeyDown : function(e){
14556             if(this.enabled){ //just in case
14557             var b = this.bindings;
14558             for(var i = 0, len = b.length; i < len; i++){
14559                 b[i].call(this, e);
14560             }
14561             }
14562         },
14563         
14564         /**
14565          * Returns true if this KeyMap is enabled
14566          * @return {Boolean} 
14567          */
14568         isEnabled : function(){
14569             return this.enabled;  
14570         },
14571         
14572         /**
14573          * Enables this KeyMap
14574          */
14575         enable: function(){
14576                 if(!this.enabled){
14577                     this.el.on(this.eventName, this.handleKeyDown, this);
14578                     this.enabled = true;
14579                 }
14580         },
14581
14582         /**
14583          * Disable this KeyMap
14584          */
14585         disable: function(){
14586                 if(this.enabled){
14587                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14588                     this.enabled = false;
14589                 }
14590         }
14591 };/*
14592  * Based on:
14593  * Ext JS Library 1.1.1
14594  * Copyright(c) 2006-2007, Ext JS, LLC.
14595  *
14596  * Originally Released Under LGPL - original licence link has changed is not relivant.
14597  *
14598  * Fork - LGPL
14599  * <script type="text/javascript">
14600  */
14601
14602  
14603 /**
14604  * @class Roo.util.TextMetrics
14605  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14606  * wide, in pixels, a given block of text will be.
14607  * @singleton
14608  */
14609 Roo.util.TextMetrics = function(){
14610     var shared;
14611     return {
14612         /**
14613          * Measures the size of the specified text
14614          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14615          * that can affect the size of the rendered text
14616          * @param {String} text The text to measure
14617          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14618          * in order to accurately measure the text height
14619          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14620          */
14621         measure : function(el, text, fixedWidth){
14622             if(!shared){
14623                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14624             }
14625             shared.bind(el);
14626             shared.setFixedWidth(fixedWidth || 'auto');
14627             return shared.getSize(text);
14628         },
14629
14630         /**
14631          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14632          * the overhead of multiple calls to initialize the style properties on each measurement.
14633          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14634          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14635          * in order to accurately measure the text height
14636          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14637          */
14638         createInstance : function(el, fixedWidth){
14639             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14640         }
14641     };
14642 }();
14643
14644  
14645
14646 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14647     var ml = new Roo.Element(document.createElement('div'));
14648     document.body.appendChild(ml.dom);
14649     ml.position('absolute');
14650     ml.setLeftTop(-1000, -1000);
14651     ml.hide();
14652
14653     if(fixedWidth){
14654         ml.setWidth(fixedWidth);
14655     }
14656      
14657     var instance = {
14658         /**
14659          * Returns the size of the specified text based on the internal element's style and width properties
14660          * @memberOf Roo.util.TextMetrics.Instance#
14661          * @param {String} text The text to measure
14662          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14663          */
14664         getSize : function(text){
14665             ml.update(text);
14666             var s = ml.getSize();
14667             ml.update('');
14668             return s;
14669         },
14670
14671         /**
14672          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14673          * that can affect the size of the rendered text
14674          * @memberOf Roo.util.TextMetrics.Instance#
14675          * @param {String/HTMLElement} el The element, dom node or id
14676          */
14677         bind : function(el){
14678             ml.setStyle(
14679                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14680             );
14681         },
14682
14683         /**
14684          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14685          * to set a fixed width in order to accurately measure the text height.
14686          * @memberOf Roo.util.TextMetrics.Instance#
14687          * @param {Number} width The width to set on the element
14688          */
14689         setFixedWidth : function(width){
14690             ml.setWidth(width);
14691         },
14692
14693         /**
14694          * Returns the measured width of the specified text
14695          * @memberOf Roo.util.TextMetrics.Instance#
14696          * @param {String} text The text to measure
14697          * @return {Number} width The width in pixels
14698          */
14699         getWidth : function(text){
14700             ml.dom.style.width = 'auto';
14701             return this.getSize(text).width;
14702         },
14703
14704         /**
14705          * Returns the measured height of the specified text.  For multiline text, be sure to call
14706          * {@link #setFixedWidth} if necessary.
14707          * @memberOf Roo.util.TextMetrics.Instance#
14708          * @param {String} text The text to measure
14709          * @return {Number} height The height in pixels
14710          */
14711         getHeight : function(text){
14712             return this.getSize(text).height;
14713         }
14714     };
14715
14716     instance.bind(bindTo);
14717
14718     return instance;
14719 };
14720
14721 // backwards compat
14722 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14723  * Based on:
14724  * Ext JS Library 1.1.1
14725  * Copyright(c) 2006-2007, Ext JS, LLC.
14726  *
14727  * Originally Released Under LGPL - original licence link has changed is not relivant.
14728  *
14729  * Fork - LGPL
14730  * <script type="text/javascript">
14731  */
14732
14733 /**
14734  * @class Roo.state.Provider
14735  * Abstract base class for state provider implementations. This class provides methods
14736  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14737  * Provider interface.
14738  */
14739 Roo.state.Provider = function(){
14740     /**
14741      * @event statechange
14742      * Fires when a state change occurs.
14743      * @param {Provider} this This state provider
14744      * @param {String} key The state key which was changed
14745      * @param {String} value The encoded value for the state
14746      */
14747     this.addEvents({
14748         "statechange": true
14749     });
14750     this.state = {};
14751     Roo.state.Provider.superclass.constructor.call(this);
14752 };
14753 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14754     /**
14755      * Returns the current value for a key
14756      * @param {String} name The key name
14757      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14758      * @return {Mixed} The state data
14759      */
14760     get : function(name, defaultValue){
14761         return typeof this.state[name] == "undefined" ?
14762             defaultValue : this.state[name];
14763     },
14764     
14765     /**
14766      * Clears a value from the state
14767      * @param {String} name The key name
14768      */
14769     clear : function(name){
14770         delete this.state[name];
14771         this.fireEvent("statechange", this, name, null);
14772     },
14773     
14774     /**
14775      * Sets the value for a key
14776      * @param {String} name The key name
14777      * @param {Mixed} value The value to set
14778      */
14779     set : function(name, value){
14780         this.state[name] = value;
14781         this.fireEvent("statechange", this, name, value);
14782     },
14783     
14784     /**
14785      * Decodes a string previously encoded with {@link #encodeValue}.
14786      * @param {String} value The value to decode
14787      * @return {Mixed} The decoded value
14788      */
14789     decodeValue : function(cookie){
14790         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14791         var matches = re.exec(unescape(cookie));
14792         if(!matches || !matches[1]) return; // non state cookie
14793         var type = matches[1];
14794         var v = matches[2];
14795         switch(type){
14796             case "n":
14797                 return parseFloat(v);
14798             case "d":
14799                 return new Date(Date.parse(v));
14800             case "b":
14801                 return (v == "1");
14802             case "a":
14803                 var all = [];
14804                 var values = v.split("^");
14805                 for(var i = 0, len = values.length; i < len; i++){
14806                     all.push(this.decodeValue(values[i]));
14807                 }
14808                 return all;
14809            case "o":
14810                 var all = {};
14811                 var values = v.split("^");
14812                 for(var i = 0, len = values.length; i < len; i++){
14813                     var kv = values[i].split("=");
14814                     all[kv[0]] = this.decodeValue(kv[1]);
14815                 }
14816                 return all;
14817            default:
14818                 return v;
14819         }
14820     },
14821     
14822     /**
14823      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14824      * @param {Mixed} value The value to encode
14825      * @return {String} The encoded value
14826      */
14827     encodeValue : function(v){
14828         var enc;
14829         if(typeof v == "number"){
14830             enc = "n:" + v;
14831         }else if(typeof v == "boolean"){
14832             enc = "b:" + (v ? "1" : "0");
14833         }else if(v instanceof Date){
14834             enc = "d:" + v.toGMTString();
14835         }else if(v instanceof Array){
14836             var flat = "";
14837             for(var i = 0, len = v.length; i < len; i++){
14838                 flat += this.encodeValue(v[i]);
14839                 if(i != len-1) flat += "^";
14840             }
14841             enc = "a:" + flat;
14842         }else if(typeof v == "object"){
14843             var flat = "";
14844             for(var key in v){
14845                 if(typeof v[key] != "function"){
14846                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14847                 }
14848             }
14849             enc = "o:" + flat.substring(0, flat.length-1);
14850         }else{
14851             enc = "s:" + v;
14852         }
14853         return escape(enc);        
14854     }
14855 });
14856
14857 /*
14858  * Based on:
14859  * Ext JS Library 1.1.1
14860  * Copyright(c) 2006-2007, Ext JS, LLC.
14861  *
14862  * Originally Released Under LGPL - original licence link has changed is not relivant.
14863  *
14864  * Fork - LGPL
14865  * <script type="text/javascript">
14866  */
14867 /**
14868  * @class Roo.state.Manager
14869  * This is the global state manager. By default all components that are "state aware" check this class
14870  * for state information if you don't pass them a custom state provider. In order for this class
14871  * to be useful, it must be initialized with a provider when your application initializes.
14872  <pre><code>
14873 // in your initialization function
14874 init : function(){
14875    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14876    ...
14877    // supposed you have a {@link Roo.BorderLayout}
14878    var layout = new Roo.BorderLayout(...);
14879    layout.restoreState();
14880    // or a {Roo.BasicDialog}
14881    var dialog = new Roo.BasicDialog(...);
14882    dialog.restoreState();
14883  </code></pre>
14884  * @singleton
14885  */
14886 Roo.state.Manager = function(){
14887     var provider = new Roo.state.Provider();
14888     
14889     return {
14890         /**
14891          * Configures the default state provider for your application
14892          * @param {Provider} stateProvider The state provider to set
14893          */
14894         setProvider : function(stateProvider){
14895             provider = stateProvider;
14896         },
14897         
14898         /**
14899          * Returns the current value for a key
14900          * @param {String} name The key name
14901          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14902          * @return {Mixed} The state data
14903          */
14904         get : function(key, defaultValue){
14905             return provider.get(key, defaultValue);
14906         },
14907         
14908         /**
14909          * Sets the value for a key
14910          * @param {String} name The key name
14911          * @param {Mixed} value The state data
14912          */
14913          set : function(key, value){
14914             provider.set(key, value);
14915         },
14916         
14917         /**
14918          * Clears a value from the state
14919          * @param {String} name The key name
14920          */
14921         clear : function(key){
14922             provider.clear(key);
14923         },
14924         
14925         /**
14926          * Gets the currently configured state provider
14927          * @return {Provider} The state provider
14928          */
14929         getProvider : function(){
14930             return provider;
14931         }
14932     };
14933 }();
14934 /*
14935  * Based on:
14936  * Ext JS Library 1.1.1
14937  * Copyright(c) 2006-2007, Ext JS, LLC.
14938  *
14939  * Originally Released Under LGPL - original licence link has changed is not relivant.
14940  *
14941  * Fork - LGPL
14942  * <script type="text/javascript">
14943  */
14944 /**
14945  * @class Roo.state.CookieProvider
14946  * @extends Roo.state.Provider
14947  * The default Provider implementation which saves state via cookies.
14948  * <br />Usage:
14949  <pre><code>
14950    var cp = new Roo.state.CookieProvider({
14951        path: "/cgi-bin/",
14952        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14953        domain: "roojs.com"
14954    })
14955    Roo.state.Manager.setProvider(cp);
14956  </code></pre>
14957  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14958  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14959  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14960  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14961  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14962  * domain the page is running on including the 'www' like 'www.roojs.com')
14963  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14964  * @constructor
14965  * Create a new CookieProvider
14966  * @param {Object} config The configuration object
14967  */
14968 Roo.state.CookieProvider = function(config){
14969     Roo.state.CookieProvider.superclass.constructor.call(this);
14970     this.path = "/";
14971     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14972     this.domain = null;
14973     this.secure = false;
14974     Roo.apply(this, config);
14975     this.state = this.readCookies();
14976 };
14977
14978 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14979     // private
14980     set : function(name, value){
14981         if(typeof value == "undefined" || value === null){
14982             this.clear(name);
14983             return;
14984         }
14985         this.setCookie(name, value);
14986         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14987     },
14988
14989     // private
14990     clear : function(name){
14991         this.clearCookie(name);
14992         Roo.state.CookieProvider.superclass.clear.call(this, name);
14993     },
14994
14995     // private
14996     readCookies : function(){
14997         var cookies = {};
14998         var c = document.cookie + ";";
14999         var re = /\s?(.*?)=(.*?);/g;
15000         var matches;
15001         while((matches = re.exec(c)) != null){
15002             var name = matches[1];
15003             var value = matches[2];
15004             if(name && name.substring(0,3) == "ys-"){
15005                 cookies[name.substr(3)] = this.decodeValue(value);
15006             }
15007         }
15008         return cookies;
15009     },
15010
15011     // private
15012     setCookie : function(name, value){
15013         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15014            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15015            ((this.path == null) ? "" : ("; path=" + this.path)) +
15016            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15017            ((this.secure == true) ? "; secure" : "");
15018     },
15019
15020     // private
15021     clearCookie : function(name){
15022         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15023            ((this.path == null) ? "" : ("; path=" + this.path)) +
15024            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15025            ((this.secure == true) ? "; secure" : "");
15026     }
15027 });/*
15028  * Based on:
15029  * Ext JS Library 1.1.1
15030  * Copyright(c) 2006-2007, Ext JS, LLC.
15031  *
15032  * Originally Released Under LGPL - original licence link has changed is not relivant.
15033  *
15034  * Fork - LGPL
15035  * <script type="text/javascript">
15036  */
15037  
15038
15039 /**
15040  * @class Roo.ComponentMgr
15041  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15042  * @singleton
15043  */
15044 Roo.ComponentMgr = function(){
15045     var all = new Roo.util.MixedCollection();
15046
15047     return {
15048         /**
15049          * Registers a component.
15050          * @param {Roo.Component} c The component
15051          */
15052         register : function(c){
15053             all.add(c);
15054         },
15055
15056         /**
15057          * Unregisters a component.
15058          * @param {Roo.Component} c The component
15059          */
15060         unregister : function(c){
15061             all.remove(c);
15062         },
15063
15064         /**
15065          * Returns a component by id
15066          * @param {String} id The component id
15067          */
15068         get : function(id){
15069             return all.get(id);
15070         },
15071
15072         /**
15073          * Registers a function that will be called when a specified component is added to ComponentMgr
15074          * @param {String} id The component id
15075          * @param {Funtction} fn The callback function
15076          * @param {Object} scope The scope of the callback
15077          */
15078         onAvailable : function(id, fn, scope){
15079             all.on("add", function(index, o){
15080                 if(o.id == id){
15081                     fn.call(scope || o, o);
15082                     all.un("add", fn, scope);
15083                 }
15084             });
15085         }
15086     };
15087 }();/*
15088  * Based on:
15089  * Ext JS Library 1.1.1
15090  * Copyright(c) 2006-2007, Ext JS, LLC.
15091  *
15092  * Originally Released Under LGPL - original licence link has changed is not relivant.
15093  *
15094  * Fork - LGPL
15095  * <script type="text/javascript">
15096  */
15097  
15098 /**
15099  * @class Roo.Component
15100  * @extends Roo.util.Observable
15101  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15102  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15103  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15104  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15105  * All visual components (widgets) that require rendering into a layout should subclass Component.
15106  * @constructor
15107  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15108  * 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
15109  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15110  */
15111 Roo.Component = function(config){
15112     config = config || {};
15113     if(config.tagName || config.dom || typeof config == "string"){ // element object
15114         config = {el: config, id: config.id || config};
15115     }
15116     this.initialConfig = config;
15117
15118     Roo.apply(this, config);
15119     this.addEvents({
15120         /**
15121          * @event disable
15122          * Fires after the component is disabled.
15123              * @param {Roo.Component} this
15124              */
15125         disable : true,
15126         /**
15127          * @event enable
15128          * Fires after the component is enabled.
15129              * @param {Roo.Component} this
15130              */
15131         enable : true,
15132         /**
15133          * @event beforeshow
15134          * Fires before the component is shown.  Return false to stop the show.
15135              * @param {Roo.Component} this
15136              */
15137         beforeshow : true,
15138         /**
15139          * @event show
15140          * Fires after the component is shown.
15141              * @param {Roo.Component} this
15142              */
15143         show : true,
15144         /**
15145          * @event beforehide
15146          * Fires before the component is hidden. Return false to stop the hide.
15147              * @param {Roo.Component} this
15148              */
15149         beforehide : true,
15150         /**
15151          * @event hide
15152          * Fires after the component is hidden.
15153              * @param {Roo.Component} this
15154              */
15155         hide : true,
15156         /**
15157          * @event beforerender
15158          * Fires before the component is rendered. Return false to stop the render.
15159              * @param {Roo.Component} this
15160              */
15161         beforerender : true,
15162         /**
15163          * @event render
15164          * Fires after the component is rendered.
15165              * @param {Roo.Component} this
15166              */
15167         render : true,
15168         /**
15169          * @event beforedestroy
15170          * Fires before the component is destroyed. Return false to stop the destroy.
15171              * @param {Roo.Component} this
15172              */
15173         beforedestroy : true,
15174         /**
15175          * @event destroy
15176          * Fires after the component is destroyed.
15177              * @param {Roo.Component} this
15178              */
15179         destroy : true
15180     });
15181     if(!this.id){
15182         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15183     }
15184     Roo.ComponentMgr.register(this);
15185     Roo.Component.superclass.constructor.call(this);
15186     this.initComponent();
15187     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15188         this.render(this.renderTo);
15189         delete this.renderTo;
15190     }
15191 };
15192
15193 /** @private */
15194 Roo.Component.AUTO_ID = 1000;
15195
15196 Roo.extend(Roo.Component, Roo.util.Observable, {
15197     /**
15198      * @scope Roo.Component.prototype
15199      * @type {Boolean}
15200      * true if this component is hidden. Read-only.
15201      */
15202     hidden : false,
15203     /**
15204      * @type {Boolean}
15205      * true if this component is disabled. Read-only.
15206      */
15207     disabled : false,
15208     /**
15209      * @type {Boolean}
15210      * true if this component has been rendered. Read-only.
15211      */
15212     rendered : false,
15213     
15214     /** @cfg {String} disableClass
15215      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15216      */
15217     disabledClass : "x-item-disabled",
15218         /** @cfg {Boolean} allowDomMove
15219          * Whether the component can move the Dom node when rendering (defaults to true).
15220          */
15221     allowDomMove : true,
15222     /** @cfg {String} hideMode (display|visibility)
15223      * How this component should hidden. Supported values are
15224      * "visibility" (css visibility), "offsets" (negative offset position) and
15225      * "display" (css display) - defaults to "display".
15226      */
15227     hideMode: 'display',
15228
15229     /** @private */
15230     ctype : "Roo.Component",
15231
15232     /**
15233      * @cfg {String} actionMode 
15234      * which property holds the element that used for  hide() / show() / disable() / enable()
15235      * default is 'el' 
15236      */
15237     actionMode : "el",
15238
15239     /** @private */
15240     getActionEl : function(){
15241         return this[this.actionMode];
15242     },
15243
15244     initComponent : Roo.emptyFn,
15245     /**
15246      * If this is a lazy rendering component, render it to its container element.
15247      * @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.
15248      */
15249     render : function(container, position){
15250         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15251             if(!container && this.el){
15252                 this.el = Roo.get(this.el);
15253                 container = this.el.dom.parentNode;
15254                 this.allowDomMove = false;
15255             }
15256             this.container = Roo.get(container);
15257             this.rendered = true;
15258             if(position !== undefined){
15259                 if(typeof position == 'number'){
15260                     position = this.container.dom.childNodes[position];
15261                 }else{
15262                     position = Roo.getDom(position);
15263                 }
15264             }
15265             this.onRender(this.container, position || null);
15266             if(this.cls){
15267                 this.el.addClass(this.cls);
15268                 delete this.cls;
15269             }
15270             if(this.style){
15271                 this.el.applyStyles(this.style);
15272                 delete this.style;
15273             }
15274             this.fireEvent("render", this);
15275             this.afterRender(this.container);
15276             if(this.hidden){
15277                 this.hide();
15278             }
15279             if(this.disabled){
15280                 this.disable();
15281             }
15282         }
15283         return this;
15284     },
15285
15286     /** @private */
15287     // default function is not really useful
15288     onRender : function(ct, position){
15289         if(this.el){
15290             this.el = Roo.get(this.el);
15291             if(this.allowDomMove !== false){
15292                 ct.dom.insertBefore(this.el.dom, position);
15293             }
15294         }
15295     },
15296
15297     /** @private */
15298     getAutoCreate : function(){
15299         var cfg = typeof this.autoCreate == "object" ?
15300                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15301         if(this.id && !cfg.id){
15302             cfg.id = this.id;
15303         }
15304         return cfg;
15305     },
15306
15307     /** @private */
15308     afterRender : Roo.emptyFn,
15309
15310     /**
15311      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15312      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15313      */
15314     destroy : function(){
15315         if(this.fireEvent("beforedestroy", this) !== false){
15316             this.purgeListeners();
15317             this.beforeDestroy();
15318             if(this.rendered){
15319                 this.el.removeAllListeners();
15320                 this.el.remove();
15321                 if(this.actionMode == "container"){
15322                     this.container.remove();
15323                 }
15324             }
15325             this.onDestroy();
15326             Roo.ComponentMgr.unregister(this);
15327             this.fireEvent("destroy", this);
15328         }
15329     },
15330
15331         /** @private */
15332     beforeDestroy : function(){
15333
15334     },
15335
15336         /** @private */
15337         onDestroy : function(){
15338
15339     },
15340
15341     /**
15342      * Returns the underlying {@link Roo.Element}.
15343      * @return {Roo.Element} The element
15344      */
15345     getEl : function(){
15346         return this.el;
15347     },
15348
15349     /**
15350      * Returns the id of this component.
15351      * @return {String}
15352      */
15353     getId : function(){
15354         return this.id;
15355     },
15356
15357     /**
15358      * Try to focus this component.
15359      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15360      * @return {Roo.Component} this
15361      */
15362     focus : function(selectText){
15363         if(this.rendered){
15364             this.el.focus();
15365             if(selectText === true){
15366                 this.el.dom.select();
15367             }
15368         }
15369         return this;
15370     },
15371
15372     /** @private */
15373     blur : function(){
15374         if(this.rendered){
15375             this.el.blur();
15376         }
15377         return this;
15378     },
15379
15380     /**
15381      * Disable this component.
15382      * @return {Roo.Component} this
15383      */
15384     disable : function(){
15385         if(this.rendered){
15386             this.onDisable();
15387         }
15388         this.disabled = true;
15389         this.fireEvent("disable", this);
15390         return this;
15391     },
15392
15393         // private
15394     onDisable : function(){
15395         this.getActionEl().addClass(this.disabledClass);
15396         this.el.dom.disabled = true;
15397     },
15398
15399     /**
15400      * Enable this component.
15401      * @return {Roo.Component} this
15402      */
15403     enable : function(){
15404         if(this.rendered){
15405             this.onEnable();
15406         }
15407         this.disabled = false;
15408         this.fireEvent("enable", this);
15409         return this;
15410     },
15411
15412         // private
15413     onEnable : function(){
15414         this.getActionEl().removeClass(this.disabledClass);
15415         this.el.dom.disabled = false;
15416     },
15417
15418     /**
15419      * Convenience function for setting disabled/enabled by boolean.
15420      * @param {Boolean} disabled
15421      */
15422     setDisabled : function(disabled){
15423         this[disabled ? "disable" : "enable"]();
15424     },
15425
15426     /**
15427      * Show this component.
15428      * @return {Roo.Component} this
15429      */
15430     show: function(){
15431         if(this.fireEvent("beforeshow", this) !== false){
15432             this.hidden = false;
15433             if(this.rendered){
15434                 this.onShow();
15435             }
15436             this.fireEvent("show", this);
15437         }
15438         return this;
15439     },
15440
15441     // private
15442     onShow : function(){
15443         var ae = this.getActionEl();
15444         if(this.hideMode == 'visibility'){
15445             ae.dom.style.visibility = "visible";
15446         }else if(this.hideMode == 'offsets'){
15447             ae.removeClass('x-hidden');
15448         }else{
15449             ae.dom.style.display = "";
15450         }
15451     },
15452
15453     /**
15454      * Hide this component.
15455      * @return {Roo.Component} this
15456      */
15457     hide: function(){
15458         if(this.fireEvent("beforehide", this) !== false){
15459             this.hidden = true;
15460             if(this.rendered){
15461                 this.onHide();
15462             }
15463             this.fireEvent("hide", this);
15464         }
15465         return this;
15466     },
15467
15468     // private
15469     onHide : function(){
15470         var ae = this.getActionEl();
15471         if(this.hideMode == 'visibility'){
15472             ae.dom.style.visibility = "hidden";
15473         }else if(this.hideMode == 'offsets'){
15474             ae.addClass('x-hidden');
15475         }else{
15476             ae.dom.style.display = "none";
15477         }
15478     },
15479
15480     /**
15481      * Convenience function to hide or show this component by boolean.
15482      * @param {Boolean} visible True to show, false to hide
15483      * @return {Roo.Component} this
15484      */
15485     setVisible: function(visible){
15486         if(visible) {
15487             this.show();
15488         }else{
15489             this.hide();
15490         }
15491         return this;
15492     },
15493
15494     /**
15495      * Returns true if this component is visible.
15496      */
15497     isVisible : function(){
15498         return this.getActionEl().isVisible();
15499     },
15500
15501     cloneConfig : function(overrides){
15502         overrides = overrides || {};
15503         var id = overrides.id || Roo.id();
15504         var cfg = Roo.applyIf(overrides, this.initialConfig);
15505         cfg.id = id; // prevent dup id
15506         return new this.constructor(cfg);
15507     }
15508 });/*
15509  * Based on:
15510  * Ext JS Library 1.1.1
15511  * Copyright(c) 2006-2007, Ext JS, LLC.
15512  *
15513  * Originally Released Under LGPL - original licence link has changed is not relivant.
15514  *
15515  * Fork - LGPL
15516  * <script type="text/javascript">
15517  */
15518
15519 /**
15520  * @class Roo.BoxComponent
15521  * @extends Roo.Component
15522  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15523  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15524  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15525  * layout containers.
15526  * @constructor
15527  * @param {Roo.Element/String/Object} config The configuration options.
15528  */
15529 Roo.BoxComponent = function(config){
15530     Roo.Component.call(this, config);
15531     this.addEvents({
15532         /**
15533          * @event resize
15534          * Fires after the component is resized.
15535              * @param {Roo.Component} this
15536              * @param {Number} adjWidth The box-adjusted width that was set
15537              * @param {Number} adjHeight The box-adjusted height that was set
15538              * @param {Number} rawWidth The width that was originally specified
15539              * @param {Number} rawHeight The height that was originally specified
15540              */
15541         resize : true,
15542         /**
15543          * @event move
15544          * Fires after the component is moved.
15545              * @param {Roo.Component} this
15546              * @param {Number} x The new x position
15547              * @param {Number} y The new y position
15548              */
15549         move : true
15550     });
15551 };
15552
15553 Roo.extend(Roo.BoxComponent, Roo.Component, {
15554     // private, set in afterRender to signify that the component has been rendered
15555     boxReady : false,
15556     // private, used to defer height settings to subclasses
15557     deferHeight: false,
15558     /** @cfg {Number} width
15559      * width (optional) size of component
15560      */
15561      /** @cfg {Number} height
15562      * height (optional) size of component
15563      */
15564      
15565     /**
15566      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15567      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15568      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15569      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15570      * @return {Roo.BoxComponent} this
15571      */
15572     setSize : function(w, h){
15573         // support for standard size objects
15574         if(typeof w == 'object'){
15575             h = w.height;
15576             w = w.width;
15577         }
15578         // not rendered
15579         if(!this.boxReady){
15580             this.width = w;
15581             this.height = h;
15582             return this;
15583         }
15584
15585         // prevent recalcs when not needed
15586         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15587             return this;
15588         }
15589         this.lastSize = {width: w, height: h};
15590
15591         var adj = this.adjustSize(w, h);
15592         var aw = adj.width, ah = adj.height;
15593         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15594             var rz = this.getResizeEl();
15595             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15596                 rz.setSize(aw, ah);
15597             }else if(!this.deferHeight && ah !== undefined){
15598                 rz.setHeight(ah);
15599             }else if(aw !== undefined){
15600                 rz.setWidth(aw);
15601             }
15602             this.onResize(aw, ah, w, h);
15603             this.fireEvent('resize', this, aw, ah, w, h);
15604         }
15605         return this;
15606     },
15607
15608     /**
15609      * Gets the current size of the component's underlying element.
15610      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15611      */
15612     getSize : function(){
15613         return this.el.getSize();
15614     },
15615
15616     /**
15617      * Gets the current XY position of the component's underlying element.
15618      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15619      * @return {Array} The XY position of the element (e.g., [100, 200])
15620      */
15621     getPosition : function(local){
15622         if(local === true){
15623             return [this.el.getLeft(true), this.el.getTop(true)];
15624         }
15625         return this.xy || this.el.getXY();
15626     },
15627
15628     /**
15629      * Gets the current box measurements of the component's underlying element.
15630      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15631      * @returns {Object} box An object in the format {x, y, width, height}
15632      */
15633     getBox : function(local){
15634         var s = this.el.getSize();
15635         if(local){
15636             s.x = this.el.getLeft(true);
15637             s.y = this.el.getTop(true);
15638         }else{
15639             var xy = this.xy || this.el.getXY();
15640             s.x = xy[0];
15641             s.y = xy[1];
15642         }
15643         return s;
15644     },
15645
15646     /**
15647      * Sets the current box measurements of the component's underlying element.
15648      * @param {Object} box An object in the format {x, y, width, height}
15649      * @returns {Roo.BoxComponent} this
15650      */
15651     updateBox : function(box){
15652         this.setSize(box.width, box.height);
15653         this.setPagePosition(box.x, box.y);
15654         return this;
15655     },
15656
15657     // protected
15658     getResizeEl : function(){
15659         return this.resizeEl || this.el;
15660     },
15661
15662     // protected
15663     getPositionEl : function(){
15664         return this.positionEl || this.el;
15665     },
15666
15667     /**
15668      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15669      * This method fires the move event.
15670      * @param {Number} left The new left
15671      * @param {Number} top The new top
15672      * @returns {Roo.BoxComponent} this
15673      */
15674     setPosition : function(x, y){
15675         this.x = x;
15676         this.y = y;
15677         if(!this.boxReady){
15678             return this;
15679         }
15680         var adj = this.adjustPosition(x, y);
15681         var ax = adj.x, ay = adj.y;
15682
15683         var el = this.getPositionEl();
15684         if(ax !== undefined || ay !== undefined){
15685             if(ax !== undefined && ay !== undefined){
15686                 el.setLeftTop(ax, ay);
15687             }else if(ax !== undefined){
15688                 el.setLeft(ax);
15689             }else if(ay !== undefined){
15690                 el.setTop(ay);
15691             }
15692             this.onPosition(ax, ay);
15693             this.fireEvent('move', this, ax, ay);
15694         }
15695         return this;
15696     },
15697
15698     /**
15699      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15700      * This method fires the move event.
15701      * @param {Number} x The new x position
15702      * @param {Number} y The new y position
15703      * @returns {Roo.BoxComponent} this
15704      */
15705     setPagePosition : function(x, y){
15706         this.pageX = x;
15707         this.pageY = y;
15708         if(!this.boxReady){
15709             return;
15710         }
15711         if(x === undefined || y === undefined){ // cannot translate undefined points
15712             return;
15713         }
15714         var p = this.el.translatePoints(x, y);
15715         this.setPosition(p.left, p.top);
15716         return this;
15717     },
15718
15719     // private
15720     onRender : function(ct, position){
15721         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15722         if(this.resizeEl){
15723             this.resizeEl = Roo.get(this.resizeEl);
15724         }
15725         if(this.positionEl){
15726             this.positionEl = Roo.get(this.positionEl);
15727         }
15728     },
15729
15730     // private
15731     afterRender : function(){
15732         Roo.BoxComponent.superclass.afterRender.call(this);
15733         this.boxReady = true;
15734         this.setSize(this.width, this.height);
15735         if(this.x || this.y){
15736             this.setPosition(this.x, this.y);
15737         }
15738         if(this.pageX || this.pageY){
15739             this.setPagePosition(this.pageX, this.pageY);
15740         }
15741     },
15742
15743     /**
15744      * Force the component's size to recalculate based on the underlying element's current height and width.
15745      * @returns {Roo.BoxComponent} this
15746      */
15747     syncSize : function(){
15748         delete this.lastSize;
15749         this.setSize(this.el.getWidth(), this.el.getHeight());
15750         return this;
15751     },
15752
15753     /**
15754      * Called after the component is resized, this method is empty by default but can be implemented by any
15755      * subclass that needs to perform custom logic after a resize occurs.
15756      * @param {Number} adjWidth The box-adjusted width that was set
15757      * @param {Number} adjHeight The box-adjusted height that was set
15758      * @param {Number} rawWidth The width that was originally specified
15759      * @param {Number} rawHeight The height that was originally specified
15760      */
15761     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15762
15763     },
15764
15765     /**
15766      * Called after the component is moved, this method is empty by default but can be implemented by any
15767      * subclass that needs to perform custom logic after a move occurs.
15768      * @param {Number} x The new x position
15769      * @param {Number} y The new y position
15770      */
15771     onPosition : function(x, y){
15772
15773     },
15774
15775     // private
15776     adjustSize : function(w, h){
15777         if(this.autoWidth){
15778             w = 'auto';
15779         }
15780         if(this.autoHeight){
15781             h = 'auto';
15782         }
15783         return {width : w, height: h};
15784     },
15785
15786     // private
15787     adjustPosition : function(x, y){
15788         return {x : x, y: y};
15789     }
15790 });/*
15791  * Original code for Roojs - LGPL
15792  * <script type="text/javascript">
15793  */
15794  
15795 /**
15796  * @class Roo.XComponent
15797  * A delayed Element creator...
15798  * Or a way to group chunks of interface together.
15799  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15800  *  used in conjunction with XComponent.build() it will create an instance of each element,
15801  *  then call addxtype() to build the User interface.
15802  * 
15803  * Mypart.xyx = new Roo.XComponent({
15804
15805     parent : 'Mypart.xyz', // empty == document.element.!!
15806     order : '001',
15807     name : 'xxxx'
15808     region : 'xxxx'
15809     disabled : function() {} 
15810      
15811     tree : function() { // return an tree of xtype declared components
15812         var MODULE = this;
15813         return 
15814         {
15815             xtype : 'NestedLayoutPanel',
15816             // technicall
15817         }
15818      ]
15819  *})
15820  *
15821  *
15822  * It can be used to build a big heiracy, with parent etc.
15823  * or you can just use this to render a single compoent to a dom element
15824  * MYPART.render(Roo.Element | String(id) | dom_element )
15825  *
15826  *
15827  * Usage patterns.
15828  *
15829  * Classic Roo
15830  *
15831  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15832  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15833  *
15834  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15835  *
15836  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15837  * - if mulitple topModules exist, the last one is defined as the top module.
15838  *
15839  * Embeded Roo
15840  * 
15841  * When the top level or multiple modules are to embedded into a existing HTML page,
15842  * the parent element can container '#id' of the element where the module will be drawn.
15843  *
15844  * Bootstrap Roo
15845  *
15846  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15847  * it relies more on a include mechanism, where sub modules are included into an outer page.
15848  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15849  * 
15850  * Bootstrap Roo Included elements
15851  *
15852  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15853  * hence confusing the component builder as it thinks there are multiple top level elements. 
15854  *
15855  * 
15856  * 
15857  * @extends Roo.util.Observable
15858  * @constructor
15859  * @param cfg {Object} configuration of component
15860  * 
15861  */
15862 Roo.XComponent = function(cfg) {
15863     Roo.apply(this, cfg);
15864     this.addEvents({ 
15865         /**
15866              * @event built
15867              * Fires when this the componnt is built
15868              * @param {Roo.XComponent} c the component
15869              */
15870         'built' : true
15871         
15872     });
15873     this.region = this.region || 'center'; // default..
15874     Roo.XComponent.register(this);
15875     this.modules = false;
15876     this.el = false; // where the layout goes..
15877     
15878     
15879 }
15880 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15881     /**
15882      * @property el
15883      * The created element (with Roo.factory())
15884      * @type {Roo.Layout}
15885      */
15886     el  : false,
15887     
15888     /**
15889      * @property el
15890      * for BC  - use el in new code
15891      * @type {Roo.Layout}
15892      */
15893     panel : false,
15894     
15895     /**
15896      * @property layout
15897      * for BC  - use el in new code
15898      * @type {Roo.Layout}
15899      */
15900     layout : false,
15901     
15902      /**
15903      * @cfg {Function|boolean} disabled
15904      * If this module is disabled by some rule, return true from the funtion
15905      */
15906     disabled : false,
15907     
15908     /**
15909      * @cfg {String} parent 
15910      * Name of parent element which it get xtype added to..
15911      */
15912     parent: false,
15913     
15914     /**
15915      * @cfg {String} order
15916      * Used to set the order in which elements are created (usefull for multiple tabs)
15917      */
15918     
15919     order : false,
15920     /**
15921      * @cfg {String} name
15922      * String to display while loading.
15923      */
15924     name : false,
15925     /**
15926      * @cfg {String} region
15927      * Region to render component to (defaults to center)
15928      */
15929     region : 'center',
15930     
15931     /**
15932      * @cfg {Array} items
15933      * A single item array - the first element is the root of the tree..
15934      * It's done this way to stay compatible with the Xtype system...
15935      */
15936     items : false,
15937     
15938     /**
15939      * @property _tree
15940      * The method that retuns the tree of parts that make up this compoennt 
15941      * @type {function}
15942      */
15943     _tree  : false,
15944     
15945      /**
15946      * render
15947      * render element to dom or tree
15948      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15949      */
15950     
15951     render : function(el)
15952     {
15953         
15954         el = el || false;
15955         var hp = this.parent ? 1 : 0;
15956         Roo.debug &&  Roo.log(this);
15957         
15958         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15959             // if parent is a '#.....' string, then let's use that..
15960             var ename = this.parent.substr(1);
15961             this.parent = false;
15962             Roo.debug && Roo.log(ename);
15963             switch (ename) {
15964                 case 'bootstrap-body' :
15965                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
15966                         this.parent = { el :  new  Roo.bootstrap.Body() };
15967                         Roo.debug && Roo.log("setting el to doc body");
15968                          
15969                     } else {
15970                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15971                     }
15972                     break;
15973                 case 'bootstrap':
15974                     this.parent = { el : true};
15975                     // fall through
15976                 default:
15977                     el = Roo.get(ename);
15978                     break;
15979             }
15980                 
15981             
15982             if (!el && !this.parent) {
15983                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15984                 return;
15985             }
15986         }
15987         Roo.debug && Roo.log("EL:");
15988         Roo.debug && Roo.log(el);
15989         Roo.debug && Roo.log("this.parent.el:");
15990         Roo.debug && Roo.log(this.parent.el);
15991         
15992         var tree = this._tree ? this._tree() : this.tree();
15993
15994         // altertive root elements ??? - we need a better way to indicate these.
15995         var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15996                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15997         
15998         if (!this.parent && is_alt) {
15999             //el = Roo.get(document.body);
16000             this.parent = { el : true };
16001         }
16002             
16003             
16004         
16005         if (!this.parent) {
16006             
16007             Roo.debug && Roo.log("no parent - creating one");
16008             
16009             el = el ? Roo.get(el) : false;      
16010             
16011             // it's a top level one..
16012             this.parent =  {
16013                 el : new Roo.BorderLayout(el || document.body, {
16014                 
16015                      center: {
16016                          titlebar: false,
16017                          autoScroll:false,
16018                          closeOnTab: true,
16019                          tabPosition: 'top',
16020                           //resizeTabs: true,
16021                          alwaysShowTabs: el && hp? false :  true,
16022                          hideTabs: el || !hp ? true :  false,
16023                          minTabWidth: 140
16024                      }
16025                  })
16026             }
16027         }
16028         
16029         if (!this.parent.el) {
16030                 // probably an old style ctor, which has been disabled.
16031                 return;
16032
16033         }
16034                 // The 'tree' method is  '_tree now' 
16035             
16036         tree.region = tree.region || this.region;
16037         
16038         if (this.parent.el === true) {
16039             // bootstrap... - body..
16040             this.parent.el = Roo.factory(tree);
16041         }
16042         
16043         this.el = this.parent.el.addxtype(tree);
16044         this.fireEvent('built', this);
16045         
16046         this.panel = this.el;
16047         this.layout = this.panel.layout;
16048         this.parentLayout = this.parent.layout  || false;  
16049          
16050     }
16051     
16052 });
16053
16054 Roo.apply(Roo.XComponent, {
16055     /**
16056      * @property  hideProgress
16057      * true to disable the building progress bar.. usefull on single page renders.
16058      * @type Boolean
16059      */
16060     hideProgress : false,
16061     /**
16062      * @property  buildCompleted
16063      * True when the builder has completed building the interface.
16064      * @type Boolean
16065      */
16066     buildCompleted : false,
16067      
16068     /**
16069      * @property  topModule
16070      * the upper most module - uses document.element as it's constructor.
16071      * @type Object
16072      */
16073      
16074     topModule  : false,
16075       
16076     /**
16077      * @property  modules
16078      * array of modules to be created by registration system.
16079      * @type {Array} of Roo.XComponent
16080      */
16081     
16082     modules : [],
16083     /**
16084      * @property  elmodules
16085      * array of modules to be created by which use #ID 
16086      * @type {Array} of Roo.XComponent
16087      */
16088      
16089     elmodules : [],
16090
16091      /**
16092      * @property  build_from_html
16093      * Build elements from html - used by bootstrap HTML stuff 
16094      *    - this is cleared after build is completed
16095      * @type {boolean} true  (default false)
16096      */
16097      
16098     build_from_html : false,
16099
16100     /**
16101      * Register components to be built later.
16102      *
16103      * This solves the following issues
16104      * - Building is not done on page load, but after an authentication process has occured.
16105      * - Interface elements are registered on page load
16106      * - Parent Interface elements may not be loaded before child, so this handles that..
16107      * 
16108      *
16109      * example:
16110      * 
16111      * MyApp.register({
16112           order : '000001',
16113           module : 'Pman.Tab.projectMgr',
16114           region : 'center',
16115           parent : 'Pman.layout',
16116           disabled : false,  // or use a function..
16117         })
16118      
16119      * * @param {Object} details about module
16120      */
16121     register : function(obj) {
16122                 
16123         Roo.XComponent.event.fireEvent('register', obj);
16124         switch(typeof(obj.disabled) ) {
16125                 
16126             case 'undefined':
16127                 break;
16128             
16129             case 'function':
16130                 if ( obj.disabled() ) {
16131                         return;
16132                 }
16133                 break;
16134             
16135             default:
16136                 if (obj.disabled) {
16137                         return;
16138                 }
16139                 break;
16140         }
16141                 
16142         this.modules.push(obj);
16143          
16144     },
16145     /**
16146      * convert a string to an object..
16147      * eg. 'AAA.BBB' -> finds AAA.BBB
16148
16149      */
16150     
16151     toObject : function(str)
16152     {
16153         if (!str || typeof(str) == 'object') {
16154             return str;
16155         }
16156         if (str.substring(0,1) == '#') {
16157             return str;
16158         }
16159
16160         var ar = str.split('.');
16161         var rt, o;
16162         rt = ar.shift();
16163             /** eval:var:o */
16164         try {
16165             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16166         } catch (e) {
16167             throw "Module not found : " + str;
16168         }
16169         
16170         if (o === false) {
16171             throw "Module not found : " + str;
16172         }
16173         Roo.each(ar, function(e) {
16174             if (typeof(o[e]) == 'undefined') {
16175                 throw "Module not found : " + str;
16176             }
16177             o = o[e];
16178         });
16179         
16180         return o;
16181         
16182     },
16183     
16184     
16185     /**
16186      * move modules into their correct place in the tree..
16187      * 
16188      */
16189     preBuild : function ()
16190     {
16191         var _t = this;
16192         Roo.each(this.modules , function (obj)
16193         {
16194             Roo.XComponent.event.fireEvent('beforebuild', obj);
16195             
16196             var opar = obj.parent;
16197             try { 
16198                 obj.parent = this.toObject(opar);
16199             } catch(e) {
16200                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16201                 return;
16202             }
16203             
16204             if (!obj.parent) {
16205                 Roo.debug && Roo.log("GOT top level module");
16206                 Roo.debug && Roo.log(obj);
16207                 obj.modules = new Roo.util.MixedCollection(false, 
16208                     function(o) { return o.order + '' }
16209                 );
16210                 this.topModule = obj;
16211                 return;
16212             }
16213                         // parent is a string (usually a dom element name..)
16214             if (typeof(obj.parent) == 'string') {
16215                 this.elmodules.push(obj);
16216                 return;
16217             }
16218             if (obj.parent.constructor != Roo.XComponent) {
16219                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16220             }
16221             if (!obj.parent.modules) {
16222                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16223                     function(o) { return o.order + '' }
16224                 );
16225             }
16226             if (obj.parent.disabled) {
16227                 obj.disabled = true;
16228             }
16229             obj.parent.modules.add(obj);
16230         }, this);
16231     },
16232     
16233      /**
16234      * make a list of modules to build.
16235      * @return {Array} list of modules. 
16236      */ 
16237     
16238     buildOrder : function()
16239     {
16240         var _this = this;
16241         var cmp = function(a,b) {   
16242             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16243         };
16244         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16245             throw "No top level modules to build";
16246         }
16247         
16248         // make a flat list in order of modules to build.
16249         var mods = this.topModule ? [ this.topModule ] : [];
16250                 
16251         
16252         // elmodules (is a list of DOM based modules )
16253         Roo.each(this.elmodules, function(e) {
16254             mods.push(e);
16255             if (!this.topModule &&
16256                 typeof(e.parent) == 'string' &&
16257                 e.parent.substring(0,1) == '#' &&
16258                 Roo.get(e.parent.substr(1))
16259                ) {
16260                 
16261                 _this.topModule = e;
16262             }
16263             
16264         });
16265
16266         
16267         // add modules to their parents..
16268         var addMod = function(m) {
16269             Roo.debug && Roo.log("build Order: add: " + m.name);
16270                 
16271             mods.push(m);
16272             if (m.modules && !m.disabled) {
16273                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16274                 m.modules.keySort('ASC',  cmp );
16275                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16276     
16277                 m.modules.each(addMod);
16278             } else {
16279                 Roo.debug && Roo.log("build Order: no child modules");
16280             }
16281             // not sure if this is used any more..
16282             if (m.finalize) {
16283                 m.finalize.name = m.name + " (clean up) ";
16284                 mods.push(m.finalize);
16285             }
16286             
16287         }
16288         if (this.topModule && this.topModule.modules) { 
16289             this.topModule.modules.keySort('ASC',  cmp );
16290             this.topModule.modules.each(addMod);
16291         } 
16292         return mods;
16293     },
16294     
16295      /**
16296      * Build the registered modules.
16297      * @param {Object} parent element.
16298      * @param {Function} optional method to call after module has been added.
16299      * 
16300      */ 
16301    
16302     build : function(opts) 
16303     {
16304         
16305         if (typeof(opts) != 'undefined') {
16306             Roo.apply(this,opts);
16307         }
16308         
16309         this.preBuild();
16310         var mods = this.buildOrder();
16311       
16312         //this.allmods = mods;
16313         //Roo.debug && Roo.log(mods);
16314         //return;
16315         if (!mods.length) { // should not happen
16316             throw "NO modules!!!";
16317         }
16318         
16319         
16320         var msg = "Building Interface...";
16321         // flash it up as modal - so we store the mask!?
16322         if (!this.hideProgress && Roo.MessageBox) {
16323             Roo.MessageBox.show({ title: 'loading' });
16324             Roo.MessageBox.show({
16325                title: "Please wait...",
16326                msg: msg,
16327                width:450,
16328                progress:true,
16329                closable:false,
16330                modal: false
16331               
16332             });
16333         }
16334         var total = mods.length;
16335         
16336         var _this = this;
16337         var progressRun = function() {
16338             if (!mods.length) {
16339                 Roo.debug && Roo.log('hide?');
16340                 if (!this.hideProgress && Roo.MessageBox) {
16341                     Roo.MessageBox.hide();
16342                 }
16343                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16344                 
16345                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16346                 
16347                 // THE END...
16348                 return false;   
16349             }
16350             
16351             var m = mods.shift();
16352             
16353             
16354             Roo.debug && Roo.log(m);
16355             // not sure if this is supported any more.. - modules that are are just function
16356             if (typeof(m) == 'function') { 
16357                 m.call(this);
16358                 return progressRun.defer(10, _this);
16359             } 
16360             
16361             
16362             msg = "Building Interface " + (total  - mods.length) + 
16363                     " of " + total + 
16364                     (m.name ? (' - ' + m.name) : '');
16365                         Roo.debug && Roo.log(msg);
16366             if (!this.hideProgress &&  Roo.MessageBox) { 
16367                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16368             }
16369             
16370          
16371             // is the module disabled?
16372             var disabled = (typeof(m.disabled) == 'function') ?
16373                 m.disabled.call(m.module.disabled) : m.disabled;    
16374             
16375             
16376             if (disabled) {
16377                 return progressRun(); // we do not update the display!
16378             }
16379             
16380             // now build 
16381             
16382                         
16383                         
16384             m.render();
16385             // it's 10 on top level, and 1 on others??? why...
16386             return progressRun.defer(10, _this);
16387              
16388         }
16389         progressRun.defer(1, _this);
16390      
16391         
16392         
16393     },
16394         
16395         
16396         /**
16397          * Event Object.
16398          *
16399          *
16400          */
16401         event: false, 
16402     /**
16403          * wrapper for event.on - aliased later..  
16404          * Typically use to register a event handler for register:
16405          *
16406          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16407          *
16408          */
16409     on : false
16410    
16411     
16412     
16413 });
16414
16415 Roo.XComponent.event = new Roo.util.Observable({
16416                 events : { 
16417                         /**
16418                          * @event register
16419                          * Fires when an Component is registered,
16420                          * set the disable property on the Component to stop registration.
16421                          * @param {Roo.XComponent} c the component being registerd.
16422                          * 
16423                          */
16424                         'register' : true,
16425             /**
16426                          * @event beforebuild
16427                          * Fires before each Component is built
16428                          * can be used to apply permissions.
16429                          * @param {Roo.XComponent} c the component being registerd.
16430                          * 
16431                          */
16432                         'beforebuild' : true,
16433                         /**
16434                          * @event buildcomplete
16435                          * Fires on the top level element when all elements have been built
16436                          * @param {Roo.XComponent} the top level component.
16437                          */
16438                         'buildcomplete' : true
16439                         
16440                 }
16441 });
16442
16443 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16444