390e7c410c75933dda5d0fcaac6bc96ee4c0ad01
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
64
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71     
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * Turn on debugging output (currently only the factory uses this)
90          * @type Boolean
91          */
92         
93         debug: false,
94
95         /**
96          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
97          * @type Boolean
98          */
99         enableGarbageCollector : true,
100
101         /**
102          * True to automatically purge event listeners after uncaching an element (defaults to false).
103          * Note: this only happens if enableGarbageCollector is true.
104          * @type Boolean
105          */
106         enableListenerCollection:false,
107
108         /**
109          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110          * the IE insecure content warning (defaults to javascript:false).
111          * @type String
112          */
113         SSL_SECURE_URL : "javascript:false",
114
115         /**
116          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
118          * @type String
119          */
120         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
121
122         emptyFn : function(){},
123         /**
124          *   Deep object/array copy. Function clones are actually wrappers around the
125          *   original function. Array-like objects are treated as arrays. Primitives are
126          *   returned untouched. Optionally, a function can be provided to handle other data
127          *   types, filter keys, validate values, etc.
128          *
129          *   **Note:** Cloning a non-trivial object is a reasonably heavy operation, due to
130          *   the need to recursively iterate down non-primitive properties. Clone should be
131          *   used only when a deep clone down to leaf level properties is explicitly
132          *   required. This method will also
133          *
134             In many cases (for example, when trying to isolate objects used as hashes for
135             configuration properties), a shallow copy, using `Y.merge()` is normally
136             sufficient. If more than one level of isolation is required, `Y.merge()` can be
137             used selectively at each level which needs to be isolated from the original
138             without going all the way to leaf properties.
139
140             @method clone
141             @param {object} o what to clone.
142             @param {boolean} safe if true, objects will not have prototype items from the
143                 source. If false, they will. In this case, the original is initially
144                 protected, but the clone is not completely immune from changes to the source
145                 object prototype. Also, cloned prototype items that are deleted from the
146                 clone will result in the value of the source prototype being exposed. If
147                 operating on a non-safe clone, items should be nulled out rather than
148                 deleted.
149             @param {function} f optional function to apply to each item in a collection; it
150                 will be executed prior to applying the value to the new object.
151                 Return false to prevent the copy.
152             @param {object} c optional execution context for f.
153             @param {object} owner Owner object passed when clone is iterating an object.
154                 Used to set up context for cloned functions.
155             @param {object} cloned hash of previously cloned objects to avoid multiple
156                 clones.
157             @return {Array|Object} the cloned object.
158           **/
159         clone : function(o, safe, f, c, owner, cloned) {
160             var o2, marked, stamp;
161
162             // Does not attempt to clone:
163             //
164             // * Non-typeof-object values, "primitive" values don't need cloning.
165             //
166             // * YUI instances, cloning complex object like YUI instances is not
167             //   advised, this is like cloning the world.
168             //
169             // * DOM nodes (#2528250), common host objects like DOM nodes cannot be
170             //   "subclassed" in Firefox and old versions of IE. Trying to use
171             //   `Object.create()` or `Y.extend()` on a DOM node will throw an error in
172             //   these browsers.
173             //
174             // Instad, the passed-in `o` will be return as-is when it matches one of the
175             // above criteria.
176 //            if (!L.isObject(o) ||
177 //                    Y.instanceOf(o, YUI) ||
178 //                    (o.addEventListener || o.attachEvent)) {
179 //
180 //                return o;
181 //            }
182
183             marked = cloned || {};
184
185             switch (this.type(o)) {
186                 case 'date':
187                     return new Date(o);
188                 case 'regexp':
189                     // if we do this we need to set the flags too
190                     // return new RegExp(o.source);
191                     return o;
192                 case 'function':
193                     // o2 = Y.bind(o, owner);
194                     // break;
195                     return o;
196                 case 'array':
197                     o2 = [];
198                     break;
199                 default:
200                     
201                     // #2528250 only one clone of a given object should be created.
202                     if (o['_~roo~_']) {
203                         return marked[o['_~roo~_']];
204                     }
205
206                     stamp = Roo.id();
207
208 //                    o2 = (safe) ? {} : Roo.Object(o);
209                     o2 = {};
210                     o['_~roo~_'] = stamp;
211                     marked[stamp] = o;
212             }
213
214             Roo.each(o, function(v, k) {
215                 if ((k || k === 0) && (!f || (f.call(c || this, v, k, this, o) !== false))) {
216                     if (k !== '_~roo~_') {
217                         if (k == 'prototype') {
218                             // skip the prototype
219                         // } else if (o[k] === o) {
220                         //     this[k] = this;
221                         } else {
222                             this[k] =
223                                 Roo.clone(v, safe, f, c, owner || o, marked);
224                         }
225                     }
226                 }
227             }, o2);
228
229             if (!cloned) {
230                 Roo.each(marked, function(v, k) {
231                     if (v['_~roo~_']) {
232                         try {
233                             delete v['_~roo~_'];
234                         } catch (e) {
235                             v['_~roo~_'] = null;
236                         }
237                     }
238                 }, this);
239                 marked = null;
240             }
241
242             return o2;
243         },
244         /**
245          * Copies all the properties of config to obj if they don't already exist.
246          * @param {Object} obj The receiver of the properties
247          * @param {Object} config The source of the properties
248          * @return {Object} returns obj
249          */
250         applyIf : function(o, c){
251             if(o && c){
252                 for(var p in c){
253                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
254                 }
255             }
256             return o;
257         },
258
259         /**
260          * Applies event listeners to elements by selectors when the document is ready.
261          * The event name is specified with an @ suffix.
262 <pre><code>
263 Roo.addBehaviors({
264    // add a listener for click on all anchors in element with id foo
265    '#foo a@click' : function(e, t){
266        // do something
267    },
268
269    // add the same listener to multiple selectors (separated by comma BEFORE the @)
270    '#foo a, #bar span.some-class@mouseover' : function(){
271        // do something
272    }
273 });
274 </code></pre>
275          * @param {Object} obj The list of behaviors to apply
276          */
277         addBehaviors : function(o){
278             if(!Roo.isReady){
279                 Roo.onReady(function(){
280                     Roo.addBehaviors(o);
281                 });
282                 return;
283             }
284             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
285             for(var b in o){
286                 var parts = b.split('@');
287                 if(parts[1]){ // for Object prototype breakers
288                     var s = parts[0];
289                     if(!cache[s]){
290                         cache[s] = Roo.select(s);
291                     }
292                     cache[s].on(parts[1], o[b]);
293                 }
294             }
295             cache = null;
296         },
297
298         /**
299          * Generates unique ids. If the element already has an id, it is unchanged
300          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
301          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
302          * @return {String} The generated Id.
303          */
304         id : function(el, prefix){
305             prefix = prefix || "roo-gen";
306             el = Roo.getDom(el);
307             var id = prefix + (++idSeed);
308             return el ? (el.id ? el.id : (el.id = id)) : id;
309         },
310          
311        
312         /**
313          * Extends one class with another class and optionally overrides members with the passed literal. This class
314          * also adds the function "override()" to the class that can be used to override
315          * members on an instance.
316          * @param {Object} subclass The class inheriting the functionality
317          * @param {Object} superclass The class being extended
318          * @param {Object} overrides (optional) A literal with members
319          * @method extend
320          */
321         extend : function(){
322             // inline overrides
323             var io = function(o){
324                 for(var m in o){
325                     this[m] = o[m];
326                 }
327             };
328             return function(sb, sp, overrides){
329                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
330                     overrides = sp;
331                     sp = sb;
332                     sb = function(){sp.apply(this, arguments);};
333                 }
334                 var F = function(){}, sbp, spp = sp.prototype;
335                 F.prototype = spp;
336                 sbp = sb.prototype = new F();
337                 sbp.constructor=sb;
338                 sb.superclass=spp;
339                 
340                 if(spp.constructor == Object.prototype.constructor){
341                     spp.constructor=sp;
342                    
343                 }
344                 
345                 sb.override = function(o){
346                     Roo.override(sb, o);
347                 };
348                 sbp.override = io;
349                 Roo.override(sb, overrides);
350                 return sb;
351             };
352         }(),
353
354         /**
355          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
356          * Usage:<pre><code>
357 Roo.override(MyClass, {
358     newMethod1: function(){
359         // etc.
360     },
361     newMethod2: function(foo){
362         // etc.
363     }
364 });
365  </code></pre>
366          * @param {Object} origclass The class to override
367          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
368          * containing one or more methods.
369          * @method override
370          */
371         override : function(origclass, overrides){
372             if(overrides){
373                 var p = origclass.prototype;
374                 for(var method in overrides){
375                     p[method] = overrides[method];
376                 }
377             }
378         },
379         /**
380          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
381          * <pre><code>
382 Roo.namespace('Company', 'Company.data');
383 Company.Widget = function() { ... }
384 Company.data.CustomStore = function(config) { ... }
385 </code></pre>
386          * @param {String} namespace1
387          * @param {String} namespace2
388          * @param {String} etc
389          * @method namespace
390          */
391         namespace : function(){
392             var a=arguments, o=null, i, j, d, rt;
393             for (i=0; i<a.length; ++i) {
394                 d=a[i].split(".");
395                 rt = d[0];
396                 /** eval:var:o */
397                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
398                 for (j=1; j<d.length; ++j) {
399                     o[d[j]]=o[d[j]] || {};
400                     o=o[d[j]];
401                 }
402             }
403         },
404         /**
405          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
406          * <pre><code>
407 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
408 Roo.factory(conf, Roo.data);
409 </code></pre>
410          * @param {String} classname
411          * @param {String} namespace (optional)
412          * @method factory
413          */
414          
415         factory : function(c, ns)
416         {
417             // no xtype, no ns or c.xns - or forced off by c.xns
418             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
419                 return c;
420             }
421             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
422             if (c.constructor == ns[c.xtype]) {// already created...
423                 return c;
424             }
425             if (ns[c.xtype]) {
426                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
427                 var ret = new ns[c.xtype](c);
428                 ret.xns = false;
429                 return ret;
430             }
431             c.xns = false; // prevent recursion..
432             return c;
433         },
434          /**
435          * Logs to console if it can.
436          *
437          * @param {String|Object} string
438          * @method log
439          */
440         log : function(s)
441         {
442             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
443                 return; // alerT?
444             }
445             console.log(s);
446             
447         },
448         /**
449          * 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.
450          * @param {Object} o
451          * @return {String}
452          */
453         urlEncode : function(o){
454             if(!o){
455                 return "";
456             }
457             var buf = [];
458             for(var key in o){
459                 var ov = o[key], k = Roo.encodeURIComponent(key);
460                 var type = typeof ov;
461                 if(type == 'undefined'){
462                     buf.push(k, "=&");
463                 }else if(type != "function" && type != "object"){
464                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
465                 }else if(ov instanceof Array){
466                     if (ov.length) {
467                             for(var i = 0, len = ov.length; i < len; i++) {
468                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
469                             }
470                         } else {
471                             buf.push(k, "=&");
472                         }
473                 }
474             }
475             buf.pop();
476             return buf.join("");
477         },
478          /**
479          * Safe version of encodeURIComponent
480          * @param {String} data 
481          * @return {String} 
482          */
483         
484         encodeURIComponent : function (data)
485         {
486             try {
487                 return encodeURIComponent(data);
488             } catch(e) {} // should be an uri encode error.
489             
490             if (data == '' || data == null){
491                return '';
492             }
493             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
494             function nibble_to_hex(nibble){
495                 var chars = '0123456789ABCDEF';
496                 return chars.charAt(nibble);
497             }
498             data = data.toString();
499             var buffer = '';
500             for(var i=0; i<data.length; i++){
501                 var c = data.charCodeAt(i);
502                 var bs = new Array();
503                 if (c > 0x10000){
504                         // 4 bytes
505                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
506                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
507                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
508                     bs[3] = 0x80 | (c & 0x3F);
509                 }else if (c > 0x800){
510                          // 3 bytes
511                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
512                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
513                     bs[2] = 0x80 | (c & 0x3F);
514                 }else if (c > 0x80){
515                        // 2 bytes
516                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
517                     bs[1] = 0x80 | (c & 0x3F);
518                 }else{
519                         // 1 byte
520                     bs[0] = c;
521                 }
522                 for(var j=0; j<bs.length; j++){
523                     var b = bs[j];
524                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
525                             + nibble_to_hex(b &0x0F);
526                     buffer += '%'+hex;
527                }
528             }
529             return buffer;    
530              
531         },
532
533         /**
534          * 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]}.
535          * @param {String} string
536          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
537          * @return {Object} A literal with members
538          */
539         urlDecode : function(string, overwrite){
540             if(!string || !string.length){
541                 return {};
542             }
543             var obj = {};
544             var pairs = string.split('&');
545             var pair, name, value;
546             for(var i = 0, len = pairs.length; i < len; i++){
547                 pair = pairs[i].split('=');
548                 name = decodeURIComponent(pair[0]);
549                 value = decodeURIComponent(pair[1]);
550                 if(overwrite !== true){
551                     if(typeof obj[name] == "undefined"){
552                         obj[name] = value;
553                     }else if(typeof obj[name] == "string"){
554                         obj[name] = [obj[name]];
555                         obj[name].push(value);
556                     }else{
557                         obj[name].push(value);
558                     }
559                 }else{
560                     obj[name] = value;
561                 }
562             }
563             return obj;
564         },
565
566         /**
567          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
568          * passed array is not really an array, your function is called once with it.
569          * The supplied function is called with (Object item, Number index, Array allItems).
570          * @param {Array/NodeList/Mixed} array
571          * @param {Function} fn
572          * @param {Object} scope
573          */
574         each : function(array, fn, scope){
575             if(typeof array.length == "undefined" || typeof array == "string"){
576                 array = [array];
577             }
578             for(var i = 0, len = array.length; i < len; i++){
579                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
580             }
581         },
582
583         // deprecated
584         combine : function(){
585             var as = arguments, l = as.length, r = [];
586             for(var i = 0; i < l; i++){
587                 var a = as[i];
588                 if(a instanceof Array){
589                     r = r.concat(a);
590                 }else if(a.length !== undefined && !a.substr){
591                     r = r.concat(Array.prototype.slice.call(a, 0));
592                 }else{
593                     r.push(a);
594                 }
595             }
596             return r;
597         },
598
599         /**
600          * Escapes the passed string for use in a regular expression
601          * @param {String} str
602          * @return {String}
603          */
604         escapeRe : function(s) {
605             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
606         },
607
608         // internal
609         callback : function(cb, scope, args, delay){
610             if(typeof cb == "function"){
611                 if(delay){
612                     cb.defer(delay, scope, args || []);
613                 }else{
614                     cb.apply(scope, args || []);
615                 }
616             }
617         },
618
619         /**
620          * Return the dom node for the passed string (id), dom node, or Roo.Element
621          * @param {String/HTMLElement/Roo.Element} el
622          * @return HTMLElement
623          */
624         getDom : function(el){
625             if(!el){
626                 return null;
627             }
628             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
629         },
630
631         /**
632         * Shorthand for {@link Roo.ComponentMgr#get}
633         * @param {String} id
634         * @return Roo.Component
635         */
636         getCmp : function(id){
637             return Roo.ComponentMgr.get(id);
638         },
639          
640         num : function(v, defaultValue){
641             if(typeof v != 'number'){
642                 return defaultValue;
643             }
644             return v;
645         },
646
647         destroy : function(){
648             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
649                 var as = a[i];
650                 if(as){
651                     if(as.dom){
652                         as.removeAllListeners();
653                         as.remove();
654                         continue;
655                     }
656                     if(typeof as.purgeListeners == 'function'){
657                         as.purgeListeners();
658                     }
659                     if(typeof as.destroy == 'function'){
660                         as.destroy();
661                     }
662                 }
663             }
664         },
665
666         // inpired by a similar function in mootools library
667         /**
668          * Returns the type of object that is passed in. If the object passed in is null or undefined it
669          * return false otherwise it returns one of the following values:<ul>
670          * <li><b>string</b>: If the object passed is a string</li>
671          * <li><b>number</b>: If the object passed is a number</li>
672          * <li><b>boolean</b>: If the object passed is a boolean value</li>
673          * <li><b>function</b>: If the object passed is a function reference</li>
674          * <li><b>object</b>: If the object passed is an object</li>
675          * <li><b>array</b>: If the object passed is an array</li>
676          * <li><b>regexp</b>: If the object passed is a regular expression</li>
677          * <li><b>element</b>: If the object passed is a DOM Element</li>
678          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
679          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
680          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
681          * @param {Mixed} object
682          * @return {String}
683          */
684         type : function(o){
685             if(o === undefined || o === null){
686                 return false;
687             }
688             if(o.htmlElement){
689                 return 'element';
690             }
691             var t = typeof o;
692             if(t == 'object' && o.nodeName) {
693                 switch(o.nodeType) {
694                     case 1: return 'element';
695                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
696                 }
697             }
698             if(t == 'object' || t == 'function') {
699                 switch(o.constructor) {
700                     case Array: return 'array';
701                     case RegExp: return 'regexp';
702                 }
703                 if(typeof o.length == 'number' && typeof o.item == 'function') {
704                     return 'nodelist';
705                 }
706             }
707             return t;
708         },
709
710         /**
711          * Returns true if the passed value is null, undefined or an empty string (optional).
712          * @param {Mixed} value The value to test
713          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
714          * @return {Boolean}
715          */
716         isEmpty : function(v, allowBlank){
717             return v === null || v === undefined || (!allowBlank ? v === '' : false);
718         },
719         
720         /** @type Boolean */
721         isOpera : isOpera,
722         /** @type Boolean */
723         isSafari : isSafari,
724         /** @type Boolean */
725         isIE : isIE,
726         /** @type Boolean */
727         isIE7 : isIE7,
728         /** @type Boolean */
729         isGecko : isGecko,
730         /** @type Boolean */
731         isBorderBox : isBorderBox,
732         /** @type Boolean */
733         isWindows : isWindows,
734         /** @type Boolean */
735         isLinux : isLinux,
736         /** @type Boolean */
737         isMac : isMac,
738
739         /**
740          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
741          * you may want to set this to true.
742          * @type Boolean
743          */
744         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
745         
746         
747                 
748         /**
749          * Selects a single element as a Roo Element
750          * This is about as close as you can get to jQuery's $('do crazy stuff')
751          * @param {String} selector The selector/xpath query
752          * @param {Node} root (optional) The start of the query (defaults to document).
753          * @return {Roo.Element}
754          */
755         selectNode : function(selector, root) 
756         {
757             var node = Roo.DomQuery.selectNode(selector,root);
758             return node ? Roo.get(node) : new Roo.Element(false);
759         }
760         
761     });
762
763
764 })();
765
766 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
767                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
768 /*
769  * Based on:
770  * Ext JS Library 1.1.1
771  * Copyright(c) 2006-2007, Ext JS, LLC.
772  *
773  * Originally Released Under LGPL - original licence link has changed is not relivant.
774  *
775  * Fork - LGPL
776  * <script type="text/javascript">
777  */
778
779 (function() {    
780     // wrappedn so fnCleanup is not in global scope...
781     if(Roo.isIE) {
782         function fnCleanUp() {
783             var p = Function.prototype;
784             delete p.createSequence;
785             delete p.defer;
786             delete p.createDelegate;
787             delete p.createCallback;
788             delete p.createInterceptor;
789
790             window.detachEvent("onunload", fnCleanUp);
791         }
792         window.attachEvent("onunload", fnCleanUp);
793     }
794 })();
795
796
797 /**
798  * @class Function
799  * These functions are available on every Function object (any JavaScript function).
800  */
801 Roo.apply(Function.prototype, {
802      /**
803      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
804      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
805      * Will create a function that is bound to those 2 args.
806      * @return {Function} The new function
807     */
808     createCallback : function(/*args...*/){
809         // make args available, in function below
810         var args = arguments;
811         var method = this;
812         return function() {
813             return method.apply(window, args);
814         };
815     },
816
817     /**
818      * Creates a delegate (callback) that sets the scope to obj.
819      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
820      * Will create a function that is automatically scoped to this.
821      * @param {Object} obj (optional) The object for which the scope is set
822      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
823      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
824      *                                             if a number the args are inserted at the specified position
825      * @return {Function} The new function
826      */
827     createDelegate : function(obj, args, appendArgs){
828         var method = this;
829         return function() {
830             var callArgs = args || arguments;
831             if(appendArgs === true){
832                 callArgs = Array.prototype.slice.call(arguments, 0);
833                 callArgs = callArgs.concat(args);
834             }else if(typeof appendArgs == "number"){
835                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
836                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
837                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
838             }
839             return method.apply(obj || window, callArgs);
840         };
841     },
842
843     /**
844      * Calls this function after the number of millseconds specified.
845      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
846      * @param {Object} obj (optional) The object for which the scope is set
847      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
848      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
849      *                                             if a number the args are inserted at the specified position
850      * @return {Number} The timeout id that can be used with clearTimeout
851      */
852     defer : function(millis, obj, args, appendArgs){
853         var fn = this.createDelegate(obj, args, appendArgs);
854         if(millis){
855             return setTimeout(fn, millis);
856         }
857         fn();
858         return 0;
859     },
860     /**
861      * Create a combined function call sequence of the original function + the passed function.
862      * The resulting function returns the results of the original function.
863      * The passed fcn is called with the parameters of the original function
864      * @param {Function} fcn The function to sequence
865      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
866      * @return {Function} The new function
867      */
868     createSequence : function(fcn, scope){
869         if(typeof fcn != "function"){
870             return this;
871         }
872         var method = this;
873         return function() {
874             var retval = method.apply(this || window, arguments);
875             fcn.apply(scope || this || window, arguments);
876             return retval;
877         };
878     },
879
880     /**
881      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
882      * The resulting function returns the results of the original function.
883      * The passed fcn is called with the parameters of the original function.
884      * @addon
885      * @param {Function} fcn The function to call before the original
886      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
887      * @return {Function} The new function
888      */
889     createInterceptor : function(fcn, scope){
890         if(typeof fcn != "function"){
891             return this;
892         }
893         var method = this;
894         return function() {
895             fcn.target = this;
896             fcn.method = method;
897             if(fcn.apply(scope || this || window, arguments) === false){
898                 return;
899             }
900             return method.apply(this || window, arguments);
901         };
902     }
903 });
904 /*
905  * Based on:
906  * Ext JS Library 1.1.1
907  * Copyright(c) 2006-2007, Ext JS, LLC.
908  *
909  * Originally Released Under LGPL - original licence link has changed is not relivant.
910  *
911  * Fork - LGPL
912  * <script type="text/javascript">
913  */
914
915 Roo.applyIf(String, {
916     
917     /** @scope String */
918     
919     /**
920      * Escapes the passed string for ' and \
921      * @param {String} string The string to escape
922      * @return {String} The escaped string
923      * @static
924      */
925     escape : function(string) {
926         return string.replace(/('|\\)/g, "\\$1");
927     },
928
929     /**
930      * Pads the left side of a string with a specified character.  This is especially useful
931      * for normalizing number and date strings.  Example usage:
932      * <pre><code>
933 var s = String.leftPad('123', 5, '0');
934 // s now contains the string: '00123'
935 </code></pre>
936      * @param {String} string The original string
937      * @param {Number} size The total length of the output string
938      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
939      * @return {String} The padded string
940      * @static
941      */
942     leftPad : function (val, size, ch) {
943         var result = new String(val);
944         if(ch === null || ch === undefined || ch === '') {
945             ch = " ";
946         }
947         while (result.length < size) {
948             result = ch + result;
949         }
950         return result;
951     },
952
953     /**
954      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
955      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
956      * <pre><code>
957 var cls = 'my-class', text = 'Some text';
958 var s = String.format('<div class="{0}">{1}</div>', cls, text);
959 // s now contains the string: '<div class="my-class">Some text</div>'
960 </code></pre>
961      * @param {String} string The tokenized string to be formatted
962      * @param {String} value1 The value to replace token {0}
963      * @param {String} value2 Etc...
964      * @return {String} The formatted string
965      * @static
966      */
967     format : function(format){
968         var args = Array.prototype.slice.call(arguments, 1);
969         return format.replace(/\{(\d+)\}/g, function(m, i){
970             return Roo.util.Format.htmlEncode(args[i]);
971         });
972     }
973 });
974
975 /**
976  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
977  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
978  * they are already different, the first value passed in is returned.  Note that this method returns the new value
979  * but does not change the current string.
980  * <pre><code>
981 // alternate sort directions
982 sort = sort.toggle('ASC', 'DESC');
983
984 // instead of conditional logic:
985 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
986 </code></pre>
987  * @param {String} value The value to compare to the current string
988  * @param {String} other The new value to use if the string already equals the first value passed in
989  * @return {String} The new value
990  */
991  
992 String.prototype.toggle = function(value, other){
993     return this == value ? other : value;
994 };/*
995  * Based on:
996  * Ext JS Library 1.1.1
997  * Copyright(c) 2006-2007, Ext JS, LLC.
998  *
999  * Originally Released Under LGPL - original licence link has changed is not relivant.
1000  *
1001  * Fork - LGPL
1002  * <script type="text/javascript">
1003  */
1004
1005  /**
1006  * @class Number
1007  */
1008 Roo.applyIf(Number.prototype, {
1009     /**
1010      * Checks whether or not the current number is within a desired range.  If the number is already within the
1011      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
1012      * exceeded.  Note that this method returns the constrained value but does not change the current number.
1013      * @param {Number} min The minimum number in the range
1014      * @param {Number} max The maximum number in the range
1015      * @return {Number} The constrained value if outside the range, otherwise the current value
1016      */
1017     constrain : function(min, max){
1018         return Math.min(Math.max(this, min), max);
1019     }
1020 });/*
1021  * Based on:
1022  * Ext JS Library 1.1.1
1023  * Copyright(c) 2006-2007, Ext JS, LLC.
1024  *
1025  * Originally Released Under LGPL - original licence link has changed is not relivant.
1026  *
1027  * Fork - LGPL
1028  * <script type="text/javascript">
1029  */
1030  /**
1031  * @class Array
1032  */
1033 Roo.applyIf(Array.prototype, {
1034     /**
1035      * Checks whether or not the specified object exists in the array.
1036      * @param {Object} o The object to check for
1037      * @return {Number} The index of o in the array (or -1 if it is not found)
1038      */
1039     indexOf : function(o){
1040        for (var i = 0, len = this.length; i < len; i++){
1041               if(this[i] == o) return i;
1042        }
1043            return -1;
1044     },
1045
1046     /**
1047      * Removes the specified object from the array.  If the object is not found nothing happens.
1048      * @param {Object} o The object to remove
1049      */
1050     remove : function(o){
1051        var index = this.indexOf(o);
1052        if(index != -1){
1053            this.splice(index, 1);
1054        }
1055     },
1056     /**
1057      * Map (JS 1.6 compatibility)
1058      * @param {Function} function  to call
1059      */
1060     map : function(fun )
1061     {
1062         var len = this.length >>> 0;
1063         if (typeof fun != "function")
1064             throw new TypeError();
1065
1066         var res = new Array(len);
1067         var thisp = arguments[1];
1068         for (var i = 0; i < len; i++)
1069         {
1070             if (i in this)
1071                 res[i] = fun.call(thisp, this[i], i, this);
1072         }
1073
1074         return res;
1075     }
1076     
1077 });
1078
1079
1080  /*
1081  * Based on:
1082  * Ext JS Library 1.1.1
1083  * Copyright(c) 2006-2007, Ext JS, LLC.
1084  *
1085  * Originally Released Under LGPL - original licence link has changed is not relivant.
1086  *
1087  * Fork - LGPL
1088  * <script type="text/javascript">
1089  */
1090
1091 /**
1092  * @class Date
1093  *
1094  * The date parsing and format syntax is a subset of
1095  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1096  * supported will provide results equivalent to their PHP versions.
1097  *
1098  * Following is the list of all currently supported formats:
1099  *<pre>
1100 Sample date:
1101 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1102
1103 Format  Output      Description
1104 ------  ----------  --------------------------------------------------------------
1105   d      10         Day of the month, 2 digits with leading zeros
1106   D      Wed        A textual representation of a day, three letters
1107   j      10         Day of the month without leading zeros
1108   l      Wednesday  A full textual representation of the day of the week
1109   S      th         English ordinal day of month suffix, 2 chars (use with j)
1110   w      3          Numeric representation of the day of the week
1111   z      9          The julian date, or day of the year (0-365)
1112   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1113   F      January    A full textual representation of the month
1114   m      01         Numeric representation of a month, with leading zeros
1115   M      Jan        Month name abbreviation, three letters
1116   n      1          Numeric representation of a month, without leading zeros
1117   t      31         Number of days in the given month
1118   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1119   Y      2007       A full numeric representation of a year, 4 digits
1120   y      07         A two digit representation of a year
1121   a      pm         Lowercase Ante meridiem and Post meridiem
1122   A      PM         Uppercase Ante meridiem and Post meridiem
1123   g      3          12-hour format of an hour without leading zeros
1124   G      15         24-hour format of an hour without leading zeros
1125   h      03         12-hour format of an hour with leading zeros
1126   H      15         24-hour format of an hour with leading zeros
1127   i      05         Minutes with leading zeros
1128   s      01         Seconds, with leading zeros
1129   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1130   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1131   T      CST        Timezone setting of the machine running the code
1132   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1133 </pre>
1134  *
1135  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1136  * <pre><code>
1137 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1138 document.write(dt.format('Y-m-d'));                         //2007-01-10
1139 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1140 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
1141  </code></pre>
1142  *
1143  * Here are some standard date/time patterns that you might find helpful.  They
1144  * are not part of the source of Date.js, but to use them you can simply copy this
1145  * block of code into any script that is included after Date.js and they will also become
1146  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1147  * <pre><code>
1148 Date.patterns = {
1149     ISO8601Long:"Y-m-d H:i:s",
1150     ISO8601Short:"Y-m-d",
1151     ShortDate: "n/j/Y",
1152     LongDate: "l, F d, Y",
1153     FullDateTime: "l, F d, Y g:i:s A",
1154     MonthDay: "F d",
1155     ShortTime: "g:i A",
1156     LongTime: "g:i:s A",
1157     SortableDateTime: "Y-m-d\\TH:i:s",
1158     UniversalSortableDateTime: "Y-m-d H:i:sO",
1159     YearMonth: "F, Y"
1160 };
1161 </code></pre>
1162  *
1163  * Example usage:
1164  * <pre><code>
1165 var dt = new Date();
1166 document.write(dt.format(Date.patterns.ShortDate));
1167  </code></pre>
1168  */
1169
1170 /*
1171  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1172  * They generate precompiled functions from date formats instead of parsing and
1173  * processing the pattern every time you format a date.  These functions are available
1174  * on every Date object (any javascript function).
1175  *
1176  * The original article and download are here:
1177  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1178  *
1179  */
1180  
1181  
1182  // was in core
1183 /**
1184  Returns the number of milliseconds between this date and date
1185  @param {Date} date (optional) Defaults to now
1186  @return {Number} The diff in milliseconds
1187  @member Date getElapsed
1188  */
1189 Date.prototype.getElapsed = function(date) {
1190         return Math.abs((date || new Date()).getTime()-this.getTime());
1191 };
1192 // was in date file..
1193
1194
1195 // private
1196 Date.parseFunctions = {count:0};
1197 // private
1198 Date.parseRegexes = [];
1199 // private
1200 Date.formatFunctions = {count:0};
1201
1202 // private
1203 Date.prototype.dateFormat = function(format) {
1204     if (Date.formatFunctions[format] == null) {
1205         Date.createNewFormat(format);
1206     }
1207     var func = Date.formatFunctions[format];
1208     return this[func]();
1209 };
1210
1211
1212 /**
1213  * Formats a date given the supplied format string
1214  * @param {String} format The format string
1215  * @return {String} The formatted date
1216  * @method
1217  */
1218 Date.prototype.format = Date.prototype.dateFormat;
1219
1220 // private
1221 Date.createNewFormat = function(format) {
1222     var funcName = "format" + Date.formatFunctions.count++;
1223     Date.formatFunctions[format] = funcName;
1224     var code = "Date.prototype." + funcName + " = function(){return ";
1225     var special = false;
1226     var ch = '';
1227     for (var i = 0; i < format.length; ++i) {
1228         ch = format.charAt(i);
1229         if (!special && ch == "\\") {
1230             special = true;
1231         }
1232         else if (special) {
1233             special = false;
1234             code += "'" + String.escape(ch) + "' + ";
1235         }
1236         else {
1237             code += Date.getFormatCode(ch);
1238         }
1239     }
1240     /** eval:var:zzzzzzzzzzzzz */
1241     eval(code.substring(0, code.length - 3) + ";}");
1242 };
1243
1244 // private
1245 Date.getFormatCode = function(character) {
1246     switch (character) {
1247     case "d":
1248         return "String.leftPad(this.getDate(), 2, '0') + ";
1249     case "D":
1250         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1251     case "j":
1252         return "this.getDate() + ";
1253     case "l":
1254         return "Date.dayNames[this.getDay()] + ";
1255     case "S":
1256         return "this.getSuffix() + ";
1257     case "w":
1258         return "this.getDay() + ";
1259     case "z":
1260         return "this.getDayOfYear() + ";
1261     case "W":
1262         return "this.getWeekOfYear() + ";
1263     case "F":
1264         return "Date.monthNames[this.getMonth()] + ";
1265     case "m":
1266         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1267     case "M":
1268         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1269     case "n":
1270         return "(this.getMonth() + 1) + ";
1271     case "t":
1272         return "this.getDaysInMonth() + ";
1273     case "L":
1274         return "(this.isLeapYear() ? 1 : 0) + ";
1275     case "Y":
1276         return "this.getFullYear() + ";
1277     case "y":
1278         return "('' + this.getFullYear()).substring(2, 4) + ";
1279     case "a":
1280         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1281     case "A":
1282         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1283     case "g":
1284         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1285     case "G":
1286         return "this.getHours() + ";
1287     case "h":
1288         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1289     case "H":
1290         return "String.leftPad(this.getHours(), 2, '0') + ";
1291     case "i":
1292         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1293     case "s":
1294         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1295     case "O":
1296         return "this.getGMTOffset() + ";
1297     case "P":
1298         return "this.getGMTColonOffset() + ";
1299     case "T":
1300         return "this.getTimezone() + ";
1301     case "Z":
1302         return "(this.getTimezoneOffset() * -60) + ";
1303     default:
1304         return "'" + String.escape(character) + "' + ";
1305     }
1306 };
1307
1308 /**
1309  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1310  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1311  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1312  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1313  * string or the parse operation will fail.
1314  * Example Usage:
1315 <pre><code>
1316 //dt = Fri May 25 2007 (current date)
1317 var dt = new Date();
1318
1319 //dt = Thu May 25 2006 (today's month/day in 2006)
1320 dt = Date.parseDate("2006", "Y");
1321
1322 //dt = Sun Jan 15 2006 (all date parts specified)
1323 dt = Date.parseDate("2006-1-15", "Y-m-d");
1324
1325 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1326 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1327 </code></pre>
1328  * @param {String} input The unparsed date as a string
1329  * @param {String} format The format the date is in
1330  * @return {Date} The parsed date
1331  * @static
1332  */
1333 Date.parseDate = function(input, format) {
1334     if (Date.parseFunctions[format] == null) {
1335         Date.createParser(format);
1336     }
1337     var func = Date.parseFunctions[format];
1338     return Date[func](input);
1339 };
1340 /**
1341  * @private
1342  */
1343 Date.createParser = function(format) {
1344     var funcName = "parse" + Date.parseFunctions.count++;
1345     var regexNum = Date.parseRegexes.length;
1346     var currentGroup = 1;
1347     Date.parseFunctions[format] = funcName;
1348
1349     var code = "Date." + funcName + " = function(input){\n"
1350         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1351         + "var d = new Date();\n"
1352         + "y = d.getFullYear();\n"
1353         + "m = d.getMonth();\n"
1354         + "d = d.getDate();\n"
1355         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1356         + "if (results && results.length > 0) {";
1357     var regex = "";
1358
1359     var special = false;
1360     var ch = '';
1361     for (var i = 0; i < format.length; ++i) {
1362         ch = format.charAt(i);
1363         if (!special && ch == "\\") {
1364             special = true;
1365         }
1366         else if (special) {
1367             special = false;
1368             regex += String.escape(ch);
1369         }
1370         else {
1371             var obj = Date.formatCodeToRegex(ch, currentGroup);
1372             currentGroup += obj.g;
1373             regex += obj.s;
1374             if (obj.g && obj.c) {
1375                 code += obj.c;
1376             }
1377         }
1378     }
1379
1380     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1381         + "{v = new Date(y, m, d, h, i, s);}\n"
1382         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1383         + "{v = new Date(y, m, d, h, i);}\n"
1384         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1385         + "{v = new Date(y, m, d, h);}\n"
1386         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1387         + "{v = new Date(y, m, d);}\n"
1388         + "else if (y >= 0 && m >= 0)\n"
1389         + "{v = new Date(y, m);}\n"
1390         + "else if (y >= 0)\n"
1391         + "{v = new Date(y);}\n"
1392         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1393         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1394         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1395         + ";}";
1396
1397     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1398     /** eval:var:zzzzzzzzzzzzz */
1399     eval(code);
1400 };
1401
1402 // private
1403 Date.formatCodeToRegex = function(character, currentGroup) {
1404     switch (character) {
1405     case "D":
1406         return {g:0,
1407         c:null,
1408         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1409     case "j":
1410         return {g:1,
1411             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1412             s:"(\\d{1,2})"}; // day of month without leading zeroes
1413     case "d":
1414         return {g:1,
1415             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1416             s:"(\\d{2})"}; // day of month with leading zeroes
1417     case "l":
1418         return {g:0,
1419             c:null,
1420             s:"(?:" + Date.dayNames.join("|") + ")"};
1421     case "S":
1422         return {g:0,
1423             c:null,
1424             s:"(?:st|nd|rd|th)"};
1425     case "w":
1426         return {g:0,
1427             c:null,
1428             s:"\\d"};
1429     case "z":
1430         return {g:0,
1431             c:null,
1432             s:"(?:\\d{1,3})"};
1433     case "W":
1434         return {g:0,
1435             c:null,
1436             s:"(?:\\d{2})"};
1437     case "F":
1438         return {g:1,
1439             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1440             s:"(" + Date.monthNames.join("|") + ")"};
1441     case "M":
1442         return {g:1,
1443             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1444             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1445     case "n":
1446         return {g:1,
1447             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1448             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1449     case "m":
1450         return {g:1,
1451             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1452             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1453     case "t":
1454         return {g:0,
1455             c:null,
1456             s:"\\d{1,2}"};
1457     case "L":
1458         return {g:0,
1459             c:null,
1460             s:"(?:1|0)"};
1461     case "Y":
1462         return {g:1,
1463             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1464             s:"(\\d{4})"};
1465     case "y":
1466         return {g:1,
1467             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1468                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1469             s:"(\\d{1,2})"};
1470     case "a":
1471         return {g:1,
1472             c:"if (results[" + currentGroup + "] == 'am') {\n"
1473                 + "if (h == 12) { h = 0; }\n"
1474                 + "} else { if (h < 12) { h += 12; }}",
1475             s:"(am|pm)"};
1476     case "A":
1477         return {g:1,
1478             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1479                 + "if (h == 12) { h = 0; }\n"
1480                 + "} else { if (h < 12) { h += 12; }}",
1481             s:"(AM|PM)"};
1482     case "g":
1483     case "G":
1484         return {g:1,
1485             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1486             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1487     case "h":
1488     case "H":
1489         return {g:1,
1490             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1491             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1492     case "i":
1493         return {g:1,
1494             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1495             s:"(\\d{2})"};
1496     case "s":
1497         return {g:1,
1498             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1499             s:"(\\d{2})"};
1500     case "O":
1501         return {g:1,
1502             c:[
1503                 "o = results[", currentGroup, "];\n",
1504                 "var sn = o.substring(0,1);\n", // get + / - sign
1505                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1506                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1507                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1508                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1509             ].join(""),
1510             s:"([+\-]\\d{2,4})"};
1511     
1512     
1513     case "P":
1514         return {g:1,
1515                 c:[
1516                    "o = results[", currentGroup, "];\n",
1517                    "var sn = o.substring(0,1);\n",
1518                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1519                    "var mn = o.substring(4,6) % 60;\n",
1520                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1521                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1522             ].join(""),
1523             s:"([+\-]\\d{4})"};
1524     case "T":
1525         return {g:0,
1526             c:null,
1527             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1528     case "Z":
1529         return {g:1,
1530             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1531                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1532             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1533     default:
1534         return {g:0,
1535             c:null,
1536             s:String.escape(character)};
1537     }
1538 };
1539
1540 /**
1541  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1542  * @return {String} The abbreviated timezone name (e.g. 'CST')
1543  */
1544 Date.prototype.getTimezone = function() {
1545     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1546 };
1547
1548 /**
1549  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1550  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1551  */
1552 Date.prototype.getGMTOffset = function() {
1553     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1554         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1555         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1556 };
1557
1558 /**
1559  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1560  * @return {String} 2-characters representing hours and 2-characters representing minutes
1561  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1562  */
1563 Date.prototype.getGMTColonOffset = function() {
1564         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1565                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1566                 + ":"
1567                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1568 }
1569
1570 /**
1571  * Get the numeric day number of the year, adjusted for leap year.
1572  * @return {Number} 0 through 364 (365 in leap years)
1573  */
1574 Date.prototype.getDayOfYear = function() {
1575     var num = 0;
1576     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1577     for (var i = 0; i < this.getMonth(); ++i) {
1578         num += Date.daysInMonth[i];
1579     }
1580     return num + this.getDate() - 1;
1581 };
1582
1583 /**
1584  * Get the string representation of the numeric week number of the year
1585  * (equivalent to the format specifier 'W').
1586  * @return {String} '00' through '52'
1587  */
1588 Date.prototype.getWeekOfYear = function() {
1589     // Skip to Thursday of this week
1590     var now = this.getDayOfYear() + (4 - this.getDay());
1591     // Find the first Thursday of the year
1592     var jan1 = new Date(this.getFullYear(), 0, 1);
1593     var then = (7 - jan1.getDay() + 4);
1594     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1595 };
1596
1597 /**
1598  * Whether or not the current date is in a leap year.
1599  * @return {Boolean} True if the current date is in a leap year, else false
1600  */
1601 Date.prototype.isLeapYear = function() {
1602     var year = this.getFullYear();
1603     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1604 };
1605
1606 /**
1607  * Get the first day of the current month, adjusted for leap year.  The returned value
1608  * is the numeric day index within the week (0-6) which can be used in conjunction with
1609  * the {@link #monthNames} array to retrieve the textual day name.
1610  * Example:
1611  *<pre><code>
1612 var dt = new Date('1/10/2007');
1613 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1614 </code></pre>
1615  * @return {Number} The day number (0-6)
1616  */
1617 Date.prototype.getFirstDayOfMonth = function() {
1618     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1619     return (day < 0) ? (day + 7) : day;
1620 };
1621
1622 /**
1623  * Get the last day of the current month, adjusted for leap year.  The returned value
1624  * is the numeric day index within the week (0-6) which can be used in conjunction with
1625  * the {@link #monthNames} array to retrieve the textual day name.
1626  * Example:
1627  *<pre><code>
1628 var dt = new Date('1/10/2007');
1629 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1630 </code></pre>
1631  * @return {Number} The day number (0-6)
1632  */
1633 Date.prototype.getLastDayOfMonth = function() {
1634     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1635     return (day < 0) ? (day + 7) : day;
1636 };
1637
1638
1639 /**
1640  * Get the first date of this date's month
1641  * @return {Date}
1642  */
1643 Date.prototype.getFirstDateOfMonth = function() {
1644     return new Date(this.getFullYear(), this.getMonth(), 1);
1645 };
1646
1647 /**
1648  * Get the last date of this date's month
1649  * @return {Date}
1650  */
1651 Date.prototype.getLastDateOfMonth = function() {
1652     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1653 };
1654 /**
1655  * Get the number of days in the current month, adjusted for leap year.
1656  * @return {Number} The number of days in the month
1657  */
1658 Date.prototype.getDaysInMonth = function() {
1659     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1660     return Date.daysInMonth[this.getMonth()];
1661 };
1662
1663 /**
1664  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1665  * @return {String} 'st, 'nd', 'rd' or 'th'
1666  */
1667 Date.prototype.getSuffix = function() {
1668     switch (this.getDate()) {
1669         case 1:
1670         case 21:
1671         case 31:
1672             return "st";
1673         case 2:
1674         case 22:
1675             return "nd";
1676         case 3:
1677         case 23:
1678             return "rd";
1679         default:
1680             return "th";
1681     }
1682 };
1683
1684 // private
1685 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1686
1687 /**
1688  * An array of textual month names.
1689  * Override these values for international dates, for example...
1690  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1691  * @type Array
1692  * @static
1693  */
1694 Date.monthNames =
1695    ["January",
1696     "February",
1697     "March",
1698     "April",
1699     "May",
1700     "June",
1701     "July",
1702     "August",
1703     "September",
1704     "October",
1705     "November",
1706     "December"];
1707
1708 /**
1709  * An array of textual day names.
1710  * Override these values for international dates, for example...
1711  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1712  * @type Array
1713  * @static
1714  */
1715 Date.dayNames =
1716    ["Sunday",
1717     "Monday",
1718     "Tuesday",
1719     "Wednesday",
1720     "Thursday",
1721     "Friday",
1722     "Saturday"];
1723
1724 // private
1725 Date.y2kYear = 50;
1726 // private
1727 Date.monthNumbers = {
1728     Jan:0,
1729     Feb:1,
1730     Mar:2,
1731     Apr:3,
1732     May:4,
1733     Jun:5,
1734     Jul:6,
1735     Aug:7,
1736     Sep:8,
1737     Oct:9,
1738     Nov:10,
1739     Dec:11};
1740
1741 /**
1742  * Creates and returns a new Date instance with the exact same date value as the called instance.
1743  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1744  * variable will also be changed.  When the intention is to create a new variable that will not
1745  * modify the original instance, you should create a clone.
1746  *
1747  * Example of correctly cloning a date:
1748  * <pre><code>
1749 //wrong way:
1750 var orig = new Date('10/1/2006');
1751 var copy = orig;
1752 copy.setDate(5);
1753 document.write(orig);  //returns 'Thu Oct 05 2006'!
1754
1755 //correct way:
1756 var orig = new Date('10/1/2006');
1757 var copy = orig.clone();
1758 copy.setDate(5);
1759 document.write(orig);  //returns 'Thu Oct 01 2006'
1760 </code></pre>
1761  * @return {Date} The new Date instance
1762  */
1763 Date.prototype.clone = function() {
1764         return new Date(this.getTime());
1765 };
1766
1767 /**
1768  * Clears any time information from this date
1769  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1770  @return {Date} this or the clone
1771  */
1772 Date.prototype.clearTime = function(clone){
1773     if(clone){
1774         return this.clone().clearTime();
1775     }
1776     this.setHours(0);
1777     this.setMinutes(0);
1778     this.setSeconds(0);
1779     this.setMilliseconds(0);
1780     return this;
1781 };
1782
1783 // private
1784 // safari setMonth is broken
1785 if(Roo.isSafari){
1786     Date.brokenSetMonth = Date.prototype.setMonth;
1787         Date.prototype.setMonth = function(num){
1788                 if(num <= -1){
1789                         var n = Math.ceil(-num);
1790                         var back_year = Math.ceil(n/12);
1791                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1792                         this.setFullYear(this.getFullYear() - back_year);
1793                         return Date.brokenSetMonth.call(this, month);
1794                 } else {
1795                         return Date.brokenSetMonth.apply(this, arguments);
1796                 }
1797         };
1798 }
1799
1800 /** Date interval constant 
1801 * @static 
1802 * @type String */
1803 Date.MILLI = "ms";
1804 /** Date interval constant 
1805 * @static 
1806 * @type String */
1807 Date.SECOND = "s";
1808 /** Date interval constant 
1809 * @static 
1810 * @type String */
1811 Date.MINUTE = "mi";
1812 /** Date interval constant 
1813 * @static 
1814 * @type String */
1815 Date.HOUR = "h";
1816 /** Date interval constant 
1817 * @static 
1818 * @type String */
1819 Date.DAY = "d";
1820 /** Date interval constant 
1821 * @static 
1822 * @type String */
1823 Date.MONTH = "mo";
1824 /** Date interval constant 
1825 * @static 
1826 * @type String */
1827 Date.YEAR = "y";
1828
1829 /**
1830  * Provides a convenient method of performing basic date arithmetic.  This method
1831  * does not modify the Date instance being called - it creates and returns
1832  * a new Date instance containing the resulting date value.
1833  *
1834  * Examples:
1835  * <pre><code>
1836 //Basic usage:
1837 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1838 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1839
1840 //Negative values will subtract correctly:
1841 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1842 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1843
1844 //You can even chain several calls together in one line!
1845 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1846 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1847  </code></pre>
1848  *
1849  * @param {String} interval   A valid date interval enum value
1850  * @param {Number} value      The amount to add to the current date
1851  * @return {Date} The new Date instance
1852  */
1853 Date.prototype.add = function(interval, value){
1854   var d = this.clone();
1855   if (!interval || value === 0) return d;
1856   switch(interval.toLowerCase()){
1857     case Date.MILLI:
1858       d.setMilliseconds(this.getMilliseconds() + value);
1859       break;
1860     case Date.SECOND:
1861       d.setSeconds(this.getSeconds() + value);
1862       break;
1863     case Date.MINUTE:
1864       d.setMinutes(this.getMinutes() + value);
1865       break;
1866     case Date.HOUR:
1867       d.setHours(this.getHours() + value);
1868       break;
1869     case Date.DAY:
1870       d.setDate(this.getDate() + value);
1871       break;
1872     case Date.MONTH:
1873       var day = this.getDate();
1874       if(day > 28){
1875           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1876       }
1877       d.setDate(day);
1878       d.setMonth(this.getMonth() + value);
1879       break;
1880     case Date.YEAR:
1881       d.setFullYear(this.getFullYear() + value);
1882       break;
1883   }
1884   return d;
1885 };
1886 /*
1887  * Based on:
1888  * Ext JS Library 1.1.1
1889  * Copyright(c) 2006-2007, Ext JS, LLC.
1890  *
1891  * Originally Released Under LGPL - original licence link has changed is not relivant.
1892  *
1893  * Fork - LGPL
1894  * <script type="text/javascript">
1895  */
1896
1897 /**
1898  * @class Roo.lib.Dom
1899  * @static
1900  * 
1901  * Dom utils (from YIU afaik)
1902  * 
1903  **/
1904 Roo.lib.Dom = {
1905     /**
1906      * Get the view width
1907      * @param {Boolean} full True will get the full document, otherwise it's the view width
1908      * @return {Number} The width
1909      */
1910      
1911     getViewWidth : function(full) {
1912         return full ? this.getDocumentWidth() : this.getViewportWidth();
1913     },
1914     /**
1915      * Get the view height
1916      * @param {Boolean} full True will get the full document, otherwise it's the view height
1917      * @return {Number} The height
1918      */
1919     getViewHeight : function(full) {
1920         return full ? this.getDocumentHeight() : this.getViewportHeight();
1921     },
1922
1923     getDocumentHeight: function() {
1924         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1925         return Math.max(scrollHeight, this.getViewportHeight());
1926     },
1927
1928     getDocumentWidth: function() {
1929         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1930         return Math.max(scrollWidth, this.getViewportWidth());
1931     },
1932
1933     getViewportHeight: function() {
1934         var height = self.innerHeight;
1935         var mode = document.compatMode;
1936
1937         if ((mode || Roo.isIE) && !Roo.isOpera) {
1938             height = (mode == "CSS1Compat") ?
1939                      document.documentElement.clientHeight :
1940                      document.body.clientHeight;
1941         }
1942
1943         return height;
1944     },
1945
1946     getViewportWidth: function() {
1947         var width = self.innerWidth;
1948         var mode = document.compatMode;
1949
1950         if (mode || Roo.isIE) {
1951             width = (mode == "CSS1Compat") ?
1952                     document.documentElement.clientWidth :
1953                     document.body.clientWidth;
1954         }
1955         return width;
1956     },
1957
1958     isAncestor : function(p, c) {
1959         p = Roo.getDom(p);
1960         c = Roo.getDom(c);
1961         if (!p || !c) {
1962             return false;
1963         }
1964
1965         if (p.contains && !Roo.isSafari) {
1966             return p.contains(c);
1967         } else if (p.compareDocumentPosition) {
1968             return !!(p.compareDocumentPosition(c) & 16);
1969         } else {
1970             var parent = c.parentNode;
1971             while (parent) {
1972                 if (parent == p) {
1973                     return true;
1974                 }
1975                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1976                     return false;
1977                 }
1978                 parent = parent.parentNode;
1979             }
1980             return false;
1981         }
1982     },
1983
1984     getRegion : function(el) {
1985         return Roo.lib.Region.getRegion(el);
1986     },
1987
1988     getY : function(el) {
1989         return this.getXY(el)[1];
1990     },
1991
1992     getX : function(el) {
1993         return this.getXY(el)[0];
1994     },
1995
1996     getXY : function(el) {
1997         var p, pe, b, scroll, bd = document.body;
1998         el = Roo.getDom(el);
1999         var fly = Roo.lib.AnimBase.fly;
2000         if (el.getBoundingClientRect) {
2001             b = el.getBoundingClientRect();
2002             scroll = fly(document).getScroll();
2003             return [b.left + scroll.left, b.top + scroll.top];
2004         }
2005         var x = 0, y = 0;
2006
2007         p = el;
2008
2009         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2010
2011         while (p) {
2012
2013             x += p.offsetLeft;
2014             y += p.offsetTop;
2015
2016             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2017                 hasAbsolute = true;
2018             }
2019
2020             if (Roo.isGecko) {
2021                 pe = fly(p);
2022
2023                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2024                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2025
2026
2027                 x += bl;
2028                 y += bt;
2029
2030
2031                 if (p != el && pe.getStyle('overflow') != 'visible') {
2032                     x += bl;
2033                     y += bt;
2034                 }
2035             }
2036             p = p.offsetParent;
2037         }
2038
2039         if (Roo.isSafari && hasAbsolute) {
2040             x -= bd.offsetLeft;
2041             y -= bd.offsetTop;
2042         }
2043
2044         if (Roo.isGecko && !hasAbsolute) {
2045             var dbd = fly(bd);
2046             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2047             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2048         }
2049
2050         p = el.parentNode;
2051         while (p && p != bd) {
2052             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2053                 x -= p.scrollLeft;
2054                 y -= p.scrollTop;
2055             }
2056             p = p.parentNode;
2057         }
2058         return [x, y];
2059     },
2060  
2061   
2062
2063
2064     setXY : function(el, xy) {
2065         el = Roo.fly(el, '_setXY');
2066         el.position();
2067         var pts = el.translatePoints(xy);
2068         if (xy[0] !== false) {
2069             el.dom.style.left = pts.left + "px";
2070         }
2071         if (xy[1] !== false) {
2072             el.dom.style.top = pts.top + "px";
2073         }
2074     },
2075
2076     setX : function(el, x) {
2077         this.setXY(el, [x, false]);
2078     },
2079
2080     setY : function(el, y) {
2081         this.setXY(el, [false, y]);
2082     }
2083 };
2084 /*
2085  * Portions of this file are based on pieces of Yahoo User Interface Library
2086  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2087  * YUI licensed under the BSD License:
2088  * http://developer.yahoo.net/yui/license.txt
2089  * <script type="text/javascript">
2090  *
2091  */
2092
2093 Roo.lib.Event = function() {
2094     var loadComplete = false;
2095     var listeners = [];
2096     var unloadListeners = [];
2097     var retryCount = 0;
2098     var onAvailStack = [];
2099     var counter = 0;
2100     var lastError = null;
2101
2102     return {
2103         POLL_RETRYS: 200,
2104         POLL_INTERVAL: 20,
2105         EL: 0,
2106         TYPE: 1,
2107         FN: 2,
2108         WFN: 3,
2109         OBJ: 3,
2110         ADJ_SCOPE: 4,
2111         _interval: null,
2112
2113         startInterval: function() {
2114             if (!this._interval) {
2115                 var self = this;
2116                 var callback = function() {
2117                     self._tryPreloadAttach();
2118                 };
2119                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2120
2121             }
2122         },
2123
2124         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2125             onAvailStack.push({ id:         p_id,
2126                 fn:         p_fn,
2127                 obj:        p_obj,
2128                 override:   p_override,
2129                 checkReady: false    });
2130
2131             retryCount = this.POLL_RETRYS;
2132             this.startInterval();
2133         },
2134
2135
2136         addListener: function(el, eventName, fn) {
2137             el = Roo.getDom(el);
2138             if (!el || !fn) {
2139                 return false;
2140             }
2141
2142             if ("unload" == eventName) {
2143                 unloadListeners[unloadListeners.length] =
2144                 [el, eventName, fn];
2145                 return true;
2146             }
2147
2148             var wrappedFn = function(e) {
2149                 return fn(Roo.lib.Event.getEvent(e));
2150             };
2151
2152             var li = [el, eventName, fn, wrappedFn];
2153
2154             var index = listeners.length;
2155             listeners[index] = li;
2156
2157             this.doAdd(el, eventName, wrappedFn, false);
2158             return true;
2159
2160         },
2161
2162
2163         removeListener: function(el, eventName, fn) {
2164             var i, len;
2165
2166             el = Roo.getDom(el);
2167
2168             if(!fn) {
2169                 return this.purgeElement(el, false, eventName);
2170             }
2171
2172
2173             if ("unload" == eventName) {
2174
2175                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2176                     var li = unloadListeners[i];
2177                     if (li &&
2178                         li[0] == el &&
2179                         li[1] == eventName &&
2180                         li[2] == fn) {
2181                         unloadListeners.splice(i, 1);
2182                         return true;
2183                     }
2184                 }
2185
2186                 return false;
2187             }
2188
2189             var cacheItem = null;
2190
2191
2192             var index = arguments[3];
2193
2194             if ("undefined" == typeof index) {
2195                 index = this._getCacheIndex(el, eventName, fn);
2196             }
2197
2198             if (index >= 0) {
2199                 cacheItem = listeners[index];
2200             }
2201
2202             if (!el || !cacheItem) {
2203                 return false;
2204             }
2205
2206             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2207
2208             delete listeners[index][this.WFN];
2209             delete listeners[index][this.FN];
2210             listeners.splice(index, 1);
2211
2212             return true;
2213
2214         },
2215
2216
2217         getTarget: function(ev, resolveTextNode) {
2218             ev = ev.browserEvent || ev;
2219             var t = ev.target || ev.srcElement;
2220             return this.resolveTextNode(t);
2221         },
2222
2223
2224         resolveTextNode: function(node) {
2225             if (Roo.isSafari && node && 3 == node.nodeType) {
2226                 return node.parentNode;
2227             } else {
2228                 return node;
2229             }
2230         },
2231
2232
2233         getPageX: function(ev) {
2234             ev = ev.browserEvent || ev;
2235             var x = ev.pageX;
2236             if (!x && 0 !== x) {
2237                 x = ev.clientX || 0;
2238
2239                 if (Roo.isIE) {
2240                     x += this.getScroll()[1];
2241                 }
2242             }
2243
2244             return x;
2245         },
2246
2247
2248         getPageY: function(ev) {
2249             ev = ev.browserEvent || ev;
2250             var y = ev.pageY;
2251             if (!y && 0 !== y) {
2252                 y = ev.clientY || 0;
2253
2254                 if (Roo.isIE) {
2255                     y += this.getScroll()[0];
2256                 }
2257             }
2258
2259
2260             return y;
2261         },
2262
2263
2264         getXY: function(ev) {
2265             ev = ev.browserEvent || ev;
2266             return [this.getPageX(ev), this.getPageY(ev)];
2267         },
2268
2269
2270         getRelatedTarget: function(ev) {
2271             ev = ev.browserEvent || ev;
2272             var t = ev.relatedTarget;
2273             if (!t) {
2274                 if (ev.type == "mouseout") {
2275                     t = ev.toElement;
2276                 } else if (ev.type == "mouseover") {
2277                     t = ev.fromElement;
2278                 }
2279             }
2280
2281             return this.resolveTextNode(t);
2282         },
2283
2284
2285         getTime: function(ev) {
2286             ev = ev.browserEvent || ev;
2287             if (!ev.time) {
2288                 var t = new Date().getTime();
2289                 try {
2290                     ev.time = t;
2291                 } catch(ex) {
2292                     this.lastError = ex;
2293                     return t;
2294                 }
2295             }
2296
2297             return ev.time;
2298         },
2299
2300
2301         stopEvent: function(ev) {
2302             this.stopPropagation(ev);
2303             this.preventDefault(ev);
2304         },
2305
2306
2307         stopPropagation: function(ev) {
2308             ev = ev.browserEvent || ev;
2309             if (ev.stopPropagation) {
2310                 ev.stopPropagation();
2311             } else {
2312                 ev.cancelBubble = true;
2313             }
2314         },
2315
2316
2317         preventDefault: function(ev) {
2318             ev = ev.browserEvent || ev;
2319             if(ev.preventDefault) {
2320                 ev.preventDefault();
2321             } else {
2322                 ev.returnValue = false;
2323             }
2324         },
2325
2326
2327         getEvent: function(e) {
2328             var ev = e || window.event;
2329             if (!ev) {
2330                 var c = this.getEvent.caller;
2331                 while (c) {
2332                     ev = c.arguments[0];
2333                     if (ev && Event == ev.constructor) {
2334                         break;
2335                     }
2336                     c = c.caller;
2337                 }
2338             }
2339             return ev;
2340         },
2341
2342
2343         getCharCode: function(ev) {
2344             ev = ev.browserEvent || ev;
2345             return ev.charCode || ev.keyCode || 0;
2346         },
2347
2348
2349         _getCacheIndex: function(el, eventName, fn) {
2350             for (var i = 0,len = listeners.length; i < len; ++i) {
2351                 var li = listeners[i];
2352                 if (li &&
2353                     li[this.FN] == fn &&
2354                     li[this.EL] == el &&
2355                     li[this.TYPE] == eventName) {
2356                     return i;
2357                 }
2358             }
2359
2360             return -1;
2361         },
2362
2363
2364         elCache: {},
2365
2366
2367         getEl: function(id) {
2368             return document.getElementById(id);
2369         },
2370
2371
2372         clearCache: function() {
2373         },
2374
2375
2376         _load: function(e) {
2377             loadComplete = true;
2378             var EU = Roo.lib.Event;
2379
2380
2381             if (Roo.isIE) {
2382                 EU.doRemove(window, "load", EU._load);
2383             }
2384         },
2385
2386
2387         _tryPreloadAttach: function() {
2388
2389             if (this.locked) {
2390                 return false;
2391             }
2392
2393             this.locked = true;
2394
2395
2396             var tryAgain = !loadComplete;
2397             if (!tryAgain) {
2398                 tryAgain = (retryCount > 0);
2399             }
2400
2401
2402             var notAvail = [];
2403             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2404                 var item = onAvailStack[i];
2405                 if (item) {
2406                     var el = this.getEl(item.id);
2407
2408                     if (el) {
2409                         if (!item.checkReady ||
2410                             loadComplete ||
2411                             el.nextSibling ||
2412                             (document && document.body)) {
2413
2414                             var scope = el;
2415                             if (item.override) {
2416                                 if (item.override === true) {
2417                                     scope = item.obj;
2418                                 } else {
2419                                     scope = item.override;
2420                                 }
2421                             }
2422                             item.fn.call(scope, item.obj);
2423                             onAvailStack[i] = null;
2424                         }
2425                     } else {
2426                         notAvail.push(item);
2427                     }
2428                 }
2429             }
2430
2431             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2432
2433             if (tryAgain) {
2434
2435                 this.startInterval();
2436             } else {
2437                 clearInterval(this._interval);
2438                 this._interval = null;
2439             }
2440
2441             this.locked = false;
2442
2443             return true;
2444
2445         },
2446
2447
2448         purgeElement: function(el, recurse, eventName) {
2449             var elListeners = this.getListeners(el, eventName);
2450             if (elListeners) {
2451                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2452                     var l = elListeners[i];
2453                     this.removeListener(el, l.type, l.fn);
2454                 }
2455             }
2456
2457             if (recurse && el && el.childNodes) {
2458                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2459                     this.purgeElement(el.childNodes[i], recurse, eventName);
2460                 }
2461             }
2462         },
2463
2464
2465         getListeners: function(el, eventName) {
2466             var results = [], searchLists;
2467             if (!eventName) {
2468                 searchLists = [listeners, unloadListeners];
2469             } else if (eventName == "unload") {
2470                 searchLists = [unloadListeners];
2471             } else {
2472                 searchLists = [listeners];
2473             }
2474
2475             for (var j = 0; j < searchLists.length; ++j) {
2476                 var searchList = searchLists[j];
2477                 if (searchList && searchList.length > 0) {
2478                     for (var i = 0,len = searchList.length; i < len; ++i) {
2479                         var l = searchList[i];
2480                         if (l && l[this.EL] === el &&
2481                             (!eventName || eventName === l[this.TYPE])) {
2482                             results.push({
2483                                 type:   l[this.TYPE],
2484                                 fn:     l[this.FN],
2485                                 obj:    l[this.OBJ],
2486                                 adjust: l[this.ADJ_SCOPE],
2487                                 index:  i
2488                             });
2489                         }
2490                     }
2491                 }
2492             }
2493
2494             return (results.length) ? results : null;
2495         },
2496
2497
2498         _unload: function(e) {
2499
2500             var EU = Roo.lib.Event, i, j, l, len, index;
2501
2502             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2503                 l = unloadListeners[i];
2504                 if (l) {
2505                     var scope = window;
2506                     if (l[EU.ADJ_SCOPE]) {
2507                         if (l[EU.ADJ_SCOPE] === true) {
2508                             scope = l[EU.OBJ];
2509                         } else {
2510                             scope = l[EU.ADJ_SCOPE];
2511                         }
2512                     }
2513                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2514                     unloadListeners[i] = null;
2515                     l = null;
2516                     scope = null;
2517                 }
2518             }
2519
2520             unloadListeners = null;
2521
2522             if (listeners && listeners.length > 0) {
2523                 j = listeners.length;
2524                 while (j) {
2525                     index = j - 1;
2526                     l = listeners[index];
2527                     if (l) {
2528                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2529                                 l[EU.FN], index);
2530                     }
2531                     j = j - 1;
2532                 }
2533                 l = null;
2534
2535                 EU.clearCache();
2536             }
2537
2538             EU.doRemove(window, "unload", EU._unload);
2539
2540         },
2541
2542
2543         getScroll: function() {
2544             var dd = document.documentElement, db = document.body;
2545             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2546                 return [dd.scrollTop, dd.scrollLeft];
2547             } else if (db) {
2548                 return [db.scrollTop, db.scrollLeft];
2549             } else {
2550                 return [0, 0];
2551             }
2552         },
2553
2554
2555         doAdd: function () {
2556             if (window.addEventListener) {
2557                 return function(el, eventName, fn, capture) {
2558                     el.addEventListener(eventName, fn, (capture));
2559                 };
2560             } else if (window.attachEvent) {
2561                 return function(el, eventName, fn, capture) {
2562                     el.attachEvent("on" + eventName, fn);
2563                 };
2564             } else {
2565                 return function() {
2566                 };
2567             }
2568         }(),
2569
2570
2571         doRemove: function() {
2572             if (window.removeEventListener) {
2573                 return function (el, eventName, fn, capture) {
2574                     el.removeEventListener(eventName, fn, (capture));
2575                 };
2576             } else if (window.detachEvent) {
2577                 return function (el, eventName, fn) {
2578                     el.detachEvent("on" + eventName, fn);
2579                 };
2580             } else {
2581                 return function() {
2582                 };
2583             }
2584         }()
2585     };
2586     
2587 }();
2588 (function() {     
2589    
2590     var E = Roo.lib.Event;
2591     E.on = E.addListener;
2592     E.un = E.removeListener;
2593
2594     if (document && document.body) {
2595         E._load();
2596     } else {
2597         E.doAdd(window, "load", E._load);
2598     }
2599     E.doAdd(window, "unload", E._unload);
2600     E._tryPreloadAttach();
2601 })();
2602
2603 /*
2604  * Portions of this file are based on pieces of Yahoo User Interface Library
2605  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2606  * YUI licensed under the BSD License:
2607  * http://developer.yahoo.net/yui/license.txt
2608  * <script type="text/javascript">
2609  *
2610  */
2611
2612 (function() {
2613     /**
2614      * @class Roo.lib.Ajax
2615      *
2616      */
2617     Roo.lib.Ajax = {
2618         /**
2619          * @static 
2620          */
2621         request : function(method, uri, cb, data, options) {
2622             if(options){
2623                 var hs = options.headers;
2624                 if(hs){
2625                     for(var h in hs){
2626                         if(hs.hasOwnProperty(h)){
2627                             this.initHeader(h, hs[h], false);
2628                         }
2629                     }
2630                 }
2631                 if(options.xmlData){
2632                     this.initHeader('Content-Type', 'text/xml', false);
2633                     method = 'POST';
2634                     data = options.xmlData;
2635                 }
2636             }
2637
2638             return this.asyncRequest(method, uri, cb, data);
2639         },
2640
2641         serializeForm : function(form) {
2642             if(typeof form == 'string') {
2643                 form = (document.getElementById(form) || document.forms[form]);
2644             }
2645
2646             var el, name, val, disabled, data = '', hasSubmit = false;
2647             for (var i = 0; i < form.elements.length; i++) {
2648                 el = form.elements[i];
2649                 disabled = form.elements[i].disabled;
2650                 name = form.elements[i].name;
2651                 val = form.elements[i].value;
2652
2653                 if (!disabled && name){
2654                     switch (el.type)
2655                             {
2656                         case 'select-one':
2657                         case 'select-multiple':
2658                             for (var j = 0; j < el.options.length; j++) {
2659                                 if (el.options[j].selected) {
2660                                     if (Roo.isIE) {
2661                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2662                                     }
2663                                     else {
2664                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2665                                     }
2666                                 }
2667                             }
2668                             break;
2669                         case 'radio':
2670                         case 'checkbox':
2671                             if (el.checked) {
2672                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2673                             }
2674                             break;
2675                         case 'file':
2676
2677                         case undefined:
2678
2679                         case 'reset':
2680
2681                         case 'button':
2682
2683                             break;
2684                         case 'submit':
2685                             if(hasSubmit == false) {
2686                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2687                                 hasSubmit = true;
2688                             }
2689                             break;
2690                         default:
2691                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2692                             break;
2693                     }
2694                 }
2695             }
2696             data = data.substr(0, data.length - 1);
2697             return data;
2698         },
2699
2700         headers:{},
2701
2702         hasHeaders:false,
2703
2704         useDefaultHeader:true,
2705
2706         defaultPostHeader:'application/x-www-form-urlencoded',
2707
2708         useDefaultXhrHeader:true,
2709
2710         defaultXhrHeader:'XMLHttpRequest',
2711
2712         hasDefaultHeaders:true,
2713
2714         defaultHeaders:{},
2715
2716         poll:{},
2717
2718         timeout:{},
2719
2720         pollInterval:50,
2721
2722         transactionId:0,
2723
2724         setProgId:function(id)
2725         {
2726             this.activeX.unshift(id);
2727         },
2728
2729         setDefaultPostHeader:function(b)
2730         {
2731             this.useDefaultHeader = b;
2732         },
2733
2734         setDefaultXhrHeader:function(b)
2735         {
2736             this.useDefaultXhrHeader = b;
2737         },
2738
2739         setPollingInterval:function(i)
2740         {
2741             if (typeof i == 'number' && isFinite(i)) {
2742                 this.pollInterval = i;
2743             }
2744         },
2745
2746         createXhrObject:function(transactionId)
2747         {
2748             var obj,http;
2749             try
2750             {
2751
2752                 http = new XMLHttpRequest();
2753
2754                 obj = { conn:http, tId:transactionId };
2755             }
2756             catch(e)
2757             {
2758                 for (var i = 0; i < this.activeX.length; ++i) {
2759                     try
2760                     {
2761
2762                         http = new ActiveXObject(this.activeX[i]);
2763
2764                         obj = { conn:http, tId:transactionId };
2765                         break;
2766                     }
2767                     catch(e) {
2768                     }
2769                 }
2770             }
2771             finally
2772             {
2773                 return obj;
2774             }
2775         },
2776
2777         getConnectionObject:function()
2778         {
2779             var o;
2780             var tId = this.transactionId;
2781
2782             try
2783             {
2784                 o = this.createXhrObject(tId);
2785                 if (o) {
2786                     this.transactionId++;
2787                 }
2788             }
2789             catch(e) {
2790             }
2791             finally
2792             {
2793                 return o;
2794             }
2795         },
2796
2797         asyncRequest:function(method, uri, callback, postData)
2798         {
2799             var o = this.getConnectionObject();
2800
2801             if (!o) {
2802                 return null;
2803             }
2804             else {
2805                 o.conn.open(method, uri, true);
2806
2807                 if (this.useDefaultXhrHeader) {
2808                     if (!this.defaultHeaders['X-Requested-With']) {
2809                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2810                     }
2811                 }
2812
2813                 if(postData && this.useDefaultHeader){
2814                     this.initHeader('Content-Type', this.defaultPostHeader);
2815                 }
2816
2817                  if (this.hasDefaultHeaders || this.hasHeaders) {
2818                     this.setHeader(o);
2819                 }
2820
2821                 this.handleReadyState(o, callback);
2822                 o.conn.send(postData || null);
2823
2824                 return o;
2825             }
2826         },
2827
2828         handleReadyState:function(o, callback)
2829         {
2830             var oConn = this;
2831
2832             if (callback && callback.timeout) {
2833                 
2834                 this.timeout[o.tId] = window.setTimeout(function() {
2835                     oConn.abort(o, callback, true);
2836                 }, callback.timeout);
2837             }
2838
2839             this.poll[o.tId] = window.setInterval(
2840                     function() {
2841                         if (o.conn && o.conn.readyState == 4) {
2842                             window.clearInterval(oConn.poll[o.tId]);
2843                             delete oConn.poll[o.tId];
2844
2845                             if(callback && callback.timeout) {
2846                                 window.clearTimeout(oConn.timeout[o.tId]);
2847                                 delete oConn.timeout[o.tId];
2848                             }
2849
2850                             oConn.handleTransactionResponse(o, callback);
2851                         }
2852                     }
2853                     , this.pollInterval);
2854         },
2855
2856         handleTransactionResponse:function(o, callback, isAbort)
2857         {
2858
2859             if (!callback) {
2860                 this.releaseObject(o);
2861                 return;
2862             }
2863
2864             var httpStatus, responseObject;
2865
2866             try
2867             {
2868                 if (o.conn.status !== undefined && o.conn.status != 0) {
2869                     httpStatus = o.conn.status;
2870                 }
2871                 else {
2872                     httpStatus = 13030;
2873                 }
2874             }
2875             catch(e) {
2876
2877
2878                 httpStatus = 13030;
2879             }
2880
2881             if (httpStatus >= 200 && httpStatus < 300) {
2882                 responseObject = this.createResponseObject(o, callback.argument);
2883                 if (callback.success) {
2884                     if (!callback.scope) {
2885                         callback.success(responseObject);
2886                     }
2887                     else {
2888
2889
2890                         callback.success.apply(callback.scope, [responseObject]);
2891                     }
2892                 }
2893             }
2894             else {
2895                 switch (httpStatus) {
2896
2897                     case 12002:
2898                     case 12029:
2899                     case 12030:
2900                     case 12031:
2901                     case 12152:
2902                     case 13030:
2903                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2904                         if (callback.failure) {
2905                             if (!callback.scope) {
2906                                 callback.failure(responseObject);
2907                             }
2908                             else {
2909                                 callback.failure.apply(callback.scope, [responseObject]);
2910                             }
2911                         }
2912                         break;
2913                     default:
2914                         responseObject = this.createResponseObject(o, callback.argument);
2915                         if (callback.failure) {
2916                             if (!callback.scope) {
2917                                 callback.failure(responseObject);
2918                             }
2919                             else {
2920                                 callback.failure.apply(callback.scope, [responseObject]);
2921                             }
2922                         }
2923                 }
2924             }
2925
2926             this.releaseObject(o);
2927             responseObject = null;
2928         },
2929
2930         createResponseObject:function(o, callbackArg)
2931         {
2932             var obj = {};
2933             var headerObj = {};
2934
2935             try
2936             {
2937                 var headerStr = o.conn.getAllResponseHeaders();
2938                 var header = headerStr.split('\n');
2939                 for (var i = 0; i < header.length; i++) {
2940                     var delimitPos = header[i].indexOf(':');
2941                     if (delimitPos != -1) {
2942                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2943                     }
2944                 }
2945             }
2946             catch(e) {
2947             }
2948
2949             obj.tId = o.tId;
2950             obj.status = o.conn.status;
2951             obj.statusText = o.conn.statusText;
2952             obj.getResponseHeader = headerObj;
2953             obj.getAllResponseHeaders = headerStr;
2954             obj.responseText = o.conn.responseText;
2955             obj.responseXML = o.conn.responseXML;
2956
2957             if (typeof callbackArg !== undefined) {
2958                 obj.argument = callbackArg;
2959             }
2960
2961             return obj;
2962         },
2963
2964         createExceptionObject:function(tId, callbackArg, isAbort)
2965         {
2966             var COMM_CODE = 0;
2967             var COMM_ERROR = 'communication failure';
2968             var ABORT_CODE = -1;
2969             var ABORT_ERROR = 'transaction aborted';
2970
2971             var obj = {};
2972
2973             obj.tId = tId;
2974             if (isAbort) {
2975                 obj.status = ABORT_CODE;
2976                 obj.statusText = ABORT_ERROR;
2977             }
2978             else {
2979                 obj.status = COMM_CODE;
2980                 obj.statusText = COMM_ERROR;
2981             }
2982
2983             if (callbackArg) {
2984                 obj.argument = callbackArg;
2985             }
2986
2987             return obj;
2988         },
2989
2990         initHeader:function(label, value, isDefault)
2991         {
2992             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2993
2994             if (headerObj[label] === undefined) {
2995                 headerObj[label] = value;
2996             }
2997             else {
2998
2999
3000                 headerObj[label] = value + "," + headerObj[label];
3001             }
3002
3003             if (isDefault) {
3004                 this.hasDefaultHeaders = true;
3005             }
3006             else {
3007                 this.hasHeaders = true;
3008             }
3009         },
3010
3011
3012         setHeader:function(o)
3013         {
3014             if (this.hasDefaultHeaders) {
3015                 for (var prop in this.defaultHeaders) {
3016                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3017                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3018                     }
3019                 }
3020             }
3021
3022             if (this.hasHeaders) {
3023                 for (var prop in this.headers) {
3024                     if (this.headers.hasOwnProperty(prop)) {
3025                         o.conn.setRequestHeader(prop, this.headers[prop]);
3026                     }
3027                 }
3028                 this.headers = {};
3029                 this.hasHeaders = false;
3030             }
3031         },
3032
3033         resetDefaultHeaders:function() {
3034             delete this.defaultHeaders;
3035             this.defaultHeaders = {};
3036             this.hasDefaultHeaders = false;
3037         },
3038
3039         abort:function(o, callback, isTimeout)
3040         {
3041             if(this.isCallInProgress(o)) {
3042                 o.conn.abort();
3043                 window.clearInterval(this.poll[o.tId]);
3044                 delete this.poll[o.tId];
3045                 if (isTimeout) {
3046                     delete this.timeout[o.tId];
3047                 }
3048
3049                 this.handleTransactionResponse(o, callback, true);
3050
3051                 return true;
3052             }
3053             else {
3054                 return false;
3055             }
3056         },
3057
3058
3059         isCallInProgress:function(o)
3060         {
3061             if (o && o.conn) {
3062                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3063             }
3064             else {
3065
3066                 return false;
3067             }
3068         },
3069
3070
3071         releaseObject:function(o)
3072         {
3073
3074             o.conn = null;
3075
3076             o = null;
3077         },
3078
3079         activeX:[
3080         'MSXML2.XMLHTTP.3.0',
3081         'MSXML2.XMLHTTP',
3082         'Microsoft.XMLHTTP'
3083         ]
3084
3085
3086     };
3087 })();/*
3088  * Portions of this file are based on pieces of Yahoo User Interface Library
3089  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3090  * YUI licensed under the BSD License:
3091  * http://developer.yahoo.net/yui/license.txt
3092  * <script type="text/javascript">
3093  *
3094  */
3095
3096 Roo.lib.Region = function(t, r, b, l) {
3097     this.top = t;
3098     this[1] = t;
3099     this.right = r;
3100     this.bottom = b;
3101     this.left = l;
3102     this[0] = l;
3103 };
3104
3105
3106 Roo.lib.Region.prototype = {
3107     contains : function(region) {
3108         return ( region.left >= this.left &&
3109                  region.right <= this.right &&
3110                  region.top >= this.top &&
3111                  region.bottom <= this.bottom    );
3112
3113     },
3114
3115     getArea : function() {
3116         return ( (this.bottom - this.top) * (this.right - this.left) );
3117     },
3118
3119     intersect : function(region) {
3120         var t = Math.max(this.top, region.top);
3121         var r = Math.min(this.right, region.right);
3122         var b = Math.min(this.bottom, region.bottom);
3123         var l = Math.max(this.left, region.left);
3124
3125         if (b >= t && r >= l) {
3126             return new Roo.lib.Region(t, r, b, l);
3127         } else {
3128             return null;
3129         }
3130     },
3131     union : function(region) {
3132         var t = Math.min(this.top, region.top);
3133         var r = Math.max(this.right, region.right);
3134         var b = Math.max(this.bottom, region.bottom);
3135         var l = Math.min(this.left, region.left);
3136
3137         return new Roo.lib.Region(t, r, b, l);
3138     },
3139
3140     adjust : function(t, l, b, r) {
3141         this.top += t;
3142         this.left += l;
3143         this.right += r;
3144         this.bottom += b;
3145         return this;
3146     }
3147 };
3148
3149 Roo.lib.Region.getRegion = function(el) {
3150     var p = Roo.lib.Dom.getXY(el);
3151
3152     var t = p[1];
3153     var r = p[0] + el.offsetWidth;
3154     var b = p[1] + el.offsetHeight;
3155     var l = p[0];
3156
3157     return new Roo.lib.Region(t, r, b, l);
3158 };
3159 /*
3160  * Portions of this file are based on pieces of Yahoo User Interface Library
3161  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3162  * YUI licensed under the BSD License:
3163  * http://developer.yahoo.net/yui/license.txt
3164  * <script type="text/javascript">
3165  *
3166  */
3167 //@@dep Roo.lib.Region
3168
3169
3170 Roo.lib.Point = function(x, y) {
3171     if (x instanceof Array) {
3172         y = x[1];
3173         x = x[0];
3174     }
3175     this.x = this.right = this.left = this[0] = x;
3176     this.y = this.top = this.bottom = this[1] = y;
3177 };
3178
3179 Roo.lib.Point.prototype = new Roo.lib.Region();
3180 /*
3181  * Portions of this file are based on pieces of Yahoo User Interface Library
3182  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3183  * YUI licensed under the BSD License:
3184  * http://developer.yahoo.net/yui/license.txt
3185  * <script type="text/javascript">
3186  *
3187  */
3188  
3189 (function() {   
3190
3191     Roo.lib.Anim = {
3192         scroll : function(el, args, duration, easing, cb, scope) {
3193             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3194         },
3195
3196         motion : function(el, args, duration, easing, cb, scope) {
3197             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3198         },
3199
3200         color : function(el, args, duration, easing, cb, scope) {
3201             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3202         },
3203
3204         run : function(el, args, duration, easing, cb, scope, type) {
3205             type = type || Roo.lib.AnimBase;
3206             if (typeof easing == "string") {
3207                 easing = Roo.lib.Easing[easing];
3208             }
3209             var anim = new type(el, args, duration, easing);
3210             anim.animateX(function() {
3211                 Roo.callback(cb, scope);
3212             });
3213             return anim;
3214         }
3215     };
3216 })();/*
3217  * Portions of this file are based on pieces of Yahoo User Interface Library
3218  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3219  * YUI licensed under the BSD License:
3220  * http://developer.yahoo.net/yui/license.txt
3221  * <script type="text/javascript">
3222  *
3223  */
3224
3225 (function() {    
3226     var libFlyweight;
3227     
3228     function fly(el) {
3229         if (!libFlyweight) {
3230             libFlyweight = new Roo.Element.Flyweight();
3231         }
3232         libFlyweight.dom = el;
3233         return libFlyweight;
3234     }
3235
3236     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3237     
3238    
3239     
3240     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3241         if (el) {
3242             this.init(el, attributes, duration, method);
3243         }
3244     };
3245
3246     Roo.lib.AnimBase.fly = fly;
3247     
3248     
3249     
3250     Roo.lib.AnimBase.prototype = {
3251
3252         toString: function() {
3253             var el = this.getEl();
3254             var id = el.id || el.tagName;
3255             return ("Anim " + id);
3256         },
3257
3258         patterns: {
3259             noNegatives:        /width|height|opacity|padding/i,
3260             offsetAttribute:  /^((width|height)|(top|left))$/,
3261             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3262             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3263         },
3264
3265
3266         doMethod: function(attr, start, end) {
3267             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3268         },
3269
3270
3271         setAttribute: function(attr, val, unit) {
3272             if (this.patterns.noNegatives.test(attr)) {
3273                 val = (val > 0) ? val : 0;
3274             }
3275
3276             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3277         },
3278
3279
3280         getAttribute: function(attr) {
3281             var el = this.getEl();
3282             var val = fly(el).getStyle(attr);
3283
3284             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3285                 return parseFloat(val);
3286             }
3287
3288             var a = this.patterns.offsetAttribute.exec(attr) || [];
3289             var pos = !!( a[3] );
3290             var box = !!( a[2] );
3291
3292
3293             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3294                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3295             } else {
3296                 val = 0;
3297             }
3298
3299             return val;
3300         },
3301
3302
3303         getDefaultUnit: function(attr) {
3304             if (this.patterns.defaultUnit.test(attr)) {
3305                 return 'px';
3306             }
3307
3308             return '';
3309         },
3310
3311         animateX : function(callback, scope) {
3312             var f = function() {
3313                 this.onComplete.removeListener(f);
3314                 if (typeof callback == "function") {
3315                     callback.call(scope || this, this);
3316                 }
3317             };
3318             this.onComplete.addListener(f, this);
3319             this.animate();
3320         },
3321
3322
3323         setRuntimeAttribute: function(attr) {
3324             var start;
3325             var end;
3326             var attributes = this.attributes;
3327
3328             this.runtimeAttributes[attr] = {};
3329
3330             var isset = function(prop) {
3331                 return (typeof prop !== 'undefined');
3332             };
3333
3334             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3335                 return false;
3336             }
3337
3338             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3339
3340
3341             if (isset(attributes[attr]['to'])) {
3342                 end = attributes[attr]['to'];
3343             } else if (isset(attributes[attr]['by'])) {
3344                 if (start.constructor == Array) {
3345                     end = [];
3346                     for (var i = 0, len = start.length; i < len; ++i) {
3347                         end[i] = start[i] + attributes[attr]['by'][i];
3348                     }
3349                 } else {
3350                     end = start + attributes[attr]['by'];
3351                 }
3352             }
3353
3354             this.runtimeAttributes[attr].start = start;
3355             this.runtimeAttributes[attr].end = end;
3356
3357
3358             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3359         },
3360
3361
3362         init: function(el, attributes, duration, method) {
3363
3364             var isAnimated = false;
3365
3366
3367             var startTime = null;
3368
3369
3370             var actualFrames = 0;
3371
3372
3373             el = Roo.getDom(el);
3374
3375
3376             this.attributes = attributes || {};
3377
3378
3379             this.duration = duration || 1;
3380
3381
3382             this.method = method || Roo.lib.Easing.easeNone;
3383
3384
3385             this.useSeconds = true;
3386
3387
3388             this.currentFrame = 0;
3389
3390
3391             this.totalFrames = Roo.lib.AnimMgr.fps;
3392
3393
3394             this.getEl = function() {
3395                 return el;
3396             };
3397
3398
3399             this.isAnimated = function() {
3400                 return isAnimated;
3401             };
3402
3403
3404             this.getStartTime = function() {
3405                 return startTime;
3406             };
3407
3408             this.runtimeAttributes = {};
3409
3410
3411             this.animate = function() {
3412                 if (this.isAnimated()) {
3413                     return false;
3414                 }
3415
3416                 this.currentFrame = 0;
3417
3418                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3419
3420                 Roo.lib.AnimMgr.registerElement(this);
3421             };
3422
3423
3424             this.stop = function(finish) {
3425                 if (finish) {
3426                     this.currentFrame = this.totalFrames;
3427                     this._onTween.fire();
3428                 }
3429                 Roo.lib.AnimMgr.stop(this);
3430             };
3431
3432             var onStart = function() {
3433                 this.onStart.fire();
3434
3435                 this.runtimeAttributes = {};
3436                 for (var attr in this.attributes) {
3437                     this.setRuntimeAttribute(attr);
3438                 }
3439
3440                 isAnimated = true;
3441                 actualFrames = 0;
3442                 startTime = new Date();
3443             };
3444
3445
3446             var onTween = function() {
3447                 var data = {
3448                     duration: new Date() - this.getStartTime(),
3449                     currentFrame: this.currentFrame
3450                 };
3451
3452                 data.toString = function() {
3453                     return (
3454                             'duration: ' + data.duration +
3455                             ', currentFrame: ' + data.currentFrame
3456                             );
3457                 };
3458
3459                 this.onTween.fire(data);
3460
3461                 var runtimeAttributes = this.runtimeAttributes;
3462
3463                 for (var attr in runtimeAttributes) {
3464                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3465                 }
3466
3467                 actualFrames += 1;
3468             };
3469
3470             var onComplete = function() {
3471                 var actual_duration = (new Date() - startTime) / 1000 ;
3472
3473                 var data = {
3474                     duration: actual_duration,
3475                     frames: actualFrames,
3476                     fps: actualFrames / actual_duration
3477                 };
3478
3479                 data.toString = function() {
3480                     return (
3481                             'duration: ' + data.duration +
3482                             ', frames: ' + data.frames +
3483                             ', fps: ' + data.fps
3484                             );
3485                 };
3486
3487                 isAnimated = false;
3488                 actualFrames = 0;
3489                 this.onComplete.fire(data);
3490             };
3491
3492
3493             this._onStart = new Roo.util.Event(this);
3494             this.onStart = new Roo.util.Event(this);
3495             this.onTween = new Roo.util.Event(this);
3496             this._onTween = new Roo.util.Event(this);
3497             this.onComplete = new Roo.util.Event(this);
3498             this._onComplete = new Roo.util.Event(this);
3499             this._onStart.addListener(onStart);
3500             this._onTween.addListener(onTween);
3501             this._onComplete.addListener(onComplete);
3502         }
3503     };
3504 })();
3505 /*
3506  * Portions of this file are based on pieces of Yahoo User Interface Library
3507  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3508  * YUI licensed under the BSD License:
3509  * http://developer.yahoo.net/yui/license.txt
3510  * <script type="text/javascript">
3511  *
3512  */
3513
3514 Roo.lib.AnimMgr = new function() {
3515
3516         var thread = null;
3517
3518
3519         var queue = [];
3520
3521
3522         var tweenCount = 0;
3523
3524
3525         this.fps = 1000;
3526
3527
3528         this.delay = 1;
3529
3530
3531         this.registerElement = function(tween) {
3532             queue[queue.length] = tween;
3533             tweenCount += 1;
3534             tween._onStart.fire();
3535             this.start();
3536         };
3537
3538
3539         this.unRegister = function(tween, index) {
3540             tween._onComplete.fire();
3541             index = index || getIndex(tween);
3542             if (index != -1) {
3543                 queue.splice(index, 1);
3544             }
3545
3546             tweenCount -= 1;
3547             if (tweenCount <= 0) {
3548                 this.stop();
3549             }
3550         };
3551
3552
3553         this.start = function() {
3554             if (thread === null) {
3555                 thread = setInterval(this.run, this.delay);
3556             }
3557         };
3558
3559
3560         this.stop = function(tween) {
3561             if (!tween) {
3562                 clearInterval(thread);
3563
3564                 for (var i = 0, len = queue.length; i < len; ++i) {
3565                     if (queue[0].isAnimated()) {
3566                         this.unRegister(queue[0], 0);
3567                     }
3568                 }
3569
3570                 queue = [];
3571                 thread = null;
3572                 tweenCount = 0;
3573             }
3574             else {
3575                 this.unRegister(tween);
3576             }
3577         };
3578
3579
3580         this.run = function() {
3581             for (var i = 0, len = queue.length; i < len; ++i) {
3582                 var tween = queue[i];
3583                 if (!tween || !tween.isAnimated()) {
3584                     continue;
3585                 }
3586
3587                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3588                 {
3589                     tween.currentFrame += 1;
3590
3591                     if (tween.useSeconds) {
3592                         correctFrame(tween);
3593                     }
3594                     tween._onTween.fire();
3595                 }
3596                 else {
3597                     Roo.lib.AnimMgr.stop(tween, i);
3598                 }
3599             }
3600         };
3601
3602         var getIndex = function(anim) {
3603             for (var i = 0, len = queue.length; i < len; ++i) {
3604                 if (queue[i] == anim) {
3605                     return i;
3606                 }
3607             }
3608             return -1;
3609         };
3610
3611
3612         var correctFrame = function(tween) {
3613             var frames = tween.totalFrames;
3614             var frame = tween.currentFrame;
3615             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3616             var elapsed = (new Date() - tween.getStartTime());
3617             var tweak = 0;
3618
3619             if (elapsed < tween.duration * 1000) {
3620                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3621             } else {
3622                 tweak = frames - (frame + 1);
3623             }
3624             if (tweak > 0 && isFinite(tweak)) {
3625                 if (tween.currentFrame + tweak >= frames) {
3626                     tweak = frames - (frame + 1);
3627                 }
3628
3629                 tween.currentFrame += tweak;
3630             }
3631         };
3632     };/*
3633  * Portions of this file are based on pieces of Yahoo User Interface Library
3634  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3635  * YUI licensed under the BSD License:
3636  * http://developer.yahoo.net/yui/license.txt
3637  * <script type="text/javascript">
3638  *
3639  */
3640 Roo.lib.Bezier = new function() {
3641
3642         this.getPosition = function(points, t) {
3643             var n = points.length;
3644             var tmp = [];
3645
3646             for (var i = 0; i < n; ++i) {
3647                 tmp[i] = [points[i][0], points[i][1]];
3648             }
3649
3650             for (var j = 1; j < n; ++j) {
3651                 for (i = 0; i < n - j; ++i) {
3652                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3653                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3654                 }
3655             }
3656
3657             return [ tmp[0][0], tmp[0][1] ];
3658
3659         };
3660     };/*
3661  * Portions of this file are based on pieces of Yahoo User Interface Library
3662  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3663  * YUI licensed under the BSD License:
3664  * http://developer.yahoo.net/yui/license.txt
3665  * <script type="text/javascript">
3666  *
3667  */
3668 (function() {
3669
3670     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3671         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3672     };
3673
3674     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3675
3676     var fly = Roo.lib.AnimBase.fly;
3677     var Y = Roo.lib;
3678     var superclass = Y.ColorAnim.superclass;
3679     var proto = Y.ColorAnim.prototype;
3680
3681     proto.toString = function() {
3682         var el = this.getEl();
3683         var id = el.id || el.tagName;
3684         return ("ColorAnim " + id);
3685     };
3686
3687     proto.patterns.color = /color$/i;
3688     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3689     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3690     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3691     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3692
3693
3694     proto.parseColor = function(s) {
3695         if (s.length == 3) {
3696             return s;
3697         }
3698
3699         var c = this.patterns.hex.exec(s);
3700         if (c && c.length == 4) {
3701             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3702         }
3703
3704         c = this.patterns.rgb.exec(s);
3705         if (c && c.length == 4) {
3706             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3707         }
3708
3709         c = this.patterns.hex3.exec(s);
3710         if (c && c.length == 4) {
3711             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3712         }
3713
3714         return null;
3715     };
3716     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3717     proto.getAttribute = function(attr) {
3718         var el = this.getEl();
3719         if (this.patterns.color.test(attr)) {
3720             var val = fly(el).getStyle(attr);
3721
3722             if (this.patterns.transparent.test(val)) {
3723                 var parent = el.parentNode;
3724                 val = fly(parent).getStyle(attr);
3725
3726                 while (parent && this.patterns.transparent.test(val)) {
3727                     parent = parent.parentNode;
3728                     val = fly(parent).getStyle(attr);
3729                     if (parent.tagName.toUpperCase() == 'HTML') {
3730                         val = '#fff';
3731                     }
3732                 }
3733             }
3734         } else {
3735             val = superclass.getAttribute.call(this, attr);
3736         }
3737
3738         return val;
3739     };
3740     proto.getAttribute = function(attr) {
3741         var el = this.getEl();
3742         if (this.patterns.color.test(attr)) {
3743             var val = fly(el).getStyle(attr);
3744
3745             if (this.patterns.transparent.test(val)) {
3746                 var parent = el.parentNode;
3747                 val = fly(parent).getStyle(attr);
3748
3749                 while (parent && this.patterns.transparent.test(val)) {
3750                     parent = parent.parentNode;
3751                     val = fly(parent).getStyle(attr);
3752                     if (parent.tagName.toUpperCase() == 'HTML') {
3753                         val = '#fff';
3754                     }
3755                 }
3756             }
3757         } else {
3758             val = superclass.getAttribute.call(this, attr);
3759         }
3760
3761         return val;
3762     };
3763
3764     proto.doMethod = function(attr, start, end) {
3765         var val;
3766
3767         if (this.patterns.color.test(attr)) {
3768             val = [];
3769             for (var i = 0, len = start.length; i < len; ++i) {
3770                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3771             }
3772
3773             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3774         }
3775         else {
3776             val = superclass.doMethod.call(this, attr, start, end);
3777         }
3778
3779         return val;
3780     };
3781
3782     proto.setRuntimeAttribute = function(attr) {
3783         superclass.setRuntimeAttribute.call(this, attr);
3784
3785         if (this.patterns.color.test(attr)) {
3786             var attributes = this.attributes;
3787             var start = this.parseColor(this.runtimeAttributes[attr].start);
3788             var end = this.parseColor(this.runtimeAttributes[attr].end);
3789
3790             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3791                 end = this.parseColor(attributes[attr].by);
3792
3793                 for (var i = 0, len = start.length; i < len; ++i) {
3794                     end[i] = start[i] + end[i];
3795                 }
3796             }
3797
3798             this.runtimeAttributes[attr].start = start;
3799             this.runtimeAttributes[attr].end = end;
3800         }
3801     };
3802 })();
3803
3804 /*
3805  * Portions of this file are based on pieces of Yahoo User Interface Library
3806  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3807  * YUI licensed under the BSD License:
3808  * http://developer.yahoo.net/yui/license.txt
3809  * <script type="text/javascript">
3810  *
3811  */
3812 Roo.lib.Easing = {
3813
3814
3815     easeNone: function (t, b, c, d) {
3816         return c * t / d + b;
3817     },
3818
3819
3820     easeIn: function (t, b, c, d) {
3821         return c * (t /= d) * t + b;
3822     },
3823
3824
3825     easeOut: function (t, b, c, d) {
3826         return -c * (t /= d) * (t - 2) + b;
3827     },
3828
3829
3830     easeBoth: function (t, b, c, d) {
3831         if ((t /= d / 2) < 1) {
3832             return c / 2 * t * t + b;
3833         }
3834
3835         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3836     },
3837
3838
3839     easeInStrong: function (t, b, c, d) {
3840         return c * (t /= d) * t * t * t + b;
3841     },
3842
3843
3844     easeOutStrong: function (t, b, c, d) {
3845         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3846     },
3847
3848
3849     easeBothStrong: function (t, b, c, d) {
3850         if ((t /= d / 2) < 1) {
3851             return c / 2 * t * t * t * t + b;
3852         }
3853
3854         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3855     },
3856
3857
3858
3859     elasticIn: function (t, b, c, d, a, p) {
3860         if (t == 0) {
3861             return b;
3862         }
3863         if ((t /= d) == 1) {
3864             return b + c;
3865         }
3866         if (!p) {
3867             p = d * .3;
3868         }
3869
3870         if (!a || a < Math.abs(c)) {
3871             a = c;
3872             var s = p / 4;
3873         }
3874         else {
3875             var s = p / (2 * Math.PI) * Math.asin(c / a);
3876         }
3877
3878         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3879     },
3880
3881
3882     elasticOut: function (t, b, c, d, a, p) {
3883         if (t == 0) {
3884             return b;
3885         }
3886         if ((t /= d) == 1) {
3887             return b + c;
3888         }
3889         if (!p) {
3890             p = d * .3;
3891         }
3892
3893         if (!a || a < Math.abs(c)) {
3894             a = c;
3895             var s = p / 4;
3896         }
3897         else {
3898             var s = p / (2 * Math.PI) * Math.asin(c / a);
3899         }
3900
3901         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3902     },
3903
3904
3905     elasticBoth: function (t, b, c, d, a, p) {
3906         if (t == 0) {
3907             return b;
3908         }
3909
3910         if ((t /= d / 2) == 2) {
3911             return b + c;
3912         }
3913
3914         if (!p) {
3915             p = d * (.3 * 1.5);
3916         }
3917
3918         if (!a || a < Math.abs(c)) {
3919             a = c;
3920             var s = p / 4;
3921         }
3922         else {
3923             var s = p / (2 * Math.PI) * Math.asin(c / a);
3924         }
3925
3926         if (t < 1) {
3927             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3928                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3929         }
3930         return a * Math.pow(2, -10 * (t -= 1)) *
3931                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3932     },
3933
3934
3935
3936     backIn: function (t, b, c, d, s) {
3937         if (typeof s == 'undefined') {
3938             s = 1.70158;
3939         }
3940         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3941     },
3942
3943
3944     backOut: function (t, b, c, d, s) {
3945         if (typeof s == 'undefined') {
3946             s = 1.70158;
3947         }
3948         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3949     },
3950
3951
3952     backBoth: function (t, b, c, d, s) {
3953         if (typeof s == 'undefined') {
3954             s = 1.70158;
3955         }
3956
3957         if ((t /= d / 2 ) < 1) {
3958             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3959         }
3960         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3961     },
3962
3963
3964     bounceIn: function (t, b, c, d) {
3965         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3966     },
3967
3968
3969     bounceOut: function (t, b, c, d) {
3970         if ((t /= d) < (1 / 2.75)) {
3971             return c * (7.5625 * t * t) + b;
3972         } else if (t < (2 / 2.75)) {
3973             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3974         } else if (t < (2.5 / 2.75)) {
3975             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3976         }
3977         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3978     },
3979
3980
3981     bounceBoth: function (t, b, c, d) {
3982         if (t < d / 2) {
3983             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3984         }
3985         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3986     }
3987 };/*
3988  * Portions of this file are based on pieces of Yahoo User Interface Library
3989  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3990  * YUI licensed under the BSD License:
3991  * http://developer.yahoo.net/yui/license.txt
3992  * <script type="text/javascript">
3993  *
3994  */
3995     (function() {
3996         Roo.lib.Motion = function(el, attributes, duration, method) {
3997             if (el) {
3998                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3999             }
4000         };
4001
4002         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4003
4004
4005         var Y = Roo.lib;
4006         var superclass = Y.Motion.superclass;
4007         var proto = Y.Motion.prototype;
4008
4009         proto.toString = function() {
4010             var el = this.getEl();
4011             var id = el.id || el.tagName;
4012             return ("Motion " + id);
4013         };
4014
4015         proto.patterns.points = /^points$/i;
4016
4017         proto.setAttribute = function(attr, val, unit) {
4018             if (this.patterns.points.test(attr)) {
4019                 unit = unit || 'px';
4020                 superclass.setAttribute.call(this, 'left', val[0], unit);
4021                 superclass.setAttribute.call(this, 'top', val[1], unit);
4022             } else {
4023                 superclass.setAttribute.call(this, attr, val, unit);
4024             }
4025         };
4026
4027         proto.getAttribute = function(attr) {
4028             if (this.patterns.points.test(attr)) {
4029                 var val = [
4030                         superclass.getAttribute.call(this, 'left'),
4031                         superclass.getAttribute.call(this, 'top')
4032                         ];
4033             } else {
4034                 val = superclass.getAttribute.call(this, attr);
4035             }
4036
4037             return val;
4038         };
4039
4040         proto.doMethod = function(attr, start, end) {
4041             var val = null;
4042
4043             if (this.patterns.points.test(attr)) {
4044                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4045                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4046             } else {
4047                 val = superclass.doMethod.call(this, attr, start, end);
4048             }
4049             return val;
4050         };
4051
4052         proto.setRuntimeAttribute = function(attr) {
4053             if (this.patterns.points.test(attr)) {
4054                 var el = this.getEl();
4055                 var attributes = this.attributes;
4056                 var start;
4057                 var control = attributes['points']['control'] || [];
4058                 var end;
4059                 var i, len;
4060
4061                 if (control.length > 0 && !(control[0] instanceof Array)) {
4062                     control = [control];
4063                 } else {
4064                     var tmp = [];
4065                     for (i = 0,len = control.length; i < len; ++i) {
4066                         tmp[i] = control[i];
4067                     }
4068                     control = tmp;
4069                 }
4070
4071                 Roo.fly(el).position();
4072
4073                 if (isset(attributes['points']['from'])) {
4074                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4075                 }
4076                 else {
4077                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4078                 }
4079
4080                 start = this.getAttribute('points');
4081
4082
4083                 if (isset(attributes['points']['to'])) {
4084                     end = translateValues.call(this, attributes['points']['to'], start);
4085
4086                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4087                     for (i = 0,len = control.length; i < len; ++i) {
4088                         control[i] = translateValues.call(this, control[i], start);
4089                     }
4090
4091
4092                 } else if (isset(attributes['points']['by'])) {
4093                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4094
4095                     for (i = 0,len = control.length; i < len; ++i) {
4096                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4097                     }
4098                 }
4099
4100                 this.runtimeAttributes[attr] = [start];
4101
4102                 if (control.length > 0) {
4103                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4104                 }
4105
4106                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4107             }
4108             else {
4109                 superclass.setRuntimeAttribute.call(this, attr);
4110             }
4111         };
4112
4113         var translateValues = function(val, start) {
4114             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4115             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4116
4117             return val;
4118         };
4119
4120         var isset = function(prop) {
4121             return (typeof prop !== 'undefined');
4122         };
4123     })();
4124 /*
4125  * Portions of this file are based on pieces of Yahoo User Interface Library
4126  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4127  * YUI licensed under the BSD License:
4128  * http://developer.yahoo.net/yui/license.txt
4129  * <script type="text/javascript">
4130  *
4131  */
4132     (function() {
4133         Roo.lib.Scroll = function(el, attributes, duration, method) {
4134             if (el) {
4135                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4136             }
4137         };
4138
4139         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4140
4141
4142         var Y = Roo.lib;
4143         var superclass = Y.Scroll.superclass;
4144         var proto = Y.Scroll.prototype;
4145
4146         proto.toString = function() {
4147             var el = this.getEl();
4148             var id = el.id || el.tagName;
4149             return ("Scroll " + id);
4150         };
4151
4152         proto.doMethod = function(attr, start, end) {
4153             var val = null;
4154
4155             if (attr == 'scroll') {
4156                 val = [
4157                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4158                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4159                         ];
4160
4161             } else {
4162                 val = superclass.doMethod.call(this, attr, start, end);
4163             }
4164             return val;
4165         };
4166
4167         proto.getAttribute = function(attr) {
4168             var val = null;
4169             var el = this.getEl();
4170
4171             if (attr == 'scroll') {
4172                 val = [ el.scrollLeft, el.scrollTop ];
4173             } else {
4174                 val = superclass.getAttribute.call(this, attr);
4175             }
4176
4177             return val;
4178         };
4179
4180         proto.setAttribute = function(attr, val, unit) {
4181             var el = this.getEl();
4182
4183             if (attr == 'scroll') {
4184                 el.scrollLeft = val[0];
4185                 el.scrollTop = val[1];
4186             } else {
4187                 superclass.setAttribute.call(this, attr, val, unit);
4188             }
4189         };
4190     })();
4191 /*
4192  * Based on:
4193  * Ext JS Library 1.1.1
4194  * Copyright(c) 2006-2007, Ext JS, LLC.
4195  *
4196  * Originally Released Under LGPL - original licence link has changed is not relivant.
4197  *
4198  * Fork - LGPL
4199  * <script type="text/javascript">
4200  */
4201
4202
4203 // nasty IE9 hack - what a pile of crap that is..
4204
4205  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4206     Range.prototype.createContextualFragment = function (html) {
4207         var doc = window.document;
4208         var container = doc.createElement("div");
4209         container.innerHTML = html;
4210         var frag = doc.createDocumentFragment(), n;
4211         while ((n = container.firstChild)) {
4212             frag.appendChild(n);
4213         }
4214         return frag;
4215     };
4216 }
4217
4218 /**
4219  * @class Roo.DomHelper
4220  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4221  * 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>.
4222  * @singleton
4223  */
4224 Roo.DomHelper = function(){
4225     var tempTableEl = null;
4226     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4227     var tableRe = /^table|tbody|tr|td$/i;
4228     var xmlns = {};
4229     // build as innerHTML where available
4230     /** @ignore */
4231     var createHtml = function(o){
4232         if(typeof o == 'string'){
4233             return o;
4234         }
4235         var b = "";
4236         if(!o.tag){
4237             o.tag = "div";
4238         }
4239         b += "<" + o.tag;
4240         for(var attr in o){
4241             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4242             if(attr == "style"){
4243                 var s = o["style"];
4244                 if(typeof s == "function"){
4245                     s = s.call();
4246                 }
4247                 if(typeof s == "string"){
4248                     b += ' style="' + s + '"';
4249                 }else if(typeof s == "object"){
4250                     b += ' style="';
4251                     for(var key in s){
4252                         if(typeof s[key] != "function"){
4253                             b += key + ":" + s[key] + ";";
4254                         }
4255                     }
4256                     b += '"';
4257                 }
4258             }else{
4259                 if(attr == "cls"){
4260                     b += ' class="' + o["cls"] + '"';
4261                 }else if(attr == "htmlFor"){
4262                     b += ' for="' + o["htmlFor"] + '"';
4263                 }else{
4264                     b += " " + attr + '="' + o[attr] + '"';
4265                 }
4266             }
4267         }
4268         if(emptyTags.test(o.tag)){
4269             b += "/>";
4270         }else{
4271             b += ">";
4272             var cn = o.children || o.cn;
4273             if(cn){
4274                 //http://bugs.kde.org/show_bug.cgi?id=71506
4275                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4276                     for(var i = 0, len = cn.length; i < len; i++) {
4277                         b += createHtml(cn[i], b);
4278                     }
4279                 }else{
4280                     b += createHtml(cn, b);
4281                 }
4282             }
4283             if(o.html){
4284                 b += o.html;
4285             }
4286             b += "</" + o.tag + ">";
4287         }
4288         return b;
4289     };
4290
4291     // build as dom
4292     /** @ignore */
4293     var createDom = function(o, parentNode){
4294          
4295         // defininition craeted..
4296         var ns = false;
4297         if (o.ns && o.ns != 'html') {
4298                
4299             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4300                 xmlns[o.ns] = o.xmlns;
4301                 ns = o.xmlns;
4302             }
4303             if (typeof(xmlns[o.ns]) == 'undefined') {
4304                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4305             }
4306             ns = xmlns[o.ns];
4307         }
4308         
4309         
4310         if (typeof(o) == 'string') {
4311             return parentNode.appendChild(document.createTextNode(o));
4312         }
4313         o.tag = o.tag || div;
4314         if (o.ns && Roo.isIE) {
4315             ns = false;
4316             o.tag = o.ns + ':' + o.tag;
4317             
4318         }
4319         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4320         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4321         for(var attr in o){
4322             
4323             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4324                     attr == "style" || typeof o[attr] == "function") continue;
4325                     
4326             if(attr=="cls" && Roo.isIE){
4327                 el.className = o["cls"];
4328             }else{
4329                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4330                 else el[attr] = o[attr];
4331             }
4332         }
4333         Roo.DomHelper.applyStyles(el, o.style);
4334         var cn = o.children || o.cn;
4335         if(cn){
4336             //http://bugs.kde.org/show_bug.cgi?id=71506
4337              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4338                 for(var i = 0, len = cn.length; i < len; i++) {
4339                     createDom(cn[i], el);
4340                 }
4341             }else{
4342                 createDom(cn, el);
4343             }
4344         }
4345         if(o.html){
4346             el.innerHTML = o.html;
4347         }
4348         if(parentNode){
4349            parentNode.appendChild(el);
4350         }
4351         return el;
4352     };
4353
4354     var ieTable = function(depth, s, h, e){
4355         tempTableEl.innerHTML = [s, h, e].join('');
4356         var i = -1, el = tempTableEl;
4357         while(++i < depth){
4358             el = el.firstChild;
4359         }
4360         return el;
4361     };
4362
4363     // kill repeat to save bytes
4364     var ts = '<table>',
4365         te = '</table>',
4366         tbs = ts+'<tbody>',
4367         tbe = '</tbody>'+te,
4368         trs = tbs + '<tr>',
4369         tre = '</tr>'+tbe;
4370
4371     /**
4372      * @ignore
4373      * Nasty code for IE's broken table implementation
4374      */
4375     var insertIntoTable = function(tag, where, el, html){
4376         if(!tempTableEl){
4377             tempTableEl = document.createElement('div');
4378         }
4379         var node;
4380         var before = null;
4381         if(tag == 'td'){
4382             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4383                 return;
4384             }
4385             if(where == 'beforebegin'){
4386                 before = el;
4387                 el = el.parentNode;
4388             } else{
4389                 before = el.nextSibling;
4390                 el = el.parentNode;
4391             }
4392             node = ieTable(4, trs, html, tre);
4393         }
4394         else if(tag == 'tr'){
4395             if(where == 'beforebegin'){
4396                 before = el;
4397                 el = el.parentNode;
4398                 node = ieTable(3, tbs, html, tbe);
4399             } else if(where == 'afterend'){
4400                 before = el.nextSibling;
4401                 el = el.parentNode;
4402                 node = ieTable(3, tbs, html, tbe);
4403             } else{ // INTO a TR
4404                 if(where == 'afterbegin'){
4405                     before = el.firstChild;
4406                 }
4407                 node = ieTable(4, trs, html, tre);
4408             }
4409         } else if(tag == 'tbody'){
4410             if(where == 'beforebegin'){
4411                 before = el;
4412                 el = el.parentNode;
4413                 node = ieTable(2, ts, html, te);
4414             } else if(where == 'afterend'){
4415                 before = el.nextSibling;
4416                 el = el.parentNode;
4417                 node = ieTable(2, ts, html, te);
4418             } else{
4419                 if(where == 'afterbegin'){
4420                     before = el.firstChild;
4421                 }
4422                 node = ieTable(3, tbs, html, tbe);
4423             }
4424         } else{ // TABLE
4425             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4426                 return;
4427             }
4428             if(where == 'afterbegin'){
4429                 before = el.firstChild;
4430             }
4431             node = ieTable(2, ts, html, te);
4432         }
4433         el.insertBefore(node, before);
4434         return node;
4435     };
4436
4437     return {
4438     /** True to force the use of DOM instead of html fragments @type Boolean */
4439     useDom : false,
4440
4441     /**
4442      * Returns the markup for the passed Element(s) config
4443      * @param {Object} o The Dom object spec (and children)
4444      * @return {String}
4445      */
4446     markup : function(o){
4447         return createHtml(o);
4448     },
4449
4450     /**
4451      * Applies a style specification to an element
4452      * @param {String/HTMLElement} el The element to apply styles to
4453      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4454      * a function which returns such a specification.
4455      */
4456     applyStyles : function(el, styles){
4457         if(styles){
4458            el = Roo.fly(el);
4459            if(typeof styles == "string"){
4460                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4461                var matches;
4462                while ((matches = re.exec(styles)) != null){
4463                    el.setStyle(matches[1], matches[2]);
4464                }
4465            }else if (typeof styles == "object"){
4466                for (var style in styles){
4467                   el.setStyle(style, styles[style]);
4468                }
4469            }else if (typeof styles == "function"){
4470                 Roo.DomHelper.applyStyles(el, styles.call());
4471            }
4472         }
4473     },
4474
4475     /**
4476      * Inserts an HTML fragment into the Dom
4477      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4478      * @param {HTMLElement} el The context element
4479      * @param {String} html The HTML fragmenet
4480      * @return {HTMLElement} The new node
4481      */
4482     insertHtml : function(where, el, html){
4483         where = where.toLowerCase();
4484         if(el.insertAdjacentHTML){
4485             if(tableRe.test(el.tagName)){
4486                 var rs;
4487                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4488                     return rs;
4489                 }
4490             }
4491             switch(where){
4492                 case "beforebegin":
4493                     el.insertAdjacentHTML('BeforeBegin', html);
4494                     return el.previousSibling;
4495                 case "afterbegin":
4496                     el.insertAdjacentHTML('AfterBegin', html);
4497                     return el.firstChild;
4498                 case "beforeend":
4499                     el.insertAdjacentHTML('BeforeEnd', html);
4500                     return el.lastChild;
4501                 case "afterend":
4502                     el.insertAdjacentHTML('AfterEnd', html);
4503                     return el.nextSibling;
4504             }
4505             throw 'Illegal insertion point -> "' + where + '"';
4506         }
4507         var range = el.ownerDocument.createRange();
4508         var frag;
4509         switch(where){
4510              case "beforebegin":
4511                 range.setStartBefore(el);
4512                 frag = range.createContextualFragment(html);
4513                 el.parentNode.insertBefore(frag, el);
4514                 return el.previousSibling;
4515              case "afterbegin":
4516                 if(el.firstChild){
4517                     range.setStartBefore(el.firstChild);
4518                     frag = range.createContextualFragment(html);
4519                     el.insertBefore(frag, el.firstChild);
4520                     return el.firstChild;
4521                 }else{
4522                     el.innerHTML = html;
4523                     return el.firstChild;
4524                 }
4525             case "beforeend":
4526                 if(el.lastChild){
4527                     range.setStartAfter(el.lastChild);
4528                     frag = range.createContextualFragment(html);
4529                     el.appendChild(frag);
4530                     return el.lastChild;
4531                 }else{
4532                     el.innerHTML = html;
4533                     return el.lastChild;
4534                 }
4535             case "afterend":
4536                 range.setStartAfter(el);
4537                 frag = range.createContextualFragment(html);
4538                 el.parentNode.insertBefore(frag, el.nextSibling);
4539                 return el.nextSibling;
4540             }
4541             throw 'Illegal insertion point -> "' + where + '"';
4542     },
4543
4544     /**
4545      * Creates new Dom element(s) and inserts them before el
4546      * @param {String/HTMLElement/Element} el The context element
4547      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4548      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4549      * @return {HTMLElement/Roo.Element} The new node
4550      */
4551     insertBefore : function(el, o, returnElement){
4552         return this.doInsert(el, o, returnElement, "beforeBegin");
4553     },
4554
4555     /**
4556      * Creates new Dom element(s) and inserts them after el
4557      * @param {String/HTMLElement/Element} el The context element
4558      * @param {Object} o The Dom object spec (and children)
4559      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4560      * @return {HTMLElement/Roo.Element} The new node
4561      */
4562     insertAfter : function(el, o, returnElement){
4563         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4564     },
4565
4566     /**
4567      * Creates new Dom element(s) and inserts them as the first child of el
4568      * @param {String/HTMLElement/Element} el The context element
4569      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4570      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4571      * @return {HTMLElement/Roo.Element} The new node
4572      */
4573     insertFirst : function(el, o, returnElement){
4574         return this.doInsert(el, o, returnElement, "afterBegin");
4575     },
4576
4577     // private
4578     doInsert : function(el, o, returnElement, pos, sibling){
4579         el = Roo.getDom(el);
4580         var newNode;
4581         if(this.useDom || o.ns){
4582             newNode = createDom(o, null);
4583             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4584         }else{
4585             var html = createHtml(o);
4586             newNode = this.insertHtml(pos, el, html);
4587         }
4588         return returnElement ? Roo.get(newNode, true) : newNode;
4589     },
4590
4591     /**
4592      * Creates new Dom element(s) and appends them to el
4593      * @param {String/HTMLElement/Element} el The context element
4594      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4595      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4596      * @return {HTMLElement/Roo.Element} The new node
4597      */
4598     append : function(el, o, returnElement){
4599         el = Roo.getDom(el);
4600         var newNode;
4601         if(this.useDom || o.ns){
4602             newNode = createDom(o, null);
4603             el.appendChild(newNode);
4604         }else{
4605             var html = createHtml(o);
4606             newNode = this.insertHtml("beforeEnd", el, html);
4607         }
4608         return returnElement ? Roo.get(newNode, true) : newNode;
4609     },
4610
4611     /**
4612      * Creates new Dom element(s) and overwrites the contents of el with them
4613      * @param {String/HTMLElement/Element} el The context element
4614      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4615      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4616      * @return {HTMLElement/Roo.Element} The new node
4617      */
4618     overwrite : function(el, o, returnElement){
4619         el = Roo.getDom(el);
4620         if (o.ns) {
4621           
4622             while (el.childNodes.length) {
4623                 el.removeChild(el.firstChild);
4624             }
4625             createDom(o, el);
4626         } else {
4627             el.innerHTML = createHtml(o);   
4628         }
4629         
4630         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4631     },
4632
4633     /**
4634      * Creates a new Roo.DomHelper.Template from the Dom object spec
4635      * @param {Object} o The Dom object spec (and children)
4636      * @return {Roo.DomHelper.Template} The new template
4637      */
4638     createTemplate : function(o){
4639         var html = createHtml(o);
4640         return new Roo.Template(html);
4641     }
4642     };
4643 }();
4644 /*
4645  * Based on:
4646  * Ext JS Library 1.1.1
4647  * Copyright(c) 2006-2007, Ext JS, LLC.
4648  *
4649  * Originally Released Under LGPL - original licence link has changed is not relivant.
4650  *
4651  * Fork - LGPL
4652  * <script type="text/javascript">
4653  */
4654  
4655 /**
4656 * @class Roo.Template
4657 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4658 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4659 * Usage:
4660 <pre><code>
4661 var t = new Roo.Template({
4662     html :  '&lt;div name="{id}"&gt;' + 
4663         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4664         '&lt;/div&gt;',
4665     myformat: function (value, allValues) {
4666         return 'XX' + value;
4667     }
4668 });
4669 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4670 </code></pre>
4671 * For more information see this blog post with examples:
4672 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4673      - Create Elements using DOM, HTML fragments and Templates</a>. 
4674 * @constructor
4675 * @param {Object} cfg - Configuration object.
4676 */
4677 Roo.Template = function(cfg){
4678     // BC!
4679     if(cfg instanceof Array){
4680         cfg = cfg.join("");
4681     }else if(arguments.length > 1){
4682         cfg = Array.prototype.join.call(arguments, "");
4683     }
4684     
4685     
4686     if (typeof(cfg) == 'object') {
4687         Roo.apply(this,cfg)
4688     } else {
4689         // bc
4690         this.html = cfg;
4691     }
4692     if (this.url) {
4693         this.load();
4694     }
4695     
4696 };
4697 Roo.Template.prototype = {
4698     
4699     /**
4700      * @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..
4701      *                    it should be fixed so that template is observable...
4702      */
4703     url : false,
4704     /**
4705      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4706      */
4707     html : '',
4708     /**
4709      * Returns an HTML fragment of this template with the specified values applied.
4710      * @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'})
4711      * @return {String} The HTML fragment
4712      */
4713     applyTemplate : function(values){
4714         try {
4715            
4716             if(this.compiled){
4717                 return this.compiled(values);
4718             }
4719             var useF = this.disableFormats !== true;
4720             var fm = Roo.util.Format, tpl = this;
4721             var fn = function(m, name, format, args){
4722                 if(format && useF){
4723                     if(format.substr(0, 5) == "this."){
4724                         return tpl.call(format.substr(5), values[name], values);
4725                     }else{
4726                         if(args){
4727                             // quoted values are required for strings in compiled templates, 
4728                             // but for non compiled we need to strip them
4729                             // quoted reversed for jsmin
4730                             var re = /^\s*['"](.*)["']\s*$/;
4731                             args = args.split(',');
4732                             for(var i = 0, len = args.length; i < len; i++){
4733                                 args[i] = args[i].replace(re, "$1");
4734                             }
4735                             args = [values[name]].concat(args);
4736                         }else{
4737                             args = [values[name]];
4738                         }
4739                         return fm[format].apply(fm, args);
4740                     }
4741                 }else{
4742                     return values[name] !== undefined ? values[name] : "";
4743                 }
4744             };
4745             return this.html.replace(this.re, fn);
4746         } catch (e) {
4747             Roo.log(e);
4748             throw e;
4749         }
4750          
4751     },
4752     
4753     loading : false,
4754       
4755     load : function ()
4756     {
4757          
4758         if (this.loading) {
4759             return;
4760         }
4761         var _t = this;
4762         
4763         this.loading = true;
4764         this.compiled = false;
4765         
4766         var cx = new Roo.data.Connection();
4767         cx.request({
4768             url : this.url,
4769             method : 'GET',
4770             success : function (response) {
4771                 _t.loading = false;
4772                 _t.html = response.responseText;
4773                 _t.url = false;
4774                 _t.compile();
4775              },
4776             failure : function(response) {
4777                 Roo.log("Template failed to load from " + _t.url);
4778                 _t.loading = false;
4779             }
4780         });
4781     },
4782
4783     /**
4784      * Sets the HTML used as the template and optionally compiles it.
4785      * @param {String} html
4786      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4787      * @return {Roo.Template} this
4788      */
4789     set : function(html, compile){
4790         this.html = html;
4791         this.compiled = null;
4792         if(compile){
4793             this.compile();
4794         }
4795         return this;
4796     },
4797     
4798     /**
4799      * True to disable format functions (defaults to false)
4800      * @type Boolean
4801      */
4802     disableFormats : false,
4803     
4804     /**
4805     * The regular expression used to match template variables 
4806     * @type RegExp
4807     * @property 
4808     */
4809     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4810     
4811     /**
4812      * Compiles the template into an internal function, eliminating the RegEx overhead.
4813      * @return {Roo.Template} this
4814      */
4815     compile : function(){
4816         var fm = Roo.util.Format;
4817         var useF = this.disableFormats !== true;
4818         var sep = Roo.isGecko ? "+" : ",";
4819         var fn = function(m, name, format, args){
4820             if(format && useF){
4821                 args = args ? ',' + args : "";
4822                 if(format.substr(0, 5) != "this."){
4823                     format = "fm." + format + '(';
4824                 }else{
4825                     format = 'this.call("'+ format.substr(5) + '", ';
4826                     args = ", values";
4827                 }
4828             }else{
4829                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4830             }
4831             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4832         };
4833         var body;
4834         // branched to use + in gecko and [].join() in others
4835         if(Roo.isGecko){
4836             body = "this.compiled = function(values){ return '" +
4837                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4838                     "';};";
4839         }else{
4840             body = ["this.compiled = function(values){ return ['"];
4841             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4842             body.push("'].join('');};");
4843             body = body.join('');
4844         }
4845         /**
4846          * eval:var:values
4847          * eval:var:fm
4848          */
4849         eval(body);
4850         return this;
4851     },
4852     
4853     // private function used to call members
4854     call : function(fnName, value, allValues){
4855         return this[fnName](value, allValues);
4856     },
4857     
4858     /**
4859      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4860      * @param {String/HTMLElement/Roo.Element} el The context element
4861      * @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'})
4862      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4863      * @return {HTMLElement/Roo.Element} The new node or Element
4864      */
4865     insertFirst: function(el, values, returnElement){
4866         return this.doInsert('afterBegin', el, values, returnElement);
4867     },
4868
4869     /**
4870      * Applies the supplied values to the template and inserts the new node(s) before el.
4871      * @param {String/HTMLElement/Roo.Element} el The context element
4872      * @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'})
4873      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4874      * @return {HTMLElement/Roo.Element} The new node or Element
4875      */
4876     insertBefore: function(el, values, returnElement){
4877         return this.doInsert('beforeBegin', el, values, returnElement);
4878     },
4879
4880     /**
4881      * Applies the supplied values to the template and inserts the new node(s) after el.
4882      * @param {String/HTMLElement/Roo.Element} el The context element
4883      * @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'})
4884      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4885      * @return {HTMLElement/Roo.Element} The new node or Element
4886      */
4887     insertAfter : function(el, values, returnElement){
4888         return this.doInsert('afterEnd', el, values, returnElement);
4889     },
4890     
4891     /**
4892      * Applies the supplied values to the template and appends the new node(s) to el.
4893      * @param {String/HTMLElement/Roo.Element} el The context element
4894      * @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'})
4895      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4896      * @return {HTMLElement/Roo.Element} The new node or Element
4897      */
4898     append : function(el, values, returnElement){
4899         return this.doInsert('beforeEnd', el, values, returnElement);
4900     },
4901
4902     doInsert : function(where, el, values, returnEl){
4903         el = Roo.getDom(el);
4904         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4905         return returnEl ? Roo.get(newNode, true) : newNode;
4906     },
4907
4908     /**
4909      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4910      * @param {String/HTMLElement/Roo.Element} el The context element
4911      * @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'})
4912      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4913      * @return {HTMLElement/Roo.Element} The new node or Element
4914      */
4915     overwrite : function(el, values, returnElement){
4916         el = Roo.getDom(el);
4917         el.innerHTML = this.applyTemplate(values);
4918         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4919     }
4920 };
4921 /**
4922  * Alias for {@link #applyTemplate}
4923  * @method
4924  */
4925 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4926
4927 // backwards compat
4928 Roo.DomHelper.Template = Roo.Template;
4929
4930 /**
4931  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4932  * @param {String/HTMLElement} el A DOM element or its id
4933  * @returns {Roo.Template} The created template
4934  * @static
4935  */
4936 Roo.Template.from = function(el){
4937     el = Roo.getDom(el);
4938     return new Roo.Template(el.value || el.innerHTML);
4939 };/*
4940  * Based on:
4941  * Ext JS Library 1.1.1
4942  * Copyright(c) 2006-2007, Ext JS, LLC.
4943  *
4944  * Originally Released Under LGPL - original licence link has changed is not relivant.
4945  *
4946  * Fork - LGPL
4947  * <script type="text/javascript">
4948  */
4949  
4950
4951 /*
4952  * This is code is also distributed under MIT license for use
4953  * with jQuery and prototype JavaScript libraries.
4954  */
4955 /**
4956  * @class Roo.DomQuery
4957 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).
4958 <p>
4959 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>
4960
4961 <p>
4962 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.
4963 </p>
4964 <h4>Element Selectors:</h4>
4965 <ul class="list">
4966     <li> <b>*</b> any element</li>
4967     <li> <b>E</b> an element with the tag E</li>
4968     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4969     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4970     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4971     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4972 </ul>
4973 <h4>Attribute Selectors:</h4>
4974 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4975 <ul class="list">
4976     <li> <b>E[foo]</b> has an attribute "foo"</li>
4977     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4978     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4979     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4980     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4981     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4982     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4983 </ul>
4984 <h4>Pseudo Classes:</h4>
4985 <ul class="list">
4986     <li> <b>E:first-child</b> E is the first child of its parent</li>
4987     <li> <b>E:last-child</b> E is the last child of its parent</li>
4988     <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>
4989     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4990     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4991     <li> <b>E:only-child</b> E is the only child of its parent</li>
4992     <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>
4993     <li> <b>E:first</b> the first E in the resultset</li>
4994     <li> <b>E:last</b> the last E in the resultset</li>
4995     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4996     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4997     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4998     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4999     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5000     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5001     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5002     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5003     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5004 </ul>
5005 <h4>CSS Value Selectors:</h4>
5006 <ul class="list">
5007     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5008     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5009     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5010     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5011     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5012     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5013 </ul>
5014  * @singleton
5015  */
5016 Roo.DomQuery = function(){
5017     var cache = {}, simpleCache = {}, valueCache = {};
5018     var nonSpace = /\S/;
5019     var trimRe = /^\s+|\s+$/g;
5020     var tplRe = /\{(\d+)\}/g;
5021     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5022     var tagTokenRe = /^(#)?([\w-\*]+)/;
5023     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5024
5025     function child(p, index){
5026         var i = 0;
5027         var n = p.firstChild;
5028         while(n){
5029             if(n.nodeType == 1){
5030                if(++i == index){
5031                    return n;
5032                }
5033             }
5034             n = n.nextSibling;
5035         }
5036         return null;
5037     };
5038
5039     function next(n){
5040         while((n = n.nextSibling) && n.nodeType != 1);
5041         return n;
5042     };
5043
5044     function prev(n){
5045         while((n = n.previousSibling) && n.nodeType != 1);
5046         return n;
5047     };
5048
5049     function children(d){
5050         var n = d.firstChild, ni = -1;
5051             while(n){
5052                 var nx = n.nextSibling;
5053                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5054                     d.removeChild(n);
5055                 }else{
5056                     n.nodeIndex = ++ni;
5057                 }
5058                 n = nx;
5059             }
5060             return this;
5061         };
5062
5063     function byClassName(c, a, v){
5064         if(!v){
5065             return c;
5066         }
5067         var r = [], ri = -1, cn;
5068         for(var i = 0, ci; ci = c[i]; i++){
5069             if((' '+ci.className+' ').indexOf(v) != -1){
5070                 r[++ri] = ci;
5071             }
5072         }
5073         return r;
5074     };
5075
5076     function attrValue(n, attr){
5077         if(!n.tagName && typeof n.length != "undefined"){
5078             n = n[0];
5079         }
5080         if(!n){
5081             return null;
5082         }
5083         if(attr == "for"){
5084             return n.htmlFor;
5085         }
5086         if(attr == "class" || attr == "className"){
5087             return n.className;
5088         }
5089         return n.getAttribute(attr) || n[attr];
5090
5091     };
5092
5093     function getNodes(ns, mode, tagName){
5094         var result = [], ri = -1, cs;
5095         if(!ns){
5096             return result;
5097         }
5098         tagName = tagName || "*";
5099         if(typeof ns.getElementsByTagName != "undefined"){
5100             ns = [ns];
5101         }
5102         if(!mode){
5103             for(var i = 0, ni; ni = ns[i]; i++){
5104                 cs = ni.getElementsByTagName(tagName);
5105                 for(var j = 0, ci; ci = cs[j]; j++){
5106                     result[++ri] = ci;
5107                 }
5108             }
5109         }else if(mode == "/" || mode == ">"){
5110             var utag = tagName.toUpperCase();
5111             for(var i = 0, ni, cn; ni = ns[i]; i++){
5112                 cn = ni.children || ni.childNodes;
5113                 for(var j = 0, cj; cj = cn[j]; j++){
5114                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5115                         result[++ri] = cj;
5116                     }
5117                 }
5118             }
5119         }else if(mode == "+"){
5120             var utag = tagName.toUpperCase();
5121             for(var i = 0, n; n = ns[i]; i++){
5122                 while((n = n.nextSibling) && n.nodeType != 1);
5123                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5124                     result[++ri] = n;
5125                 }
5126             }
5127         }else if(mode == "~"){
5128             for(var i = 0, n; n = ns[i]; i++){
5129                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5130                 if(n){
5131                     result[++ri] = n;
5132                 }
5133             }
5134         }
5135         return result;
5136     };
5137
5138     function concat(a, b){
5139         if(b.slice){
5140             return a.concat(b);
5141         }
5142         for(var i = 0, l = b.length; i < l; i++){
5143             a[a.length] = b[i];
5144         }
5145         return a;
5146     }
5147
5148     function byTag(cs, tagName){
5149         if(cs.tagName || cs == document){
5150             cs = [cs];
5151         }
5152         if(!tagName){
5153             return cs;
5154         }
5155         var r = [], ri = -1;
5156         tagName = tagName.toLowerCase();
5157         for(var i = 0, ci; ci = cs[i]; i++){
5158             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5159                 r[++ri] = ci;
5160             }
5161         }
5162         return r;
5163     };
5164
5165     function byId(cs, attr, id){
5166         if(cs.tagName || cs == document){
5167             cs = [cs];
5168         }
5169         if(!id){
5170             return cs;
5171         }
5172         var r = [], ri = -1;
5173         for(var i = 0,ci; ci = cs[i]; i++){
5174             if(ci && ci.id == id){
5175                 r[++ri] = ci;
5176                 return r;
5177             }
5178         }
5179         return r;
5180     };
5181
5182     function byAttribute(cs, attr, value, op, custom){
5183         var r = [], ri = -1, st = custom=="{";
5184         var f = Roo.DomQuery.operators[op];
5185         for(var i = 0, ci; ci = cs[i]; i++){
5186             var a;
5187             if(st){
5188                 a = Roo.DomQuery.getStyle(ci, attr);
5189             }
5190             else if(attr == "class" || attr == "className"){
5191                 a = ci.className;
5192             }else if(attr == "for"){
5193                 a = ci.htmlFor;
5194             }else if(attr == "href"){
5195                 a = ci.getAttribute("href", 2);
5196             }else{
5197                 a = ci.getAttribute(attr);
5198             }
5199             if((f && f(a, value)) || (!f && a)){
5200                 r[++ri] = ci;
5201             }
5202         }
5203         return r;
5204     };
5205
5206     function byPseudo(cs, name, value){
5207         return Roo.DomQuery.pseudos[name](cs, value);
5208     };
5209
5210     // This is for IE MSXML which does not support expandos.
5211     // IE runs the same speed using setAttribute, however FF slows way down
5212     // and Safari completely fails so they need to continue to use expandos.
5213     var isIE = window.ActiveXObject ? true : false;
5214
5215     // this eval is stop the compressor from
5216     // renaming the variable to something shorter
5217     
5218     /** eval:var:batch */
5219     var batch = 30803; 
5220
5221     var key = 30803;
5222
5223     function nodupIEXml(cs){
5224         var d = ++key;
5225         cs[0].setAttribute("_nodup", d);
5226         var r = [cs[0]];
5227         for(var i = 1, len = cs.length; i < len; i++){
5228             var c = cs[i];
5229             if(!c.getAttribute("_nodup") != d){
5230                 c.setAttribute("_nodup", d);
5231                 r[r.length] = c;
5232             }
5233         }
5234         for(var i = 0, len = cs.length; i < len; i++){
5235             cs[i].removeAttribute("_nodup");
5236         }
5237         return r;
5238     }
5239
5240     function nodup(cs){
5241         if(!cs){
5242             return [];
5243         }
5244         var len = cs.length, c, i, r = cs, cj, ri = -1;
5245         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5246             return cs;
5247         }
5248         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5249             return nodupIEXml(cs);
5250         }
5251         var d = ++key;
5252         cs[0]._nodup = d;
5253         for(i = 1; c = cs[i]; i++){
5254             if(c._nodup != d){
5255                 c._nodup = d;
5256             }else{
5257                 r = [];
5258                 for(var j = 0; j < i; j++){
5259                     r[++ri] = cs[j];
5260                 }
5261                 for(j = i+1; cj = cs[j]; j++){
5262                     if(cj._nodup != d){
5263                         cj._nodup = d;
5264                         r[++ri] = cj;
5265                     }
5266                 }
5267                 return r;
5268             }
5269         }
5270         return r;
5271     }
5272
5273     function quickDiffIEXml(c1, c2){
5274         var d = ++key;
5275         for(var i = 0, len = c1.length; i < len; i++){
5276             c1[i].setAttribute("_qdiff", d);
5277         }
5278         var r = [];
5279         for(var i = 0, len = c2.length; i < len; i++){
5280             if(c2[i].getAttribute("_qdiff") != d){
5281                 r[r.length] = c2[i];
5282             }
5283         }
5284         for(var i = 0, len = c1.length; i < len; i++){
5285            c1[i].removeAttribute("_qdiff");
5286         }
5287         return r;
5288     }
5289
5290     function quickDiff(c1, c2){
5291         var len1 = c1.length;
5292         if(!len1){
5293             return c2;
5294         }
5295         if(isIE && c1[0].selectSingleNode){
5296             return quickDiffIEXml(c1, c2);
5297         }
5298         var d = ++key;
5299         for(var i = 0; i < len1; i++){
5300             c1[i]._qdiff = d;
5301         }
5302         var r = [];
5303         for(var i = 0, len = c2.length; i < len; i++){
5304             if(c2[i]._qdiff != d){
5305                 r[r.length] = c2[i];
5306             }
5307         }
5308         return r;
5309     }
5310
5311     function quickId(ns, mode, root, id){
5312         if(ns == root){
5313            var d = root.ownerDocument || root;
5314            return d.getElementById(id);
5315         }
5316         ns = getNodes(ns, mode, "*");
5317         return byId(ns, null, id);
5318     }
5319
5320     return {
5321         getStyle : function(el, name){
5322             return Roo.fly(el).getStyle(name);
5323         },
5324         /**
5325          * Compiles a selector/xpath query into a reusable function. The returned function
5326          * takes one parameter "root" (optional), which is the context node from where the query should start.
5327          * @param {String} selector The selector/xpath query
5328          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5329          * @return {Function}
5330          */
5331         compile : function(path, type){
5332             type = type || "select";
5333             
5334             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5335             var q = path, mode, lq;
5336             var tk = Roo.DomQuery.matchers;
5337             var tklen = tk.length;
5338             var mm;
5339
5340             // accept leading mode switch
5341             var lmode = q.match(modeRe);
5342             if(lmode && lmode[1]){
5343                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5344                 q = q.replace(lmode[1], "");
5345             }
5346             // strip leading slashes
5347             while(path.substr(0, 1)=="/"){
5348                 path = path.substr(1);
5349             }
5350
5351             while(q && lq != q){
5352                 lq = q;
5353                 var tm = q.match(tagTokenRe);
5354                 if(type == "select"){
5355                     if(tm){
5356                         if(tm[1] == "#"){
5357                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5358                         }else{
5359                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5360                         }
5361                         q = q.replace(tm[0], "");
5362                     }else if(q.substr(0, 1) != '@'){
5363                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5364                     }
5365                 }else{
5366                     if(tm){
5367                         if(tm[1] == "#"){
5368                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5369                         }else{
5370                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5371                         }
5372                         q = q.replace(tm[0], "");
5373                     }
5374                 }
5375                 while(!(mm = q.match(modeRe))){
5376                     var matched = false;
5377                     for(var j = 0; j < tklen; j++){
5378                         var t = tk[j];
5379                         var m = q.match(t.re);
5380                         if(m){
5381                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5382                                                     return m[i];
5383                                                 });
5384                             q = q.replace(m[0], "");
5385                             matched = true;
5386                             break;
5387                         }
5388                     }
5389                     // prevent infinite loop on bad selector
5390                     if(!matched){
5391                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5392                     }
5393                 }
5394                 if(mm[1]){
5395                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5396                     q = q.replace(mm[1], "");
5397                 }
5398             }
5399             fn[fn.length] = "return nodup(n);\n}";
5400             
5401              /** 
5402               * list of variables that need from compression as they are used by eval.
5403              *  eval:var:batch 
5404              *  eval:var:nodup
5405              *  eval:var:byTag
5406              *  eval:var:ById
5407              *  eval:var:getNodes
5408              *  eval:var:quickId
5409              *  eval:var:mode
5410              *  eval:var:root
5411              *  eval:var:n
5412              *  eval:var:byClassName
5413              *  eval:var:byPseudo
5414              *  eval:var:byAttribute
5415              *  eval:var:attrValue
5416              * 
5417              **/ 
5418             eval(fn.join(""));
5419             return f;
5420         },
5421
5422         /**
5423          * Selects a group of elements.
5424          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5425          * @param {Node} root (optional) The start of the query (defaults to document).
5426          * @return {Array}
5427          */
5428         select : function(path, root, type){
5429             if(!root || root == document){
5430                 root = document;
5431             }
5432             if(typeof root == "string"){
5433                 root = document.getElementById(root);
5434             }
5435             var paths = path.split(",");
5436             var results = [];
5437             for(var i = 0, len = paths.length; i < len; i++){
5438                 var p = paths[i].replace(trimRe, "");
5439                 if(!cache[p]){
5440                     cache[p] = Roo.DomQuery.compile(p);
5441                     if(!cache[p]){
5442                         throw p + " is not a valid selector";
5443                     }
5444                 }
5445                 var result = cache[p](root);
5446                 if(result && result != document){
5447                     results = results.concat(result);
5448                 }
5449             }
5450             if(paths.length > 1){
5451                 return nodup(results);
5452             }
5453             return results;
5454         },
5455
5456         /**
5457          * Selects a single element.
5458          * @param {String} selector The selector/xpath query
5459          * @param {Node} root (optional) The start of the query (defaults to document).
5460          * @return {Element}
5461          */
5462         selectNode : function(path, root){
5463             return Roo.DomQuery.select(path, root)[0];
5464         },
5465
5466         /**
5467          * Selects the value of a node, optionally replacing null with the defaultValue.
5468          * @param {String} selector The selector/xpath query
5469          * @param {Node} root (optional) The start of the query (defaults to document).
5470          * @param {String} defaultValue
5471          */
5472         selectValue : function(path, root, defaultValue){
5473             path = path.replace(trimRe, "");
5474             if(!valueCache[path]){
5475                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5476             }
5477             var n = valueCache[path](root);
5478             n = n[0] ? n[0] : n;
5479             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5480             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5481         },
5482
5483         /**
5484          * Selects the value of a node, parsing integers and floats.
5485          * @param {String} selector The selector/xpath query
5486          * @param {Node} root (optional) The start of the query (defaults to document).
5487          * @param {Number} defaultValue
5488          * @return {Number}
5489          */
5490         selectNumber : function(path, root, defaultValue){
5491             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5492             return parseFloat(v);
5493         },
5494
5495         /**
5496          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5497          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5498          * @param {String} selector The simple selector to test
5499          * @return {Boolean}
5500          */
5501         is : function(el, ss){
5502             if(typeof el == "string"){
5503                 el = document.getElementById(el);
5504             }
5505             var isArray = (el instanceof Array);
5506             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5507             return isArray ? (result.length == el.length) : (result.length > 0);
5508         },
5509
5510         /**
5511          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5512          * @param {Array} el An array of elements to filter
5513          * @param {String} selector The simple selector to test
5514          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5515          * the selector instead of the ones that match
5516          * @return {Array}
5517          */
5518         filter : function(els, ss, nonMatches){
5519             ss = ss.replace(trimRe, "");
5520             if(!simpleCache[ss]){
5521                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5522             }
5523             var result = simpleCache[ss](els);
5524             return nonMatches ? quickDiff(result, els) : result;
5525         },
5526
5527         /**
5528          * Collection of matching regular expressions and code snippets.
5529          */
5530         matchers : [{
5531                 re: /^\.([\w-]+)/,
5532                 select: 'n = byClassName(n, null, " {1} ");'
5533             }, {
5534                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5535                 select: 'n = byPseudo(n, "{1}", "{2}");'
5536             },{
5537                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5538                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5539             }, {
5540                 re: /^#([\w-]+)/,
5541                 select: 'n = byId(n, null, "{1}");'
5542             },{
5543                 re: /^@([\w-]+)/,
5544                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5545             }
5546         ],
5547
5548         /**
5549          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5550          * 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;.
5551          */
5552         operators : {
5553             "=" : function(a, v){
5554                 return a == v;
5555             },
5556             "!=" : function(a, v){
5557                 return a != v;
5558             },
5559             "^=" : function(a, v){
5560                 return a && a.substr(0, v.length) == v;
5561             },
5562             "$=" : function(a, v){
5563                 return a && a.substr(a.length-v.length) == v;
5564             },
5565             "*=" : function(a, v){
5566                 return a && a.indexOf(v) !== -1;
5567             },
5568             "%=" : function(a, v){
5569                 return (a % v) == 0;
5570             },
5571             "|=" : function(a, v){
5572                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5573             },
5574             "~=" : function(a, v){
5575                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5576             }
5577         },
5578
5579         /**
5580          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5581          * and the argument (if any) supplied in the selector.
5582          */
5583         pseudos : {
5584             "first-child" : function(c){
5585                 var r = [], ri = -1, n;
5586                 for(var i = 0, ci; ci = n = c[i]; i++){
5587                     while((n = n.previousSibling) && n.nodeType != 1);
5588                     if(!n){
5589                         r[++ri] = ci;
5590                     }
5591                 }
5592                 return r;
5593             },
5594
5595             "last-child" : function(c){
5596                 var r = [], ri = -1, n;
5597                 for(var i = 0, ci; ci = n = c[i]; i++){
5598                     while((n = n.nextSibling) && n.nodeType != 1);
5599                     if(!n){
5600                         r[++ri] = ci;
5601                     }
5602                 }
5603                 return r;
5604             },
5605
5606             "nth-child" : function(c, a) {
5607                 var r = [], ri = -1;
5608                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5609                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5610                 for(var i = 0, n; n = c[i]; i++){
5611                     var pn = n.parentNode;
5612                     if (batch != pn._batch) {
5613                         var j = 0;
5614                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5615                             if(cn.nodeType == 1){
5616                                cn.nodeIndex = ++j;
5617                             }
5618                         }
5619                         pn._batch = batch;
5620                     }
5621                     if (f == 1) {
5622                         if (l == 0 || n.nodeIndex == l){
5623                             r[++ri] = n;
5624                         }
5625                     } else if ((n.nodeIndex + l) % f == 0){
5626                         r[++ri] = n;
5627                     }
5628                 }
5629
5630                 return r;
5631             },
5632
5633             "only-child" : function(c){
5634                 var r = [], ri = -1;;
5635                 for(var i = 0, ci; ci = c[i]; i++){
5636                     if(!prev(ci) && !next(ci)){
5637                         r[++ri] = ci;
5638                     }
5639                 }
5640                 return r;
5641             },
5642
5643             "empty" : function(c){
5644                 var r = [], ri = -1;
5645                 for(var i = 0, ci; ci = c[i]; i++){
5646                     var cns = ci.childNodes, j = 0, cn, empty = true;
5647                     while(cn = cns[j]){
5648                         ++j;
5649                         if(cn.nodeType == 1 || cn.nodeType == 3){
5650                             empty = false;
5651                             break;
5652                         }
5653                     }
5654                     if(empty){
5655                         r[++ri] = ci;
5656                     }
5657                 }
5658                 return r;
5659             },
5660
5661             "contains" : function(c, v){
5662                 var r = [], ri = -1;
5663                 for(var i = 0, ci; ci = c[i]; i++){
5664                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5665                         r[++ri] = ci;
5666                     }
5667                 }
5668                 return r;
5669             },
5670
5671             "nodeValue" : function(c, v){
5672                 var r = [], ri = -1;
5673                 for(var i = 0, ci; ci = c[i]; i++){
5674                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5675                         r[++ri] = ci;
5676                     }
5677                 }
5678                 return r;
5679             },
5680
5681             "checked" : function(c){
5682                 var r = [], ri = -1;
5683                 for(var i = 0, ci; ci = c[i]; i++){
5684                     if(ci.checked == true){
5685                         r[++ri] = ci;
5686                     }
5687                 }
5688                 return r;
5689             },
5690
5691             "not" : function(c, ss){
5692                 return Roo.DomQuery.filter(c, ss, true);
5693             },
5694
5695             "odd" : function(c){
5696                 return this["nth-child"](c, "odd");
5697             },
5698
5699             "even" : function(c){
5700                 return this["nth-child"](c, "even");
5701             },
5702
5703             "nth" : function(c, a){
5704                 return c[a-1] || [];
5705             },
5706
5707             "first" : function(c){
5708                 return c[0] || [];
5709             },
5710
5711             "last" : function(c){
5712                 return c[c.length-1] || [];
5713             },
5714
5715             "has" : function(c, ss){
5716                 var s = Roo.DomQuery.select;
5717                 var r = [], ri = -1;
5718                 for(var i = 0, ci; ci = c[i]; i++){
5719                     if(s(ss, ci).length > 0){
5720                         r[++ri] = ci;
5721                     }
5722                 }
5723                 return r;
5724             },
5725
5726             "next" : function(c, ss){
5727                 var is = Roo.DomQuery.is;
5728                 var r = [], ri = -1;
5729                 for(var i = 0, ci; ci = c[i]; i++){
5730                     var n = next(ci);
5731                     if(n && is(n, ss)){
5732                         r[++ri] = ci;
5733                     }
5734                 }
5735                 return r;
5736             },
5737
5738             "prev" : function(c, ss){
5739                 var is = Roo.DomQuery.is;
5740                 var r = [], ri = -1;
5741                 for(var i = 0, ci; ci = c[i]; i++){
5742                     var n = prev(ci);
5743                     if(n && is(n, ss)){
5744                         r[++ri] = ci;
5745                     }
5746                 }
5747                 return r;
5748             }
5749         }
5750     };
5751 }();
5752
5753 /**
5754  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5755  * @param {String} path The selector/xpath query
5756  * @param {Node} root (optional) The start of the query (defaults to document).
5757  * @return {Array}
5758  * @member Roo
5759  * @method query
5760  */
5761 Roo.query = Roo.DomQuery.select;
5762 /*
5763  * Based on:
5764  * Ext JS Library 1.1.1
5765  * Copyright(c) 2006-2007, Ext JS, LLC.
5766  *
5767  * Originally Released Under LGPL - original licence link has changed is not relivant.
5768  *
5769  * Fork - LGPL
5770  * <script type="text/javascript">
5771  */
5772
5773 /**
5774  * @class Roo.util.Observable
5775  * Base class that provides a common interface for publishing events. Subclasses are expected to
5776  * to have a property "events" with all the events defined.<br>
5777  * For example:
5778  * <pre><code>
5779  Employee = function(name){
5780     this.name = name;
5781     this.addEvents({
5782         "fired" : true,
5783         "quit" : true
5784     });
5785  }
5786  Roo.extend(Employee, Roo.util.Observable);
5787 </code></pre>
5788  * @param {Object} config properties to use (incuding events / listeners)
5789  */
5790
5791 Roo.util.Observable = function(cfg){
5792     
5793     cfg = cfg|| {};
5794     this.addEvents(cfg.events || {});
5795     if (cfg.events) {
5796         delete cfg.events; // make sure
5797     }
5798      
5799     Roo.apply(this, cfg);
5800     
5801     if(this.listeners){
5802         this.on(this.listeners);
5803         delete this.listeners;
5804     }
5805 };
5806 Roo.util.Observable.prototype = {
5807     /** 
5808  * @cfg {Object} listeners  list of events and functions to call for this object, 
5809  * For example :
5810  * <pre><code>
5811     listeners :  { 
5812        'click' : function(e) {
5813            ..... 
5814         } ,
5815         .... 
5816     } 
5817   </code></pre>
5818  */
5819     
5820     
5821     /**
5822      * Fires the specified event with the passed parameters (minus the event name).
5823      * @param {String} eventName
5824      * @param {Object...} args Variable number of parameters are passed to handlers
5825      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5826      */
5827     fireEvent : function(){
5828         var ce = this.events[arguments[0].toLowerCase()];
5829         if(typeof ce == "object"){
5830             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5831         }else{
5832             return true;
5833         }
5834     },
5835
5836     // private
5837     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5838
5839     /**
5840      * Appends an event handler to this component
5841      * @param {String}   eventName The type of event to listen for
5842      * @param {Function} handler The method the event invokes
5843      * @param {Object}   scope (optional) The scope in which to execute the handler
5844      * function. The handler function's "this" context.
5845      * @param {Object}   options (optional) An object containing handler configuration
5846      * properties. This may contain any of the following properties:<ul>
5847      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5848      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5849      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5850      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5851      * by the specified number of milliseconds. If the event fires again within that time, the original
5852      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5853      * </ul><br>
5854      * <p>
5855      * <b>Combining Options</b><br>
5856      * Using the options argument, it is possible to combine different types of listeners:<br>
5857      * <br>
5858      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5859                 <pre><code>
5860                 el.on('click', this.onClick, this, {
5861                         single: true,
5862                 delay: 100,
5863                 forumId: 4
5864                 });
5865                 </code></pre>
5866      * <p>
5867      * <b>Attaching multiple handlers in 1 call</b><br>
5868      * The method also allows for a single argument to be passed which is a config object containing properties
5869      * which specify multiple handlers.
5870      * <pre><code>
5871                 el.on({
5872                         'click': {
5873                         fn: this.onClick,
5874                         scope: this,
5875                         delay: 100
5876                 }, 
5877                 'mouseover': {
5878                         fn: this.onMouseOver,
5879                         scope: this
5880                 },
5881                 'mouseout': {
5882                         fn: this.onMouseOut,
5883                         scope: this
5884                 }
5885                 });
5886                 </code></pre>
5887      * <p>
5888      * Or a shorthand syntax which passes the same scope object to all handlers:
5889         <pre><code>
5890                 el.on({
5891                         'click': this.onClick,
5892                 'mouseover': this.onMouseOver,
5893                 'mouseout': this.onMouseOut,
5894                 scope: this
5895                 });
5896                 </code></pre>
5897      */
5898     addListener : function(eventName, fn, scope, o){
5899         if(typeof eventName == "object"){
5900             o = eventName;
5901             for(var e in o){
5902                 if(this.filterOptRe.test(e)){
5903                     continue;
5904                 }
5905                 if(typeof o[e] == "function"){
5906                     // shared options
5907                     this.addListener(e, o[e], o.scope,  o);
5908                 }else{
5909                     // individual options
5910                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5911                 }
5912             }
5913             return;
5914         }
5915         o = (!o || typeof o == "boolean") ? {} : o;
5916         eventName = eventName.toLowerCase();
5917         var ce = this.events[eventName] || true;
5918         if(typeof ce == "boolean"){
5919             ce = new Roo.util.Event(this, eventName);
5920             this.events[eventName] = ce;
5921         }
5922         ce.addListener(fn, scope, o);
5923     },
5924
5925     /**
5926      * Removes a listener
5927      * @param {String}   eventName     The type of event to listen for
5928      * @param {Function} handler        The handler to remove
5929      * @param {Object}   scope  (optional) The scope (this object) for the handler
5930      */
5931     removeListener : function(eventName, fn, scope){
5932         var ce = this.events[eventName.toLowerCase()];
5933         if(typeof ce == "object"){
5934             ce.removeListener(fn, scope);
5935         }
5936     },
5937
5938     /**
5939      * Removes all listeners for this object
5940      */
5941     purgeListeners : function(){
5942         for(var evt in this.events){
5943             if(typeof this.events[evt] == "object"){
5944                  this.events[evt].clearListeners();
5945             }
5946         }
5947     },
5948
5949     relayEvents : function(o, events){
5950         var createHandler = function(ename){
5951             return function(){
5952                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5953             };
5954         };
5955         for(var i = 0, len = events.length; i < len; i++){
5956             var ename = events[i];
5957             if(!this.events[ename]){ this.events[ename] = true; };
5958             o.on(ename, createHandler(ename), this);
5959         }
5960     },
5961
5962     /**
5963      * Used to define events on this Observable
5964      * @param {Object} object The object with the events defined
5965      */
5966     addEvents : function(o){
5967         if(!this.events){
5968             this.events = {};
5969         }
5970         Roo.applyIf(this.events, o);
5971     },
5972
5973     /**
5974      * Checks to see if this object has any listeners for a specified event
5975      * @param {String} eventName The name of the event to check for
5976      * @return {Boolean} True if the event is being listened for, else false
5977      */
5978     hasListener : function(eventName){
5979         var e = this.events[eventName];
5980         return typeof e == "object" && e.listeners.length > 0;
5981     }
5982 };
5983 /**
5984  * Appends an event handler to this element (shorthand for addListener)
5985  * @param {String}   eventName     The type of event to listen for
5986  * @param {Function} handler        The method the event invokes
5987  * @param {Object}   scope (optional) The scope in which to execute the handler
5988  * function. The handler function's "this" context.
5989  * @param {Object}   options  (optional)
5990  * @method
5991  */
5992 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5993 /**
5994  * Removes a listener (shorthand for removeListener)
5995  * @param {String}   eventName     The type of event to listen for
5996  * @param {Function} handler        The handler to remove
5997  * @param {Object}   scope  (optional) The scope (this object) for the handler
5998  * @method
5999  */
6000 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6001
6002 /**
6003  * Starts capture on the specified Observable. All events will be passed
6004  * to the supplied function with the event name + standard signature of the event
6005  * <b>before</b> the event is fired. If the supplied function returns false,
6006  * the event will not fire.
6007  * @param {Observable} o The Observable to capture
6008  * @param {Function} fn The function to call
6009  * @param {Object} scope (optional) The scope (this object) for the fn
6010  * @static
6011  */
6012 Roo.util.Observable.capture = function(o, fn, scope){
6013     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6014 };
6015
6016 /**
6017  * Removes <b>all</b> added captures from the Observable.
6018  * @param {Observable} o The Observable to release
6019  * @static
6020  */
6021 Roo.util.Observable.releaseCapture = function(o){
6022     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6023 };
6024
6025 (function(){
6026
6027     var createBuffered = function(h, o, scope){
6028         var task = new Roo.util.DelayedTask();
6029         return function(){
6030             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6031         };
6032     };
6033
6034     var createSingle = function(h, e, fn, scope){
6035         return function(){
6036             e.removeListener(fn, scope);
6037             return h.apply(scope, arguments);
6038         };
6039     };
6040
6041     var createDelayed = function(h, o, scope){
6042         return function(){
6043             var args = Array.prototype.slice.call(arguments, 0);
6044             setTimeout(function(){
6045                 h.apply(scope, args);
6046             }, o.delay || 10);
6047         };
6048     };
6049
6050     Roo.util.Event = function(obj, name){
6051         this.name = name;
6052         this.obj = obj;
6053         this.listeners = [];
6054     };
6055
6056     Roo.util.Event.prototype = {
6057         addListener : function(fn, scope, options){
6058             var o = options || {};
6059             scope = scope || this.obj;
6060             if(!this.isListening(fn, scope)){
6061                 var l = {fn: fn, scope: scope, options: o};
6062                 var h = fn;
6063                 if(o.delay){
6064                     h = createDelayed(h, o, scope);
6065                 }
6066                 if(o.single){
6067                     h = createSingle(h, this, fn, scope);
6068                 }
6069                 if(o.buffer){
6070                     h = createBuffered(h, o, scope);
6071                 }
6072                 l.fireFn = h;
6073                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6074                     this.listeners.push(l);
6075                 }else{
6076                     this.listeners = this.listeners.slice(0);
6077                     this.listeners.push(l);
6078                 }
6079             }
6080         },
6081
6082         findListener : function(fn, scope){
6083             scope = scope || this.obj;
6084             var ls = this.listeners;
6085             for(var i = 0, len = ls.length; i < len; i++){
6086                 var l = ls[i];
6087                 if(l.fn == fn && l.scope == scope){
6088                     return i;
6089                 }
6090             }
6091             return -1;
6092         },
6093
6094         isListening : function(fn, scope){
6095             return this.findListener(fn, scope) != -1;
6096         },
6097
6098         removeListener : function(fn, scope){
6099             var index;
6100             if((index = this.findListener(fn, scope)) != -1){
6101                 if(!this.firing){
6102                     this.listeners.splice(index, 1);
6103                 }else{
6104                     this.listeners = this.listeners.slice(0);
6105                     this.listeners.splice(index, 1);
6106                 }
6107                 return true;
6108             }
6109             return false;
6110         },
6111
6112         clearListeners : function(){
6113             this.listeners = [];
6114         },
6115
6116         fire : function(){
6117             var ls = this.listeners, scope, len = ls.length;
6118             if(len > 0){
6119                 this.firing = true;
6120                 var args = Array.prototype.slice.call(arguments, 0);
6121                 for(var i = 0; i < len; i++){
6122                     var l = ls[i];
6123                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6124                         this.firing = false;
6125                         return false;
6126                     }
6127                 }
6128                 this.firing = false;
6129             }
6130             return true;
6131         }
6132     };
6133 })();/*
6134  * Based on:
6135  * Ext JS Library 1.1.1
6136  * Copyright(c) 2006-2007, Ext JS, LLC.
6137  *
6138  * Originally Released Under LGPL - original licence link has changed is not relivant.
6139  *
6140  * Fork - LGPL
6141  * <script type="text/javascript">
6142  */
6143
6144 /**
6145  * @class Roo.EventManager
6146  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6147  * several useful events directly.
6148  * See {@link Roo.EventObject} for more details on normalized event objects.
6149  * @singleton
6150  */
6151 Roo.EventManager = function(){
6152     var docReadyEvent, docReadyProcId, docReadyState = false;
6153     var resizeEvent, resizeTask, textEvent, textSize;
6154     var E = Roo.lib.Event;
6155     var D = Roo.lib.Dom;
6156
6157
6158     var fireDocReady = function(){
6159         if(!docReadyState){
6160             docReadyState = true;
6161             Roo.isReady = true;
6162             if(docReadyProcId){
6163                 clearInterval(docReadyProcId);
6164             }
6165             if(Roo.isGecko || Roo.isOpera) {
6166                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6167             }
6168             if(Roo.isIE){
6169                 var defer = document.getElementById("ie-deferred-loader");
6170                 if(defer){
6171                     defer.onreadystatechange = null;
6172                     defer.parentNode.removeChild(defer);
6173                 }
6174             }
6175             if(docReadyEvent){
6176                 docReadyEvent.fire();
6177                 docReadyEvent.clearListeners();
6178             }
6179         }
6180     };
6181     
6182     var initDocReady = function(){
6183         docReadyEvent = new Roo.util.Event();
6184         if(Roo.isGecko || Roo.isOpera) {
6185             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6186         }else if(Roo.isIE){
6187             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6188             var defer = document.getElementById("ie-deferred-loader");
6189             defer.onreadystatechange = function(){
6190                 if(this.readyState == "complete"){
6191                     fireDocReady();
6192                 }
6193             };
6194         }else if(Roo.isSafari){ 
6195             docReadyProcId = setInterval(function(){
6196                 var rs = document.readyState;
6197                 if(rs == "complete") {
6198                     fireDocReady();     
6199                  }
6200             }, 10);
6201         }
6202         // no matter what, make sure it fires on load
6203         E.on(window, "load", fireDocReady);
6204     };
6205
6206     var createBuffered = function(h, o){
6207         var task = new Roo.util.DelayedTask(h);
6208         return function(e){
6209             // create new event object impl so new events don't wipe out properties
6210             e = new Roo.EventObjectImpl(e);
6211             task.delay(o.buffer, h, null, [e]);
6212         };
6213     };
6214
6215     var createSingle = function(h, el, ename, fn){
6216         return function(e){
6217             Roo.EventManager.removeListener(el, ename, fn);
6218             h(e);
6219         };
6220     };
6221
6222     var createDelayed = function(h, o){
6223         return function(e){
6224             // create new event object impl so new events don't wipe out properties
6225             e = new Roo.EventObjectImpl(e);
6226             setTimeout(function(){
6227                 h(e);
6228             }, o.delay || 10);
6229         };
6230     };
6231
6232     var listen = function(element, ename, opt, fn, scope){
6233         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6234         fn = fn || o.fn; scope = scope || o.scope;
6235         var el = Roo.getDom(element);
6236         if(!el){
6237             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6238         }
6239         var h = function(e){
6240             e = Roo.EventObject.setEvent(e);
6241             var t;
6242             if(o.delegate){
6243                 t = e.getTarget(o.delegate, el);
6244                 if(!t){
6245                     return;
6246                 }
6247             }else{
6248                 t = e.target;
6249             }
6250             if(o.stopEvent === true){
6251                 e.stopEvent();
6252             }
6253             if(o.preventDefault === true){
6254                e.preventDefault();
6255             }
6256             if(o.stopPropagation === true){
6257                 e.stopPropagation();
6258             }
6259
6260             if(o.normalized === false){
6261                 e = e.browserEvent;
6262             }
6263
6264             fn.call(scope || el, e, t, o);
6265         };
6266         if(o.delay){
6267             h = createDelayed(h, o);
6268         }
6269         if(o.single){
6270             h = createSingle(h, el, ename, fn);
6271         }
6272         if(o.buffer){
6273             h = createBuffered(h, o);
6274         }
6275         fn._handlers = fn._handlers || [];
6276         fn._handlers.push([Roo.id(el), ename, h]);
6277
6278         E.on(el, ename, h);
6279         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6280             el.addEventListener("DOMMouseScroll", h, false);
6281             E.on(window, 'unload', function(){
6282                 el.removeEventListener("DOMMouseScroll", h, false);
6283             });
6284         }
6285         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6286             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6287         }
6288         return h;
6289     };
6290
6291     var stopListening = function(el, ename, fn){
6292         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6293         if(hds){
6294             for(var i = 0, len = hds.length; i < len; i++){
6295                 var h = hds[i];
6296                 if(h[0] == id && h[1] == ename){
6297                     hd = h[2];
6298                     hds.splice(i, 1);
6299                     break;
6300                 }
6301             }
6302         }
6303         E.un(el, ename, hd);
6304         el = Roo.getDom(el);
6305         if(ename == "mousewheel" && el.addEventListener){
6306             el.removeEventListener("DOMMouseScroll", hd, false);
6307         }
6308         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6309             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6310         }
6311     };
6312
6313     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6314     
6315     var pub = {
6316         
6317         
6318         /** 
6319          * Fix for doc tools
6320          * @scope Roo.EventManager
6321          */
6322         
6323         
6324         /** 
6325          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6326          * object with a Roo.EventObject
6327          * @param {Function} fn        The method the event invokes
6328          * @param {Object}   scope    An object that becomes the scope of the handler
6329          * @param {boolean}  override If true, the obj passed in becomes
6330          *                             the execution scope of the listener
6331          * @return {Function} The wrapped function
6332          * @deprecated
6333          */
6334         wrap : function(fn, scope, override){
6335             return function(e){
6336                 Roo.EventObject.setEvent(e);
6337                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6338             };
6339         },
6340         
6341         /**
6342      * Appends an event handler to an element (shorthand for addListener)
6343      * @param {String/HTMLElement}   element        The html element or id to assign the
6344      * @param {String}   eventName The type of event to listen for
6345      * @param {Function} handler The method the event invokes
6346      * @param {Object}   scope (optional) The scope in which to execute the handler
6347      * function. The handler function's "this" context.
6348      * @param {Object}   options (optional) An object containing handler configuration
6349      * properties. This may contain any of the following properties:<ul>
6350      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6351      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6352      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6353      * <li>preventDefault {Boolean} True to prevent the default action</li>
6354      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6355      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6356      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6357      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6358      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6359      * by the specified number of milliseconds. If the event fires again within that time, the original
6360      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6361      * </ul><br>
6362      * <p>
6363      * <b>Combining Options</b><br>
6364      * Using the options argument, it is possible to combine different types of listeners:<br>
6365      * <br>
6366      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6367      * Code:<pre><code>
6368 el.on('click', this.onClick, this, {
6369     single: true,
6370     delay: 100,
6371     stopEvent : true,
6372     forumId: 4
6373 });</code></pre>
6374      * <p>
6375      * <b>Attaching multiple handlers in 1 call</b><br>
6376       * The method also allows for a single argument to be passed which is a config object containing properties
6377      * which specify multiple handlers.
6378      * <p>
6379      * Code:<pre><code>
6380 el.on({
6381     'click' : {
6382         fn: this.onClick
6383         scope: this,
6384         delay: 100
6385     },
6386     'mouseover' : {
6387         fn: this.onMouseOver
6388         scope: this
6389     },
6390     'mouseout' : {
6391         fn: this.onMouseOut
6392         scope: this
6393     }
6394 });</code></pre>
6395      * <p>
6396      * Or a shorthand syntax:<br>
6397      * Code:<pre><code>
6398 el.on({
6399     'click' : this.onClick,
6400     'mouseover' : this.onMouseOver,
6401     'mouseout' : this.onMouseOut
6402     scope: this
6403 });</code></pre>
6404      */
6405         addListener : function(element, eventName, fn, scope, options){
6406             if(typeof eventName == "object"){
6407                 var o = eventName;
6408                 for(var e in o){
6409                     if(propRe.test(e)){
6410                         continue;
6411                     }
6412                     if(typeof o[e] == "function"){
6413                         // shared options
6414                         listen(element, e, o, o[e], o.scope);
6415                     }else{
6416                         // individual options
6417                         listen(element, e, o[e]);
6418                     }
6419                 }
6420                 return;
6421             }
6422             return listen(element, eventName, options, fn, scope);
6423         },
6424         
6425         /**
6426          * Removes an event handler
6427          *
6428          * @param {String/HTMLElement}   element        The id or html element to remove the 
6429          *                             event from
6430          * @param {String}   eventName     The type of event
6431          * @param {Function} fn
6432          * @return {Boolean} True if a listener was actually removed
6433          */
6434         removeListener : function(element, eventName, fn){
6435             return stopListening(element, eventName, fn);
6436         },
6437         
6438         /**
6439          * Fires when the document is ready (before onload and before images are loaded). Can be 
6440          * accessed shorthanded Roo.onReady().
6441          * @param {Function} fn        The method the event invokes
6442          * @param {Object}   scope    An  object that becomes the scope of the handler
6443          * @param {boolean}  options
6444          */
6445         onDocumentReady : function(fn, scope, options){
6446             if(docReadyState){ // if it already fired
6447                 docReadyEvent.addListener(fn, scope, options);
6448                 docReadyEvent.fire();
6449                 docReadyEvent.clearListeners();
6450                 return;
6451             }
6452             if(!docReadyEvent){
6453                 initDocReady();
6454             }
6455             docReadyEvent.addListener(fn, scope, options);
6456         },
6457         
6458         /**
6459          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6460          * @param {Function} fn        The method the event invokes
6461          * @param {Object}   scope    An object that becomes the scope of the handler
6462          * @param {boolean}  options
6463          */
6464         onWindowResize : function(fn, scope, options){
6465             if(!resizeEvent){
6466                 resizeEvent = new Roo.util.Event();
6467                 resizeTask = new Roo.util.DelayedTask(function(){
6468                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6469                 });
6470                 E.on(window, "resize", function(){
6471                     if(Roo.isIE){
6472                         resizeTask.delay(50);
6473                     }else{
6474                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6475                     }
6476                 });
6477             }
6478             resizeEvent.addListener(fn, scope, options);
6479         },
6480
6481         /**
6482          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6483          * @param {Function} fn        The method the event invokes
6484          * @param {Object}   scope    An object that becomes the scope of the handler
6485          * @param {boolean}  options
6486          */
6487         onTextResize : function(fn, scope, options){
6488             if(!textEvent){
6489                 textEvent = new Roo.util.Event();
6490                 var textEl = new Roo.Element(document.createElement('div'));
6491                 textEl.dom.className = 'x-text-resize';
6492                 textEl.dom.innerHTML = 'X';
6493                 textEl.appendTo(document.body);
6494                 textSize = textEl.dom.offsetHeight;
6495                 setInterval(function(){
6496                     if(textEl.dom.offsetHeight != textSize){
6497                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6498                     }
6499                 }, this.textResizeInterval);
6500             }
6501             textEvent.addListener(fn, scope, options);
6502         },
6503
6504         /**
6505          * Removes the passed window resize listener.
6506          * @param {Function} fn        The method the event invokes
6507          * @param {Object}   scope    The scope of handler
6508          */
6509         removeResizeListener : function(fn, scope){
6510             if(resizeEvent){
6511                 resizeEvent.removeListener(fn, scope);
6512             }
6513         },
6514
6515         // private
6516         fireResize : function(){
6517             if(resizeEvent){
6518                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6519             }   
6520         },
6521         /**
6522          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6523          */
6524         ieDeferSrc : false,
6525         /**
6526          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6527          */
6528         textResizeInterval : 50
6529     };
6530     
6531     /**
6532      * Fix for doc tools
6533      * @scopeAlias pub=Roo.EventManager
6534      */
6535     
6536      /**
6537      * Appends an event handler to an element (shorthand for addListener)
6538      * @param {String/HTMLElement}   element        The html element or id to assign the
6539      * @param {String}   eventName The type of event to listen for
6540      * @param {Function} handler The method the event invokes
6541      * @param {Object}   scope (optional) The scope in which to execute the handler
6542      * function. The handler function's "this" context.
6543      * @param {Object}   options (optional) An object containing handler configuration
6544      * properties. This may contain any of the following properties:<ul>
6545      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6546      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6547      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6548      * <li>preventDefault {Boolean} True to prevent the default action</li>
6549      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6550      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6551      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6552      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6553      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6554      * by the specified number of milliseconds. If the event fires again within that time, the original
6555      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6556      * </ul><br>
6557      * <p>
6558      * <b>Combining Options</b><br>
6559      * Using the options argument, it is possible to combine different types of listeners:<br>
6560      * <br>
6561      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6562      * Code:<pre><code>
6563 el.on('click', this.onClick, this, {
6564     single: true,
6565     delay: 100,
6566     stopEvent : true,
6567     forumId: 4
6568 });</code></pre>
6569      * <p>
6570      * <b>Attaching multiple handlers in 1 call</b><br>
6571       * The method also allows for a single argument to be passed which is a config object containing properties
6572      * which specify multiple handlers.
6573      * <p>
6574      * Code:<pre><code>
6575 el.on({
6576     'click' : {
6577         fn: this.onClick
6578         scope: this,
6579         delay: 100
6580     },
6581     'mouseover' : {
6582         fn: this.onMouseOver
6583         scope: this
6584     },
6585     'mouseout' : {
6586         fn: this.onMouseOut
6587         scope: this
6588     }
6589 });</code></pre>
6590      * <p>
6591      * Or a shorthand syntax:<br>
6592      * Code:<pre><code>
6593 el.on({
6594     'click' : this.onClick,
6595     'mouseover' : this.onMouseOver,
6596     'mouseout' : this.onMouseOut
6597     scope: this
6598 });</code></pre>
6599      */
6600     pub.on = pub.addListener;
6601     pub.un = pub.removeListener;
6602
6603     pub.stoppedMouseDownEvent = new Roo.util.Event();
6604     return pub;
6605 }();
6606 /**
6607   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6608   * @param {Function} fn        The method the event invokes
6609   * @param {Object}   scope    An  object that becomes the scope of the handler
6610   * @param {boolean}  override If true, the obj passed in becomes
6611   *                             the execution scope of the listener
6612   * @member Roo
6613   * @method onReady
6614  */
6615 Roo.onReady = Roo.EventManager.onDocumentReady;
6616
6617 Roo.onReady(function(){
6618     var bd = Roo.get(document.body);
6619     if(!bd){ return; }
6620
6621     var cls = [
6622             Roo.isIE ? "roo-ie"
6623             : Roo.isGecko ? "roo-gecko"
6624             : Roo.isOpera ? "roo-opera"
6625             : Roo.isSafari ? "roo-safari" : ""];
6626
6627     if(Roo.isMac){
6628         cls.push("roo-mac");
6629     }
6630     if(Roo.isLinux){
6631         cls.push("roo-linux");
6632     }
6633     if(Roo.isBorderBox){
6634         cls.push('roo-border-box');
6635     }
6636     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6637         var p = bd.dom.parentNode;
6638         if(p){
6639             p.className += ' roo-strict';
6640         }
6641     }
6642     bd.addClass(cls.join(' '));
6643 });
6644
6645 /**
6646  * @class Roo.EventObject
6647  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6648  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6649  * Example:
6650  * <pre><code>
6651  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6652     e.preventDefault();
6653     var target = e.getTarget();
6654     ...
6655  }
6656  var myDiv = Roo.get("myDiv");
6657  myDiv.on("click", handleClick);
6658  //or
6659  Roo.EventManager.on("myDiv", 'click', handleClick);
6660  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6661  </code></pre>
6662  * @singleton
6663  */
6664 Roo.EventObject = function(){
6665     
6666     var E = Roo.lib.Event;
6667     
6668     // safari keypress events for special keys return bad keycodes
6669     var safariKeys = {
6670         63234 : 37, // left
6671         63235 : 39, // right
6672         63232 : 38, // up
6673         63233 : 40, // down
6674         63276 : 33, // page up
6675         63277 : 34, // page down
6676         63272 : 46, // delete
6677         63273 : 36, // home
6678         63275 : 35  // end
6679     };
6680
6681     // normalize button clicks
6682     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6683                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6684
6685     Roo.EventObjectImpl = function(e){
6686         if(e){
6687             this.setEvent(e.browserEvent || e);
6688         }
6689     };
6690     Roo.EventObjectImpl.prototype = {
6691         /**
6692          * Used to fix doc tools.
6693          * @scope Roo.EventObject.prototype
6694          */
6695             
6696
6697         
6698         
6699         /** The normal browser event */
6700         browserEvent : null,
6701         /** The button pressed in a mouse event */
6702         button : -1,
6703         /** True if the shift key was down during the event */
6704         shiftKey : false,
6705         /** True if the control key was down during the event */
6706         ctrlKey : false,
6707         /** True if the alt key was down during the event */
6708         altKey : false,
6709
6710         /** Key constant 
6711         * @type Number */
6712         BACKSPACE : 8,
6713         /** Key constant 
6714         * @type Number */
6715         TAB : 9,
6716         /** Key constant 
6717         * @type Number */
6718         RETURN : 13,
6719         /** Key constant 
6720         * @type Number */
6721         ENTER : 13,
6722         /** Key constant 
6723         * @type Number */
6724         SHIFT : 16,
6725         /** Key constant 
6726         * @type Number */
6727         CONTROL : 17,
6728         /** Key constant 
6729         * @type Number */
6730         ESC : 27,
6731         /** Key constant 
6732         * @type Number */
6733         SPACE : 32,
6734         /** Key constant 
6735         * @type Number */
6736         PAGEUP : 33,
6737         /** Key constant 
6738         * @type Number */
6739         PAGEDOWN : 34,
6740         /** Key constant 
6741         * @type Number */
6742         END : 35,
6743         /** Key constant 
6744         * @type Number */
6745         HOME : 36,
6746         /** Key constant 
6747         * @type Number */
6748         LEFT : 37,
6749         /** Key constant 
6750         * @type Number */
6751         UP : 38,
6752         /** Key constant 
6753         * @type Number */
6754         RIGHT : 39,
6755         /** Key constant 
6756         * @type Number */
6757         DOWN : 40,
6758         /** Key constant 
6759         * @type Number */
6760         DELETE : 46,
6761         /** Key constant 
6762         * @type Number */
6763         F5 : 116,
6764
6765            /** @private */
6766         setEvent : function(e){
6767             if(e == this || (e && e.browserEvent)){ // already wrapped
6768                 return e;
6769             }
6770             this.browserEvent = e;
6771             if(e){
6772                 // normalize buttons
6773                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6774                 if(e.type == 'click' && this.button == -1){
6775                     this.button = 0;
6776                 }
6777                 this.type = e.type;
6778                 this.shiftKey = e.shiftKey;
6779                 // mac metaKey behaves like ctrlKey
6780                 this.ctrlKey = e.ctrlKey || e.metaKey;
6781                 this.altKey = e.altKey;
6782                 // in getKey these will be normalized for the mac
6783                 this.keyCode = e.keyCode;
6784                 // keyup warnings on firefox.
6785                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6786                 // cache the target for the delayed and or buffered events
6787                 this.target = E.getTarget(e);
6788                 // same for XY
6789                 this.xy = E.getXY(e);
6790             }else{
6791                 this.button = -1;
6792                 this.shiftKey = false;
6793                 this.ctrlKey = false;
6794                 this.altKey = false;
6795                 this.keyCode = 0;
6796                 this.charCode =0;
6797                 this.target = null;
6798                 this.xy = [0, 0];
6799             }
6800             return this;
6801         },
6802
6803         /**
6804          * Stop the event (preventDefault and stopPropagation)
6805          */
6806         stopEvent : function(){
6807             if(this.browserEvent){
6808                 if(this.browserEvent.type == 'mousedown'){
6809                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6810                 }
6811                 E.stopEvent(this.browserEvent);
6812             }
6813         },
6814
6815         /**
6816          * Prevents the browsers default handling of the event.
6817          */
6818         preventDefault : function(){
6819             if(this.browserEvent){
6820                 E.preventDefault(this.browserEvent);
6821             }
6822         },
6823
6824         /** @private */
6825         isNavKeyPress : function(){
6826             var k = this.keyCode;
6827             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6828             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6829         },
6830
6831         isSpecialKey : function(){
6832             var k = this.keyCode;
6833             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6834             (k == 16) || (k == 17) ||
6835             (k >= 18 && k <= 20) ||
6836             (k >= 33 && k <= 35) ||
6837             (k >= 36 && k <= 39) ||
6838             (k >= 44 && k <= 45);
6839         },
6840         /**
6841          * Cancels bubbling of the event.
6842          */
6843         stopPropagation : function(){
6844             if(this.browserEvent){
6845                 if(this.type == 'mousedown'){
6846                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6847                 }
6848                 E.stopPropagation(this.browserEvent);
6849             }
6850         },
6851
6852         /**
6853          * Gets the key code for the event.
6854          * @return {Number}
6855          */
6856         getCharCode : function(){
6857             return this.charCode || this.keyCode;
6858         },
6859
6860         /**
6861          * Returns a normalized keyCode for the event.
6862          * @return {Number} The key code
6863          */
6864         getKey : function(){
6865             var k = this.keyCode || this.charCode;
6866             return Roo.isSafari ? (safariKeys[k] || k) : k;
6867         },
6868
6869         /**
6870          * Gets the x coordinate of the event.
6871          * @return {Number}
6872          */
6873         getPageX : function(){
6874             return this.xy[0];
6875         },
6876
6877         /**
6878          * Gets the y coordinate of the event.
6879          * @return {Number}
6880          */
6881         getPageY : function(){
6882             return this.xy[1];
6883         },
6884
6885         /**
6886          * Gets the time of the event.
6887          * @return {Number}
6888          */
6889         getTime : function(){
6890             if(this.browserEvent){
6891                 return E.getTime(this.browserEvent);
6892             }
6893             return null;
6894         },
6895
6896         /**
6897          * Gets the page coordinates of the event.
6898          * @return {Array} The xy values like [x, y]
6899          */
6900         getXY : function(){
6901             return this.xy;
6902         },
6903
6904         /**
6905          * Gets the target for the event.
6906          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6907          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6908                 search as a number or element (defaults to 10 || document.body)
6909          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6910          * @return {HTMLelement}
6911          */
6912         getTarget : function(selector, maxDepth, returnEl){
6913             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6914         },
6915         /**
6916          * Gets the related target.
6917          * @return {HTMLElement}
6918          */
6919         getRelatedTarget : function(){
6920             if(this.browserEvent){
6921                 return E.getRelatedTarget(this.browserEvent);
6922             }
6923             return null;
6924         },
6925
6926         /**
6927          * Normalizes mouse wheel delta across browsers
6928          * @return {Number} The delta
6929          */
6930         getWheelDelta : function(){
6931             var e = this.browserEvent;
6932             var delta = 0;
6933             if(e.wheelDelta){ /* IE/Opera. */
6934                 delta = e.wheelDelta/120;
6935             }else if(e.detail){ /* Mozilla case. */
6936                 delta = -e.detail/3;
6937             }
6938             return delta;
6939         },
6940
6941         /**
6942          * Returns true if the control, meta, shift or alt key was pressed during this event.
6943          * @return {Boolean}
6944          */
6945         hasModifier : function(){
6946             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6947         },
6948
6949         /**
6950          * Returns true if the target of this event equals el or is a child of el
6951          * @param {String/HTMLElement/Element} el
6952          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6953          * @return {Boolean}
6954          */
6955         within : function(el, related){
6956             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6957             return t && Roo.fly(el).contains(t);
6958         },
6959
6960         getPoint : function(){
6961             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6962         }
6963     };
6964
6965     return new Roo.EventObjectImpl();
6966 }();
6967             
6968     /*
6969  * Based on:
6970  * Ext JS Library 1.1.1
6971  * Copyright(c) 2006-2007, Ext JS, LLC.
6972  *
6973  * Originally Released Under LGPL - original licence link has changed is not relivant.
6974  *
6975  * Fork - LGPL
6976  * <script type="text/javascript">
6977  */
6978
6979  
6980 // was in Composite Element!??!?!
6981  
6982 (function(){
6983     var D = Roo.lib.Dom;
6984     var E = Roo.lib.Event;
6985     var A = Roo.lib.Anim;
6986
6987     // local style camelizing for speed
6988     var propCache = {};
6989     var camelRe = /(-[a-z])/gi;
6990     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6991     var view = document.defaultView;
6992
6993 /**
6994  * @class Roo.Element
6995  * Represents an Element in the DOM.<br><br>
6996  * Usage:<br>
6997 <pre><code>
6998 var el = Roo.get("my-div");
6999
7000 // or with getEl
7001 var el = getEl("my-div");
7002
7003 // or with a DOM element
7004 var el = Roo.get(myDivElement);
7005 </code></pre>
7006  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7007  * each call instead of constructing a new one.<br><br>
7008  * <b>Animations</b><br />
7009  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7010  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7011 <pre>
7012 Option    Default   Description
7013 --------- --------  ---------------------------------------------
7014 duration  .35       The duration of the animation in seconds
7015 easing    easeOut   The YUI easing method
7016 callback  none      A function to execute when the anim completes
7017 scope     this      The scope (this) of the callback function
7018 </pre>
7019 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7020 * manipulate the animation. Here's an example:
7021 <pre><code>
7022 var el = Roo.get("my-div");
7023
7024 // no animation
7025 el.setWidth(100);
7026
7027 // default animation
7028 el.setWidth(100, true);
7029
7030 // animation with some options set
7031 el.setWidth(100, {
7032     duration: 1,
7033     callback: this.foo,
7034     scope: this
7035 });
7036
7037 // using the "anim" property to get the Anim object
7038 var opt = {
7039     duration: 1,
7040     callback: this.foo,
7041     scope: this
7042 };
7043 el.setWidth(100, opt);
7044 ...
7045 if(opt.anim.isAnimated()){
7046     opt.anim.stop();
7047 }
7048 </code></pre>
7049 * <b> Composite (Collections of) Elements</b><br />
7050  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7051  * @constructor Create a new Element directly.
7052  * @param {String/HTMLElement} element
7053  * @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).
7054  */
7055     Roo.Element = function(element, forceNew){
7056         var dom = typeof element == "string" ?
7057                 document.getElementById(element) : element;
7058         if(!dom){ // invalid id/element
7059             return null;
7060         }
7061         var id = dom.id;
7062         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7063             return Roo.Element.cache[id];
7064         }
7065
7066         /**
7067          * The DOM element
7068          * @type HTMLElement
7069          */
7070         this.dom = dom;
7071
7072         /**
7073          * The DOM element ID
7074          * @type String
7075          */
7076         this.id = id || Roo.id(dom);
7077     };
7078
7079     var El = Roo.Element;
7080
7081     El.prototype = {
7082         /**
7083          * The element's default display mode  (defaults to "")
7084          * @type String
7085          */
7086         originalDisplay : "",
7087
7088         visibilityMode : 1,
7089         /**
7090          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7091          * @type String
7092          */
7093         defaultUnit : "px",
7094         /**
7095          * Sets the element's visibility mode. When setVisible() is called it
7096          * will use this to determine whether to set the visibility or the display property.
7097          * @param visMode Element.VISIBILITY or Element.DISPLAY
7098          * @return {Roo.Element} this
7099          */
7100         setVisibilityMode : function(visMode){
7101             this.visibilityMode = visMode;
7102             return this;
7103         },
7104         /**
7105          * Convenience method for setVisibilityMode(Element.DISPLAY)
7106          * @param {String} display (optional) What to set display to when visible
7107          * @return {Roo.Element} this
7108          */
7109         enableDisplayMode : function(display){
7110             this.setVisibilityMode(El.DISPLAY);
7111             if(typeof display != "undefined") this.originalDisplay = display;
7112             return this;
7113         },
7114
7115         /**
7116          * 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)
7117          * @param {String} selector The simple selector to test
7118          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7119                 search as a number or element (defaults to 10 || document.body)
7120          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7121          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7122          */
7123         findParent : function(simpleSelector, maxDepth, returnEl){
7124             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7125             maxDepth = maxDepth || 50;
7126             if(typeof maxDepth != "number"){
7127                 stopEl = Roo.getDom(maxDepth);
7128                 maxDepth = 10;
7129             }
7130             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7131                 if(dq.is(p, simpleSelector)){
7132                     return returnEl ? Roo.get(p) : p;
7133                 }
7134                 depth++;
7135                 p = p.parentNode;
7136             }
7137             return null;
7138         },
7139
7140
7141         /**
7142          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7143          * @param {String} selector The simple selector to test
7144          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7145                 search as a number or element (defaults to 10 || document.body)
7146          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7147          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7148          */
7149         findParentNode : function(simpleSelector, maxDepth, returnEl){
7150             var p = Roo.fly(this.dom.parentNode, '_internal');
7151             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7152         },
7153
7154         /**
7155          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7156          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7157          * @param {String} selector The simple selector to test
7158          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7159                 search as a number or element (defaults to 10 || document.body)
7160          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7161          */
7162         up : function(simpleSelector, maxDepth){
7163             return this.findParentNode(simpleSelector, maxDepth, true);
7164         },
7165
7166
7167
7168         /**
7169          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7170          * @param {String} selector The simple selector to test
7171          * @return {Boolean} True if this element matches the selector, else false
7172          */
7173         is : function(simpleSelector){
7174             return Roo.DomQuery.is(this.dom, simpleSelector);
7175         },
7176
7177         /**
7178          * Perform animation on this element.
7179          * @param {Object} args The YUI animation control args
7180          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7181          * @param {Function} onComplete (optional) Function to call when animation completes
7182          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7183          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7184          * @return {Roo.Element} this
7185          */
7186         animate : function(args, duration, onComplete, easing, animType){
7187             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7188             return this;
7189         },
7190
7191         /*
7192          * @private Internal animation call
7193          */
7194         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7195             animType = animType || 'run';
7196             opt = opt || {};
7197             var anim = Roo.lib.Anim[animType](
7198                 this.dom, args,
7199                 (opt.duration || defaultDur) || .35,
7200                 (opt.easing || defaultEase) || 'easeOut',
7201                 function(){
7202                     Roo.callback(cb, this);
7203                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7204                 },
7205                 this
7206             );
7207             opt.anim = anim;
7208             return anim;
7209         },
7210
7211         // private legacy anim prep
7212         preanim : function(a, i){
7213             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7214         },
7215
7216         /**
7217          * Removes worthless text nodes
7218          * @param {Boolean} forceReclean (optional) By default the element
7219          * keeps track if it has been cleaned already so
7220          * you can call this over and over. However, if you update the element and
7221          * need to force a reclean, you can pass true.
7222          */
7223         clean : function(forceReclean){
7224             if(this.isCleaned && forceReclean !== true){
7225                 return this;
7226             }
7227             var ns = /\S/;
7228             var d = this.dom, n = d.firstChild, ni = -1;
7229             while(n){
7230                 var nx = n.nextSibling;
7231                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7232                     d.removeChild(n);
7233                 }else{
7234                     n.nodeIndex = ++ni;
7235                 }
7236                 n = nx;
7237             }
7238             this.isCleaned = true;
7239             return this;
7240         },
7241
7242         // private
7243         calcOffsetsTo : function(el){
7244             el = Roo.get(el);
7245             var d = el.dom;
7246             var restorePos = false;
7247             if(el.getStyle('position') == 'static'){
7248                 el.position('relative');
7249                 restorePos = true;
7250             }
7251             var x = 0, y =0;
7252             var op = this.dom;
7253             while(op && op != d && op.tagName != 'HTML'){
7254                 x+= op.offsetLeft;
7255                 y+= op.offsetTop;
7256                 op = op.offsetParent;
7257             }
7258             if(restorePos){
7259                 el.position('static');
7260             }
7261             return [x, y];
7262         },
7263
7264         /**
7265          * Scrolls this element into view within the passed container.
7266          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7267          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7268          * @return {Roo.Element} this
7269          */
7270         scrollIntoView : function(container, hscroll){
7271             var c = Roo.getDom(container) || document.body;
7272             var el = this.dom;
7273
7274             var o = this.calcOffsetsTo(c),
7275                 l = o[0],
7276                 t = o[1],
7277                 b = t+el.offsetHeight,
7278                 r = l+el.offsetWidth;
7279
7280             var ch = c.clientHeight;
7281             var ct = parseInt(c.scrollTop, 10);
7282             var cl = parseInt(c.scrollLeft, 10);
7283             var cb = ct + ch;
7284             var cr = cl + c.clientWidth;
7285
7286             if(t < ct){
7287                 c.scrollTop = t;
7288             }else if(b > cb){
7289                 c.scrollTop = b-ch;
7290             }
7291
7292             if(hscroll !== false){
7293                 if(l < cl){
7294                     c.scrollLeft = l;
7295                 }else if(r > cr){
7296                     c.scrollLeft = r-c.clientWidth;
7297                 }
7298             }
7299             return this;
7300         },
7301
7302         // private
7303         scrollChildIntoView : function(child, hscroll){
7304             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7305         },
7306
7307         /**
7308          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7309          * the new height may not be available immediately.
7310          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7311          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7312          * @param {Function} onComplete (optional) Function to call when animation completes
7313          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7314          * @return {Roo.Element} this
7315          */
7316         autoHeight : function(animate, duration, onComplete, easing){
7317             var oldHeight = this.getHeight();
7318             this.clip();
7319             this.setHeight(1); // force clipping
7320             setTimeout(function(){
7321                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7322                 if(!animate){
7323                     this.setHeight(height);
7324                     this.unclip();
7325                     if(typeof onComplete == "function"){
7326                         onComplete();
7327                     }
7328                 }else{
7329                     this.setHeight(oldHeight); // restore original height
7330                     this.setHeight(height, animate, duration, function(){
7331                         this.unclip();
7332                         if(typeof onComplete == "function") onComplete();
7333                     }.createDelegate(this), easing);
7334                 }
7335             }.createDelegate(this), 0);
7336             return this;
7337         },
7338
7339         /**
7340          * Returns true if this element is an ancestor of the passed element
7341          * @param {HTMLElement/String} el The element to check
7342          * @return {Boolean} True if this element is an ancestor of el, else false
7343          */
7344         contains : function(el){
7345             if(!el){return false;}
7346             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7347         },
7348
7349         /**
7350          * Checks whether the element is currently visible using both visibility and display properties.
7351          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7352          * @return {Boolean} True if the element is currently visible, else false
7353          */
7354         isVisible : function(deep) {
7355             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7356             if(deep !== true || !vis){
7357                 return vis;
7358             }
7359             var p = this.dom.parentNode;
7360             while(p && p.tagName.toLowerCase() != "body"){
7361                 if(!Roo.fly(p, '_isVisible').isVisible()){
7362                     return false;
7363                 }
7364                 p = p.parentNode;
7365             }
7366             return true;
7367         },
7368
7369         /**
7370          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7371          * @param {String} selector The CSS selector
7372          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7373          * @return {CompositeElement/CompositeElementLite} The composite element
7374          */
7375         select : function(selector, unique){
7376             return El.select(selector, unique, this.dom);
7377         },
7378
7379         /**
7380          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7381          * @param {String} selector The CSS selector
7382          * @return {Array} An array of the matched nodes
7383          */
7384         query : function(selector, unique){
7385             return Roo.DomQuery.select(selector, this.dom);
7386         },
7387
7388         /**
7389          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7390          * @param {String} selector The CSS selector
7391          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7392          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7393          */
7394         child : function(selector, returnDom){
7395             var n = Roo.DomQuery.selectNode(selector, this.dom);
7396             return returnDom ? n : Roo.get(n);
7397         },
7398
7399         /**
7400          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7401          * @param {String} selector The CSS selector
7402          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7403          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7404          */
7405         down : function(selector, returnDom){
7406             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7407             return returnDom ? n : Roo.get(n);
7408         },
7409
7410         /**
7411          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7412          * @param {String} group The group the DD object is member of
7413          * @param {Object} config The DD config object
7414          * @param {Object} overrides An object containing methods to override/implement on the DD object
7415          * @return {Roo.dd.DD} The DD object
7416          */
7417         initDD : function(group, config, overrides){
7418             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7419             return Roo.apply(dd, overrides);
7420         },
7421
7422         /**
7423          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7424          * @param {String} group The group the DDProxy object is member of
7425          * @param {Object} config The DDProxy config object
7426          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7427          * @return {Roo.dd.DDProxy} The DDProxy object
7428          */
7429         initDDProxy : function(group, config, overrides){
7430             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7431             return Roo.apply(dd, overrides);
7432         },
7433
7434         /**
7435          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7436          * @param {String} group The group the DDTarget object is member of
7437          * @param {Object} config The DDTarget config object
7438          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7439          * @return {Roo.dd.DDTarget} The DDTarget object
7440          */
7441         initDDTarget : function(group, config, overrides){
7442             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7443             return Roo.apply(dd, overrides);
7444         },
7445
7446         /**
7447          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7448          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7449          * @param {Boolean} visible Whether the element is visible
7450          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7451          * @return {Roo.Element} this
7452          */
7453          setVisible : function(visible, animate){
7454             if(!animate || !A){
7455                 if(this.visibilityMode == El.DISPLAY){
7456                     this.setDisplayed(visible);
7457                 }else{
7458                     this.fixDisplay();
7459                     this.dom.style.visibility = visible ? "visible" : "hidden";
7460                 }
7461             }else{
7462                 // closure for composites
7463                 var dom = this.dom;
7464                 var visMode = this.visibilityMode;
7465                 if(visible){
7466                     this.setOpacity(.01);
7467                     this.setVisible(true);
7468                 }
7469                 this.anim({opacity: { to: (visible?1:0) }},
7470                       this.preanim(arguments, 1),
7471                       null, .35, 'easeIn', function(){
7472                          if(!visible){
7473                              if(visMode == El.DISPLAY){
7474                                  dom.style.display = "none";
7475                              }else{
7476                                  dom.style.visibility = "hidden";
7477                              }
7478                              Roo.get(dom).setOpacity(1);
7479                          }
7480                      });
7481             }
7482             return this;
7483         },
7484
7485         /**
7486          * Returns true if display is not "none"
7487          * @return {Boolean}
7488          */
7489         isDisplayed : function() {
7490             return this.getStyle("display") != "none";
7491         },
7492
7493         /**
7494          * Toggles the element's visibility or display, depending on visibility mode.
7495          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7496          * @return {Roo.Element} this
7497          */
7498         toggle : function(animate){
7499             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7500             return this;
7501         },
7502
7503         /**
7504          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7505          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7506          * @return {Roo.Element} this
7507          */
7508         setDisplayed : function(value) {
7509             if(typeof value == "boolean"){
7510                value = value ? this.originalDisplay : "none";
7511             }
7512             this.setStyle("display", value);
7513             return this;
7514         },
7515
7516         /**
7517          * Tries to focus the element. Any exceptions are caught and ignored.
7518          * @return {Roo.Element} this
7519          */
7520         focus : function() {
7521             try{
7522                 this.dom.focus();
7523             }catch(e){}
7524             return this;
7525         },
7526
7527         /**
7528          * Tries to blur the element. Any exceptions are caught and ignored.
7529          * @return {Roo.Element} this
7530          */
7531         blur : function() {
7532             try{
7533                 this.dom.blur();
7534             }catch(e){}
7535             return this;
7536         },
7537
7538         /**
7539          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7540          * @param {String/Array} className The CSS class to add, or an array of classes
7541          * @return {Roo.Element} this
7542          */
7543         addClass : function(className){
7544             if(className instanceof Array){
7545                 for(var i = 0, len = className.length; i < len; i++) {
7546                     this.addClass(className[i]);
7547                 }
7548             }else{
7549                 if(className && !this.hasClass(className)){
7550                     this.dom.className = this.dom.className + " " + className;
7551                 }
7552             }
7553             return this;
7554         },
7555
7556         /**
7557          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7558          * @param {String/Array} className The CSS class to add, or an array of classes
7559          * @return {Roo.Element} this
7560          */
7561         radioClass : function(className){
7562             var siblings = this.dom.parentNode.childNodes;
7563             for(var i = 0; i < siblings.length; i++) {
7564                 var s = siblings[i];
7565                 if(s.nodeType == 1){
7566                     Roo.get(s).removeClass(className);
7567                 }
7568             }
7569             this.addClass(className);
7570             return this;
7571         },
7572
7573         /**
7574          * Removes one or more CSS classes from the element.
7575          * @param {String/Array} className The CSS class to remove, or an array of classes
7576          * @return {Roo.Element} this
7577          */
7578         removeClass : function(className){
7579             if(!className || !this.dom.className){
7580                 return this;
7581             }
7582             if(className instanceof Array){
7583                 for(var i = 0, len = className.length; i < len; i++) {
7584                     this.removeClass(className[i]);
7585                 }
7586             }else{
7587                 if(this.hasClass(className)){
7588                     var re = this.classReCache[className];
7589                     if (!re) {
7590                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7591                        this.classReCache[className] = re;
7592                     }
7593                     this.dom.className =
7594                         this.dom.className.replace(re, " ");
7595                 }
7596             }
7597             return this;
7598         },
7599
7600         // private
7601         classReCache: {},
7602
7603         /**
7604          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7605          * @param {String} className The CSS class to toggle
7606          * @return {Roo.Element} this
7607          */
7608         toggleClass : function(className){
7609             if(this.hasClass(className)){
7610                 this.removeClass(className);
7611             }else{
7612                 this.addClass(className);
7613             }
7614             return this;
7615         },
7616
7617         /**
7618          * Checks if the specified CSS class exists on this element's DOM node.
7619          * @param {String} className The CSS class to check for
7620          * @return {Boolean} True if the class exists, else false
7621          */
7622         hasClass : function(className){
7623             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7624         },
7625
7626         /**
7627          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7628          * @param {String} oldClassName The CSS class to replace
7629          * @param {String} newClassName The replacement CSS class
7630          * @return {Roo.Element} this
7631          */
7632         replaceClass : function(oldClassName, newClassName){
7633             this.removeClass(oldClassName);
7634             this.addClass(newClassName);
7635             return this;
7636         },
7637
7638         /**
7639          * Returns an object with properties matching the styles requested.
7640          * For example, el.getStyles('color', 'font-size', 'width') might return
7641          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7642          * @param {String} style1 A style name
7643          * @param {String} style2 A style name
7644          * @param {String} etc.
7645          * @return {Object} The style object
7646          */
7647         getStyles : function(){
7648             var a = arguments, len = a.length, r = {};
7649             for(var i = 0; i < len; i++){
7650                 r[a[i]] = this.getStyle(a[i]);
7651             }
7652             return r;
7653         },
7654
7655         /**
7656          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7657          * @param {String} property The style property whose value is returned.
7658          * @return {String} The current value of the style property for this element.
7659          */
7660         getStyle : function(){
7661             return view && view.getComputedStyle ?
7662                 function(prop){
7663                     var el = this.dom, v, cs, camel;
7664                     if(prop == 'float'){
7665                         prop = "cssFloat";
7666                     }
7667                     if(el.style && (v = el.style[prop])){
7668                         return v;
7669                     }
7670                     if(cs = view.getComputedStyle(el, "")){
7671                         if(!(camel = propCache[prop])){
7672                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7673                         }
7674                         return cs[camel];
7675                     }
7676                     return null;
7677                 } :
7678                 function(prop){
7679                     var el = this.dom, v, cs, camel;
7680                     if(prop == 'opacity'){
7681                         if(typeof el.style.filter == 'string'){
7682                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7683                             if(m){
7684                                 var fv = parseFloat(m[1]);
7685                                 if(!isNaN(fv)){
7686                                     return fv ? fv / 100 : 0;
7687                                 }
7688                             }
7689                         }
7690                         return 1;
7691                     }else if(prop == 'float'){
7692                         prop = "styleFloat";
7693                     }
7694                     if(!(camel = propCache[prop])){
7695                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7696                     }
7697                     if(v = el.style[camel]){
7698                         return v;
7699                     }
7700                     if(cs = el.currentStyle){
7701                         return cs[camel];
7702                     }
7703                     return null;
7704                 };
7705         }(),
7706
7707         /**
7708          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7709          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7710          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7711          * @return {Roo.Element} this
7712          */
7713         setStyle : function(prop, value){
7714             if(typeof prop == "string"){
7715                 
7716                 if (prop == 'float') {
7717                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7718                     return this;
7719                 }
7720                 
7721                 var camel;
7722                 if(!(camel = propCache[prop])){
7723                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7724                 }
7725                 
7726                 if(camel == 'opacity') {
7727                     this.setOpacity(value);
7728                 }else{
7729                     this.dom.style[camel] = value;
7730                 }
7731             }else{
7732                 for(var style in prop){
7733                     if(typeof prop[style] != "function"){
7734                        this.setStyle(style, prop[style]);
7735                     }
7736                 }
7737             }
7738             return this;
7739         },
7740
7741         /**
7742          * More flexible version of {@link #setStyle} for setting style properties.
7743          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7744          * a function which returns such a specification.
7745          * @return {Roo.Element} this
7746          */
7747         applyStyles : function(style){
7748             Roo.DomHelper.applyStyles(this.dom, style);
7749             return this;
7750         },
7751
7752         /**
7753           * 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).
7754           * @return {Number} The X position of the element
7755           */
7756         getX : function(){
7757             return D.getX(this.dom);
7758         },
7759
7760         /**
7761           * 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).
7762           * @return {Number} The Y position of the element
7763           */
7764         getY : function(){
7765             return D.getY(this.dom);
7766         },
7767
7768         /**
7769           * 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).
7770           * @return {Array} The XY position of the element
7771           */
7772         getXY : function(){
7773             return D.getXY(this.dom);
7774         },
7775
7776         /**
7777          * 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).
7778          * @param {Number} The X position of the element
7779          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7780          * @return {Roo.Element} this
7781          */
7782         setX : function(x, animate){
7783             if(!animate || !A){
7784                 D.setX(this.dom, x);
7785             }else{
7786                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7787             }
7788             return this;
7789         },
7790
7791         /**
7792          * 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).
7793          * @param {Number} The Y position of the element
7794          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7795          * @return {Roo.Element} this
7796          */
7797         setY : function(y, animate){
7798             if(!animate || !A){
7799                 D.setY(this.dom, y);
7800             }else{
7801                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7802             }
7803             return this;
7804         },
7805
7806         /**
7807          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7808          * @param {String} left The left CSS property value
7809          * @return {Roo.Element} this
7810          */
7811         setLeft : function(left){
7812             this.setStyle("left", this.addUnits(left));
7813             return this;
7814         },
7815
7816         /**
7817          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7818          * @param {String} top The top CSS property value
7819          * @return {Roo.Element} this
7820          */
7821         setTop : function(top){
7822             this.setStyle("top", this.addUnits(top));
7823             return this;
7824         },
7825
7826         /**
7827          * Sets the element's CSS right style.
7828          * @param {String} right The right CSS property value
7829          * @return {Roo.Element} this
7830          */
7831         setRight : function(right){
7832             this.setStyle("right", this.addUnits(right));
7833             return this;
7834         },
7835
7836         /**
7837          * Sets the element's CSS bottom style.
7838          * @param {String} bottom The bottom CSS property value
7839          * @return {Roo.Element} this
7840          */
7841         setBottom : function(bottom){
7842             this.setStyle("bottom", this.addUnits(bottom));
7843             return this;
7844         },
7845
7846         /**
7847          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7848          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7849          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7850          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7851          * @return {Roo.Element} this
7852          */
7853         setXY : function(pos, animate){
7854             if(!animate || !A){
7855                 D.setXY(this.dom, pos);
7856             }else{
7857                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7858             }
7859             return this;
7860         },
7861
7862         /**
7863          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7864          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7865          * @param {Number} x X value for new position (coordinates are page-based)
7866          * @param {Number} y Y value for new position (coordinates are page-based)
7867          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7868          * @return {Roo.Element} this
7869          */
7870         setLocation : function(x, y, animate){
7871             this.setXY([x, y], this.preanim(arguments, 2));
7872             return this;
7873         },
7874
7875         /**
7876          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7877          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7878          * @param {Number} x X value for new position (coordinates are page-based)
7879          * @param {Number} y Y value for new position (coordinates are page-based)
7880          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7881          * @return {Roo.Element} this
7882          */
7883         moveTo : function(x, y, animate){
7884             this.setXY([x, y], this.preanim(arguments, 2));
7885             return this;
7886         },
7887
7888         /**
7889          * Returns the region of the given element.
7890          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7891          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7892          */
7893         getRegion : function(){
7894             return D.getRegion(this.dom);
7895         },
7896
7897         /**
7898          * Returns the offset height of the element
7899          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7900          * @return {Number} The element's height
7901          */
7902         getHeight : function(contentHeight){
7903             var h = this.dom.offsetHeight || 0;
7904             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7905         },
7906
7907         /**
7908          * Returns the offset width of the element
7909          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7910          * @return {Number} The element's width
7911          */
7912         getWidth : function(contentWidth){
7913             var w = this.dom.offsetWidth || 0;
7914             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7915         },
7916
7917         /**
7918          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7919          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7920          * if a height has not been set using CSS.
7921          * @return {Number}
7922          */
7923         getComputedHeight : function(){
7924             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7925             if(!h){
7926                 h = parseInt(this.getStyle('height'), 10) || 0;
7927                 if(!this.isBorderBox()){
7928                     h += this.getFrameWidth('tb');
7929                 }
7930             }
7931             return h;
7932         },
7933
7934         /**
7935          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7936          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7937          * if a width has not been set using CSS.
7938          * @return {Number}
7939          */
7940         getComputedWidth : function(){
7941             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7942             if(!w){
7943                 w = parseInt(this.getStyle('width'), 10) || 0;
7944                 if(!this.isBorderBox()){
7945                     w += this.getFrameWidth('lr');
7946                 }
7947             }
7948             return w;
7949         },
7950
7951         /**
7952          * Returns the size of the element.
7953          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7954          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7955          */
7956         getSize : function(contentSize){
7957             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7958         },
7959
7960         /**
7961          * Returns the width and height of the viewport.
7962          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7963          */
7964         getViewSize : function(){
7965             var d = this.dom, doc = document, aw = 0, ah = 0;
7966             if(d == doc || d == doc.body){
7967                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7968             }else{
7969                 return {
7970                     width : d.clientWidth,
7971                     height: d.clientHeight
7972                 };
7973             }
7974         },
7975
7976         /**
7977          * Returns the value of the "value" attribute
7978          * @param {Boolean} asNumber true to parse the value as a number
7979          * @return {String/Number}
7980          */
7981         getValue : function(asNumber){
7982             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7983         },
7984
7985         // private
7986         adjustWidth : function(width){
7987             if(typeof width == "number"){
7988                 if(this.autoBoxAdjust && !this.isBorderBox()){
7989                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7990                 }
7991                 if(width < 0){
7992                     width = 0;
7993                 }
7994             }
7995             return width;
7996         },
7997
7998         // private
7999         adjustHeight : function(height){
8000             if(typeof height == "number"){
8001                if(this.autoBoxAdjust && !this.isBorderBox()){
8002                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8003                }
8004                if(height < 0){
8005                    height = 0;
8006                }
8007             }
8008             return height;
8009         },
8010
8011         /**
8012          * Set the width of the element
8013          * @param {Number} width The new width
8014          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8015          * @return {Roo.Element} this
8016          */
8017         setWidth : function(width, animate){
8018             width = this.adjustWidth(width);
8019             if(!animate || !A){
8020                 this.dom.style.width = this.addUnits(width);
8021             }else{
8022                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8023             }
8024             return this;
8025         },
8026
8027         /**
8028          * Set the height of the element
8029          * @param {Number} height The new height
8030          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8031          * @return {Roo.Element} this
8032          */
8033          setHeight : function(height, animate){
8034             height = this.adjustHeight(height);
8035             if(!animate || !A){
8036                 this.dom.style.height = this.addUnits(height);
8037             }else{
8038                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8039             }
8040             return this;
8041         },
8042
8043         /**
8044          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8045          * @param {Number} width The new width
8046          * @param {Number} height The new height
8047          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8048          * @return {Roo.Element} this
8049          */
8050          setSize : function(width, height, animate){
8051             if(typeof width == "object"){ // in case of object from getSize()
8052                 height = width.height; width = width.width;
8053             }
8054             width = this.adjustWidth(width); height = this.adjustHeight(height);
8055             if(!animate || !A){
8056                 this.dom.style.width = this.addUnits(width);
8057                 this.dom.style.height = this.addUnits(height);
8058             }else{
8059                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8060             }
8061             return this;
8062         },
8063
8064         /**
8065          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8066          * @param {Number} x X value for new position (coordinates are page-based)
8067          * @param {Number} y Y value for new position (coordinates are page-based)
8068          * @param {Number} width The new width
8069          * @param {Number} height The new height
8070          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8071          * @return {Roo.Element} this
8072          */
8073         setBounds : function(x, y, width, height, animate){
8074             if(!animate || !A){
8075                 this.setSize(width, height);
8076                 this.setLocation(x, y);
8077             }else{
8078                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8079                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8080                               this.preanim(arguments, 4), 'motion');
8081             }
8082             return this;
8083         },
8084
8085         /**
8086          * 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.
8087          * @param {Roo.lib.Region} region The region to fill
8088          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8089          * @return {Roo.Element} this
8090          */
8091         setRegion : function(region, animate){
8092             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8093             return this;
8094         },
8095
8096         /**
8097          * Appends an event handler
8098          *
8099          * @param {String}   eventName     The type of event to append
8100          * @param {Function} fn        The method the event invokes
8101          * @param {Object} scope       (optional) The scope (this object) of the fn
8102          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8103          */
8104         addListener : function(eventName, fn, scope, options){
8105             if (this.dom) {
8106                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8107             }
8108         },
8109
8110         /**
8111          * Removes an event handler from this element
8112          * @param {String} eventName the type of event to remove
8113          * @param {Function} fn the method the event invokes
8114          * @return {Roo.Element} this
8115          */
8116         removeListener : function(eventName, fn){
8117             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8118             return this;
8119         },
8120
8121         /**
8122          * Removes all previous added listeners from this element
8123          * @return {Roo.Element} this
8124          */
8125         removeAllListeners : function(){
8126             E.purgeElement(this.dom);
8127             return this;
8128         },
8129
8130         relayEvent : function(eventName, observable){
8131             this.on(eventName, function(e){
8132                 observable.fireEvent(eventName, e);
8133             });
8134         },
8135
8136         /**
8137          * Set the opacity of the element
8138          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8139          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8140          * @return {Roo.Element} this
8141          */
8142          setOpacity : function(opacity, animate){
8143             if(!animate || !A){
8144                 var s = this.dom.style;
8145                 if(Roo.isIE){
8146                     s.zoom = 1;
8147                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8148                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8149                 }else{
8150                     s.opacity = opacity;
8151                 }
8152             }else{
8153                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8154             }
8155             return this;
8156         },
8157
8158         /**
8159          * Gets the left X coordinate
8160          * @param {Boolean} local True to get the local css position instead of page coordinate
8161          * @return {Number}
8162          */
8163         getLeft : function(local){
8164             if(!local){
8165                 return this.getX();
8166             }else{
8167                 return parseInt(this.getStyle("left"), 10) || 0;
8168             }
8169         },
8170
8171         /**
8172          * Gets the right X coordinate of the element (element X position + element width)
8173          * @param {Boolean} local True to get the local css position instead of page coordinate
8174          * @return {Number}
8175          */
8176         getRight : function(local){
8177             if(!local){
8178                 return this.getX() + this.getWidth();
8179             }else{
8180                 return (this.getLeft(true) + this.getWidth()) || 0;
8181             }
8182         },
8183
8184         /**
8185          * Gets the top Y coordinate
8186          * @param {Boolean} local True to get the local css position instead of page coordinate
8187          * @return {Number}
8188          */
8189         getTop : function(local) {
8190             if(!local){
8191                 return this.getY();
8192             }else{
8193                 return parseInt(this.getStyle("top"), 10) || 0;
8194             }
8195         },
8196
8197         /**
8198          * Gets the bottom Y coordinate of the element (element Y position + element height)
8199          * @param {Boolean} local True to get the local css position instead of page coordinate
8200          * @return {Number}
8201          */
8202         getBottom : function(local){
8203             if(!local){
8204                 return this.getY() + this.getHeight();
8205             }else{
8206                 return (this.getTop(true) + this.getHeight()) || 0;
8207             }
8208         },
8209
8210         /**
8211         * Initializes positioning on this element. If a desired position is not passed, it will make the
8212         * the element positioned relative IF it is not already positioned.
8213         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8214         * @param {Number} zIndex (optional) The zIndex to apply
8215         * @param {Number} x (optional) Set the page X position
8216         * @param {Number} y (optional) Set the page Y position
8217         */
8218         position : function(pos, zIndex, x, y){
8219             if(!pos){
8220                if(this.getStyle('position') == 'static'){
8221                    this.setStyle('position', 'relative');
8222                }
8223             }else{
8224                 this.setStyle("position", pos);
8225             }
8226             if(zIndex){
8227                 this.setStyle("z-index", zIndex);
8228             }
8229             if(x !== undefined && y !== undefined){
8230                 this.setXY([x, y]);
8231             }else if(x !== undefined){
8232                 this.setX(x);
8233             }else if(y !== undefined){
8234                 this.setY(y);
8235             }
8236         },
8237
8238         /**
8239         * Clear positioning back to the default when the document was loaded
8240         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8241         * @return {Roo.Element} this
8242          */
8243         clearPositioning : function(value){
8244             value = value ||'';
8245             this.setStyle({
8246                 "left": value,
8247                 "right": value,
8248                 "top": value,
8249                 "bottom": value,
8250                 "z-index": "",
8251                 "position" : "static"
8252             });
8253             return this;
8254         },
8255
8256         /**
8257         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8258         * snapshot before performing an update and then restoring the element.
8259         * @return {Object}
8260         */
8261         getPositioning : function(){
8262             var l = this.getStyle("left");
8263             var t = this.getStyle("top");
8264             return {
8265                 "position" : this.getStyle("position"),
8266                 "left" : l,
8267                 "right" : l ? "" : this.getStyle("right"),
8268                 "top" : t,
8269                 "bottom" : t ? "" : this.getStyle("bottom"),
8270                 "z-index" : this.getStyle("z-index")
8271             };
8272         },
8273
8274         /**
8275          * Gets the width of the border(s) for the specified side(s)
8276          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8277          * passing lr would get the border (l)eft width + the border (r)ight width.
8278          * @return {Number} The width of the sides passed added together
8279          */
8280         getBorderWidth : function(side){
8281             return this.addStyles(side, El.borders);
8282         },
8283
8284         /**
8285          * Gets the width of the padding(s) for the specified side(s)
8286          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8287          * passing lr would get the padding (l)eft + the padding (r)ight.
8288          * @return {Number} The padding of the sides passed added together
8289          */
8290         getPadding : function(side){
8291             return this.addStyles(side, El.paddings);
8292         },
8293
8294         /**
8295         * Set positioning with an object returned by getPositioning().
8296         * @param {Object} posCfg
8297         * @return {Roo.Element} this
8298          */
8299         setPositioning : function(pc){
8300             this.applyStyles(pc);
8301             if(pc.right == "auto"){
8302                 this.dom.style.right = "";
8303             }
8304             if(pc.bottom == "auto"){
8305                 this.dom.style.bottom = "";
8306             }
8307             return this;
8308         },
8309
8310         // private
8311         fixDisplay : function(){
8312             if(this.getStyle("display") == "none"){
8313                 this.setStyle("visibility", "hidden");
8314                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8315                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8316                     this.setStyle("display", "block");
8317                 }
8318             }
8319         },
8320
8321         /**
8322          * Quick set left and top adding default units
8323          * @param {String} left The left CSS property value
8324          * @param {String} top The top CSS property value
8325          * @return {Roo.Element} this
8326          */
8327          setLeftTop : function(left, top){
8328             this.dom.style.left = this.addUnits(left);
8329             this.dom.style.top = this.addUnits(top);
8330             return this;
8331         },
8332
8333         /**
8334          * Move this element relative to its current position.
8335          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8336          * @param {Number} distance How far to move the element in pixels
8337          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8338          * @return {Roo.Element} this
8339          */
8340          move : function(direction, distance, animate){
8341             var xy = this.getXY();
8342             direction = direction.toLowerCase();
8343             switch(direction){
8344                 case "l":
8345                 case "left":
8346                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8347                     break;
8348                case "r":
8349                case "right":
8350                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8351                     break;
8352                case "t":
8353                case "top":
8354                case "up":
8355                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8356                     break;
8357                case "b":
8358                case "bottom":
8359                case "down":
8360                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8361                     break;
8362             }
8363             return this;
8364         },
8365
8366         /**
8367          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8368          * @return {Roo.Element} this
8369          */
8370         clip : function(){
8371             if(!this.isClipped){
8372                this.isClipped = true;
8373                this.originalClip = {
8374                    "o": this.getStyle("overflow"),
8375                    "x": this.getStyle("overflow-x"),
8376                    "y": this.getStyle("overflow-y")
8377                };
8378                this.setStyle("overflow", "hidden");
8379                this.setStyle("overflow-x", "hidden");
8380                this.setStyle("overflow-y", "hidden");
8381             }
8382             return this;
8383         },
8384
8385         /**
8386          *  Return clipping (overflow) to original clipping before clip() was called
8387          * @return {Roo.Element} this
8388          */
8389         unclip : function(){
8390             if(this.isClipped){
8391                 this.isClipped = false;
8392                 var o = this.originalClip;
8393                 if(o.o){this.setStyle("overflow", o.o);}
8394                 if(o.x){this.setStyle("overflow-x", o.x);}
8395                 if(o.y){this.setStyle("overflow-y", o.y);}
8396             }
8397             return this;
8398         },
8399
8400
8401         /**
8402          * Gets the x,y coordinates specified by the anchor position on the element.
8403          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8404          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8405          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8406          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8407          * @return {Array} [x, y] An array containing the element's x and y coordinates
8408          */
8409         getAnchorXY : function(anchor, local, s){
8410             //Passing a different size is useful for pre-calculating anchors,
8411             //especially for anchored animations that change the el size.
8412
8413             var w, h, vp = false;
8414             if(!s){
8415                 var d = this.dom;
8416                 if(d == document.body || d == document){
8417                     vp = true;
8418                     w = D.getViewWidth(); h = D.getViewHeight();
8419                 }else{
8420                     w = this.getWidth(); h = this.getHeight();
8421                 }
8422             }else{
8423                 w = s.width;  h = s.height;
8424             }
8425             var x = 0, y = 0, r = Math.round;
8426             switch((anchor || "tl").toLowerCase()){
8427                 case "c":
8428                     x = r(w*.5);
8429                     y = r(h*.5);
8430                 break;
8431                 case "t":
8432                     x = r(w*.5);
8433                     y = 0;
8434                 break;
8435                 case "l":
8436                     x = 0;
8437                     y = r(h*.5);
8438                 break;
8439                 case "r":
8440                     x = w;
8441                     y = r(h*.5);
8442                 break;
8443                 case "b":
8444                     x = r(w*.5);
8445                     y = h;
8446                 break;
8447                 case "tl":
8448                     x = 0;
8449                     y = 0;
8450                 break;
8451                 case "bl":
8452                     x = 0;
8453                     y = h;
8454                 break;
8455                 case "br":
8456                     x = w;
8457                     y = h;
8458                 break;
8459                 case "tr":
8460                     x = w;
8461                     y = 0;
8462                 break;
8463             }
8464             if(local === true){
8465                 return [x, y];
8466             }
8467             if(vp){
8468                 var sc = this.getScroll();
8469                 return [x + sc.left, y + sc.top];
8470             }
8471             //Add the element's offset xy
8472             var o = this.getXY();
8473             return [x+o[0], y+o[1]];
8474         },
8475
8476         /**
8477          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8478          * supported position values.
8479          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8480          * @param {String} position The position to align to.
8481          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8482          * @return {Array} [x, y]
8483          */
8484         getAlignToXY : function(el, p, o){
8485             el = Roo.get(el);
8486             var d = this.dom;
8487             if(!el.dom){
8488                 throw "Element.alignTo with an element that doesn't exist";
8489             }
8490             var c = false; //constrain to viewport
8491             var p1 = "", p2 = "";
8492             o = o || [0,0];
8493
8494             if(!p){
8495                 p = "tl-bl";
8496             }else if(p == "?"){
8497                 p = "tl-bl?";
8498             }else if(p.indexOf("-") == -1){
8499                 p = "tl-" + p;
8500             }
8501             p = p.toLowerCase();
8502             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8503             if(!m){
8504                throw "Element.alignTo with an invalid alignment " + p;
8505             }
8506             p1 = m[1]; p2 = m[2]; c = !!m[3];
8507
8508             //Subtract the aligned el's internal xy from the target's offset xy
8509             //plus custom offset to get the aligned el's new offset xy
8510             var a1 = this.getAnchorXY(p1, true);
8511             var a2 = el.getAnchorXY(p2, false);
8512             var x = a2[0] - a1[0] + o[0];
8513             var y = a2[1] - a1[1] + o[1];
8514             if(c){
8515                 //constrain the aligned el to viewport if necessary
8516                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8517                 // 5px of margin for ie
8518                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8519
8520                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8521                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8522                 //otherwise swap the aligned el to the opposite border of the target.
8523                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8524                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8525                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8526                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8527
8528                var doc = document;
8529                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8530                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8531
8532                if((x+w) > dw + scrollX){
8533                     x = swapX ? r.left-w : dw+scrollX-w;
8534                 }
8535                if(x < scrollX){
8536                    x = swapX ? r.right : scrollX;
8537                }
8538                if((y+h) > dh + scrollY){
8539                     y = swapY ? r.top-h : dh+scrollY-h;
8540                 }
8541                if (y < scrollY){
8542                    y = swapY ? r.bottom : scrollY;
8543                }
8544             }
8545             return [x,y];
8546         },
8547
8548         // private
8549         getConstrainToXY : function(){
8550             var os = {top:0, left:0, bottom:0, right: 0};
8551
8552             return function(el, local, offsets, proposedXY){
8553                 el = Roo.get(el);
8554                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8555
8556                 var vw, vh, vx = 0, vy = 0;
8557                 if(el.dom == document.body || el.dom == document){
8558                     vw = Roo.lib.Dom.getViewWidth();
8559                     vh = Roo.lib.Dom.getViewHeight();
8560                 }else{
8561                     vw = el.dom.clientWidth;
8562                     vh = el.dom.clientHeight;
8563                     if(!local){
8564                         var vxy = el.getXY();
8565                         vx = vxy[0];
8566                         vy = vxy[1];
8567                     }
8568                 }
8569
8570                 var s = el.getScroll();
8571
8572                 vx += offsets.left + s.left;
8573                 vy += offsets.top + s.top;
8574
8575                 vw -= offsets.right;
8576                 vh -= offsets.bottom;
8577
8578                 var vr = vx+vw;
8579                 var vb = vy+vh;
8580
8581                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8582                 var x = xy[0], y = xy[1];
8583                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8584
8585                 // only move it if it needs it
8586                 var moved = false;
8587
8588                 // first validate right/bottom
8589                 if((x + w) > vr){
8590                     x = vr - w;
8591                     moved = true;
8592                 }
8593                 if((y + h) > vb){
8594                     y = vb - h;
8595                     moved = true;
8596                 }
8597                 // then make sure top/left isn't negative
8598                 if(x < vx){
8599                     x = vx;
8600                     moved = true;
8601                 }
8602                 if(y < vy){
8603                     y = vy;
8604                     moved = true;
8605                 }
8606                 return moved ? [x, y] : false;
8607             };
8608         }(),
8609
8610         // private
8611         adjustForConstraints : function(xy, parent, offsets){
8612             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8613         },
8614
8615         /**
8616          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8617          * document it aligns it to the viewport.
8618          * The position parameter is optional, and can be specified in any one of the following formats:
8619          * <ul>
8620          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8621          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8622          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8623          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8624          *   <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
8625          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8626          * </ul>
8627          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8628          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8629          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8630          * that specified in order to enforce the viewport constraints.
8631          * Following are all of the supported anchor positions:
8632     <pre>
8633     Value  Description
8634     -----  -----------------------------
8635     tl     The top left corner (default)
8636     t      The center of the top edge
8637     tr     The top right corner
8638     l      The center of the left edge
8639     c      In the center of the element
8640     r      The center of the right edge
8641     bl     The bottom left corner
8642     b      The center of the bottom edge
8643     br     The bottom right corner
8644     </pre>
8645     Example Usage:
8646     <pre><code>
8647     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8648     el.alignTo("other-el");
8649
8650     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8651     el.alignTo("other-el", "tr?");
8652
8653     // align the bottom right corner of el with the center left edge of other-el
8654     el.alignTo("other-el", "br-l?");
8655
8656     // align the center of el with the bottom left corner of other-el and
8657     // adjust the x position by -6 pixels (and the y position by 0)
8658     el.alignTo("other-el", "c-bl", [-6, 0]);
8659     </code></pre>
8660          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8661          * @param {String} position The position to align to.
8662          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8663          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8664          * @return {Roo.Element} this
8665          */
8666         alignTo : function(element, position, offsets, animate){
8667             var xy = this.getAlignToXY(element, position, offsets);
8668             this.setXY(xy, this.preanim(arguments, 3));
8669             return this;
8670         },
8671
8672         /**
8673          * Anchors an element to another element and realigns it when the window is resized.
8674          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8675          * @param {String} position The position to align to.
8676          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8677          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8678          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8679          * is a number, it is used as the buffer delay (defaults to 50ms).
8680          * @param {Function} callback The function to call after the animation finishes
8681          * @return {Roo.Element} this
8682          */
8683         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8684             var action = function(){
8685                 this.alignTo(el, alignment, offsets, animate);
8686                 Roo.callback(callback, this);
8687             };
8688             Roo.EventManager.onWindowResize(action, this);
8689             var tm = typeof monitorScroll;
8690             if(tm != 'undefined'){
8691                 Roo.EventManager.on(window, 'scroll', action, this,
8692                     {buffer: tm == 'number' ? monitorScroll : 50});
8693             }
8694             action.call(this); // align immediately
8695             return this;
8696         },
8697         /**
8698          * Clears any opacity settings from this element. Required in some cases for IE.
8699          * @return {Roo.Element} this
8700          */
8701         clearOpacity : function(){
8702             if (window.ActiveXObject) {
8703                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8704                     this.dom.style.filter = "";
8705                 }
8706             } else {
8707                 this.dom.style.opacity = "";
8708                 this.dom.style["-moz-opacity"] = "";
8709                 this.dom.style["-khtml-opacity"] = "";
8710             }
8711             return this;
8712         },
8713
8714         /**
8715          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8716          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8717          * @return {Roo.Element} this
8718          */
8719         hide : function(animate){
8720             this.setVisible(false, this.preanim(arguments, 0));
8721             return this;
8722         },
8723
8724         /**
8725         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8726         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8727          * @return {Roo.Element} this
8728          */
8729         show : function(animate){
8730             this.setVisible(true, this.preanim(arguments, 0));
8731             return this;
8732         },
8733
8734         /**
8735          * @private Test if size has a unit, otherwise appends the default
8736          */
8737         addUnits : function(size){
8738             return Roo.Element.addUnits(size, this.defaultUnit);
8739         },
8740
8741         /**
8742          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8743          * @return {Roo.Element} this
8744          */
8745         beginMeasure : function(){
8746             var el = this.dom;
8747             if(el.offsetWidth || el.offsetHeight){
8748                 return this; // offsets work already
8749             }
8750             var changed = [];
8751             var p = this.dom, b = document.body; // start with this element
8752             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8753                 var pe = Roo.get(p);
8754                 if(pe.getStyle('display') == 'none'){
8755                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8756                     p.style.visibility = "hidden";
8757                     p.style.display = "block";
8758                 }
8759                 p = p.parentNode;
8760             }
8761             this._measureChanged = changed;
8762             return this;
8763
8764         },
8765
8766         /**
8767          * Restores displays to before beginMeasure was called
8768          * @return {Roo.Element} this
8769          */
8770         endMeasure : function(){
8771             var changed = this._measureChanged;
8772             if(changed){
8773                 for(var i = 0, len = changed.length; i < len; i++) {
8774                     var r = changed[i];
8775                     r.el.style.visibility = r.visibility;
8776                     r.el.style.display = "none";
8777                 }
8778                 this._measureChanged = null;
8779             }
8780             return this;
8781         },
8782
8783         /**
8784         * Update the innerHTML of this element, optionally searching for and processing scripts
8785         * @param {String} html The new HTML
8786         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8787         * @param {Function} callback For async script loading you can be noticed when the update completes
8788         * @return {Roo.Element} this
8789          */
8790         update : function(html, loadScripts, callback){
8791             if(typeof html == "undefined"){
8792                 html = "";
8793             }
8794             if(loadScripts !== true){
8795                 this.dom.innerHTML = html;
8796                 if(typeof callback == "function"){
8797                     callback();
8798                 }
8799                 return this;
8800             }
8801             var id = Roo.id();
8802             var dom = this.dom;
8803
8804             html += '<span id="' + id + '"></span>';
8805
8806             E.onAvailable(id, function(){
8807                 var hd = document.getElementsByTagName("head")[0];
8808                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8809                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8810                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8811
8812                 var match;
8813                 while(match = re.exec(html)){
8814                     var attrs = match[1];
8815                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8816                     if(srcMatch && srcMatch[2]){
8817                        var s = document.createElement("script");
8818                        s.src = srcMatch[2];
8819                        var typeMatch = attrs.match(typeRe);
8820                        if(typeMatch && typeMatch[2]){
8821                            s.type = typeMatch[2];
8822                        }
8823                        hd.appendChild(s);
8824                     }else if(match[2] && match[2].length > 0){
8825                         if(window.execScript) {
8826                            window.execScript(match[2]);
8827                         } else {
8828                             /**
8829                              * eval:var:id
8830                              * eval:var:dom
8831                              * eval:var:html
8832                              * 
8833                              */
8834                            window.eval(match[2]);
8835                         }
8836                     }
8837                 }
8838                 var el = document.getElementById(id);
8839                 if(el){el.parentNode.removeChild(el);}
8840                 if(typeof callback == "function"){
8841                     callback();
8842                 }
8843             });
8844             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8845             return this;
8846         },
8847
8848         /**
8849          * Direct access to the UpdateManager update() method (takes the same parameters).
8850          * @param {String/Function} url The url for this request or a function to call to get the url
8851          * @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}
8852          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8853          * @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.
8854          * @return {Roo.Element} this
8855          */
8856         load : function(){
8857             var um = this.getUpdateManager();
8858             um.update.apply(um, arguments);
8859             return this;
8860         },
8861
8862         /**
8863         * Gets this element's UpdateManager
8864         * @return {Roo.UpdateManager} The UpdateManager
8865         */
8866         getUpdateManager : function(){
8867             if(!this.updateManager){
8868                 this.updateManager = new Roo.UpdateManager(this);
8869             }
8870             return this.updateManager;
8871         },
8872
8873         /**
8874          * Disables text selection for this element (normalized across browsers)
8875          * @return {Roo.Element} this
8876          */
8877         unselectable : function(){
8878             this.dom.unselectable = "on";
8879             this.swallowEvent("selectstart", true);
8880             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8881             this.addClass("x-unselectable");
8882             return this;
8883         },
8884
8885         /**
8886         * Calculates the x, y to center this element on the screen
8887         * @return {Array} The x, y values [x, y]
8888         */
8889         getCenterXY : function(){
8890             return this.getAlignToXY(document, 'c-c');
8891         },
8892
8893         /**
8894         * Centers the Element in either the viewport, or another Element.
8895         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8896         */
8897         center : function(centerIn){
8898             this.alignTo(centerIn || document, 'c-c');
8899             return this;
8900         },
8901
8902         /**
8903          * Tests various css rules/browsers to determine if this element uses a border box
8904          * @return {Boolean}
8905          */
8906         isBorderBox : function(){
8907             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8908         },
8909
8910         /**
8911          * Return a box {x, y, width, height} that can be used to set another elements
8912          * size/location to match this element.
8913          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8914          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8915          * @return {Object} box An object in the format {x, y, width, height}
8916          */
8917         getBox : function(contentBox, local){
8918             var xy;
8919             if(!local){
8920                 xy = this.getXY();
8921             }else{
8922                 var left = parseInt(this.getStyle("left"), 10) || 0;
8923                 var top = parseInt(this.getStyle("top"), 10) || 0;
8924                 xy = [left, top];
8925             }
8926             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8927             if(!contentBox){
8928                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8929             }else{
8930                 var l = this.getBorderWidth("l")+this.getPadding("l");
8931                 var r = this.getBorderWidth("r")+this.getPadding("r");
8932                 var t = this.getBorderWidth("t")+this.getPadding("t");
8933                 var b = this.getBorderWidth("b")+this.getPadding("b");
8934                 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)};
8935             }
8936             bx.right = bx.x + bx.width;
8937             bx.bottom = bx.y + bx.height;
8938             return bx;
8939         },
8940
8941         /**
8942          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8943          for more information about the sides.
8944          * @param {String} sides
8945          * @return {Number}
8946          */
8947         getFrameWidth : function(sides, onlyContentBox){
8948             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8949         },
8950
8951         /**
8952          * 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.
8953          * @param {Object} box The box to fill {x, y, width, height}
8954          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8955          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8956          * @return {Roo.Element} this
8957          */
8958         setBox : function(box, adjust, animate){
8959             var w = box.width, h = box.height;
8960             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8961                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8962                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8963             }
8964             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8965             return this;
8966         },
8967
8968         /**
8969          * Forces the browser to repaint this element
8970          * @return {Roo.Element} this
8971          */
8972          repaint : function(){
8973             var dom = this.dom;
8974             this.addClass("x-repaint");
8975             setTimeout(function(){
8976                 Roo.get(dom).removeClass("x-repaint");
8977             }, 1);
8978             return this;
8979         },
8980
8981         /**
8982          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8983          * then it returns the calculated width of the sides (see getPadding)
8984          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8985          * @return {Object/Number}
8986          */
8987         getMargins : function(side){
8988             if(!side){
8989                 return {
8990                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8991                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8992                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8993                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8994                 };
8995             }else{
8996                 return this.addStyles(side, El.margins);
8997              }
8998         },
8999
9000         // private
9001         addStyles : function(sides, styles){
9002             var val = 0, v, w;
9003             for(var i = 0, len = sides.length; i < len; i++){
9004                 v = this.getStyle(styles[sides.charAt(i)]);
9005                 if(v){
9006                      w = parseInt(v, 10);
9007                      if(w){ val += w; }
9008                 }
9009             }
9010             return val;
9011         },
9012
9013         /**
9014          * Creates a proxy element of this element
9015          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9016          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9017          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9018          * @return {Roo.Element} The new proxy element
9019          */
9020         createProxy : function(config, renderTo, matchBox){
9021             if(renderTo){
9022                 renderTo = Roo.getDom(renderTo);
9023             }else{
9024                 renderTo = document.body;
9025             }
9026             config = typeof config == "object" ?
9027                 config : {tag : "div", cls: config};
9028             var proxy = Roo.DomHelper.append(renderTo, config, true);
9029             if(matchBox){
9030                proxy.setBox(this.getBox());
9031             }
9032             return proxy;
9033         },
9034
9035         /**
9036          * Puts a mask over this element to disable user interaction. Requires core.css.
9037          * This method can only be applied to elements which accept child nodes.
9038          * @param {String} msg (optional) A message to display in the mask
9039          * @param {String} msgCls (optional) A css class to apply to the msg element
9040          * @return {Element} The mask  element
9041          */
9042         mask : function(msg, msgCls)
9043         {
9044             if(this.getStyle("position") == "static"){
9045                 this.setStyle("position", "relative");
9046             }
9047             if(!this._mask){
9048                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9049             }
9050             this.addClass("x-masked");
9051             this._mask.setDisplayed(true);
9052             
9053             // we wander
9054             var z = 0;
9055             var dom = this.dom
9056             while (dom && dom.style) {
9057                 if (!isNaN(parseInt(dom.style.zIndex))) {
9058                     z = Math.max(z, parseInt(dom.style.zIndex));
9059                 }
9060                 dom = dom.parentNode;
9061             }
9062             // if we are masking the body - then it hides everything..
9063             if (this.dom == document.body) {
9064                 z = 1000000;
9065                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9066                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9067             }
9068            
9069             if(typeof msg == 'string'){
9070                 if(!this._maskMsg){
9071                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9072                 }
9073                 var mm = this._maskMsg;
9074                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9075                 mm.dom.firstChild.innerHTML = msg;
9076                 mm.setDisplayed(true);
9077                 mm.center(this);
9078                 mm.setStyle('z-index', z + 102);
9079             }
9080             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9081                 this._mask.setHeight(this.getHeight());
9082             }
9083             this._mask.setStyle('z-index', z + 100);
9084             
9085             return this._mask;
9086         },
9087
9088         /**
9089          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9090          * it is cached for reuse.
9091          */
9092         unmask : function(removeEl){
9093             if(this._mask){
9094                 if(removeEl === true){
9095                     this._mask.remove();
9096                     delete this._mask;
9097                     if(this._maskMsg){
9098                         this._maskMsg.remove();
9099                         delete this._maskMsg;
9100                     }
9101                 }else{
9102                     this._mask.setDisplayed(false);
9103                     if(this._maskMsg){
9104                         this._maskMsg.setDisplayed(false);
9105                     }
9106                 }
9107             }
9108             this.removeClass("x-masked");
9109         },
9110
9111         /**
9112          * Returns true if this element is masked
9113          * @return {Boolean}
9114          */
9115         isMasked : function(){
9116             return this._mask && this._mask.isVisible();
9117         },
9118
9119         /**
9120          * Creates an iframe shim for this element to keep selects and other windowed objects from
9121          * showing through.
9122          * @return {Roo.Element} The new shim element
9123          */
9124         createShim : function(){
9125             var el = document.createElement('iframe');
9126             el.frameBorder = 'no';
9127             el.className = 'roo-shim';
9128             if(Roo.isIE && Roo.isSecure){
9129                 el.src = Roo.SSL_SECURE_URL;
9130             }
9131             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9132             shim.autoBoxAdjust = false;
9133             return shim;
9134         },
9135
9136         /**
9137          * Removes this element from the DOM and deletes it from the cache
9138          */
9139         remove : function(){
9140             if(this.dom.parentNode){
9141                 this.dom.parentNode.removeChild(this.dom);
9142             }
9143             delete El.cache[this.dom.id];
9144         },
9145
9146         /**
9147          * Sets up event handlers to add and remove a css class when the mouse is over this element
9148          * @param {String} className
9149          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9150          * mouseout events for children elements
9151          * @return {Roo.Element} this
9152          */
9153         addClassOnOver : function(className, preventFlicker){
9154             this.on("mouseover", function(){
9155                 Roo.fly(this, '_internal').addClass(className);
9156             }, this.dom);
9157             var removeFn = function(e){
9158                 if(preventFlicker !== true || !e.within(this, true)){
9159                     Roo.fly(this, '_internal').removeClass(className);
9160                 }
9161             };
9162             this.on("mouseout", removeFn, this.dom);
9163             return this;
9164         },
9165
9166         /**
9167          * Sets up event handlers to add and remove a css class when this element has the focus
9168          * @param {String} className
9169          * @return {Roo.Element} this
9170          */
9171         addClassOnFocus : function(className){
9172             this.on("focus", function(){
9173                 Roo.fly(this, '_internal').addClass(className);
9174             }, this.dom);
9175             this.on("blur", function(){
9176                 Roo.fly(this, '_internal').removeClass(className);
9177             }, this.dom);
9178             return this;
9179         },
9180         /**
9181          * 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)
9182          * @param {String} className
9183          * @return {Roo.Element} this
9184          */
9185         addClassOnClick : function(className){
9186             var dom = this.dom;
9187             this.on("mousedown", function(){
9188                 Roo.fly(dom, '_internal').addClass(className);
9189                 var d = Roo.get(document);
9190                 var fn = function(){
9191                     Roo.fly(dom, '_internal').removeClass(className);
9192                     d.removeListener("mouseup", fn);
9193                 };
9194                 d.on("mouseup", fn);
9195             });
9196             return this;
9197         },
9198
9199         /**
9200          * Stops the specified event from bubbling and optionally prevents the default action
9201          * @param {String} eventName
9202          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9203          * @return {Roo.Element} this
9204          */
9205         swallowEvent : function(eventName, preventDefault){
9206             var fn = function(e){
9207                 e.stopPropagation();
9208                 if(preventDefault){
9209                     e.preventDefault();
9210                 }
9211             };
9212             if(eventName instanceof Array){
9213                 for(var i = 0, len = eventName.length; i < len; i++){
9214                      this.on(eventName[i], fn);
9215                 }
9216                 return this;
9217             }
9218             this.on(eventName, fn);
9219             return this;
9220         },
9221
9222         /**
9223          * @private
9224          */
9225       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9226
9227         /**
9228          * Sizes this element to its parent element's dimensions performing
9229          * neccessary box adjustments.
9230          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9231          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9232          * @return {Roo.Element} this
9233          */
9234         fitToParent : function(monitorResize, targetParent) {
9235           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9236           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9237           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9238             return;
9239           }
9240           var p = Roo.get(targetParent || this.dom.parentNode);
9241           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9242           if (monitorResize === true) {
9243             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9244             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9245           }
9246           return this;
9247         },
9248
9249         /**
9250          * Gets the next sibling, skipping text nodes
9251          * @return {HTMLElement} The next sibling or null
9252          */
9253         getNextSibling : function(){
9254             var n = this.dom.nextSibling;
9255             while(n && n.nodeType != 1){
9256                 n = n.nextSibling;
9257             }
9258             return n;
9259         },
9260
9261         /**
9262          * Gets the previous sibling, skipping text nodes
9263          * @return {HTMLElement} The previous sibling or null
9264          */
9265         getPrevSibling : function(){
9266             var n = this.dom.previousSibling;
9267             while(n && n.nodeType != 1){
9268                 n = n.previousSibling;
9269             }
9270             return n;
9271         },
9272
9273
9274         /**
9275          * Appends the passed element(s) to this element
9276          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9277          * @return {Roo.Element} this
9278          */
9279         appendChild: function(el){
9280             el = Roo.get(el);
9281             el.appendTo(this);
9282             return this;
9283         },
9284
9285         /**
9286          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9287          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9288          * automatically generated with the specified attributes.
9289          * @param {HTMLElement} insertBefore (optional) a child element of this element
9290          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9291          * @return {Roo.Element} The new child element
9292          */
9293         createChild: function(config, insertBefore, returnDom){
9294             config = config || {tag:'div'};
9295             if(insertBefore){
9296                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9297             }
9298             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9299         },
9300
9301         /**
9302          * Appends this element to the passed element
9303          * @param {String/HTMLElement/Element} el The new parent element
9304          * @return {Roo.Element} this
9305          */
9306         appendTo: function(el){
9307             el = Roo.getDom(el);
9308             el.appendChild(this.dom);
9309             return this;
9310         },
9311
9312         /**
9313          * Inserts this element before the passed element in the DOM
9314          * @param {String/HTMLElement/Element} el The element to insert before
9315          * @return {Roo.Element} this
9316          */
9317         insertBefore: function(el){
9318             el = Roo.getDom(el);
9319             el.parentNode.insertBefore(this.dom, el);
9320             return this;
9321         },
9322
9323         /**
9324          * Inserts this element after the passed element in the DOM
9325          * @param {String/HTMLElement/Element} el The element to insert after
9326          * @return {Roo.Element} this
9327          */
9328         insertAfter: function(el){
9329             el = Roo.getDom(el);
9330             el.parentNode.insertBefore(this.dom, el.nextSibling);
9331             return this;
9332         },
9333
9334         /**
9335          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9336          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9337          * @return {Roo.Element} The new child
9338          */
9339         insertFirst: function(el, returnDom){
9340             el = el || {};
9341             if(typeof el == 'object' && !el.nodeType){ // dh config
9342                 return this.createChild(el, this.dom.firstChild, returnDom);
9343             }else{
9344                 el = Roo.getDom(el);
9345                 this.dom.insertBefore(el, this.dom.firstChild);
9346                 return !returnDom ? Roo.get(el) : el;
9347             }
9348         },
9349
9350         /**
9351          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9352          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9353          * @param {String} where (optional) 'before' or 'after' defaults to before
9354          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9355          * @return {Roo.Element} the inserted Element
9356          */
9357         insertSibling: function(el, where, returnDom){
9358             where = where ? where.toLowerCase() : 'before';
9359             el = el || {};
9360             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9361
9362             if(typeof el == 'object' && !el.nodeType){ // dh config
9363                 if(where == 'after' && !this.dom.nextSibling){
9364                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9365                 }else{
9366                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9367                 }
9368
9369             }else{
9370                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9371                             where == 'before' ? this.dom : this.dom.nextSibling);
9372                 if(!returnDom){
9373                     rt = Roo.get(rt);
9374                 }
9375             }
9376             return rt;
9377         },
9378
9379         /**
9380          * Creates and wraps this element with another element
9381          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9382          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9383          * @return {HTMLElement/Element} The newly created wrapper element
9384          */
9385         wrap: function(config, returnDom){
9386             if(!config){
9387                 config = {tag: "div"};
9388             }
9389             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9390             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9391             return newEl;
9392         },
9393
9394         /**
9395          * Replaces the passed element with this element
9396          * @param {String/HTMLElement/Element} el The element to replace
9397          * @return {Roo.Element} this
9398          */
9399         replace: function(el){
9400             el = Roo.get(el);
9401             this.insertBefore(el);
9402             el.remove();
9403             return this;
9404         },
9405
9406         /**
9407          * Inserts an html fragment into this element
9408          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9409          * @param {String} html The HTML fragment
9410          * @param {Boolean} returnEl True to return an Roo.Element
9411          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9412          */
9413         insertHtml : function(where, html, returnEl){
9414             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9415             return returnEl ? Roo.get(el) : el;
9416         },
9417
9418         /**
9419          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9420          * @param {Object} o The object with the attributes
9421          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9422          * @return {Roo.Element} this
9423          */
9424         set : function(o, useSet){
9425             var el = this.dom;
9426             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9427             for(var attr in o){
9428                 if(attr == "style" || typeof o[attr] == "function") continue;
9429                 if(attr=="cls"){
9430                     el.className = o["cls"];
9431                 }else{
9432                     if(useSet) el.setAttribute(attr, o[attr]);
9433                     else el[attr] = o[attr];
9434                 }
9435             }
9436             if(o.style){
9437                 Roo.DomHelper.applyStyles(el, o.style);
9438             }
9439             return this;
9440         },
9441
9442         /**
9443          * Convenience method for constructing a KeyMap
9444          * @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:
9445          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9446          * @param {Function} fn The function to call
9447          * @param {Object} scope (optional) The scope of the function
9448          * @return {Roo.KeyMap} The KeyMap created
9449          */
9450         addKeyListener : function(key, fn, scope){
9451             var config;
9452             if(typeof key != "object" || key instanceof Array){
9453                 config = {
9454                     key: key,
9455                     fn: fn,
9456                     scope: scope
9457                 };
9458             }else{
9459                 config = {
9460                     key : key.key,
9461                     shift : key.shift,
9462                     ctrl : key.ctrl,
9463                     alt : key.alt,
9464                     fn: fn,
9465                     scope: scope
9466                 };
9467             }
9468             return new Roo.KeyMap(this, config);
9469         },
9470
9471         /**
9472          * Creates a KeyMap for this element
9473          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9474          * @return {Roo.KeyMap} The KeyMap created
9475          */
9476         addKeyMap : function(config){
9477             return new Roo.KeyMap(this, config);
9478         },
9479
9480         /**
9481          * Returns true if this element is scrollable.
9482          * @return {Boolean}
9483          */
9484          isScrollable : function(){
9485             var dom = this.dom;
9486             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9487         },
9488
9489         /**
9490          * 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().
9491          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9492          * @param {Number} value The new scroll value
9493          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9494          * @return {Element} this
9495          */
9496
9497         scrollTo : function(side, value, animate){
9498             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9499             if(!animate || !A){
9500                 this.dom[prop] = value;
9501             }else{
9502                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9503                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9504             }
9505             return this;
9506         },
9507
9508         /**
9509          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9510          * within this element's scrollable range.
9511          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9512          * @param {Number} distance How far to scroll the element in pixels
9513          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9514          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9515          * was scrolled as far as it could go.
9516          */
9517          scroll : function(direction, distance, animate){
9518              if(!this.isScrollable()){
9519                  return;
9520              }
9521              var el = this.dom;
9522              var l = el.scrollLeft, t = el.scrollTop;
9523              var w = el.scrollWidth, h = el.scrollHeight;
9524              var cw = el.clientWidth, ch = el.clientHeight;
9525              direction = direction.toLowerCase();
9526              var scrolled = false;
9527              var a = this.preanim(arguments, 2);
9528              switch(direction){
9529                  case "l":
9530                  case "left":
9531                      if(w - l > cw){
9532                          var v = Math.min(l + distance, w-cw);
9533                          this.scrollTo("left", v, a);
9534                          scrolled = true;
9535                      }
9536                      break;
9537                 case "r":
9538                 case "right":
9539                      if(l > 0){
9540                          var v = Math.max(l - distance, 0);
9541                          this.scrollTo("left", v, a);
9542                          scrolled = true;
9543                      }
9544                      break;
9545                 case "t":
9546                 case "top":
9547                 case "up":
9548                      if(t > 0){
9549                          var v = Math.max(t - distance, 0);
9550                          this.scrollTo("top", v, a);
9551                          scrolled = true;
9552                      }
9553                      break;
9554                 case "b":
9555                 case "bottom":
9556                 case "down":
9557                      if(h - t > ch){
9558                          var v = Math.min(t + distance, h-ch);
9559                          this.scrollTo("top", v, a);
9560                          scrolled = true;
9561                      }
9562                      break;
9563              }
9564              return scrolled;
9565         },
9566
9567         /**
9568          * Translates the passed page coordinates into left/top css values for this element
9569          * @param {Number/Array} x The page x or an array containing [x, y]
9570          * @param {Number} y The page y
9571          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9572          */
9573         translatePoints : function(x, y){
9574             if(typeof x == 'object' || x instanceof Array){
9575                 y = x[1]; x = x[0];
9576             }
9577             var p = this.getStyle('position');
9578             var o = this.getXY();
9579
9580             var l = parseInt(this.getStyle('left'), 10);
9581             var t = parseInt(this.getStyle('top'), 10);
9582
9583             if(isNaN(l)){
9584                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9585             }
9586             if(isNaN(t)){
9587                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9588             }
9589
9590             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9591         },
9592
9593         /**
9594          * Returns the current scroll position of the element.
9595          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9596          */
9597         getScroll : function(){
9598             var d = this.dom, doc = document;
9599             if(d == doc || d == doc.body){
9600                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9601                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9602                 return {left: l, top: t};
9603             }else{
9604                 return {left: d.scrollLeft, top: d.scrollTop};
9605             }
9606         },
9607
9608         /**
9609          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9610          * are convert to standard 6 digit hex color.
9611          * @param {String} attr The css attribute
9612          * @param {String} defaultValue The default value to use when a valid color isn't found
9613          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9614          * YUI color anims.
9615          */
9616         getColor : function(attr, defaultValue, prefix){
9617             var v = this.getStyle(attr);
9618             if(!v || v == "transparent" || v == "inherit") {
9619                 return defaultValue;
9620             }
9621             var color = typeof prefix == "undefined" ? "#" : prefix;
9622             if(v.substr(0, 4) == "rgb("){
9623                 var rvs = v.slice(4, v.length -1).split(",");
9624                 for(var i = 0; i < 3; i++){
9625                     var h = parseInt(rvs[i]).toString(16);
9626                     if(h < 16){
9627                         h = "0" + h;
9628                     }
9629                     color += h;
9630                 }
9631             } else {
9632                 if(v.substr(0, 1) == "#"){
9633                     if(v.length == 4) {
9634                         for(var i = 1; i < 4; i++){
9635                             var c = v.charAt(i);
9636                             color +=  c + c;
9637                         }
9638                     }else if(v.length == 7){
9639                         color += v.substr(1);
9640                     }
9641                 }
9642             }
9643             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9644         },
9645
9646         /**
9647          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9648          * gradient background, rounded corners and a 4-way shadow.
9649          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9650          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9651          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9652          * @return {Roo.Element} this
9653          */
9654         boxWrap : function(cls){
9655             cls = cls || 'x-box';
9656             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9657             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9658             return el;
9659         },
9660
9661         /**
9662          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9663          * @param {String} namespace The namespace in which to look for the attribute
9664          * @param {String} name The attribute name
9665          * @return {String} The attribute value
9666          */
9667         getAttributeNS : Roo.isIE ? function(ns, name){
9668             var d = this.dom;
9669             var type = typeof d[ns+":"+name];
9670             if(type != 'undefined' && type != 'unknown'){
9671                 return d[ns+":"+name];
9672             }
9673             return d[name];
9674         } : function(ns, name){
9675             var d = this.dom;
9676             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9677         },
9678         
9679         
9680         /**
9681          * Sets or Returns the value the dom attribute value
9682          * @param {String} name The attribute name
9683          * @param {String} value (optional) The value to set the attribute to
9684          * @return {String} The attribute value
9685          */
9686         attr : function(name){
9687             if (arguments.length > 1) {
9688                 this.dom.setAttribute(name, arguments[1]);
9689                 return arguments[1];
9690             }
9691             if (!this.dom.hasAttribute(name)) {
9692                 return undefined;
9693             }
9694             return this.dom.getAttribute(name);
9695         }
9696         
9697         
9698         
9699     };
9700
9701     var ep = El.prototype;
9702
9703     /**
9704      * Appends an event handler (Shorthand for addListener)
9705      * @param {String}   eventName     The type of event to append
9706      * @param {Function} fn        The method the event invokes
9707      * @param {Object} scope       (optional) The scope (this object) of the fn
9708      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9709      * @method
9710      */
9711     ep.on = ep.addListener;
9712         // backwards compat
9713     ep.mon = ep.addListener;
9714
9715     /**
9716      * Removes an event handler from this element (shorthand for removeListener)
9717      * @param {String} eventName the type of event to remove
9718      * @param {Function} fn the method the event invokes
9719      * @return {Roo.Element} this
9720      * @method
9721      */
9722     ep.un = ep.removeListener;
9723
9724     /**
9725      * true to automatically adjust width and height settings for box-model issues (default to true)
9726      */
9727     ep.autoBoxAdjust = true;
9728
9729     // private
9730     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9731
9732     // private
9733     El.addUnits = function(v, defaultUnit){
9734         if(v === "" || v == "auto"){
9735             return v;
9736         }
9737         if(v === undefined){
9738             return '';
9739         }
9740         if(typeof v == "number" || !El.unitPattern.test(v)){
9741             return v + (defaultUnit || 'px');
9742         }
9743         return v;
9744     };
9745
9746     // special markup used throughout Roo when box wrapping elements
9747     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>';
9748     /**
9749      * Visibility mode constant - Use visibility to hide element
9750      * @static
9751      * @type Number
9752      */
9753     El.VISIBILITY = 1;
9754     /**
9755      * Visibility mode constant - Use display to hide element
9756      * @static
9757      * @type Number
9758      */
9759     El.DISPLAY = 2;
9760
9761     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9762     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9763     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9764
9765
9766
9767     /**
9768      * @private
9769      */
9770     El.cache = {};
9771
9772     var docEl;
9773
9774     /**
9775      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9776      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9777      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9778      * @return {Element} The Element object
9779      * @static
9780      */
9781     El.get = function(el){
9782         var ex, elm, id;
9783         if(!el){ return null; }
9784         if(typeof el == "string"){ // element id
9785             if(!(elm = document.getElementById(el))){
9786                 return null;
9787             }
9788             if(ex = El.cache[el]){
9789                 ex.dom = elm;
9790             }else{
9791                 ex = El.cache[el] = new El(elm);
9792             }
9793             return ex;
9794         }else if(el.tagName){ // dom element
9795             if(!(id = el.id)){
9796                 id = Roo.id(el);
9797             }
9798             if(ex = El.cache[id]){
9799                 ex.dom = el;
9800             }else{
9801                 ex = El.cache[id] = new El(el);
9802             }
9803             return ex;
9804         }else if(el instanceof El){
9805             if(el != docEl){
9806                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9807                                                               // catch case where it hasn't been appended
9808                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9809             }
9810             return el;
9811         }else if(el.isComposite){
9812             return el;
9813         }else if(el instanceof Array){
9814             return El.select(el);
9815         }else if(el == document){
9816             // create a bogus element object representing the document object
9817             if(!docEl){
9818                 var f = function(){};
9819                 f.prototype = El.prototype;
9820                 docEl = new f();
9821                 docEl.dom = document;
9822             }
9823             return docEl;
9824         }
9825         return null;
9826     };
9827
9828     // private
9829     El.uncache = function(el){
9830         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9831             if(a[i]){
9832                 delete El.cache[a[i].id || a[i]];
9833             }
9834         }
9835     };
9836
9837     // private
9838     // Garbage collection - uncache elements/purge listeners on orphaned elements
9839     // so we don't hold a reference and cause the browser to retain them
9840     El.garbageCollect = function(){
9841         if(!Roo.enableGarbageCollector){
9842             clearInterval(El.collectorThread);
9843             return;
9844         }
9845         for(var eid in El.cache){
9846             var el = El.cache[eid], d = el.dom;
9847             // -------------------------------------------------------
9848             // Determining what is garbage:
9849             // -------------------------------------------------------
9850             // !d
9851             // dom node is null, definitely garbage
9852             // -------------------------------------------------------
9853             // !d.parentNode
9854             // no parentNode == direct orphan, definitely garbage
9855             // -------------------------------------------------------
9856             // !d.offsetParent && !document.getElementById(eid)
9857             // display none elements have no offsetParent so we will
9858             // also try to look it up by it's id. However, check
9859             // offsetParent first so we don't do unneeded lookups.
9860             // This enables collection of elements that are not orphans
9861             // directly, but somewhere up the line they have an orphan
9862             // parent.
9863             // -------------------------------------------------------
9864             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9865                 delete El.cache[eid];
9866                 if(d && Roo.enableListenerCollection){
9867                     E.purgeElement(d);
9868                 }
9869             }
9870         }
9871     }
9872     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9873
9874
9875     // dom is optional
9876     El.Flyweight = function(dom){
9877         this.dom = dom;
9878     };
9879     El.Flyweight.prototype = El.prototype;
9880
9881     El._flyweights = {};
9882     /**
9883      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9884      * the dom node can be overwritten by other code.
9885      * @param {String/HTMLElement} el The dom node or id
9886      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9887      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9888      * @static
9889      * @return {Element} The shared Element object
9890      */
9891     El.fly = function(el, named){
9892         named = named || '_global';
9893         el = Roo.getDom(el);
9894         if(!el){
9895             return null;
9896         }
9897         if(!El._flyweights[named]){
9898             El._flyweights[named] = new El.Flyweight();
9899         }
9900         El._flyweights[named].dom = el;
9901         return El._flyweights[named];
9902     };
9903
9904     /**
9905      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9906      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9907      * Shorthand of {@link Roo.Element#get}
9908      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9909      * @return {Element} The Element object
9910      * @member Roo
9911      * @method get
9912      */
9913     Roo.get = El.get;
9914     /**
9915      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9916      * the dom node can be overwritten by other code.
9917      * Shorthand of {@link Roo.Element#fly}
9918      * @param {String/HTMLElement} el The dom node or id
9919      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9920      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9921      * @static
9922      * @return {Element} The shared Element object
9923      * @member Roo
9924      * @method fly
9925      */
9926     Roo.fly = El.fly;
9927
9928     // speedy lookup for elements never to box adjust
9929     var noBoxAdjust = Roo.isStrict ? {
9930         select:1
9931     } : {
9932         input:1, select:1, textarea:1
9933     };
9934     if(Roo.isIE || Roo.isGecko){
9935         noBoxAdjust['button'] = 1;
9936     }
9937
9938
9939     Roo.EventManager.on(window, 'unload', function(){
9940         delete El.cache;
9941         delete El._flyweights;
9942     });
9943 })();
9944
9945
9946
9947
9948 if(Roo.DomQuery){
9949     Roo.Element.selectorFunction = Roo.DomQuery.select;
9950 }
9951
9952 Roo.Element.select = function(selector, unique, root){
9953     var els;
9954     if(typeof selector == "string"){
9955         els = Roo.Element.selectorFunction(selector, root);
9956     }else if(selector.length !== undefined){
9957         els = selector;
9958     }else{
9959         throw "Invalid selector";
9960     }
9961     if(unique === true){
9962         return new Roo.CompositeElement(els);
9963     }else{
9964         return new Roo.CompositeElementLite(els);
9965     }
9966 };
9967 /**
9968  * Selects elements based on the passed CSS selector to enable working on them as 1.
9969  * @param {String/Array} selector The CSS selector or an array of elements
9970  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9971  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9972  * @return {CompositeElementLite/CompositeElement}
9973  * @member Roo
9974  * @method select
9975  */
9976 Roo.select = Roo.Element.select;
9977
9978
9979
9980
9981
9982
9983
9984
9985
9986
9987
9988
9989
9990
9991 /*
9992  * Based on:
9993  * Ext JS Library 1.1.1
9994  * Copyright(c) 2006-2007, Ext JS, LLC.
9995  *
9996  * Originally Released Under LGPL - original licence link has changed is not relivant.
9997  *
9998  * Fork - LGPL
9999  * <script type="text/javascript">
10000  */
10001
10002
10003
10004 //Notifies Element that fx methods are available
10005 Roo.enableFx = true;
10006
10007 /**
10008  * @class Roo.Fx
10009  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10010  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10011  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10012  * Element effects to work.</p><br/>
10013  *
10014  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10015  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10016  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10017  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10018  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10019  * expected results and should be done with care.</p><br/>
10020  *
10021  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10022  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10023 <pre>
10024 Value  Description
10025 -----  -----------------------------
10026 tl     The top left corner
10027 t      The center of the top edge
10028 tr     The top right corner
10029 l      The center of the left edge
10030 r      The center of the right edge
10031 bl     The bottom left corner
10032 b      The center of the bottom edge
10033 br     The bottom right corner
10034 </pre>
10035  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10036  * below are common options that can be passed to any Fx method.</b>
10037  * @cfg {Function} callback A function called when the effect is finished
10038  * @cfg {Object} scope The scope of the effect function
10039  * @cfg {String} easing A valid Easing value for the effect
10040  * @cfg {String} afterCls A css class to apply after the effect
10041  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10042  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10043  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10044  * effects that end with the element being visually hidden, ignored otherwise)
10045  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10046  * a function which returns such a specification that will be applied to the Element after the effect finishes
10047  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10048  * @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
10049  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10050  */
10051 Roo.Fx = {
10052         /**
10053          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10054          * origin for the slide effect.  This function automatically handles wrapping the element with
10055          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10056          * Usage:
10057          *<pre><code>
10058 // default: slide the element in from the top
10059 el.slideIn();
10060
10061 // custom: slide the element in from the right with a 2-second duration
10062 el.slideIn('r', { duration: 2 });
10063
10064 // common config options shown with default values
10065 el.slideIn('t', {
10066     easing: 'easeOut',
10067     duration: .5
10068 });
10069 </code></pre>
10070          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10071          * @param {Object} options (optional) Object literal with any of the Fx config options
10072          * @return {Roo.Element} The Element
10073          */
10074     slideIn : function(anchor, o){
10075         var el = this.getFxEl();
10076         o = o || {};
10077
10078         el.queueFx(o, function(){
10079
10080             anchor = anchor || "t";
10081
10082             // fix display to visibility
10083             this.fixDisplay();
10084
10085             // restore values after effect
10086             var r = this.getFxRestore();
10087             var b = this.getBox();
10088             // fixed size for slide
10089             this.setSize(b);
10090
10091             // wrap if needed
10092             var wrap = this.fxWrap(r.pos, o, "hidden");
10093
10094             var st = this.dom.style;
10095             st.visibility = "visible";
10096             st.position = "absolute";
10097
10098             // clear out temp styles after slide and unwrap
10099             var after = function(){
10100                 el.fxUnwrap(wrap, r.pos, o);
10101                 st.width = r.width;
10102                 st.height = r.height;
10103                 el.afterFx(o);
10104             };
10105             // time to calc the positions
10106             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10107
10108             switch(anchor.toLowerCase()){
10109                 case "t":
10110                     wrap.setSize(b.width, 0);
10111                     st.left = st.bottom = "0";
10112                     a = {height: bh};
10113                 break;
10114                 case "l":
10115                     wrap.setSize(0, b.height);
10116                     st.right = st.top = "0";
10117                     a = {width: bw};
10118                 break;
10119                 case "r":
10120                     wrap.setSize(0, b.height);
10121                     wrap.setX(b.right);
10122                     st.left = st.top = "0";
10123                     a = {width: bw, points: pt};
10124                 break;
10125                 case "b":
10126                     wrap.setSize(b.width, 0);
10127                     wrap.setY(b.bottom);
10128                     st.left = st.top = "0";
10129                     a = {height: bh, points: pt};
10130                 break;
10131                 case "tl":
10132                     wrap.setSize(0, 0);
10133                     st.right = st.bottom = "0";
10134                     a = {width: bw, height: bh};
10135                 break;
10136                 case "bl":
10137                     wrap.setSize(0, 0);
10138                     wrap.setY(b.y+b.height);
10139                     st.right = st.top = "0";
10140                     a = {width: bw, height: bh, points: pt};
10141                 break;
10142                 case "br":
10143                     wrap.setSize(0, 0);
10144                     wrap.setXY([b.right, b.bottom]);
10145                     st.left = st.top = "0";
10146                     a = {width: bw, height: bh, points: pt};
10147                 break;
10148                 case "tr":
10149                     wrap.setSize(0, 0);
10150                     wrap.setX(b.x+b.width);
10151                     st.left = st.bottom = "0";
10152                     a = {width: bw, height: bh, points: pt};
10153                 break;
10154             }
10155             this.dom.style.visibility = "visible";
10156             wrap.show();
10157
10158             arguments.callee.anim = wrap.fxanim(a,
10159                 o,
10160                 'motion',
10161                 .5,
10162                 'easeOut', after);
10163         });
10164         return this;
10165     },
10166     
10167         /**
10168          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10169          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10170          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10171          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10172          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10173          * Usage:
10174          *<pre><code>
10175 // default: slide the element out to the top
10176 el.slideOut();
10177
10178 // custom: slide the element out to the right with a 2-second duration
10179 el.slideOut('r', { duration: 2 });
10180
10181 // common config options shown with default values
10182 el.slideOut('t', {
10183     easing: 'easeOut',
10184     duration: .5,
10185     remove: false,
10186     useDisplay: false
10187 });
10188 </code></pre>
10189          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10190          * @param {Object} options (optional) Object literal with any of the Fx config options
10191          * @return {Roo.Element} The Element
10192          */
10193     slideOut : function(anchor, o){
10194         var el = this.getFxEl();
10195         o = o || {};
10196
10197         el.queueFx(o, function(){
10198
10199             anchor = anchor || "t";
10200
10201             // restore values after effect
10202             var r = this.getFxRestore();
10203             
10204             var b = this.getBox();
10205             // fixed size for slide
10206             this.setSize(b);
10207
10208             // wrap if needed
10209             var wrap = this.fxWrap(r.pos, o, "visible");
10210
10211             var st = this.dom.style;
10212             st.visibility = "visible";
10213             st.position = "absolute";
10214
10215             wrap.setSize(b);
10216
10217             var after = function(){
10218                 if(o.useDisplay){
10219                     el.setDisplayed(false);
10220                 }else{
10221                     el.hide();
10222                 }
10223
10224                 el.fxUnwrap(wrap, r.pos, o);
10225
10226                 st.width = r.width;
10227                 st.height = r.height;
10228
10229                 el.afterFx(o);
10230             };
10231
10232             var a, zero = {to: 0};
10233             switch(anchor.toLowerCase()){
10234                 case "t":
10235                     st.left = st.bottom = "0";
10236                     a = {height: zero};
10237                 break;
10238                 case "l":
10239                     st.right = st.top = "0";
10240                     a = {width: zero};
10241                 break;
10242                 case "r":
10243                     st.left = st.top = "0";
10244                     a = {width: zero, points: {to:[b.right, b.y]}};
10245                 break;
10246                 case "b":
10247                     st.left = st.top = "0";
10248                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10249                 break;
10250                 case "tl":
10251                     st.right = st.bottom = "0";
10252                     a = {width: zero, height: zero};
10253                 break;
10254                 case "bl":
10255                     st.right = st.top = "0";
10256                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10257                 break;
10258                 case "br":
10259                     st.left = st.top = "0";
10260                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10261                 break;
10262                 case "tr":
10263                     st.left = st.bottom = "0";
10264                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10265                 break;
10266             }
10267
10268             arguments.callee.anim = wrap.fxanim(a,
10269                 o,
10270                 'motion',
10271                 .5,
10272                 "easeOut", after);
10273         });
10274         return this;
10275     },
10276
10277         /**
10278          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10279          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10280          * The element must be removed from the DOM using the 'remove' config option if desired.
10281          * Usage:
10282          *<pre><code>
10283 // default
10284 el.puff();
10285
10286 // common config options shown with default values
10287 el.puff({
10288     easing: 'easeOut',
10289     duration: .5,
10290     remove: false,
10291     useDisplay: false
10292 });
10293 </code></pre>
10294          * @param {Object} options (optional) Object literal with any of the Fx config options
10295          * @return {Roo.Element} The Element
10296          */
10297     puff : function(o){
10298         var el = this.getFxEl();
10299         o = o || {};
10300
10301         el.queueFx(o, function(){
10302             this.clearOpacity();
10303             this.show();
10304
10305             // restore values after effect
10306             var r = this.getFxRestore();
10307             var st = this.dom.style;
10308
10309             var after = function(){
10310                 if(o.useDisplay){
10311                     el.setDisplayed(false);
10312                 }else{
10313                     el.hide();
10314                 }
10315
10316                 el.clearOpacity();
10317
10318                 el.setPositioning(r.pos);
10319                 st.width = r.width;
10320                 st.height = r.height;
10321                 st.fontSize = '';
10322                 el.afterFx(o);
10323             };
10324
10325             var width = this.getWidth();
10326             var height = this.getHeight();
10327
10328             arguments.callee.anim = this.fxanim({
10329                     width : {to: this.adjustWidth(width * 2)},
10330                     height : {to: this.adjustHeight(height * 2)},
10331                     points : {by: [-(width * .5), -(height * .5)]},
10332                     opacity : {to: 0},
10333                     fontSize: {to:200, unit: "%"}
10334                 },
10335                 o,
10336                 'motion',
10337                 .5,
10338                 "easeOut", after);
10339         });
10340         return this;
10341     },
10342
10343         /**
10344          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10345          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10346          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10347          * Usage:
10348          *<pre><code>
10349 // default
10350 el.switchOff();
10351
10352 // all config options shown with default values
10353 el.switchOff({
10354     easing: 'easeIn',
10355     duration: .3,
10356     remove: false,
10357     useDisplay: false
10358 });
10359 </code></pre>
10360          * @param {Object} options (optional) Object literal with any of the Fx config options
10361          * @return {Roo.Element} The Element
10362          */
10363     switchOff : function(o){
10364         var el = this.getFxEl();
10365         o = o || {};
10366
10367         el.queueFx(o, function(){
10368             this.clearOpacity();
10369             this.clip();
10370
10371             // restore values after effect
10372             var r = this.getFxRestore();
10373             var st = this.dom.style;
10374
10375             var after = function(){
10376                 if(o.useDisplay){
10377                     el.setDisplayed(false);
10378                 }else{
10379                     el.hide();
10380                 }
10381
10382                 el.clearOpacity();
10383                 el.setPositioning(r.pos);
10384                 st.width = r.width;
10385                 st.height = r.height;
10386
10387                 el.afterFx(o);
10388             };
10389
10390             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10391                 this.clearOpacity();
10392                 (function(){
10393                     this.fxanim({
10394                         height:{to:1},
10395                         points:{by:[0, this.getHeight() * .5]}
10396                     }, o, 'motion', 0.3, 'easeIn', after);
10397                 }).defer(100, this);
10398             });
10399         });
10400         return this;
10401     },
10402
10403     /**
10404      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10405      * changed using the "attr" config option) and then fading back to the original color. If no original
10406      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10407      * Usage:
10408 <pre><code>
10409 // default: highlight background to yellow
10410 el.highlight();
10411
10412 // custom: highlight foreground text to blue for 2 seconds
10413 el.highlight("0000ff", { attr: 'color', duration: 2 });
10414
10415 // common config options shown with default values
10416 el.highlight("ffff9c", {
10417     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10418     endColor: (current color) or "ffffff",
10419     easing: 'easeIn',
10420     duration: 1
10421 });
10422 </code></pre>
10423      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10424      * @param {Object} options (optional) Object literal with any of the Fx config options
10425      * @return {Roo.Element} The Element
10426      */ 
10427     highlight : function(color, o){
10428         var el = this.getFxEl();
10429         o = o || {};
10430
10431         el.queueFx(o, function(){
10432             color = color || "ffff9c";
10433             attr = o.attr || "backgroundColor";
10434
10435             this.clearOpacity();
10436             this.show();
10437
10438             var origColor = this.getColor(attr);
10439             var restoreColor = this.dom.style[attr];
10440             endColor = (o.endColor || origColor) || "ffffff";
10441
10442             var after = function(){
10443                 el.dom.style[attr] = restoreColor;
10444                 el.afterFx(o);
10445             };
10446
10447             var a = {};
10448             a[attr] = {from: color, to: endColor};
10449             arguments.callee.anim = this.fxanim(a,
10450                 o,
10451                 'color',
10452                 1,
10453                 'easeIn', after);
10454         });
10455         return this;
10456     },
10457
10458    /**
10459     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10460     * Usage:
10461 <pre><code>
10462 // default: a single light blue ripple
10463 el.frame();
10464
10465 // custom: 3 red ripples lasting 3 seconds total
10466 el.frame("ff0000", 3, { duration: 3 });
10467
10468 // common config options shown with default values
10469 el.frame("C3DAF9", 1, {
10470     duration: 1 //duration of entire animation (not each individual ripple)
10471     // Note: Easing is not configurable and will be ignored if included
10472 });
10473 </code></pre>
10474     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10475     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10476     * @param {Object} options (optional) Object literal with any of the Fx config options
10477     * @return {Roo.Element} The Element
10478     */
10479     frame : function(color, count, o){
10480         var el = this.getFxEl();
10481         o = o || {};
10482
10483         el.queueFx(o, function(){
10484             color = color || "#C3DAF9";
10485             if(color.length == 6){
10486                 color = "#" + color;
10487             }
10488             count = count || 1;
10489             duration = o.duration || 1;
10490             this.show();
10491
10492             var b = this.getBox();
10493             var animFn = function(){
10494                 var proxy = this.createProxy({
10495
10496                      style:{
10497                         visbility:"hidden",
10498                         position:"absolute",
10499                         "z-index":"35000", // yee haw
10500                         border:"0px solid " + color
10501                      }
10502                   });
10503                 var scale = Roo.isBorderBox ? 2 : 1;
10504                 proxy.animate({
10505                     top:{from:b.y, to:b.y - 20},
10506                     left:{from:b.x, to:b.x - 20},
10507                     borderWidth:{from:0, to:10},
10508                     opacity:{from:1, to:0},
10509                     height:{from:b.height, to:(b.height + (20*scale))},
10510                     width:{from:b.width, to:(b.width + (20*scale))}
10511                 }, duration, function(){
10512                     proxy.remove();
10513                 });
10514                 if(--count > 0){
10515                      animFn.defer((duration/2)*1000, this);
10516                 }else{
10517                     el.afterFx(o);
10518                 }
10519             };
10520             animFn.call(this);
10521         });
10522         return this;
10523     },
10524
10525    /**
10526     * Creates a pause before any subsequent queued effects begin.  If there are
10527     * no effects queued after the pause it will have no effect.
10528     * Usage:
10529 <pre><code>
10530 el.pause(1);
10531 </code></pre>
10532     * @param {Number} seconds The length of time to pause (in seconds)
10533     * @return {Roo.Element} The Element
10534     */
10535     pause : function(seconds){
10536         var el = this.getFxEl();
10537         var o = {};
10538
10539         el.queueFx(o, function(){
10540             setTimeout(function(){
10541                 el.afterFx(o);
10542             }, seconds * 1000);
10543         });
10544         return this;
10545     },
10546
10547    /**
10548     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10549     * using the "endOpacity" config option.
10550     * Usage:
10551 <pre><code>
10552 // default: fade in from opacity 0 to 100%
10553 el.fadeIn();
10554
10555 // custom: fade in from opacity 0 to 75% over 2 seconds
10556 el.fadeIn({ endOpacity: .75, duration: 2});
10557
10558 // common config options shown with default values
10559 el.fadeIn({
10560     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10561     easing: 'easeOut',
10562     duration: .5
10563 });
10564 </code></pre>
10565     * @param {Object} options (optional) Object literal with any of the Fx config options
10566     * @return {Roo.Element} The Element
10567     */
10568     fadeIn : function(o){
10569         var el = this.getFxEl();
10570         o = o || {};
10571         el.queueFx(o, function(){
10572             this.setOpacity(0);
10573             this.fixDisplay();
10574             this.dom.style.visibility = 'visible';
10575             var to = o.endOpacity || 1;
10576             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10577                 o, null, .5, "easeOut", function(){
10578                 if(to == 1){
10579                     this.clearOpacity();
10580                 }
10581                 el.afterFx(o);
10582             });
10583         });
10584         return this;
10585     },
10586
10587    /**
10588     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10589     * using the "endOpacity" config option.
10590     * Usage:
10591 <pre><code>
10592 // default: fade out from the element's current opacity to 0
10593 el.fadeOut();
10594
10595 // custom: fade out from the element's current opacity to 25% over 2 seconds
10596 el.fadeOut({ endOpacity: .25, duration: 2});
10597
10598 // common config options shown with default values
10599 el.fadeOut({
10600     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10601     easing: 'easeOut',
10602     duration: .5
10603     remove: false,
10604     useDisplay: false
10605 });
10606 </code></pre>
10607     * @param {Object} options (optional) Object literal with any of the Fx config options
10608     * @return {Roo.Element} The Element
10609     */
10610     fadeOut : function(o){
10611         var el = this.getFxEl();
10612         o = o || {};
10613         el.queueFx(o, function(){
10614             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10615                 o, null, .5, "easeOut", function(){
10616                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10617                      this.dom.style.display = "none";
10618                 }else{
10619                      this.dom.style.visibility = "hidden";
10620                 }
10621                 this.clearOpacity();
10622                 el.afterFx(o);
10623             });
10624         });
10625         return this;
10626     },
10627
10628    /**
10629     * Animates the transition of an element's dimensions from a starting height/width
10630     * to an ending height/width.
10631     * Usage:
10632 <pre><code>
10633 // change height and width to 100x100 pixels
10634 el.scale(100, 100);
10635
10636 // common config options shown with default values.  The height and width will default to
10637 // the element's existing values if passed as null.
10638 el.scale(
10639     [element's width],
10640     [element's height], {
10641     easing: 'easeOut',
10642     duration: .35
10643 });
10644 </code></pre>
10645     * @param {Number} width  The new width (pass undefined to keep the original width)
10646     * @param {Number} height  The new height (pass undefined to keep the original height)
10647     * @param {Object} options (optional) Object literal with any of the Fx config options
10648     * @return {Roo.Element} The Element
10649     */
10650     scale : function(w, h, o){
10651         this.shift(Roo.apply({}, o, {
10652             width: w,
10653             height: h
10654         }));
10655         return this;
10656     },
10657
10658    /**
10659     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10660     * Any of these properties not specified in the config object will not be changed.  This effect 
10661     * requires that at least one new dimension, position or opacity setting must be passed in on
10662     * the config object in order for the function to have any effect.
10663     * Usage:
10664 <pre><code>
10665 // slide the element horizontally to x position 200 while changing the height and opacity
10666 el.shift({ x: 200, height: 50, opacity: .8 });
10667
10668 // common config options shown with default values.
10669 el.shift({
10670     width: [element's width],
10671     height: [element's height],
10672     x: [element's x position],
10673     y: [element's y position],
10674     opacity: [element's opacity],
10675     easing: 'easeOut',
10676     duration: .35
10677 });
10678 </code></pre>
10679     * @param {Object} options  Object literal with any of the Fx config options
10680     * @return {Roo.Element} The Element
10681     */
10682     shift : function(o){
10683         var el = this.getFxEl();
10684         o = o || {};
10685         el.queueFx(o, function(){
10686             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10687             if(w !== undefined){
10688                 a.width = {to: this.adjustWidth(w)};
10689             }
10690             if(h !== undefined){
10691                 a.height = {to: this.adjustHeight(h)};
10692             }
10693             if(x !== undefined || y !== undefined){
10694                 a.points = {to: [
10695                     x !== undefined ? x : this.getX(),
10696                     y !== undefined ? y : this.getY()
10697                 ]};
10698             }
10699             if(op !== undefined){
10700                 a.opacity = {to: op};
10701             }
10702             if(o.xy !== undefined){
10703                 a.points = {to: o.xy};
10704             }
10705             arguments.callee.anim = this.fxanim(a,
10706                 o, 'motion', .35, "easeOut", function(){
10707                 el.afterFx(o);
10708             });
10709         });
10710         return this;
10711     },
10712
10713         /**
10714          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10715          * ending point of the effect.
10716          * Usage:
10717          *<pre><code>
10718 // default: slide the element downward while fading out
10719 el.ghost();
10720
10721 // custom: slide the element out to the right with a 2-second duration
10722 el.ghost('r', { duration: 2 });
10723
10724 // common config options shown with default values
10725 el.ghost('b', {
10726     easing: 'easeOut',
10727     duration: .5
10728     remove: false,
10729     useDisplay: false
10730 });
10731 </code></pre>
10732          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10733          * @param {Object} options (optional) Object literal with any of the Fx config options
10734          * @return {Roo.Element} The Element
10735          */
10736     ghost : function(anchor, o){
10737         var el = this.getFxEl();
10738         o = o || {};
10739
10740         el.queueFx(o, function(){
10741             anchor = anchor || "b";
10742
10743             // restore values after effect
10744             var r = this.getFxRestore();
10745             var w = this.getWidth(),
10746                 h = this.getHeight();
10747
10748             var st = this.dom.style;
10749
10750             var after = function(){
10751                 if(o.useDisplay){
10752                     el.setDisplayed(false);
10753                 }else{
10754                     el.hide();
10755                 }
10756
10757                 el.clearOpacity();
10758                 el.setPositioning(r.pos);
10759                 st.width = r.width;
10760                 st.height = r.height;
10761
10762                 el.afterFx(o);
10763             };
10764
10765             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10766             switch(anchor.toLowerCase()){
10767                 case "t":
10768                     pt.by = [0, -h];
10769                 break;
10770                 case "l":
10771                     pt.by = [-w, 0];
10772                 break;
10773                 case "r":
10774                     pt.by = [w, 0];
10775                 break;
10776                 case "b":
10777                     pt.by = [0, h];
10778                 break;
10779                 case "tl":
10780                     pt.by = [-w, -h];
10781                 break;
10782                 case "bl":
10783                     pt.by = [-w, h];
10784                 break;
10785                 case "br":
10786                     pt.by = [w, h];
10787                 break;
10788                 case "tr":
10789                     pt.by = [w, -h];
10790                 break;
10791             }
10792
10793             arguments.callee.anim = this.fxanim(a,
10794                 o,
10795                 'motion',
10796                 .5,
10797                 "easeOut", after);
10798         });
10799         return this;
10800     },
10801
10802         /**
10803          * Ensures that all effects queued after syncFx is called on the element are
10804          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10805          * @return {Roo.Element} The Element
10806          */
10807     syncFx : function(){
10808         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10809             block : false,
10810             concurrent : true,
10811             stopFx : false
10812         });
10813         return this;
10814     },
10815
10816         /**
10817          * Ensures that all effects queued after sequenceFx is called on the element are
10818          * run in sequence.  This is the opposite of {@link #syncFx}.
10819          * @return {Roo.Element} The Element
10820          */
10821     sequenceFx : function(){
10822         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10823             block : false,
10824             concurrent : false,
10825             stopFx : false
10826         });
10827         return this;
10828     },
10829
10830         /* @private */
10831     nextFx : function(){
10832         var ef = this.fxQueue[0];
10833         if(ef){
10834             ef.call(this);
10835         }
10836     },
10837
10838         /**
10839          * Returns true if the element has any effects actively running or queued, else returns false.
10840          * @return {Boolean} True if element has active effects, else false
10841          */
10842     hasActiveFx : function(){
10843         return this.fxQueue && this.fxQueue[0];
10844     },
10845
10846         /**
10847          * Stops any running effects and clears the element's internal effects queue if it contains
10848          * any additional effects that haven't started yet.
10849          * @return {Roo.Element} The Element
10850          */
10851     stopFx : function(){
10852         if(this.hasActiveFx()){
10853             var cur = this.fxQueue[0];
10854             if(cur && cur.anim && cur.anim.isAnimated()){
10855                 this.fxQueue = [cur]; // clear out others
10856                 cur.anim.stop(true);
10857             }
10858         }
10859         return this;
10860     },
10861
10862         /* @private */
10863     beforeFx : function(o){
10864         if(this.hasActiveFx() && !o.concurrent){
10865            if(o.stopFx){
10866                this.stopFx();
10867                return true;
10868            }
10869            return false;
10870         }
10871         return true;
10872     },
10873
10874         /**
10875          * Returns true if the element is currently blocking so that no other effect can be queued
10876          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10877          * used to ensure that an effect initiated by a user action runs to completion prior to the
10878          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10879          * @return {Boolean} True if blocking, else false
10880          */
10881     hasFxBlock : function(){
10882         var q = this.fxQueue;
10883         return q && q[0] && q[0].block;
10884     },
10885
10886         /* @private */
10887     queueFx : function(o, fn){
10888         if(!this.fxQueue){
10889             this.fxQueue = [];
10890         }
10891         if(!this.hasFxBlock()){
10892             Roo.applyIf(o, this.fxDefaults);
10893             if(!o.concurrent){
10894                 var run = this.beforeFx(o);
10895                 fn.block = o.block;
10896                 this.fxQueue.push(fn);
10897                 if(run){
10898                     this.nextFx();
10899                 }
10900             }else{
10901                 fn.call(this);
10902             }
10903         }
10904         return this;
10905     },
10906
10907         /* @private */
10908     fxWrap : function(pos, o, vis){
10909         var wrap;
10910         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10911             var wrapXY;
10912             if(o.fixPosition){
10913                 wrapXY = this.getXY();
10914             }
10915             var div = document.createElement("div");
10916             div.style.visibility = vis;
10917             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10918             wrap.setPositioning(pos);
10919             if(wrap.getStyle("position") == "static"){
10920                 wrap.position("relative");
10921             }
10922             this.clearPositioning('auto');
10923             wrap.clip();
10924             wrap.dom.appendChild(this.dom);
10925             if(wrapXY){
10926                 wrap.setXY(wrapXY);
10927             }
10928         }
10929         return wrap;
10930     },
10931
10932         /* @private */
10933     fxUnwrap : function(wrap, pos, o){
10934         this.clearPositioning();
10935         this.setPositioning(pos);
10936         if(!o.wrap){
10937             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10938             wrap.remove();
10939         }
10940     },
10941
10942         /* @private */
10943     getFxRestore : function(){
10944         var st = this.dom.style;
10945         return {pos: this.getPositioning(), width: st.width, height : st.height};
10946     },
10947
10948         /* @private */
10949     afterFx : function(o){
10950         if(o.afterStyle){
10951             this.applyStyles(o.afterStyle);
10952         }
10953         if(o.afterCls){
10954             this.addClass(o.afterCls);
10955         }
10956         if(o.remove === true){
10957             this.remove();
10958         }
10959         Roo.callback(o.callback, o.scope, [this]);
10960         if(!o.concurrent){
10961             this.fxQueue.shift();
10962             this.nextFx();
10963         }
10964     },
10965
10966         /* @private */
10967     getFxEl : function(){ // support for composite element fx
10968         return Roo.get(this.dom);
10969     },
10970
10971         /* @private */
10972     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10973         animType = animType || 'run';
10974         opt = opt || {};
10975         var anim = Roo.lib.Anim[animType](
10976             this.dom, args,
10977             (opt.duration || defaultDur) || .35,
10978             (opt.easing || defaultEase) || 'easeOut',
10979             function(){
10980                 Roo.callback(cb, this);
10981             },
10982             this
10983         );
10984         opt.anim = anim;
10985         return anim;
10986     }
10987 };
10988
10989 // backwords compat
10990 Roo.Fx.resize = Roo.Fx.scale;
10991
10992 //When included, Roo.Fx is automatically applied to Element so that all basic
10993 //effects are available directly via the Element API
10994 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10995  * Based on:
10996  * Ext JS Library 1.1.1
10997  * Copyright(c) 2006-2007, Ext JS, LLC.
10998  *
10999  * Originally Released Under LGPL - original licence link has changed is not relivant.
11000  *
11001  * Fork - LGPL
11002  * <script type="text/javascript">
11003  */
11004
11005
11006 /**
11007  * @class Roo.CompositeElement
11008  * Standard composite class. Creates a Roo.Element for every element in the collection.
11009  * <br><br>
11010  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11011  * actions will be performed on all the elements in this collection.</b>
11012  * <br><br>
11013  * All methods return <i>this</i> and can be chained.
11014  <pre><code>
11015  var els = Roo.select("#some-el div.some-class", true);
11016  // or select directly from an existing element
11017  var el = Roo.get('some-el');
11018  el.select('div.some-class', true);
11019
11020  els.setWidth(100); // all elements become 100 width
11021  els.hide(true); // all elements fade out and hide
11022  // or
11023  els.setWidth(100).hide(true);
11024  </code></pre>
11025  */
11026 Roo.CompositeElement = function(els){
11027     this.elements = [];
11028     this.addElements(els);
11029 };
11030 Roo.CompositeElement.prototype = {
11031     isComposite: true,
11032     addElements : function(els){
11033         if(!els) return this;
11034         if(typeof els == "string"){
11035             els = Roo.Element.selectorFunction(els);
11036         }
11037         var yels = this.elements;
11038         var index = yels.length-1;
11039         for(var i = 0, len = els.length; i < len; i++) {
11040                 yels[++index] = Roo.get(els[i]);
11041         }
11042         return this;
11043     },
11044
11045     /**
11046     * Clears this composite and adds the elements returned by the passed selector.
11047     * @param {String/Array} els A string CSS selector, an array of elements or an element
11048     * @return {CompositeElement} this
11049     */
11050     fill : function(els){
11051         this.elements = [];
11052         this.add(els);
11053         return this;
11054     },
11055
11056     /**
11057     * Filters this composite to only elements that match the passed selector.
11058     * @param {String} selector A string CSS selector
11059     * @return {CompositeElement} this
11060     */
11061     filter : function(selector){
11062         var els = [];
11063         this.each(function(el){
11064             if(el.is(selector)){
11065                 els[els.length] = el.dom;
11066             }
11067         });
11068         this.fill(els);
11069         return this;
11070     },
11071
11072     invoke : function(fn, args){
11073         var els = this.elements;
11074         for(var i = 0, len = els.length; i < len; i++) {
11075                 Roo.Element.prototype[fn].apply(els[i], args);
11076         }
11077         return this;
11078     },
11079     /**
11080     * Adds elements to this composite.
11081     * @param {String/Array} els A string CSS selector, an array of elements or an element
11082     * @return {CompositeElement} this
11083     */
11084     add : function(els){
11085         if(typeof els == "string"){
11086             this.addElements(Roo.Element.selectorFunction(els));
11087         }else if(els.length !== undefined){
11088             this.addElements(els);
11089         }else{
11090             this.addElements([els]);
11091         }
11092         return this;
11093     },
11094     /**
11095     * Calls the passed function passing (el, this, index) for each element in this composite.
11096     * @param {Function} fn The function to call
11097     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11098     * @return {CompositeElement} this
11099     */
11100     each : function(fn, scope){
11101         var els = this.elements;
11102         for(var i = 0, len = els.length; i < len; i++){
11103             if(fn.call(scope || els[i], els[i], this, i) === false) {
11104                 break;
11105             }
11106         }
11107         return this;
11108     },
11109
11110     /**
11111      * Returns the Element object at the specified index
11112      * @param {Number} index
11113      * @return {Roo.Element}
11114      */
11115     item : function(index){
11116         return this.elements[index] || null;
11117     },
11118
11119     /**
11120      * Returns the first Element
11121      * @return {Roo.Element}
11122      */
11123     first : function(){
11124         return this.item(0);
11125     },
11126
11127     /**
11128      * Returns the last Element
11129      * @return {Roo.Element}
11130      */
11131     last : function(){
11132         return this.item(this.elements.length-1);
11133     },
11134
11135     /**
11136      * Returns the number of elements in this composite
11137      * @return Number
11138      */
11139     getCount : function(){
11140         return this.elements.length;
11141     },
11142
11143     /**
11144      * Returns true if this composite contains the passed element
11145      * @return Boolean
11146      */
11147     contains : function(el){
11148         return this.indexOf(el) !== -1;
11149     },
11150
11151     /**
11152      * Returns true if this composite contains the passed element
11153      * @return Boolean
11154      */
11155     indexOf : function(el){
11156         return this.elements.indexOf(Roo.get(el));
11157     },
11158
11159
11160     /**
11161     * Removes the specified element(s).
11162     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11163     * or an array of any of those.
11164     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11165     * @return {CompositeElement} this
11166     */
11167     removeElement : function(el, removeDom){
11168         if(el instanceof Array){
11169             for(var i = 0, len = el.length; i < len; i++){
11170                 this.removeElement(el[i]);
11171             }
11172             return this;
11173         }
11174         var index = typeof el == 'number' ? el : this.indexOf(el);
11175         if(index !== -1){
11176             if(removeDom){
11177                 var d = this.elements[index];
11178                 if(d.dom){
11179                     d.remove();
11180                 }else{
11181                     d.parentNode.removeChild(d);
11182                 }
11183             }
11184             this.elements.splice(index, 1);
11185         }
11186         return this;
11187     },
11188
11189     /**
11190     * Replaces the specified element with the passed element.
11191     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11192     * to replace.
11193     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11194     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11195     * @return {CompositeElement} this
11196     */
11197     replaceElement : function(el, replacement, domReplace){
11198         var index = typeof el == 'number' ? el : this.indexOf(el);
11199         if(index !== -1){
11200             if(domReplace){
11201                 this.elements[index].replaceWith(replacement);
11202             }else{
11203                 this.elements.splice(index, 1, Roo.get(replacement))
11204             }
11205         }
11206         return this;
11207     },
11208
11209     /**
11210      * Removes all elements.
11211      */
11212     clear : function(){
11213         this.elements = [];
11214     }
11215 };
11216 (function(){
11217     Roo.CompositeElement.createCall = function(proto, fnName){
11218         if(!proto[fnName]){
11219             proto[fnName] = function(){
11220                 return this.invoke(fnName, arguments);
11221             };
11222         }
11223     };
11224     for(var fnName in Roo.Element.prototype){
11225         if(typeof Roo.Element.prototype[fnName] == "function"){
11226             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11227         }
11228     };
11229 })();
11230 /*
11231  * Based on:
11232  * Ext JS Library 1.1.1
11233  * Copyright(c) 2006-2007, Ext JS, LLC.
11234  *
11235  * Originally Released Under LGPL - original licence link has changed is not relivant.
11236  *
11237  * Fork - LGPL
11238  * <script type="text/javascript">
11239  */
11240
11241 /**
11242  * @class Roo.CompositeElementLite
11243  * @extends Roo.CompositeElement
11244  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11245  <pre><code>
11246  var els = Roo.select("#some-el div.some-class");
11247  // or select directly from an existing element
11248  var el = Roo.get('some-el');
11249  el.select('div.some-class');
11250
11251  els.setWidth(100); // all elements become 100 width
11252  els.hide(true); // all elements fade out and hide
11253  // or
11254  els.setWidth(100).hide(true);
11255  </code></pre><br><br>
11256  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11257  * actions will be performed on all the elements in this collection.</b>
11258  */
11259 Roo.CompositeElementLite = function(els){
11260     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11261     this.el = new Roo.Element.Flyweight();
11262 };
11263 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11264     addElements : function(els){
11265         if(els){
11266             if(els instanceof Array){
11267                 this.elements = this.elements.concat(els);
11268             }else{
11269                 var yels = this.elements;
11270                 var index = yels.length-1;
11271                 for(var i = 0, len = els.length; i < len; i++) {
11272                     yels[++index] = els[i];
11273                 }
11274             }
11275         }
11276         return this;
11277     },
11278     invoke : function(fn, args){
11279         var els = this.elements;
11280         var el = this.el;
11281         for(var i = 0, len = els.length; i < len; i++) {
11282             el.dom = els[i];
11283                 Roo.Element.prototype[fn].apply(el, args);
11284         }
11285         return this;
11286     },
11287     /**
11288      * Returns a flyweight Element of the dom element object at the specified index
11289      * @param {Number} index
11290      * @return {Roo.Element}
11291      */
11292     item : function(index){
11293         if(!this.elements[index]){
11294             return null;
11295         }
11296         this.el.dom = this.elements[index];
11297         return this.el;
11298     },
11299
11300     // fixes scope with flyweight
11301     addListener : function(eventName, handler, scope, opt){
11302         var els = this.elements;
11303         for(var i = 0, len = els.length; i < len; i++) {
11304             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11305         }
11306         return this;
11307     },
11308
11309     /**
11310     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11311     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11312     * a reference to the dom node, use el.dom.</b>
11313     * @param {Function} fn The function to call
11314     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11315     * @return {CompositeElement} this
11316     */
11317     each : function(fn, scope){
11318         var els = this.elements;
11319         var el = this.el;
11320         for(var i = 0, len = els.length; i < len; i++){
11321             el.dom = els[i];
11322                 if(fn.call(scope || el, el, this, i) === false){
11323                 break;
11324             }
11325         }
11326         return this;
11327     },
11328
11329     indexOf : function(el){
11330         return this.elements.indexOf(Roo.getDom(el));
11331     },
11332
11333     replaceElement : function(el, replacement, domReplace){
11334         var index = typeof el == 'number' ? el : this.indexOf(el);
11335         if(index !== -1){
11336             replacement = Roo.getDom(replacement);
11337             if(domReplace){
11338                 var d = this.elements[index];
11339                 d.parentNode.insertBefore(replacement, d);
11340                 d.parentNode.removeChild(d);
11341             }
11342             this.elements.splice(index, 1, replacement);
11343         }
11344         return this;
11345     }
11346 });
11347 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11348
11349 /*
11350  * Based on:
11351  * Ext JS Library 1.1.1
11352  * Copyright(c) 2006-2007, Ext JS, LLC.
11353  *
11354  * Originally Released Under LGPL - original licence link has changed is not relivant.
11355  *
11356  * Fork - LGPL
11357  * <script type="text/javascript">
11358  */
11359
11360  
11361
11362 /**
11363  * @class Roo.data.Connection
11364  * @extends Roo.util.Observable
11365  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11366  * either to a configured URL, or to a URL specified at request time.<br><br>
11367  * <p>
11368  * Requests made by this class are asynchronous, and will return immediately. No data from
11369  * the server will be available to the statement immediately following the {@link #request} call.
11370  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11371  * <p>
11372  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11373  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11374  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11375  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11376  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11377  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11378  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11379  * standard DOM methods.
11380  * @constructor
11381  * @param {Object} config a configuration object.
11382  */
11383 Roo.data.Connection = function(config){
11384     Roo.apply(this, config);
11385     this.addEvents({
11386         /**
11387          * @event beforerequest
11388          * Fires before a network request is made to retrieve a data object.
11389          * @param {Connection} conn This Connection object.
11390          * @param {Object} options The options config object passed to the {@link #request} method.
11391          */
11392         "beforerequest" : true,
11393         /**
11394          * @event requestcomplete
11395          * Fires if the request was successfully completed.
11396          * @param {Connection} conn This Connection object.
11397          * @param {Object} response The XHR object containing the response data.
11398          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11399          * @param {Object} options The options config object passed to the {@link #request} method.
11400          */
11401         "requestcomplete" : true,
11402         /**
11403          * @event requestexception
11404          * Fires if an error HTTP status was returned from the server.
11405          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11406          * @param {Connection} conn This Connection object.
11407          * @param {Object} response The XHR object containing the response data.
11408          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11409          * @param {Object} options The options config object passed to the {@link #request} method.
11410          */
11411         "requestexception" : true
11412     });
11413     Roo.data.Connection.superclass.constructor.call(this);
11414 };
11415
11416 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11417     /**
11418      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11419      */
11420     /**
11421      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11422      * extra parameters to each request made by this object. (defaults to undefined)
11423      */
11424     /**
11425      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11426      *  to each request made by this object. (defaults to undefined)
11427      */
11428     /**
11429      * @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)
11430      */
11431     /**
11432      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11433      */
11434     timeout : 30000,
11435     /**
11436      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11437      * @type Boolean
11438      */
11439     autoAbort:false,
11440
11441     /**
11442      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11443      * @type Boolean
11444      */
11445     disableCaching: true,
11446
11447     /**
11448      * Sends an HTTP request to a remote server.
11449      * @param {Object} options An object which may contain the following properties:<ul>
11450      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11451      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11452      * request, a url encoded string or a function to call to get either.</li>
11453      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11454      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11455      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11456      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11457      * <li>options {Object} The parameter to the request call.</li>
11458      * <li>success {Boolean} True if the request succeeded.</li>
11459      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11460      * </ul></li>
11461      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11462      * The callback is passed the following parameters:<ul>
11463      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11464      * <li>options {Object} The parameter to the request call.</li>
11465      * </ul></li>
11466      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11467      * The callback is passed the following parameters:<ul>
11468      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11469      * <li>options {Object} The parameter to the request call.</li>
11470      * </ul></li>
11471      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11472      * for the callback function. Defaults to the browser window.</li>
11473      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11474      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11475      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11476      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11477      * params for the post data. Any params will be appended to the URL.</li>
11478      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11479      * </ul>
11480      * @return {Number} transactionId
11481      */
11482     request : function(o){
11483         if(this.fireEvent("beforerequest", this, o) !== false){
11484             var p = o.params;
11485
11486             if(typeof p == "function"){
11487                 p = p.call(o.scope||window, o);
11488             }
11489             if(typeof p == "object"){
11490                 p = Roo.urlEncode(o.params);
11491             }
11492             if(this.extraParams){
11493                 var extras = Roo.urlEncode(this.extraParams);
11494                 p = p ? (p + '&' + extras) : extras;
11495             }
11496
11497             var url = o.url || this.url;
11498             if(typeof url == 'function'){
11499                 url = url.call(o.scope||window, o);
11500             }
11501
11502             if(o.form){
11503                 var form = Roo.getDom(o.form);
11504                 url = url || form.action;
11505
11506                 var enctype = form.getAttribute("enctype");
11507                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11508                     return this.doFormUpload(o, p, url);
11509                 }
11510                 var f = Roo.lib.Ajax.serializeForm(form);
11511                 p = p ? (p + '&' + f) : f;
11512             }
11513
11514             var hs = o.headers;
11515             if(this.defaultHeaders){
11516                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11517                 if(!o.headers){
11518                     o.headers = hs;
11519                 }
11520             }
11521
11522             var cb = {
11523                 success: this.handleResponse,
11524                 failure: this.handleFailure,
11525                 scope: this,
11526                 argument: {options: o},
11527                 timeout : o.timeout || this.timeout
11528             };
11529
11530             var method = o.method||this.method||(p ? "POST" : "GET");
11531
11532             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11533                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11534             }
11535
11536             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11537                 if(o.autoAbort){
11538                     this.abort();
11539                 }
11540             }else if(this.autoAbort !== false){
11541                 this.abort();
11542             }
11543
11544             if((method == 'GET' && p) || o.xmlData){
11545                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11546                 p = '';
11547             }
11548             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11549             return this.transId;
11550         }else{
11551             Roo.callback(o.callback, o.scope, [o, null, null]);
11552             return null;
11553         }
11554     },
11555
11556     /**
11557      * Determine whether this object has a request outstanding.
11558      * @param {Number} transactionId (Optional) defaults to the last transaction
11559      * @return {Boolean} True if there is an outstanding request.
11560      */
11561     isLoading : function(transId){
11562         if(transId){
11563             return Roo.lib.Ajax.isCallInProgress(transId);
11564         }else{
11565             return this.transId ? true : false;
11566         }
11567     },
11568
11569     /**
11570      * Aborts any outstanding request.
11571      * @param {Number} transactionId (Optional) defaults to the last transaction
11572      */
11573     abort : function(transId){
11574         if(transId || this.isLoading()){
11575             Roo.lib.Ajax.abort(transId || this.transId);
11576         }
11577     },
11578
11579     // private
11580     handleResponse : function(response){
11581         this.transId = false;
11582         var options = response.argument.options;
11583         response.argument = options ? options.argument : null;
11584         this.fireEvent("requestcomplete", this, response, options);
11585         Roo.callback(options.success, options.scope, [response, options]);
11586         Roo.callback(options.callback, options.scope, [options, true, response]);
11587     },
11588
11589     // private
11590     handleFailure : function(response, e){
11591         this.transId = false;
11592         var options = response.argument.options;
11593         response.argument = options ? options.argument : null;
11594         this.fireEvent("requestexception", this, response, options, e);
11595         Roo.callback(options.failure, options.scope, [response, options]);
11596         Roo.callback(options.callback, options.scope, [options, false, response]);
11597     },
11598
11599     // private
11600     doFormUpload : function(o, ps, url){
11601         var id = Roo.id();
11602         var frame = document.createElement('iframe');
11603         frame.id = id;
11604         frame.name = id;
11605         frame.className = 'x-hidden';
11606         if(Roo.isIE){
11607             frame.src = Roo.SSL_SECURE_URL;
11608         }
11609         document.body.appendChild(frame);
11610
11611         if(Roo.isIE){
11612            document.frames[id].name = id;
11613         }
11614
11615         var form = Roo.getDom(o.form);
11616         form.target = id;
11617         form.method = 'POST';
11618         form.enctype = form.encoding = 'multipart/form-data';
11619         if(url){
11620             form.action = url;
11621         }
11622
11623         var hiddens, hd;
11624         if(ps){ // add dynamic params
11625             hiddens = [];
11626             ps = Roo.urlDecode(ps, false);
11627             for(var k in ps){
11628                 if(ps.hasOwnProperty(k)){
11629                     hd = document.createElement('input');
11630                     hd.type = 'hidden';
11631                     hd.name = k;
11632                     hd.value = ps[k];
11633                     form.appendChild(hd);
11634                     hiddens.push(hd);
11635                 }
11636             }
11637         }
11638
11639         function cb(){
11640             var r = {  // bogus response object
11641                 responseText : '',
11642                 responseXML : null
11643             };
11644
11645             r.argument = o ? o.argument : null;
11646
11647             try { //
11648                 var doc;
11649                 if(Roo.isIE){
11650                     doc = frame.contentWindow.document;
11651                 }else {
11652                     doc = (frame.contentDocument || window.frames[id].document);
11653                 }
11654                 if(doc && doc.body){
11655                     r.responseText = doc.body.innerHTML;
11656                 }
11657                 if(doc && doc.XMLDocument){
11658                     r.responseXML = doc.XMLDocument;
11659                 }else {
11660                     r.responseXML = doc;
11661                 }
11662             }
11663             catch(e) {
11664                 // ignore
11665             }
11666
11667             Roo.EventManager.removeListener(frame, 'load', cb, this);
11668
11669             this.fireEvent("requestcomplete", this, r, o);
11670             Roo.callback(o.success, o.scope, [r, o]);
11671             Roo.callback(o.callback, o.scope, [o, true, r]);
11672
11673             setTimeout(function(){document.body.removeChild(frame);}, 100);
11674         }
11675
11676         Roo.EventManager.on(frame, 'load', cb, this);
11677         form.submit();
11678
11679         if(hiddens){ // remove dynamic params
11680             for(var i = 0, len = hiddens.length; i < len; i++){
11681                 form.removeChild(hiddens[i]);
11682             }
11683         }
11684     }
11685 });
11686 /*
11687  * Based on:
11688  * Ext JS Library 1.1.1
11689  * Copyright(c) 2006-2007, Ext JS, LLC.
11690  *
11691  * Originally Released Under LGPL - original licence link has changed is not relivant.
11692  *
11693  * Fork - LGPL
11694  * <script type="text/javascript">
11695  */
11696  
11697 /**
11698  * Global Ajax request class.
11699  * 
11700  * @class Roo.Ajax
11701  * @extends Roo.data.Connection
11702  * @static
11703  * 
11704  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11705  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11706  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11707  * @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)
11708  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11709  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11710  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11711  */
11712 Roo.Ajax = new Roo.data.Connection({
11713     // fix up the docs
11714     /**
11715      * @scope Roo.Ajax
11716      * @type {Boolear} 
11717      */
11718     autoAbort : false,
11719
11720     /**
11721      * Serialize the passed form into a url encoded string
11722      * @scope Roo.Ajax
11723      * @param {String/HTMLElement} form
11724      * @return {String}
11725      */
11726     serializeForm : function(form){
11727         return Roo.lib.Ajax.serializeForm(form);
11728     }
11729 });/*
11730  * Based on:
11731  * Ext JS Library 1.1.1
11732  * Copyright(c) 2006-2007, Ext JS, LLC.
11733  *
11734  * Originally Released Under LGPL - original licence link has changed is not relivant.
11735  *
11736  * Fork - LGPL
11737  * <script type="text/javascript">
11738  */
11739
11740  
11741 /**
11742  * @class Roo.UpdateManager
11743  * @extends Roo.util.Observable
11744  * Provides AJAX-style update for Element object.<br><br>
11745  * Usage:<br>
11746  * <pre><code>
11747  * // Get it from a Roo.Element object
11748  * var el = Roo.get("foo");
11749  * var mgr = el.getUpdateManager();
11750  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11751  * ...
11752  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11753  * <br>
11754  * // or directly (returns the same UpdateManager instance)
11755  * var mgr = new Roo.UpdateManager("myElementId");
11756  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11757  * mgr.on("update", myFcnNeedsToKnow);
11758  * <br>
11759    // short handed call directly from the element object
11760    Roo.get("foo").load({
11761         url: "bar.php",
11762         scripts:true,
11763         params: "for=bar",
11764         text: "Loading Foo..."
11765    });
11766  * </code></pre>
11767  * @constructor
11768  * Create new UpdateManager directly.
11769  * @param {String/HTMLElement/Roo.Element} el The element to update
11770  * @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).
11771  */
11772 Roo.UpdateManager = function(el, forceNew){
11773     el = Roo.get(el);
11774     if(!forceNew && el.updateManager){
11775         return el.updateManager;
11776     }
11777     /**
11778      * The Element object
11779      * @type Roo.Element
11780      */
11781     this.el = el;
11782     /**
11783      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11784      * @type String
11785      */
11786     this.defaultUrl = null;
11787
11788     this.addEvents({
11789         /**
11790          * @event beforeupdate
11791          * Fired before an update is made, return false from your handler and the update is cancelled.
11792          * @param {Roo.Element} el
11793          * @param {String/Object/Function} url
11794          * @param {String/Object} params
11795          */
11796         "beforeupdate": true,
11797         /**
11798          * @event update
11799          * Fired after successful update is made.
11800          * @param {Roo.Element} el
11801          * @param {Object} oResponseObject The response Object
11802          */
11803         "update": true,
11804         /**
11805          * @event failure
11806          * Fired on update failure.
11807          * @param {Roo.Element} el
11808          * @param {Object} oResponseObject The response Object
11809          */
11810         "failure": true
11811     });
11812     var d = Roo.UpdateManager.defaults;
11813     /**
11814      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11815      * @type String
11816      */
11817     this.sslBlankUrl = d.sslBlankUrl;
11818     /**
11819      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11820      * @type Boolean
11821      */
11822     this.disableCaching = d.disableCaching;
11823     /**
11824      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11825      * @type String
11826      */
11827     this.indicatorText = d.indicatorText;
11828     /**
11829      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11830      * @type String
11831      */
11832     this.showLoadIndicator = d.showLoadIndicator;
11833     /**
11834      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11835      * @type Number
11836      */
11837     this.timeout = d.timeout;
11838
11839     /**
11840      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11841      * @type Boolean
11842      */
11843     this.loadScripts = d.loadScripts;
11844
11845     /**
11846      * Transaction object of current executing transaction
11847      */
11848     this.transaction = null;
11849
11850     /**
11851      * @private
11852      */
11853     this.autoRefreshProcId = null;
11854     /**
11855      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11856      * @type Function
11857      */
11858     this.refreshDelegate = this.refresh.createDelegate(this);
11859     /**
11860      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11861      * @type Function
11862      */
11863     this.updateDelegate = this.update.createDelegate(this);
11864     /**
11865      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11866      * @type Function
11867      */
11868     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11869     /**
11870      * @private
11871      */
11872     this.successDelegate = this.processSuccess.createDelegate(this);
11873     /**
11874      * @private
11875      */
11876     this.failureDelegate = this.processFailure.createDelegate(this);
11877
11878     if(!this.renderer){
11879      /**
11880       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11881       */
11882     this.renderer = new Roo.UpdateManager.BasicRenderer();
11883     }
11884     
11885     Roo.UpdateManager.superclass.constructor.call(this);
11886 };
11887
11888 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11889     /**
11890      * Get the Element this UpdateManager is bound to
11891      * @return {Roo.Element} The element
11892      */
11893     getEl : function(){
11894         return this.el;
11895     },
11896     /**
11897      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11898      * @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:
11899 <pre><code>
11900 um.update({<br/>
11901     url: "your-url.php",<br/>
11902     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11903     callback: yourFunction,<br/>
11904     scope: yourObject, //(optional scope)  <br/>
11905     discardUrl: false, <br/>
11906     nocache: false,<br/>
11907     text: "Loading...",<br/>
11908     timeout: 30,<br/>
11909     scripts: false<br/>
11910 });
11911 </code></pre>
11912      * The only required property is url. The optional properties nocache, text and scripts
11913      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11914      * @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}
11915      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11916      * @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.
11917      */
11918     update : function(url, params, callback, discardUrl){
11919         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11920             var method = this.method,
11921                 cfg;
11922             if(typeof url == "object"){ // must be config object
11923                 cfg = url;
11924                 url = cfg.url;
11925                 params = params || cfg.params;
11926                 callback = callback || cfg.callback;
11927                 discardUrl = discardUrl || cfg.discardUrl;
11928                 if(callback && cfg.scope){
11929                     callback = callback.createDelegate(cfg.scope);
11930                 }
11931                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11932                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11933                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11934                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11935                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11936             }
11937             this.showLoading();
11938             if(!discardUrl){
11939                 this.defaultUrl = url;
11940             }
11941             if(typeof url == "function"){
11942                 url = url.call(this);
11943             }
11944
11945             method = method || (params ? "POST" : "GET");
11946             if(method == "GET"){
11947                 url = this.prepareUrl(url);
11948             }
11949
11950             var o = Roo.apply(cfg ||{}, {
11951                 url : url,
11952                 params: params,
11953                 success: this.successDelegate,
11954                 failure: this.failureDelegate,
11955                 callback: undefined,
11956                 timeout: (this.timeout*1000),
11957                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11958             });
11959             Roo.log("updated manager called with timeout of " + o.timeout);
11960             this.transaction = Roo.Ajax.request(o);
11961         }
11962     },
11963
11964     /**
11965      * 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.
11966      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11967      * @param {String/HTMLElement} form The form Id or form element
11968      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11969      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11970      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11971      */
11972     formUpdate : function(form, url, reset, callback){
11973         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11974             if(typeof url == "function"){
11975                 url = url.call(this);
11976             }
11977             form = Roo.getDom(form);
11978             this.transaction = Roo.Ajax.request({
11979                 form: form,
11980                 url:url,
11981                 success: this.successDelegate,
11982                 failure: this.failureDelegate,
11983                 timeout: (this.timeout*1000),
11984                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11985             });
11986             this.showLoading.defer(1, this);
11987         }
11988     },
11989
11990     /**
11991      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11992      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11993      */
11994     refresh : function(callback){
11995         if(this.defaultUrl == null){
11996             return;
11997         }
11998         this.update(this.defaultUrl, null, callback, true);
11999     },
12000
12001     /**
12002      * Set this element to auto refresh.
12003      * @param {Number} interval How often to update (in seconds).
12004      * @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)
12005      * @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}
12006      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12007      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12008      */
12009     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12010         if(refreshNow){
12011             this.update(url || this.defaultUrl, params, callback, true);
12012         }
12013         if(this.autoRefreshProcId){
12014             clearInterval(this.autoRefreshProcId);
12015         }
12016         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12017     },
12018
12019     /**
12020      * Stop auto refresh on this element.
12021      */
12022      stopAutoRefresh : function(){
12023         if(this.autoRefreshProcId){
12024             clearInterval(this.autoRefreshProcId);
12025             delete this.autoRefreshProcId;
12026         }
12027     },
12028
12029     isAutoRefreshing : function(){
12030        return this.autoRefreshProcId ? true : false;
12031     },
12032     /**
12033      * Called to update the element to "Loading" state. Override to perform custom action.
12034      */
12035     showLoading : function(){
12036         if(this.showLoadIndicator){
12037             this.el.update(this.indicatorText);
12038         }
12039     },
12040
12041     /**
12042      * Adds unique parameter to query string if disableCaching = true
12043      * @private
12044      */
12045     prepareUrl : function(url){
12046         if(this.disableCaching){
12047             var append = "_dc=" + (new Date().getTime());
12048             if(url.indexOf("?") !== -1){
12049                 url += "&" + append;
12050             }else{
12051                 url += "?" + append;
12052             }
12053         }
12054         return url;
12055     },
12056
12057     /**
12058      * @private
12059      */
12060     processSuccess : function(response){
12061         this.transaction = null;
12062         if(response.argument.form && response.argument.reset){
12063             try{ // put in try/catch since some older FF releases had problems with this
12064                 response.argument.form.reset();
12065             }catch(e){}
12066         }
12067         if(this.loadScripts){
12068             this.renderer.render(this.el, response, this,
12069                 this.updateComplete.createDelegate(this, [response]));
12070         }else{
12071             this.renderer.render(this.el, response, this);
12072             this.updateComplete(response);
12073         }
12074     },
12075
12076     updateComplete : function(response){
12077         this.fireEvent("update", this.el, response);
12078         if(typeof response.argument.callback == "function"){
12079             response.argument.callback(this.el, true, response);
12080         }
12081     },
12082
12083     /**
12084      * @private
12085      */
12086     processFailure : function(response){
12087         this.transaction = null;
12088         this.fireEvent("failure", this.el, response);
12089         if(typeof response.argument.callback == "function"){
12090             response.argument.callback(this.el, false, response);
12091         }
12092     },
12093
12094     /**
12095      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12096      * @param {Object} renderer The object implementing the render() method
12097      */
12098     setRenderer : function(renderer){
12099         this.renderer = renderer;
12100     },
12101
12102     getRenderer : function(){
12103        return this.renderer;
12104     },
12105
12106     /**
12107      * Set the defaultUrl used for updates
12108      * @param {String/Function} defaultUrl The url or a function to call to get the url
12109      */
12110     setDefaultUrl : function(defaultUrl){
12111         this.defaultUrl = defaultUrl;
12112     },
12113
12114     /**
12115      * Aborts the executing transaction
12116      */
12117     abort : function(){
12118         if(this.transaction){
12119             Roo.Ajax.abort(this.transaction);
12120         }
12121     },
12122
12123     /**
12124      * Returns true if an update is in progress
12125      * @return {Boolean}
12126      */
12127     isUpdating : function(){
12128         if(this.transaction){
12129             return Roo.Ajax.isLoading(this.transaction);
12130         }
12131         return false;
12132     }
12133 });
12134
12135 /**
12136  * @class Roo.UpdateManager.defaults
12137  * @static (not really - but it helps the doc tool)
12138  * The defaults collection enables customizing the default properties of UpdateManager
12139  */
12140    Roo.UpdateManager.defaults = {
12141        /**
12142          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12143          * @type Number
12144          */
12145          timeout : 30,
12146
12147          /**
12148          * True to process scripts by default (Defaults to false).
12149          * @type Boolean
12150          */
12151         loadScripts : false,
12152
12153         /**
12154         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12155         * @type String
12156         */
12157         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12158         /**
12159          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12160          * @type Boolean
12161          */
12162         disableCaching : false,
12163         /**
12164          * Whether to show indicatorText when loading (Defaults to true).
12165          * @type Boolean
12166          */
12167         showLoadIndicator : true,
12168         /**
12169          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12170          * @type String
12171          */
12172         indicatorText : '<div class="loading-indicator">Loading...</div>'
12173    };
12174
12175 /**
12176  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12177  *Usage:
12178  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12179  * @param {String/HTMLElement/Roo.Element} el The element to update
12180  * @param {String} url The url
12181  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12182  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12183  * @static
12184  * @deprecated
12185  * @member Roo.UpdateManager
12186  */
12187 Roo.UpdateManager.updateElement = function(el, url, params, options){
12188     var um = Roo.get(el, true).getUpdateManager();
12189     Roo.apply(um, options);
12190     um.update(url, params, options ? options.callback : null);
12191 };
12192 // alias for backwards compat
12193 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12194 /**
12195  * @class Roo.UpdateManager.BasicRenderer
12196  * Default Content renderer. Updates the elements innerHTML with the responseText.
12197  */
12198 Roo.UpdateManager.BasicRenderer = function(){};
12199
12200 Roo.UpdateManager.BasicRenderer.prototype = {
12201     /**
12202      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12203      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12204      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12205      * @param {Roo.Element} el The element being rendered
12206      * @param {Object} response The YUI Connect response object
12207      * @param {UpdateManager} updateManager The calling update manager
12208      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12209      */
12210      render : function(el, response, updateManager, callback){
12211         el.update(response.responseText, updateManager.loadScripts, callback);
12212     }
12213 };
12214 /*
12215  * Based on:
12216  * Roo JS
12217  * (c)) Alan Knowles
12218  * Licence : LGPL
12219  */
12220
12221
12222 /**
12223  * @class Roo.DomTemplate
12224  * @extends Roo.Template
12225  * An effort at a dom based template engine..
12226  *
12227  * Similar to XTemplate, except it uses dom parsing to create the template..
12228  *
12229  * Supported features:
12230  *
12231  *  Tags:
12232
12233 <pre><code>
12234       {a_variable} - output encoded.
12235       {a_variable.format:("Y-m-d")} - call a method on the variable
12236       {a_variable:raw} - unencoded output
12237       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12238       {a_variable:this.method_on_template(...)} - call a method on the template object.
12239  
12240 </code></pre>
12241  *  The tpl tag:
12242 <pre><code>
12243         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12244         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12245         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12246         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12247   
12248 </code></pre>
12249  *      
12250  */
12251 Roo.DomTemplate = function()
12252 {
12253      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12254      if (this.html) {
12255         this.compile();
12256      }
12257 };
12258
12259
12260 Roo.extend(Roo.DomTemplate, Roo.Template, {
12261     /**
12262      * id counter for sub templates.
12263      */
12264     id : 0,
12265     /**
12266      * flag to indicate if dom parser is inside a pre,
12267      * it will strip whitespace if not.
12268      */
12269     inPre : false,
12270     
12271     /**
12272      * The various sub templates
12273      */
12274     tpls : false,
12275     
12276     
12277     
12278     /**
12279      *
12280      * basic tag replacing syntax
12281      * WORD:WORD()
12282      *
12283      * // you can fake an object call by doing this
12284      *  x.t:(test,tesT) 
12285      * 
12286      */
12287     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12288     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12289     
12290     iterChild : function (node, method) {
12291         
12292         var oldPre = this.inPre;
12293         if (node.tagName == 'PRE') {
12294             this.inPre = true;
12295         }
12296         for( var i = 0; i < node.childNodes.length; i++) {
12297             method.call(this, node.childNodes[i]);
12298         }
12299         this.inPre = oldPre;
12300     },
12301     
12302     
12303     
12304     /**
12305      * compile the template
12306      *
12307      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12308      *
12309      */
12310     compile: function()
12311     {
12312         var s = this.html;
12313         
12314         // covert the html into DOM...
12315         var doc = false;
12316         var div =false;
12317         try {
12318             doc = document.implementation.createHTMLDocument("");
12319             doc.documentElement.innerHTML =   this.html  ;
12320             div = doc.documentElement;
12321         } catch (e) {
12322             // old IE... - nasty -- it causes all sorts of issues.. with
12323             // images getting pulled from server..
12324             div = document.createElement('div');
12325             div.innerHTML = this.html;
12326         }
12327         //doc.documentElement.innerHTML = htmlBody
12328          
12329         
12330         
12331         this.tpls = [];
12332         var _t = this;
12333         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12334         
12335         var tpls = this.tpls;
12336         
12337         // create a top level template from the snippet..
12338         
12339         //Roo.log(div.innerHTML);
12340         
12341         var tpl = {
12342             uid : 'master',
12343             id : this.id++,
12344             attr : false,
12345             value : false,
12346             body : div.innerHTML,
12347             
12348             forCall : false,
12349             execCall : false,
12350             dom : div,
12351             isTop : true
12352             
12353         };
12354         tpls.unshift(tpl);
12355         
12356         
12357         // compile them...
12358         this.tpls = [];
12359         Roo.each(tpls, function(tp){
12360             this.compileTpl(tp);
12361             this.tpls[tp.id] = tp;
12362         }, this);
12363         
12364         this.master = tpls[0];
12365         return this;
12366         
12367         
12368     },
12369     
12370     compileNode : function(node, istop) {
12371         // test for
12372         //Roo.log(node);
12373         
12374         
12375         // skip anything not a tag..
12376         if (node.nodeType != 1) {
12377             if (node.nodeType == 3 && !this.inPre) {
12378                 // reduce white space..
12379                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12380                 
12381             }
12382             return;
12383         }
12384         
12385         var tpl = {
12386             uid : false,
12387             id : false,
12388             attr : false,
12389             value : false,
12390             body : '',
12391             
12392             forCall : false,
12393             execCall : false,
12394             dom : false,
12395             isTop : istop
12396             
12397             
12398         };
12399         
12400         
12401         switch(true) {
12402             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12403             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12404             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12405             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12406             // no default..
12407         }
12408         
12409         
12410         if (!tpl.attr) {
12411             // just itterate children..
12412             this.iterChild(node,this.compileNode);
12413             return;
12414         }
12415         tpl.uid = this.id++;
12416         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12417         node.removeAttribute('roo-'+ tpl.attr);
12418         if (tpl.attr != 'name') {
12419             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12420             node.parentNode.replaceChild(placeholder,  node);
12421         } else {
12422             
12423             var placeholder =  document.createElement('span');
12424             placeholder.className = 'roo-tpl-' + tpl.value;
12425             node.parentNode.replaceChild(placeholder,  node);
12426         }
12427         
12428         // parent now sees '{domtplXXXX}
12429         this.iterChild(node,this.compileNode);
12430         
12431         // we should now have node body...
12432         var div = document.createElement('div');
12433         div.appendChild(node);
12434         tpl.dom = node;
12435         // this has the unfortunate side effect of converting tagged attributes
12436         // eg. href="{...}" into %7C...%7D
12437         // this has been fixed by searching for those combo's although it's a bit hacky..
12438         
12439         
12440         tpl.body = div.innerHTML;
12441         
12442         
12443          
12444         tpl.id = tpl.uid;
12445         switch(tpl.attr) {
12446             case 'for' :
12447                 switch (tpl.value) {
12448                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12449                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12450                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12451                 }
12452                 break;
12453             
12454             case 'exec':
12455                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12456                 break;
12457             
12458             case 'if':     
12459                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12460                 break;
12461             
12462             case 'name':
12463                 tpl.id  = tpl.value; // replace non characters???
12464                 break;
12465             
12466         }
12467         
12468         
12469         this.tpls.push(tpl);
12470         
12471         
12472         
12473     },
12474     
12475     
12476     
12477     
12478     /**
12479      * Compile a segment of the template into a 'sub-template'
12480      *
12481      * 
12482      * 
12483      *
12484      */
12485     compileTpl : function(tpl)
12486     {
12487         var fm = Roo.util.Format;
12488         var useF = this.disableFormats !== true;
12489         
12490         var sep = Roo.isGecko ? "+\n" : ",\n";
12491         
12492         var undef = function(str) {
12493             Roo.debug && Roo.log("Property not found :"  + str);
12494             return '';
12495         };
12496           
12497         //Roo.log(tpl.body);
12498         
12499         
12500         
12501         var fn = function(m, lbrace, name, format, args)
12502         {
12503             //Roo.log("ARGS");
12504             //Roo.log(arguments);
12505             args = args ? args.replace(/\\'/g,"'") : args;
12506             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12507             if (typeof(format) == 'undefined') {
12508                 format =  'htmlEncode'; 
12509             }
12510             if (format == 'raw' ) {
12511                 format = false;
12512             }
12513             
12514             if(name.substr(0, 6) == 'domtpl'){
12515                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12516             }
12517             
12518             // build an array of options to determine if value is undefined..
12519             
12520             // basically get 'xxxx.yyyy' then do
12521             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12522             //    (function () { Roo.log("Property not found"); return ''; })() :
12523             //    ......
12524             
12525             var udef_ar = [];
12526             var lookfor = '';
12527             Roo.each(name.split('.'), function(st) {
12528                 lookfor += (lookfor.length ? '.': '') + st;
12529                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12530             });
12531             
12532             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12533             
12534             
12535             if(format && useF){
12536                 
12537                 args = args ? ',' + args : "";
12538                  
12539                 if(format.substr(0, 5) != "this."){
12540                     format = "fm." + format + '(';
12541                 }else{
12542                     format = 'this.call("'+ format.substr(5) + '", ';
12543                     args = ", values";
12544                 }
12545                 
12546                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12547             }
12548              
12549             if (args && args.length) {
12550                 // called with xxyx.yuu:(test,test)
12551                 // change to ()
12552                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12553             }
12554             // raw.. - :raw modifier..
12555             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12556             
12557         };
12558         var body;
12559         // branched to use + in gecko and [].join() in others
12560         if(Roo.isGecko){
12561             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12562                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12563                     "';};};";
12564         }else{
12565             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12566             body.push(tpl.body.replace(/(\r\n|\n)/g,
12567                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12568             body.push("'].join('');};};");
12569             body = body.join('');
12570         }
12571         
12572         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12573        
12574         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12575         eval(body);
12576         
12577         return this;
12578     },
12579      
12580     /**
12581      * same as applyTemplate, except it's done to one of the subTemplates
12582      * when using named templates, you can do:
12583      *
12584      * var str = pl.applySubTemplate('your-name', values);
12585      *
12586      * 
12587      * @param {Number} id of the template
12588      * @param {Object} values to apply to template
12589      * @param {Object} parent (normaly the instance of this object)
12590      */
12591     applySubTemplate : function(id, values, parent)
12592     {
12593         
12594         
12595         var t = this.tpls[id];
12596         
12597         
12598         try { 
12599             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12600                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12601                 return '';
12602             }
12603         } catch(e) {
12604             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12605             Roo.log(values);
12606           
12607             return '';
12608         }
12609         try { 
12610             
12611             if(t.execCall && t.execCall.call(this, values, parent)){
12612                 return '';
12613             }
12614         } catch(e) {
12615             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12616             Roo.log(values);
12617             return '';
12618         }
12619         
12620         try {
12621             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12622             parent = t.target ? values : parent;
12623             if(t.forCall && vs instanceof Array){
12624                 var buf = [];
12625                 for(var i = 0, len = vs.length; i < len; i++){
12626                     try {
12627                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12628                     } catch (e) {
12629                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12630                         Roo.log(e.body);
12631                         //Roo.log(t.compiled);
12632                         Roo.log(vs[i]);
12633                     }   
12634                 }
12635                 return buf.join('');
12636             }
12637         } catch (e) {
12638             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12639             Roo.log(values);
12640             return '';
12641         }
12642         try {
12643             return t.compiled.call(this, vs, parent);
12644         } catch (e) {
12645             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12646             Roo.log(e.body);
12647             //Roo.log(t.compiled);
12648             Roo.log(values);
12649             return '';
12650         }
12651     },
12652
12653    
12654
12655     applyTemplate : function(values){
12656         return this.master.compiled.call(this, values, {});
12657         //var s = this.subs;
12658     },
12659
12660     apply : function(){
12661         return this.applyTemplate.apply(this, arguments);
12662     }
12663
12664  });
12665
12666 Roo.DomTemplate.from = function(el){
12667     el = Roo.getDom(el);
12668     return new Roo.Domtemplate(el.value || el.innerHTML);
12669 };/*
12670  * Based on:
12671  * Ext JS Library 1.1.1
12672  * Copyright(c) 2006-2007, Ext JS, LLC.
12673  *
12674  * Originally Released Under LGPL - original licence link has changed is not relivant.
12675  *
12676  * Fork - LGPL
12677  * <script type="text/javascript">
12678  */
12679
12680 /**
12681  * @class Roo.util.DelayedTask
12682  * Provides a convenient method of performing setTimeout where a new
12683  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12684  * You can use this class to buffer
12685  * the keypress events for a certain number of milliseconds, and perform only if they stop
12686  * for that amount of time.
12687  * @constructor The parameters to this constructor serve as defaults and are not required.
12688  * @param {Function} fn (optional) The default function to timeout
12689  * @param {Object} scope (optional) The default scope of that timeout
12690  * @param {Array} args (optional) The default Array of arguments
12691  */
12692 Roo.util.DelayedTask = function(fn, scope, args){
12693     var id = null, d, t;
12694
12695     var call = function(){
12696         var now = new Date().getTime();
12697         if(now - t >= d){
12698             clearInterval(id);
12699             id = null;
12700             fn.apply(scope, args || []);
12701         }
12702     };
12703     /**
12704      * Cancels any pending timeout and queues a new one
12705      * @param {Number} delay The milliseconds to delay
12706      * @param {Function} newFn (optional) Overrides function passed to constructor
12707      * @param {Object} newScope (optional) Overrides scope passed to constructor
12708      * @param {Array} newArgs (optional) Overrides args passed to constructor
12709      */
12710     this.delay = function(delay, newFn, newScope, newArgs){
12711         if(id && delay != d){
12712             this.cancel();
12713         }
12714         d = delay;
12715         t = new Date().getTime();
12716         fn = newFn || fn;
12717         scope = newScope || scope;
12718         args = newArgs || args;
12719         if(!id){
12720             id = setInterval(call, d);
12721         }
12722     };
12723
12724     /**
12725      * Cancel the last queued timeout
12726      */
12727     this.cancel = function(){
12728         if(id){
12729             clearInterval(id);
12730             id = null;
12731         }
12732     };
12733 };/*
12734  * Based on:
12735  * Ext JS Library 1.1.1
12736  * Copyright(c) 2006-2007, Ext JS, LLC.
12737  *
12738  * Originally Released Under LGPL - original licence link has changed is not relivant.
12739  *
12740  * Fork - LGPL
12741  * <script type="text/javascript">
12742  */
12743  
12744  
12745 Roo.util.TaskRunner = function(interval){
12746     interval = interval || 10;
12747     var tasks = [], removeQueue = [];
12748     var id = 0;
12749     var running = false;
12750
12751     var stopThread = function(){
12752         running = false;
12753         clearInterval(id);
12754         id = 0;
12755     };
12756
12757     var startThread = function(){
12758         if(!running){
12759             running = true;
12760             id = setInterval(runTasks, interval);
12761         }
12762     };
12763
12764     var removeTask = function(task){
12765         removeQueue.push(task);
12766         if(task.onStop){
12767             task.onStop();
12768         }
12769     };
12770
12771     var runTasks = function(){
12772         if(removeQueue.length > 0){
12773             for(var i = 0, len = removeQueue.length; i < len; i++){
12774                 tasks.remove(removeQueue[i]);
12775             }
12776             removeQueue = [];
12777             if(tasks.length < 1){
12778                 stopThread();
12779                 return;
12780             }
12781         }
12782         var now = new Date().getTime();
12783         for(var i = 0, len = tasks.length; i < len; ++i){
12784             var t = tasks[i];
12785             var itime = now - t.taskRunTime;
12786             if(t.interval <= itime){
12787                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12788                 t.taskRunTime = now;
12789                 if(rt === false || t.taskRunCount === t.repeat){
12790                     removeTask(t);
12791                     return;
12792                 }
12793             }
12794             if(t.duration && t.duration <= (now - t.taskStartTime)){
12795                 removeTask(t);
12796             }
12797         }
12798     };
12799
12800     /**
12801      * Queues a new task.
12802      * @param {Object} task
12803      */
12804     this.start = function(task){
12805         tasks.push(task);
12806         task.taskStartTime = new Date().getTime();
12807         task.taskRunTime = 0;
12808         task.taskRunCount = 0;
12809         startThread();
12810         return task;
12811     };
12812
12813     this.stop = function(task){
12814         removeTask(task);
12815         return task;
12816     };
12817
12818     this.stopAll = function(){
12819         stopThread();
12820         for(var i = 0, len = tasks.length; i < len; i++){
12821             if(tasks[i].onStop){
12822                 tasks[i].onStop();
12823             }
12824         }
12825         tasks = [];
12826         removeQueue = [];
12827     };
12828 };
12829
12830 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12831  * Based on:
12832  * Ext JS Library 1.1.1
12833  * Copyright(c) 2006-2007, Ext JS, LLC.
12834  *
12835  * Originally Released Under LGPL - original licence link has changed is not relivant.
12836  *
12837  * Fork - LGPL
12838  * <script type="text/javascript">
12839  */
12840
12841  
12842 /**
12843  * @class Roo.util.MixedCollection
12844  * @extends Roo.util.Observable
12845  * A Collection class that maintains both numeric indexes and keys and exposes events.
12846  * @constructor
12847  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12848  * collection (defaults to false)
12849  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12850  * and return the key value for that item.  This is used when available to look up the key on items that
12851  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12852  * equivalent to providing an implementation for the {@link #getKey} method.
12853  */
12854 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12855     this.items = [];
12856     this.map = {};
12857     this.keys = [];
12858     this.length = 0;
12859     this.addEvents({
12860         /**
12861          * @event clear
12862          * Fires when the collection is cleared.
12863          */
12864         "clear" : true,
12865         /**
12866          * @event add
12867          * Fires when an item is added to the collection.
12868          * @param {Number} index The index at which the item was added.
12869          * @param {Object} o The item added.
12870          * @param {String} key The key associated with the added item.
12871          */
12872         "add" : true,
12873         /**
12874          * @event replace
12875          * Fires when an item is replaced in the collection.
12876          * @param {String} key he key associated with the new added.
12877          * @param {Object} old The item being replaced.
12878          * @param {Object} new The new item.
12879          */
12880         "replace" : true,
12881         /**
12882          * @event remove
12883          * Fires when an item is removed from the collection.
12884          * @param {Object} o The item being removed.
12885          * @param {String} key (optional) The key associated with the removed item.
12886          */
12887         "remove" : true,
12888         "sort" : true
12889     });
12890     this.allowFunctions = allowFunctions === true;
12891     if(keyFn){
12892         this.getKey = keyFn;
12893     }
12894     Roo.util.MixedCollection.superclass.constructor.call(this);
12895 };
12896
12897 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12898     allowFunctions : false,
12899     
12900 /**
12901  * Adds an item to the collection.
12902  * @param {String} key The key to associate with the item
12903  * @param {Object} o The item to add.
12904  * @return {Object} The item added.
12905  */
12906     add : function(key, o){
12907         if(arguments.length == 1){
12908             o = arguments[0];
12909             key = this.getKey(o);
12910         }
12911         if(typeof key == "undefined" || key === null){
12912             this.length++;
12913             this.items.push(o);
12914             this.keys.push(null);
12915         }else{
12916             var old = this.map[key];
12917             if(old){
12918                 return this.replace(key, o);
12919             }
12920             this.length++;
12921             this.items.push(o);
12922             this.map[key] = o;
12923             this.keys.push(key);
12924         }
12925         this.fireEvent("add", this.length-1, o, key);
12926         return o;
12927     },
12928        
12929 /**
12930   * MixedCollection has a generic way to fetch keys if you implement getKey.
12931 <pre><code>
12932 // normal way
12933 var mc = new Roo.util.MixedCollection();
12934 mc.add(someEl.dom.id, someEl);
12935 mc.add(otherEl.dom.id, otherEl);
12936 //and so on
12937
12938 // using getKey
12939 var mc = new Roo.util.MixedCollection();
12940 mc.getKey = function(el){
12941    return el.dom.id;
12942 };
12943 mc.add(someEl);
12944 mc.add(otherEl);
12945
12946 // or via the constructor
12947 var mc = new Roo.util.MixedCollection(false, function(el){
12948    return el.dom.id;
12949 });
12950 mc.add(someEl);
12951 mc.add(otherEl);
12952 </code></pre>
12953  * @param o {Object} The item for which to find the key.
12954  * @return {Object} The key for the passed item.
12955  */
12956     getKey : function(o){
12957          return o.id; 
12958     },
12959    
12960 /**
12961  * Replaces an item in the collection.
12962  * @param {String} key The key associated with the item to replace, or the item to replace.
12963  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12964  * @return {Object}  The new item.
12965  */
12966     replace : function(key, o){
12967         if(arguments.length == 1){
12968             o = arguments[0];
12969             key = this.getKey(o);
12970         }
12971         var old = this.item(key);
12972         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12973              return this.add(key, o);
12974         }
12975         var index = this.indexOfKey(key);
12976         this.items[index] = o;
12977         this.map[key] = o;
12978         this.fireEvent("replace", key, old, o);
12979         return o;
12980     },
12981    
12982 /**
12983  * Adds all elements of an Array or an Object to the collection.
12984  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12985  * an Array of values, each of which are added to the collection.
12986  */
12987     addAll : function(objs){
12988         if(arguments.length > 1 || objs instanceof Array){
12989             var args = arguments.length > 1 ? arguments : objs;
12990             for(var i = 0, len = args.length; i < len; i++){
12991                 this.add(args[i]);
12992             }
12993         }else{
12994             for(var key in objs){
12995                 if(this.allowFunctions || typeof objs[key] != "function"){
12996                     this.add(key, objs[key]);
12997                 }
12998             }
12999         }
13000     },
13001    
13002 /**
13003  * Executes the specified function once for every item in the collection, passing each
13004  * item as the first and only parameter. returning false from the function will stop the iteration.
13005  * @param {Function} fn The function to execute for each item.
13006  * @param {Object} scope (optional) The scope in which to execute the function.
13007  */
13008     each : function(fn, scope){
13009         var items = [].concat(this.items); // each safe for removal
13010         for(var i = 0, len = items.length; i < len; i++){
13011             if(fn.call(scope || items[i], items[i], i, len) === false){
13012                 break;
13013             }
13014         }
13015     },
13016    
13017 /**
13018  * Executes the specified function once for every key in the collection, passing each
13019  * key, and its associated item as the first two parameters.
13020  * @param {Function} fn The function to execute for each item.
13021  * @param {Object} scope (optional) The scope in which to execute the function.
13022  */
13023     eachKey : function(fn, scope){
13024         for(var i = 0, len = this.keys.length; i < len; i++){
13025             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13026         }
13027     },
13028    
13029 /**
13030  * Returns the first item in the collection which elicits a true return value from the
13031  * passed selection function.
13032  * @param {Function} fn The selection function to execute for each item.
13033  * @param {Object} scope (optional) The scope in which to execute the function.
13034  * @return {Object} The first item in the collection which returned true from the selection function.
13035  */
13036     find : function(fn, scope){
13037         for(var i = 0, len = this.items.length; i < len; i++){
13038             if(fn.call(scope || window, this.items[i], this.keys[i])){
13039                 return this.items[i];
13040             }
13041         }
13042         return null;
13043     },
13044    
13045 /**
13046  * Inserts an item at the specified index in the collection.
13047  * @param {Number} index The index to insert the item at.
13048  * @param {String} key The key to associate with the new item, or the item itself.
13049  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13050  * @return {Object} The item inserted.
13051  */
13052     insert : function(index, key, o){
13053         if(arguments.length == 2){
13054             o = arguments[1];
13055             key = this.getKey(o);
13056         }
13057         if(index >= this.length){
13058             return this.add(key, o);
13059         }
13060         this.length++;
13061         this.items.splice(index, 0, o);
13062         if(typeof key != "undefined" && key != null){
13063             this.map[key] = o;
13064         }
13065         this.keys.splice(index, 0, key);
13066         this.fireEvent("add", index, o, key);
13067         return o;
13068     },
13069    
13070 /**
13071  * Removed an item from the collection.
13072  * @param {Object} o The item to remove.
13073  * @return {Object} The item removed.
13074  */
13075     remove : function(o){
13076         return this.removeAt(this.indexOf(o));
13077     },
13078    
13079 /**
13080  * Remove an item from a specified index in the collection.
13081  * @param {Number} index The index within the collection of the item to remove.
13082  */
13083     removeAt : function(index){
13084         if(index < this.length && index >= 0){
13085             this.length--;
13086             var o = this.items[index];
13087             this.items.splice(index, 1);
13088             var key = this.keys[index];
13089             if(typeof key != "undefined"){
13090                 delete this.map[key];
13091             }
13092             this.keys.splice(index, 1);
13093             this.fireEvent("remove", o, key);
13094         }
13095     },
13096    
13097 /**
13098  * Removed an item associated with the passed key fom the collection.
13099  * @param {String} key The key of the item to remove.
13100  */
13101     removeKey : function(key){
13102         return this.removeAt(this.indexOfKey(key));
13103     },
13104    
13105 /**
13106  * Returns the number of items in the collection.
13107  * @return {Number} the number of items in the collection.
13108  */
13109     getCount : function(){
13110         return this.length; 
13111     },
13112    
13113 /**
13114  * Returns index within the collection of the passed Object.
13115  * @param {Object} o The item to find the index of.
13116  * @return {Number} index of the item.
13117  */
13118     indexOf : function(o){
13119         if(!this.items.indexOf){
13120             for(var i = 0, len = this.items.length; i < len; i++){
13121                 if(this.items[i] == o) return i;
13122             }
13123             return -1;
13124         }else{
13125             return this.items.indexOf(o);
13126         }
13127     },
13128    
13129 /**
13130  * Returns index within the collection of the passed key.
13131  * @param {String} key The key to find the index of.
13132  * @return {Number} index of the key.
13133  */
13134     indexOfKey : function(key){
13135         if(!this.keys.indexOf){
13136             for(var i = 0, len = this.keys.length; i < len; i++){
13137                 if(this.keys[i] == key) return i;
13138             }
13139             return -1;
13140         }else{
13141             return this.keys.indexOf(key);
13142         }
13143     },
13144    
13145 /**
13146  * Returns the item associated with the passed key OR index. Key has priority over index.
13147  * @param {String/Number} key The key or index of the item.
13148  * @return {Object} The item associated with the passed key.
13149  */
13150     item : function(key){
13151         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13152         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13153     },
13154     
13155 /**
13156  * Returns the item at the specified index.
13157  * @param {Number} index The index of the item.
13158  * @return {Object}
13159  */
13160     itemAt : function(index){
13161         return this.items[index];
13162     },
13163     
13164 /**
13165  * Returns the item associated with the passed key.
13166  * @param {String/Number} key The key of the item.
13167  * @return {Object} The item associated with the passed key.
13168  */
13169     key : function(key){
13170         return this.map[key];
13171     },
13172    
13173 /**
13174  * Returns true if the collection contains the passed Object as an item.
13175  * @param {Object} o  The Object to look for in the collection.
13176  * @return {Boolean} True if the collection contains the Object as an item.
13177  */
13178     contains : function(o){
13179         return this.indexOf(o) != -1;
13180     },
13181    
13182 /**
13183  * Returns true if the collection contains the passed Object as a key.
13184  * @param {String} key The key to look for in the collection.
13185  * @return {Boolean} True if the collection contains the Object as a key.
13186  */
13187     containsKey : function(key){
13188         return typeof this.map[key] != "undefined";
13189     },
13190    
13191 /**
13192  * Removes all items from the collection.
13193  */
13194     clear : function(){
13195         this.length = 0;
13196         this.items = [];
13197         this.keys = [];
13198         this.map = {};
13199         this.fireEvent("clear");
13200     },
13201    
13202 /**
13203  * Returns the first item in the collection.
13204  * @return {Object} the first item in the collection..
13205  */
13206     first : function(){
13207         return this.items[0]; 
13208     },
13209    
13210 /**
13211  * Returns the last item in the collection.
13212  * @return {Object} the last item in the collection..
13213  */
13214     last : function(){
13215         return this.items[this.length-1];   
13216     },
13217     
13218     _sort : function(property, dir, fn){
13219         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13220         fn = fn || function(a, b){
13221             return a-b;
13222         };
13223         var c = [], k = this.keys, items = this.items;
13224         for(var i = 0, len = items.length; i < len; i++){
13225             c[c.length] = {key: k[i], value: items[i], index: i};
13226         }
13227         c.sort(function(a, b){
13228             var v = fn(a[property], b[property]) * dsc;
13229             if(v == 0){
13230                 v = (a.index < b.index ? -1 : 1);
13231             }
13232             return v;
13233         });
13234         for(var i = 0, len = c.length; i < len; i++){
13235             items[i] = c[i].value;
13236             k[i] = c[i].key;
13237         }
13238         this.fireEvent("sort", this);
13239     },
13240     
13241     /**
13242      * Sorts this collection with the passed comparison function
13243      * @param {String} direction (optional) "ASC" or "DESC"
13244      * @param {Function} fn (optional) comparison function
13245      */
13246     sort : function(dir, fn){
13247         this._sort("value", dir, fn);
13248     },
13249     
13250     /**
13251      * Sorts this collection by keys
13252      * @param {String} direction (optional) "ASC" or "DESC"
13253      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13254      */
13255     keySort : function(dir, fn){
13256         this._sort("key", dir, fn || function(a, b){
13257             return String(a).toUpperCase()-String(b).toUpperCase();
13258         });
13259     },
13260     
13261     /**
13262      * Returns a range of items in this collection
13263      * @param {Number} startIndex (optional) defaults to 0
13264      * @param {Number} endIndex (optional) default to the last item
13265      * @return {Array} An array of items
13266      */
13267     getRange : function(start, end){
13268         var items = this.items;
13269         if(items.length < 1){
13270             return [];
13271         }
13272         start = start || 0;
13273         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13274         var r = [];
13275         if(start <= end){
13276             for(var i = start; i <= end; i++) {
13277                     r[r.length] = items[i];
13278             }
13279         }else{
13280             for(var i = start; i >= end; i--) {
13281                     r[r.length] = items[i];
13282             }
13283         }
13284         return r;
13285     },
13286         
13287     /**
13288      * Filter the <i>objects</i> in this collection by a specific property. 
13289      * Returns a new collection that has been filtered.
13290      * @param {String} property A property on your objects
13291      * @param {String/RegExp} value Either string that the property values 
13292      * should start with or a RegExp to test against the property
13293      * @return {MixedCollection} The new filtered collection
13294      */
13295     filter : function(property, value){
13296         if(!value.exec){ // not a regex
13297             value = String(value);
13298             if(value.length == 0){
13299                 return this.clone();
13300             }
13301             value = new RegExp("^" + Roo.escapeRe(value), "i");
13302         }
13303         return this.filterBy(function(o){
13304             return o && value.test(o[property]);
13305         });
13306         },
13307     
13308     /**
13309      * Filter by a function. * Returns a new collection that has been filtered.
13310      * The passed function will be called with each 
13311      * object in the collection. If the function returns true, the value is included 
13312      * otherwise it is filtered.
13313      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13314      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13315      * @return {MixedCollection} The new filtered collection
13316      */
13317     filterBy : function(fn, scope){
13318         var r = new Roo.util.MixedCollection();
13319         r.getKey = this.getKey;
13320         var k = this.keys, it = this.items;
13321         for(var i = 0, len = it.length; i < len; i++){
13322             if(fn.call(scope||this, it[i], k[i])){
13323                                 r.add(k[i], it[i]);
13324                         }
13325         }
13326         return r;
13327     },
13328     
13329     /**
13330      * Creates a duplicate of this collection
13331      * @return {MixedCollection}
13332      */
13333     clone : function(){
13334         var r = new Roo.util.MixedCollection();
13335         var k = this.keys, it = this.items;
13336         for(var i = 0, len = it.length; i < len; i++){
13337             r.add(k[i], it[i]);
13338         }
13339         r.getKey = this.getKey;
13340         return r;
13341     }
13342 });
13343 /**
13344  * Returns the item associated with the passed key or index.
13345  * @method
13346  * @param {String/Number} key The key or index of the item.
13347  * @return {Object} The item associated with the passed key.
13348  */
13349 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13350  * Based on:
13351  * Ext JS Library 1.1.1
13352  * Copyright(c) 2006-2007, Ext JS, LLC.
13353  *
13354  * Originally Released Under LGPL - original licence link has changed is not relivant.
13355  *
13356  * Fork - LGPL
13357  * <script type="text/javascript">
13358  */
13359 /**
13360  * @class Roo.util.JSON
13361  * Modified version of Douglas Crockford"s json.js that doesn"t
13362  * mess with the Object prototype 
13363  * http://www.json.org/js.html
13364  * @singleton
13365  */
13366 Roo.util.JSON = new (function(){
13367     var useHasOwn = {}.hasOwnProperty ? true : false;
13368     
13369     // crashes Safari in some instances
13370     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13371     
13372     var pad = function(n) {
13373         return n < 10 ? "0" + n : n;
13374     };
13375     
13376     var m = {
13377         "\b": '\\b',
13378         "\t": '\\t',
13379         "\n": '\\n',
13380         "\f": '\\f',
13381         "\r": '\\r',
13382         '"' : '\\"',
13383         "\\": '\\\\'
13384     };
13385
13386     var encodeString = function(s){
13387         if (/["\\\x00-\x1f]/.test(s)) {
13388             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13389                 var c = m[b];
13390                 if(c){
13391                     return c;
13392                 }
13393                 c = b.charCodeAt();
13394                 return "\\u00" +
13395                     Math.floor(c / 16).toString(16) +
13396                     (c % 16).toString(16);
13397             }) + '"';
13398         }
13399         return '"' + s + '"';
13400     };
13401     
13402     var encodeArray = function(o){
13403         var a = ["["], b, i, l = o.length, v;
13404             for (i = 0; i < l; i += 1) {
13405                 v = o[i];
13406                 switch (typeof v) {
13407                     case "undefined":
13408                     case "function":
13409                     case "unknown":
13410                         break;
13411                     default:
13412                         if (b) {
13413                             a.push(',');
13414                         }
13415                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13416                         b = true;
13417                 }
13418             }
13419             a.push("]");
13420             return a.join("");
13421     };
13422     
13423     var encodeDate = function(o){
13424         return '"' + o.getFullYear() + "-" +
13425                 pad(o.getMonth() + 1) + "-" +
13426                 pad(o.getDate()) + "T" +
13427                 pad(o.getHours()) + ":" +
13428                 pad(o.getMinutes()) + ":" +
13429                 pad(o.getSeconds()) + '"';
13430     };
13431     
13432     /**
13433      * Encodes an Object, Array or other value
13434      * @param {Mixed} o The variable to encode
13435      * @return {String} The JSON string
13436      */
13437     this.encode = function(o)
13438     {
13439         // should this be extended to fully wrap stringify..
13440         
13441         if(typeof o == "undefined" || o === null){
13442             return "null";
13443         }else if(o instanceof Array){
13444             return encodeArray(o);
13445         }else if(o instanceof Date){
13446             return encodeDate(o);
13447         }else if(typeof o == "string"){
13448             return encodeString(o);
13449         }else if(typeof o == "number"){
13450             return isFinite(o) ? String(o) : "null";
13451         }else if(typeof o == "boolean"){
13452             return String(o);
13453         }else {
13454             var a = ["{"], b, i, v;
13455             for (i in o) {
13456                 if(!useHasOwn || o.hasOwnProperty(i)) {
13457                     v = o[i];
13458                     switch (typeof v) {
13459                     case "undefined":
13460                     case "function":
13461                     case "unknown":
13462                         break;
13463                     default:
13464                         if(b){
13465                             a.push(',');
13466                         }
13467                         a.push(this.encode(i), ":",
13468                                 v === null ? "null" : this.encode(v));
13469                         b = true;
13470                     }
13471                 }
13472             }
13473             a.push("}");
13474             return a.join("");
13475         }
13476     };
13477     
13478     /**
13479      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13480      * @param {String} json The JSON string
13481      * @return {Object} The resulting object
13482      */
13483     this.decode = function(json){
13484         
13485         return  /** eval:var:json */ eval("(" + json + ')');
13486     };
13487 })();
13488 /** 
13489  * Shorthand for {@link Roo.util.JSON#encode}
13490  * @member Roo encode 
13491  * @method */
13492 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13493 /** 
13494  * Shorthand for {@link Roo.util.JSON#decode}
13495  * @member Roo decode 
13496  * @method */
13497 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13498 /*
13499  * Based on:
13500  * Ext JS Library 1.1.1
13501  * Copyright(c) 2006-2007, Ext JS, LLC.
13502  *
13503  * Originally Released Under LGPL - original licence link has changed is not relivant.
13504  *
13505  * Fork - LGPL
13506  * <script type="text/javascript">
13507  */
13508  
13509 /**
13510  * @class Roo.util.Format
13511  * Reusable data formatting functions
13512  * @singleton
13513  */
13514 Roo.util.Format = function(){
13515     var trimRe = /^\s+|\s+$/g;
13516     return {
13517         /**
13518          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13519          * @param {String} value The string to truncate
13520          * @param {Number} length The maximum length to allow before truncating
13521          * @return {String} The converted text
13522          */
13523         ellipsis : function(value, len){
13524             if(value && value.length > len){
13525                 return value.substr(0, len-3)+"...";
13526             }
13527             return value;
13528         },
13529
13530         /**
13531          * Checks a reference and converts it to empty string if it is undefined
13532          * @param {Mixed} value Reference to check
13533          * @return {Mixed} Empty string if converted, otherwise the original value
13534          */
13535         undef : function(value){
13536             return typeof value != "undefined" ? value : "";
13537         },
13538
13539         /**
13540          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13541          * @param {String} value The string to encode
13542          * @return {String} The encoded text
13543          */
13544         htmlEncode : function(value){
13545             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13546         },
13547
13548         /**
13549          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13550          * @param {String} value The string to decode
13551          * @return {String} The decoded text
13552          */
13553         htmlDecode : function(value){
13554             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13555         },
13556
13557         /**
13558          * Trims any whitespace from either side of a string
13559          * @param {String} value The text to trim
13560          * @return {String} The trimmed text
13561          */
13562         trim : function(value){
13563             return String(value).replace(trimRe, "");
13564         },
13565
13566         /**
13567          * Returns a substring from within an original string
13568          * @param {String} value The original text
13569          * @param {Number} start The start index of the substring
13570          * @param {Number} length The length of the substring
13571          * @return {String} The substring
13572          */
13573         substr : function(value, start, length){
13574             return String(value).substr(start, length);
13575         },
13576
13577         /**
13578          * Converts a string to all lower case letters
13579          * @param {String} value The text to convert
13580          * @return {String} The converted text
13581          */
13582         lowercase : function(value){
13583             return String(value).toLowerCase();
13584         },
13585
13586         /**
13587          * Converts a string to all upper case letters
13588          * @param {String} value The text to convert
13589          * @return {String} The converted text
13590          */
13591         uppercase : function(value){
13592             return String(value).toUpperCase();
13593         },
13594
13595         /**
13596          * Converts the first character only of a string to upper case
13597          * @param {String} value The text to convert
13598          * @return {String} The converted text
13599          */
13600         capitalize : function(value){
13601             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13602         },
13603
13604         // private
13605         call : function(value, fn){
13606             if(arguments.length > 2){
13607                 var args = Array.prototype.slice.call(arguments, 2);
13608                 args.unshift(value);
13609                  
13610                 return /** eval:var:value */  eval(fn).apply(window, args);
13611             }else{
13612                 /** eval:var:value */
13613                 return /** eval:var:value */ eval(fn).call(window, value);
13614             }
13615         },
13616
13617        
13618         /**
13619          * safer version of Math.toFixed..??/
13620          * @param {Number/String} value The numeric value to format
13621          * @param {Number/String} value Decimal places 
13622          * @return {String} The formatted currency string
13623          */
13624         toFixed : function(v, n)
13625         {
13626             // why not use to fixed - precision is buggered???
13627             if (!n) {
13628                 return Math.round(v-0);
13629             }
13630             var fact = Math.pow(10,n+1);
13631             v = (Math.round((v-0)*fact))/fact;
13632             var z = (''+fact).substring(2);
13633             if (v == Math.floor(v)) {
13634                 return Math.floor(v) + '.' + z;
13635             }
13636             
13637             // now just padd decimals..
13638             var ps = String(v).split('.');
13639             var fd = (ps[1] + z);
13640             var r = fd.substring(0,n); 
13641             var rm = fd.substring(n); 
13642             if (rm < 5) {
13643                 return ps[0] + '.' + r;
13644             }
13645             r*=1; // turn it into a number;
13646             r++;
13647             if (String(r).length != n) {
13648                 ps[0]*=1;
13649                 ps[0]++;
13650                 r = String(r).substring(1); // chop the end off.
13651             }
13652             
13653             return ps[0] + '.' + r;
13654              
13655         },
13656         
13657         /**
13658          * Format a number as US currency
13659          * @param {Number/String} value The numeric value to format
13660          * @return {String} The formatted currency string
13661          */
13662         usMoney : function(v){
13663             return '$' + Roo.util.Format.number(v);
13664         },
13665         
13666         /**
13667          * Format a number
13668          * eventually this should probably emulate php's number_format
13669          * @param {Number/String} value The numeric value to format
13670          * @param {Number} decimals number of decimal places
13671          * @return {String} The formatted currency string
13672          */
13673         number : function(v,decimals)
13674         {
13675             // multiply and round.
13676             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13677             var mul = Math.pow(10, decimals);
13678             var zero = String(mul).substring(1);
13679             v = (Math.round((v-0)*mul))/mul;
13680             
13681             // if it's '0' number.. then
13682             
13683             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13684             v = String(v);
13685             var ps = v.split('.');
13686             var whole = ps[0];
13687             
13688             
13689             var r = /(\d+)(\d{3})/;
13690             // add comma's
13691             while (r.test(whole)) {
13692                 whole = whole.replace(r, '$1' + ',' + '$2');
13693             }
13694             
13695             
13696             var sub = ps[1] ?
13697                     // has decimals..
13698                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13699                     // does not have decimals
13700                     (decimals ? ('.' + zero) : '');
13701             
13702             
13703             return whole + sub ;
13704         },
13705         
13706         /**
13707          * Parse a value into a formatted date using the specified format pattern.
13708          * @param {Mixed} value The value to format
13709          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13710          * @return {String} The formatted date string
13711          */
13712         date : function(v, format){
13713             if(!v){
13714                 return "";
13715             }
13716             if(!(v instanceof Date)){
13717                 v = new Date(Date.parse(v));
13718             }
13719             return v.dateFormat(format || "m/d/Y");
13720         },
13721
13722         /**
13723          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13724          * @param {String} format Any valid date format string
13725          * @return {Function} The date formatting function
13726          */
13727         dateRenderer : function(format){
13728             return function(v){
13729                 return Roo.util.Format.date(v, format);  
13730             };
13731         },
13732
13733         // private
13734         stripTagsRE : /<\/?[^>]+>/gi,
13735         
13736         /**
13737          * Strips all HTML tags
13738          * @param {Mixed} value The text from which to strip tags
13739          * @return {String} The stripped text
13740          */
13741         stripTags : function(v){
13742             return !v ? v : String(v).replace(this.stripTagsRE, "");
13743         }
13744     };
13745 }();/*
13746  * Based on:
13747  * Ext JS Library 1.1.1
13748  * Copyright(c) 2006-2007, Ext JS, LLC.
13749  *
13750  * Originally Released Under LGPL - original licence link has changed is not relivant.
13751  *
13752  * Fork - LGPL
13753  * <script type="text/javascript">
13754  */
13755
13756
13757  
13758
13759 /**
13760  * @class Roo.MasterTemplate
13761  * @extends Roo.Template
13762  * Provides a template that can have child templates. The syntax is:
13763 <pre><code>
13764 var t = new Roo.MasterTemplate(
13765         '&lt;select name="{name}"&gt;',
13766                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13767         '&lt;/select&gt;'
13768 );
13769 t.add('options', {value: 'foo', text: 'bar'});
13770 // or you can add multiple child elements in one shot
13771 t.addAll('options', [
13772     {value: 'foo', text: 'bar'},
13773     {value: 'foo2', text: 'bar2'},
13774     {value: 'foo3', text: 'bar3'}
13775 ]);
13776 // then append, applying the master template values
13777 t.append('my-form', {name: 'my-select'});
13778 </code></pre>
13779 * A name attribute for the child template is not required if you have only one child
13780 * template or you want to refer to them by index.
13781  */
13782 Roo.MasterTemplate = function(){
13783     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13784     this.originalHtml = this.html;
13785     var st = {};
13786     var m, re = this.subTemplateRe;
13787     re.lastIndex = 0;
13788     var subIndex = 0;
13789     while(m = re.exec(this.html)){
13790         var name = m[1], content = m[2];
13791         st[subIndex] = {
13792             name: name,
13793             index: subIndex,
13794             buffer: [],
13795             tpl : new Roo.Template(content)
13796         };
13797         if(name){
13798             st[name] = st[subIndex];
13799         }
13800         st[subIndex].tpl.compile();
13801         st[subIndex].tpl.call = this.call.createDelegate(this);
13802         subIndex++;
13803     }
13804     this.subCount = subIndex;
13805     this.subs = st;
13806 };
13807 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13808     /**
13809     * The regular expression used to match sub templates
13810     * @type RegExp
13811     * @property
13812     */
13813     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13814
13815     /**
13816      * Applies the passed values to a child template.
13817      * @param {String/Number} name (optional) The name or index of the child template
13818      * @param {Array/Object} values The values to be applied to the template
13819      * @return {MasterTemplate} this
13820      */
13821      add : function(name, values){
13822         if(arguments.length == 1){
13823             values = arguments[0];
13824             name = 0;
13825         }
13826         var s = this.subs[name];
13827         s.buffer[s.buffer.length] = s.tpl.apply(values);
13828         return this;
13829     },
13830
13831     /**
13832      * Applies all the passed values to a child template.
13833      * @param {String/Number} name (optional) The name or index of the child template
13834      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13835      * @param {Boolean} reset (optional) True to reset the template first
13836      * @return {MasterTemplate} this
13837      */
13838     fill : function(name, values, reset){
13839         var a = arguments;
13840         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13841             values = a[0];
13842             name = 0;
13843             reset = a[1];
13844         }
13845         if(reset){
13846             this.reset();
13847         }
13848         for(var i = 0, len = values.length; i < len; i++){
13849             this.add(name, values[i]);
13850         }
13851         return this;
13852     },
13853
13854     /**
13855      * Resets the template for reuse
13856      * @return {MasterTemplate} this
13857      */
13858      reset : function(){
13859         var s = this.subs;
13860         for(var i = 0; i < this.subCount; i++){
13861             s[i].buffer = [];
13862         }
13863         return this;
13864     },
13865
13866     applyTemplate : function(values){
13867         var s = this.subs;
13868         var replaceIndex = -1;
13869         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13870             return s[++replaceIndex].buffer.join("");
13871         });
13872         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13873     },
13874
13875     apply : function(){
13876         return this.applyTemplate.apply(this, arguments);
13877     },
13878
13879     compile : function(){return this;}
13880 });
13881
13882 /**
13883  * Alias for fill().
13884  * @method
13885  */
13886 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13887  /**
13888  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13889  * var tpl = Roo.MasterTemplate.from('element-id');
13890  * @param {String/HTMLElement} el
13891  * @param {Object} config
13892  * @static
13893  */
13894 Roo.MasterTemplate.from = function(el, config){
13895     el = Roo.getDom(el);
13896     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13897 };/*
13898  * Based on:
13899  * Ext JS Library 1.1.1
13900  * Copyright(c) 2006-2007, Ext JS, LLC.
13901  *
13902  * Originally Released Under LGPL - original licence link has changed is not relivant.
13903  *
13904  * Fork - LGPL
13905  * <script type="text/javascript">
13906  */
13907
13908  
13909 /**
13910  * @class Roo.util.CSS
13911  * Utility class for manipulating CSS rules
13912  * @singleton
13913  */
13914 Roo.util.CSS = function(){
13915         var rules = null;
13916         var doc = document;
13917
13918     var camelRe = /(-[a-z])/gi;
13919     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13920
13921    return {
13922    /**
13923     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13924     * tag and appended to the HEAD of the document.
13925     * @param {String|Object} cssText The text containing the css rules
13926     * @param {String} id An id to add to the stylesheet for later removal
13927     * @return {StyleSheet}
13928     */
13929     createStyleSheet : function(cssText, id){
13930         var ss;
13931         var head = doc.getElementsByTagName("head")[0];
13932         var nrules = doc.createElement("style");
13933         nrules.setAttribute("type", "text/css");
13934         if(id){
13935             nrules.setAttribute("id", id);
13936         }
13937         if (typeof(cssText) != 'string') {
13938             // support object maps..
13939             // not sure if this a good idea.. 
13940             // perhaps it should be merged with the general css handling
13941             // and handle js style props.
13942             var cssTextNew = [];
13943             for(var n in cssText) {
13944                 var citems = [];
13945                 for(var k in cssText[n]) {
13946                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13947                 }
13948                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13949                 
13950             }
13951             cssText = cssTextNew.join("\n");
13952             
13953         }
13954        
13955        
13956        if(Roo.isIE){
13957            head.appendChild(nrules);
13958            ss = nrules.styleSheet;
13959            ss.cssText = cssText;
13960        }else{
13961            try{
13962                 nrules.appendChild(doc.createTextNode(cssText));
13963            }catch(e){
13964                nrules.cssText = cssText; 
13965            }
13966            head.appendChild(nrules);
13967            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13968        }
13969        this.cacheStyleSheet(ss);
13970        return ss;
13971    },
13972
13973    /**
13974     * Removes a style or link tag by id
13975     * @param {String} id The id of the tag
13976     */
13977    removeStyleSheet : function(id){
13978        var existing = doc.getElementById(id);
13979        if(existing){
13980            existing.parentNode.removeChild(existing);
13981        }
13982    },
13983
13984    /**
13985     * Dynamically swaps an existing stylesheet reference for a new one
13986     * @param {String} id The id of an existing link tag to remove
13987     * @param {String} url The href of the new stylesheet to include
13988     */
13989    swapStyleSheet : function(id, url){
13990        this.removeStyleSheet(id);
13991        var ss = doc.createElement("link");
13992        ss.setAttribute("rel", "stylesheet");
13993        ss.setAttribute("type", "text/css");
13994        ss.setAttribute("id", id);
13995        ss.setAttribute("href", url);
13996        doc.getElementsByTagName("head")[0].appendChild(ss);
13997    },
13998    
13999    /**
14000     * Refresh the rule cache if you have dynamically added stylesheets
14001     * @return {Object} An object (hash) of rules indexed by selector
14002     */
14003    refreshCache : function(){
14004        return this.getRules(true);
14005    },
14006
14007    // private
14008    cacheStyleSheet : function(stylesheet){
14009        if(!rules){
14010            rules = {};
14011        }
14012        try{// try catch for cross domain access issue
14013            var ssRules = stylesheet.cssRules || stylesheet.rules;
14014            for(var j = ssRules.length-1; j >= 0; --j){
14015                rules[ssRules[j].selectorText] = ssRules[j];
14016            }
14017        }catch(e){}
14018    },
14019    
14020    /**
14021     * Gets all css rules for the document
14022     * @param {Boolean} refreshCache true to refresh the internal cache
14023     * @return {Object} An object (hash) of rules indexed by selector
14024     */
14025    getRules : function(refreshCache){
14026                 if(rules == null || refreshCache){
14027                         rules = {};
14028                         var ds = doc.styleSheets;
14029                         for(var i =0, len = ds.length; i < len; i++){
14030                             try{
14031                         this.cacheStyleSheet(ds[i]);
14032                     }catch(e){} 
14033                 }
14034                 }
14035                 return rules;
14036         },
14037         
14038         /**
14039     * Gets an an individual CSS rule by selector(s)
14040     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14041     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14042     * @return {CSSRule} The CSS rule or null if one is not found
14043     */
14044    getRule : function(selector, refreshCache){
14045                 var rs = this.getRules(refreshCache);
14046                 if(!(selector instanceof Array)){
14047                     return rs[selector];
14048                 }
14049                 for(var i = 0; i < selector.length; i++){
14050                         if(rs[selector[i]]){
14051                                 return rs[selector[i]];
14052                         }
14053                 }
14054                 return null;
14055         },
14056         
14057         
14058         /**
14059     * Updates a rule property
14060     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14061     * @param {String} property The css property
14062     * @param {String} value The new value for the property
14063     * @return {Boolean} true If a rule was found and updated
14064     */
14065    updateRule : function(selector, property, value){
14066                 if(!(selector instanceof Array)){
14067                         var rule = this.getRule(selector);
14068                         if(rule){
14069                                 rule.style[property.replace(camelRe, camelFn)] = value;
14070                                 return true;
14071                         }
14072                 }else{
14073                         for(var i = 0; i < selector.length; i++){
14074                                 if(this.updateRule(selector[i], property, value)){
14075                                         return true;
14076                                 }
14077                         }
14078                 }
14079                 return false;
14080         }
14081    };   
14082 }();/*
14083  * Based on:
14084  * Ext JS Library 1.1.1
14085  * Copyright(c) 2006-2007, Ext JS, LLC.
14086  *
14087  * Originally Released Under LGPL - original licence link has changed is not relivant.
14088  *
14089  * Fork - LGPL
14090  * <script type="text/javascript">
14091  */
14092
14093  
14094
14095 /**
14096  * @class Roo.util.ClickRepeater
14097  * @extends Roo.util.Observable
14098  * 
14099  * A wrapper class which can be applied to any element. Fires a "click" event while the
14100  * mouse is pressed. The interval between firings may be specified in the config but
14101  * defaults to 10 milliseconds.
14102  * 
14103  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14104  * 
14105  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14106  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14107  * Similar to an autorepeat key delay.
14108  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14109  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14110  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14111  *           "interval" and "delay" are ignored. "immediate" is honored.
14112  * @cfg {Boolean} preventDefault True to prevent the default click event
14113  * @cfg {Boolean} stopDefault True to stop the default click event
14114  * 
14115  * @history
14116  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14117  *     2007-02-02 jvs Renamed to ClickRepeater
14118  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14119  *
14120  *  @constructor
14121  * @param {String/HTMLElement/Element} el The element to listen on
14122  * @param {Object} config
14123  **/
14124 Roo.util.ClickRepeater = function(el, config)
14125 {
14126     this.el = Roo.get(el);
14127     this.el.unselectable();
14128
14129     Roo.apply(this, config);
14130
14131     this.addEvents({
14132     /**
14133      * @event mousedown
14134      * Fires when the mouse button is depressed.
14135      * @param {Roo.util.ClickRepeater} this
14136      */
14137         "mousedown" : true,
14138     /**
14139      * @event click
14140      * Fires on a specified interval during the time the element is pressed.
14141      * @param {Roo.util.ClickRepeater} this
14142      */
14143         "click" : true,
14144     /**
14145      * @event mouseup
14146      * Fires when the mouse key is released.
14147      * @param {Roo.util.ClickRepeater} this
14148      */
14149         "mouseup" : true
14150     });
14151
14152     this.el.on("mousedown", this.handleMouseDown, this);
14153     if(this.preventDefault || this.stopDefault){
14154         this.el.on("click", function(e){
14155             if(this.preventDefault){
14156                 e.preventDefault();
14157             }
14158             if(this.stopDefault){
14159                 e.stopEvent();
14160             }
14161         }, this);
14162     }
14163
14164     // allow inline handler
14165     if(this.handler){
14166         this.on("click", this.handler,  this.scope || this);
14167     }
14168
14169     Roo.util.ClickRepeater.superclass.constructor.call(this);
14170 };
14171
14172 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14173     interval : 20,
14174     delay: 250,
14175     preventDefault : true,
14176     stopDefault : false,
14177     timer : 0,
14178
14179     // private
14180     handleMouseDown : function(){
14181         clearTimeout(this.timer);
14182         this.el.blur();
14183         if(this.pressClass){
14184             this.el.addClass(this.pressClass);
14185         }
14186         this.mousedownTime = new Date();
14187
14188         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14189         this.el.on("mouseout", this.handleMouseOut, this);
14190
14191         this.fireEvent("mousedown", this);
14192         this.fireEvent("click", this);
14193         
14194         this.timer = this.click.defer(this.delay || this.interval, this);
14195     },
14196
14197     // private
14198     click : function(){
14199         this.fireEvent("click", this);
14200         this.timer = this.click.defer(this.getInterval(), this);
14201     },
14202
14203     // private
14204     getInterval: function(){
14205         if(!this.accelerate){
14206             return this.interval;
14207         }
14208         var pressTime = this.mousedownTime.getElapsed();
14209         if(pressTime < 500){
14210             return 400;
14211         }else if(pressTime < 1700){
14212             return 320;
14213         }else if(pressTime < 2600){
14214             return 250;
14215         }else if(pressTime < 3500){
14216             return 180;
14217         }else if(pressTime < 4400){
14218             return 140;
14219         }else if(pressTime < 5300){
14220             return 80;
14221         }else if(pressTime < 6200){
14222             return 50;
14223         }else{
14224             return 10;
14225         }
14226     },
14227
14228     // private
14229     handleMouseOut : function(){
14230         clearTimeout(this.timer);
14231         if(this.pressClass){
14232             this.el.removeClass(this.pressClass);
14233         }
14234         this.el.on("mouseover", this.handleMouseReturn, this);
14235     },
14236
14237     // private
14238     handleMouseReturn : function(){
14239         this.el.un("mouseover", this.handleMouseReturn);
14240         if(this.pressClass){
14241             this.el.addClass(this.pressClass);
14242         }
14243         this.click();
14244     },
14245
14246     // private
14247     handleMouseUp : function(){
14248         clearTimeout(this.timer);
14249         this.el.un("mouseover", this.handleMouseReturn);
14250         this.el.un("mouseout", this.handleMouseOut);
14251         Roo.get(document).un("mouseup", this.handleMouseUp);
14252         this.el.removeClass(this.pressClass);
14253         this.fireEvent("mouseup", this);
14254     }
14255 });/*
14256  * Based on:
14257  * Ext JS Library 1.1.1
14258  * Copyright(c) 2006-2007, Ext JS, LLC.
14259  *
14260  * Originally Released Under LGPL - original licence link has changed is not relivant.
14261  *
14262  * Fork - LGPL
14263  * <script type="text/javascript">
14264  */
14265
14266  
14267 /**
14268  * @class Roo.KeyNav
14269  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14270  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14271  * way to implement custom navigation schemes for any UI component.</p>
14272  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14273  * pageUp, pageDown, del, home, end.  Usage:</p>
14274  <pre><code>
14275 var nav = new Roo.KeyNav("my-element", {
14276     "left" : function(e){
14277         this.moveLeft(e.ctrlKey);
14278     },
14279     "right" : function(e){
14280         this.moveRight(e.ctrlKey);
14281     },
14282     "enter" : function(e){
14283         this.save();
14284     },
14285     scope : this
14286 });
14287 </code></pre>
14288  * @constructor
14289  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14290  * @param {Object} config The config
14291  */
14292 Roo.KeyNav = function(el, config){
14293     this.el = Roo.get(el);
14294     Roo.apply(this, config);
14295     if(!this.disabled){
14296         this.disabled = true;
14297         this.enable();
14298     }
14299 };
14300
14301 Roo.KeyNav.prototype = {
14302     /**
14303      * @cfg {Boolean} disabled
14304      * True to disable this KeyNav instance (defaults to false)
14305      */
14306     disabled : false,
14307     /**
14308      * @cfg {String} defaultEventAction
14309      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14310      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14311      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14312      */
14313     defaultEventAction: "stopEvent",
14314     /**
14315      * @cfg {Boolean} forceKeyDown
14316      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14317      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14318      * handle keydown instead of keypress.
14319      */
14320     forceKeyDown : false,
14321
14322     // private
14323     prepareEvent : function(e){
14324         var k = e.getKey();
14325         var h = this.keyToHandler[k];
14326         //if(h && this[h]){
14327         //    e.stopPropagation();
14328         //}
14329         if(Roo.isSafari && h && k >= 37 && k <= 40){
14330             e.stopEvent();
14331         }
14332     },
14333
14334     // private
14335     relay : function(e){
14336         var k = e.getKey();
14337         var h = this.keyToHandler[k];
14338         if(h && this[h]){
14339             if(this.doRelay(e, this[h], h) !== true){
14340                 e[this.defaultEventAction]();
14341             }
14342         }
14343     },
14344
14345     // private
14346     doRelay : function(e, h, hname){
14347         return h.call(this.scope || this, e);
14348     },
14349
14350     // possible handlers
14351     enter : false,
14352     left : false,
14353     right : false,
14354     up : false,
14355     down : false,
14356     tab : false,
14357     esc : false,
14358     pageUp : false,
14359     pageDown : false,
14360     del : false,
14361     home : false,
14362     end : false,
14363
14364     // quick lookup hash
14365     keyToHandler : {
14366         37 : "left",
14367         39 : "right",
14368         38 : "up",
14369         40 : "down",
14370         33 : "pageUp",
14371         34 : "pageDown",
14372         46 : "del",
14373         36 : "home",
14374         35 : "end",
14375         13 : "enter",
14376         27 : "esc",
14377         9  : "tab"
14378     },
14379
14380         /**
14381          * Enable this KeyNav
14382          */
14383         enable: function(){
14384                 if(this.disabled){
14385             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14386             // the EventObject will normalize Safari automatically
14387             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14388                 this.el.on("keydown", this.relay,  this);
14389             }else{
14390                 this.el.on("keydown", this.prepareEvent,  this);
14391                 this.el.on("keypress", this.relay,  this);
14392             }
14393                     this.disabled = false;
14394                 }
14395         },
14396
14397         /**
14398          * Disable this KeyNav
14399          */
14400         disable: function(){
14401                 if(!this.disabled){
14402                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14403                 this.el.un("keydown", this.relay);
14404             }else{
14405                 this.el.un("keydown", this.prepareEvent);
14406                 this.el.un("keypress", this.relay);
14407             }
14408                     this.disabled = true;
14409                 }
14410         }
14411 };/*
14412  * Based on:
14413  * Ext JS Library 1.1.1
14414  * Copyright(c) 2006-2007, Ext JS, LLC.
14415  *
14416  * Originally Released Under LGPL - original licence link has changed is not relivant.
14417  *
14418  * Fork - LGPL
14419  * <script type="text/javascript">
14420  */
14421
14422  
14423 /**
14424  * @class Roo.KeyMap
14425  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14426  * The constructor accepts the same config object as defined by {@link #addBinding}.
14427  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14428  * combination it will call the function with this signature (if the match is a multi-key
14429  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14430  * A KeyMap can also handle a string representation of keys.<br />
14431  * Usage:
14432  <pre><code>
14433 // map one key by key code
14434 var map = new Roo.KeyMap("my-element", {
14435     key: 13, // or Roo.EventObject.ENTER
14436     fn: myHandler,
14437     scope: myObject
14438 });
14439
14440 // map multiple keys to one action by string
14441 var map = new Roo.KeyMap("my-element", {
14442     key: "a\r\n\t",
14443     fn: myHandler,
14444     scope: myObject
14445 });
14446
14447 // map multiple keys to multiple actions by strings and array of codes
14448 var map = new Roo.KeyMap("my-element", [
14449     {
14450         key: [10,13],
14451         fn: function(){ alert("Return was pressed"); }
14452     }, {
14453         key: "abc",
14454         fn: function(){ alert('a, b or c was pressed'); }
14455     }, {
14456         key: "\t",
14457         ctrl:true,
14458         shift:true,
14459         fn: function(){ alert('Control + shift + tab was pressed.'); }
14460     }
14461 ]);
14462 </code></pre>
14463  * <b>Note: A KeyMap starts enabled</b>
14464  * @constructor
14465  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14466  * @param {Object} config The config (see {@link #addBinding})
14467  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14468  */
14469 Roo.KeyMap = function(el, config, eventName){
14470     this.el  = Roo.get(el);
14471     this.eventName = eventName || "keydown";
14472     this.bindings = [];
14473     if(config){
14474         this.addBinding(config);
14475     }
14476     this.enable();
14477 };
14478
14479 Roo.KeyMap.prototype = {
14480     /**
14481      * True to stop the event from bubbling and prevent the default browser action if the
14482      * key was handled by the KeyMap (defaults to false)
14483      * @type Boolean
14484      */
14485     stopEvent : false,
14486
14487     /**
14488      * Add a new binding to this KeyMap. The following config object properties are supported:
14489      * <pre>
14490 Property    Type             Description
14491 ----------  ---------------  ----------------------------------------------------------------------
14492 key         String/Array     A single keycode or an array of keycodes to handle
14493 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14494 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14495 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14496 fn          Function         The function to call when KeyMap finds the expected key combination
14497 scope       Object           The scope of the callback function
14498 </pre>
14499      *
14500      * Usage:
14501      * <pre><code>
14502 // Create a KeyMap
14503 var map = new Roo.KeyMap(document, {
14504     key: Roo.EventObject.ENTER,
14505     fn: handleKey,
14506     scope: this
14507 });
14508
14509 //Add a new binding to the existing KeyMap later
14510 map.addBinding({
14511     key: 'abc',
14512     shift: true,
14513     fn: handleKey,
14514     scope: this
14515 });
14516 </code></pre>
14517      * @param {Object/Array} config A single KeyMap config or an array of configs
14518      */
14519         addBinding : function(config){
14520         if(config instanceof Array){
14521             for(var i = 0, len = config.length; i < len; i++){
14522                 this.addBinding(config[i]);
14523             }
14524             return;
14525         }
14526         var keyCode = config.key,
14527             shift = config.shift, 
14528             ctrl = config.ctrl, 
14529             alt = config.alt,
14530             fn = config.fn,
14531             scope = config.scope;
14532         if(typeof keyCode == "string"){
14533             var ks = [];
14534             var keyString = keyCode.toUpperCase();
14535             for(var j = 0, len = keyString.length; j < len; j++){
14536                 ks.push(keyString.charCodeAt(j));
14537             }
14538             keyCode = ks;
14539         }
14540         var keyArray = keyCode instanceof Array;
14541         var handler = function(e){
14542             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14543                 var k = e.getKey();
14544                 if(keyArray){
14545                     for(var i = 0, len = keyCode.length; i < len; i++){
14546                         if(keyCode[i] == k){
14547                           if(this.stopEvent){
14548                               e.stopEvent();
14549                           }
14550                           fn.call(scope || window, k, e);
14551                           return;
14552                         }
14553                     }
14554                 }else{
14555                     if(k == keyCode){
14556                         if(this.stopEvent){
14557                            e.stopEvent();
14558                         }
14559                         fn.call(scope || window, k, e);
14560                     }
14561                 }
14562             }
14563         };
14564         this.bindings.push(handler);  
14565         },
14566
14567     /**
14568      * Shorthand for adding a single key listener
14569      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14570      * following options:
14571      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14572      * @param {Function} fn The function to call
14573      * @param {Object} scope (optional) The scope of the function
14574      */
14575     on : function(key, fn, scope){
14576         var keyCode, shift, ctrl, alt;
14577         if(typeof key == "object" && !(key instanceof Array)){
14578             keyCode = key.key;
14579             shift = key.shift;
14580             ctrl = key.ctrl;
14581             alt = key.alt;
14582         }else{
14583             keyCode = key;
14584         }
14585         this.addBinding({
14586             key: keyCode,
14587             shift: shift,
14588             ctrl: ctrl,
14589             alt: alt,
14590             fn: fn,
14591             scope: scope
14592         })
14593     },
14594
14595     // private
14596     handleKeyDown : function(e){
14597             if(this.enabled){ //just in case
14598             var b = this.bindings;
14599             for(var i = 0, len = b.length; i < len; i++){
14600                 b[i].call(this, e);
14601             }
14602             }
14603         },
14604         
14605         /**
14606          * Returns true if this KeyMap is enabled
14607          * @return {Boolean} 
14608          */
14609         isEnabled : function(){
14610             return this.enabled;  
14611         },
14612         
14613         /**
14614          * Enables this KeyMap
14615          */
14616         enable: function(){
14617                 if(!this.enabled){
14618                     this.el.on(this.eventName, this.handleKeyDown, this);
14619                     this.enabled = true;
14620                 }
14621         },
14622
14623         /**
14624          * Disable this KeyMap
14625          */
14626         disable: function(){
14627                 if(this.enabled){
14628                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14629                     this.enabled = false;
14630                 }
14631         }
14632 };/*
14633  * Based on:
14634  * Ext JS Library 1.1.1
14635  * Copyright(c) 2006-2007, Ext JS, LLC.
14636  *
14637  * Originally Released Under LGPL - original licence link has changed is not relivant.
14638  *
14639  * Fork - LGPL
14640  * <script type="text/javascript">
14641  */
14642
14643  
14644 /**
14645  * @class Roo.util.TextMetrics
14646  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14647  * wide, in pixels, a given block of text will be.
14648  * @singleton
14649  */
14650 Roo.util.TextMetrics = function(){
14651     var shared;
14652     return {
14653         /**
14654          * Measures the size of the specified text
14655          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14656          * that can affect the size of the rendered text
14657          * @param {String} text The text to measure
14658          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14659          * in order to accurately measure the text height
14660          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14661          */
14662         measure : function(el, text, fixedWidth){
14663             if(!shared){
14664                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14665             }
14666             shared.bind(el);
14667             shared.setFixedWidth(fixedWidth || 'auto');
14668             return shared.getSize(text);
14669         },
14670
14671         /**
14672          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14673          * the overhead of multiple calls to initialize the style properties on each measurement.
14674          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14675          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14676          * in order to accurately measure the text height
14677          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14678          */
14679         createInstance : function(el, fixedWidth){
14680             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14681         }
14682     };
14683 }();
14684
14685  
14686
14687 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14688     var ml = new Roo.Element(document.createElement('div'));
14689     document.body.appendChild(ml.dom);
14690     ml.position('absolute');
14691     ml.setLeftTop(-1000, -1000);
14692     ml.hide();
14693
14694     if(fixedWidth){
14695         ml.setWidth(fixedWidth);
14696     }
14697      
14698     var instance = {
14699         /**
14700          * Returns the size of the specified text based on the internal element's style and width properties
14701          * @memberOf Roo.util.TextMetrics.Instance#
14702          * @param {String} text The text to measure
14703          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14704          */
14705         getSize : function(text){
14706             ml.update(text);
14707             var s = ml.getSize();
14708             ml.update('');
14709             return s;
14710         },
14711
14712         /**
14713          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14714          * that can affect the size of the rendered text
14715          * @memberOf Roo.util.TextMetrics.Instance#
14716          * @param {String/HTMLElement} el The element, dom node or id
14717          */
14718         bind : function(el){
14719             ml.setStyle(
14720                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14721             );
14722         },
14723
14724         /**
14725          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14726          * to set a fixed width in order to accurately measure the text height.
14727          * @memberOf Roo.util.TextMetrics.Instance#
14728          * @param {Number} width The width to set on the element
14729          */
14730         setFixedWidth : function(width){
14731             ml.setWidth(width);
14732         },
14733
14734         /**
14735          * Returns the measured width of the specified text
14736          * @memberOf Roo.util.TextMetrics.Instance#
14737          * @param {String} text The text to measure
14738          * @return {Number} width The width in pixels
14739          */
14740         getWidth : function(text){
14741             ml.dom.style.width = 'auto';
14742             return this.getSize(text).width;
14743         },
14744
14745         /**
14746          * Returns the measured height of the specified text.  For multiline text, be sure to call
14747          * {@link #setFixedWidth} if necessary.
14748          * @memberOf Roo.util.TextMetrics.Instance#
14749          * @param {String} text The text to measure
14750          * @return {Number} height The height in pixels
14751          */
14752         getHeight : function(text){
14753             return this.getSize(text).height;
14754         }
14755     };
14756
14757     instance.bind(bindTo);
14758
14759     return instance;
14760 };
14761
14762 // backwards compat
14763 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14764  * Based on:
14765  * Ext JS Library 1.1.1
14766  * Copyright(c) 2006-2007, Ext JS, LLC.
14767  *
14768  * Originally Released Under LGPL - original licence link has changed is not relivant.
14769  *
14770  * Fork - LGPL
14771  * <script type="text/javascript">
14772  */
14773
14774 /**
14775  * @class Roo.state.Provider
14776  * Abstract base class for state provider implementations. This class provides methods
14777  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14778  * Provider interface.
14779  */
14780 Roo.state.Provider = function(){
14781     /**
14782      * @event statechange
14783      * Fires when a state change occurs.
14784      * @param {Provider} this This state provider
14785      * @param {String} key The state key which was changed
14786      * @param {String} value The encoded value for the state
14787      */
14788     this.addEvents({
14789         "statechange": true
14790     });
14791     this.state = {};
14792     Roo.state.Provider.superclass.constructor.call(this);
14793 };
14794 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14795     /**
14796      * Returns the current value for a key
14797      * @param {String} name The key name
14798      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14799      * @return {Mixed} The state data
14800      */
14801     get : function(name, defaultValue){
14802         return typeof this.state[name] == "undefined" ?
14803             defaultValue : this.state[name];
14804     },
14805     
14806     /**
14807      * Clears a value from the state
14808      * @param {String} name The key name
14809      */
14810     clear : function(name){
14811         delete this.state[name];
14812         this.fireEvent("statechange", this, name, null);
14813     },
14814     
14815     /**
14816      * Sets the value for a key
14817      * @param {String} name The key name
14818      * @param {Mixed} value The value to set
14819      */
14820     set : function(name, value){
14821         this.state[name] = value;
14822         this.fireEvent("statechange", this, name, value);
14823     },
14824     
14825     /**
14826      * Decodes a string previously encoded with {@link #encodeValue}.
14827      * @param {String} value The value to decode
14828      * @return {Mixed} The decoded value
14829      */
14830     decodeValue : function(cookie){
14831         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14832         var matches = re.exec(unescape(cookie));
14833         if(!matches || !matches[1]) return; // non state cookie
14834         var type = matches[1];
14835         var v = matches[2];
14836         switch(type){
14837             case "n":
14838                 return parseFloat(v);
14839             case "d":
14840                 return new Date(Date.parse(v));
14841             case "b":
14842                 return (v == "1");
14843             case "a":
14844                 var all = [];
14845                 var values = v.split("^");
14846                 for(var i = 0, len = values.length; i < len; i++){
14847                     all.push(this.decodeValue(values[i]));
14848                 }
14849                 return all;
14850            case "o":
14851                 var all = {};
14852                 var values = v.split("^");
14853                 for(var i = 0, len = values.length; i < len; i++){
14854                     var kv = values[i].split("=");
14855                     all[kv[0]] = this.decodeValue(kv[1]);
14856                 }
14857                 return all;
14858            default:
14859                 return v;
14860         }
14861     },
14862     
14863     /**
14864      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14865      * @param {Mixed} value The value to encode
14866      * @return {String} The encoded value
14867      */
14868     encodeValue : function(v){
14869         var enc;
14870         if(typeof v == "number"){
14871             enc = "n:" + v;
14872         }else if(typeof v == "boolean"){
14873             enc = "b:" + (v ? "1" : "0");
14874         }else if(v instanceof Date){
14875             enc = "d:" + v.toGMTString();
14876         }else if(v instanceof Array){
14877             var flat = "";
14878             for(var i = 0, len = v.length; i < len; i++){
14879                 flat += this.encodeValue(v[i]);
14880                 if(i != len-1) flat += "^";
14881             }
14882             enc = "a:" + flat;
14883         }else if(typeof v == "object"){
14884             var flat = "";
14885             for(var key in v){
14886                 if(typeof v[key] != "function"){
14887                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14888                 }
14889             }
14890             enc = "o:" + flat.substring(0, flat.length-1);
14891         }else{
14892             enc = "s:" + v;
14893         }
14894         return escape(enc);        
14895     }
14896 });
14897
14898 /*
14899  * Based on:
14900  * Ext JS Library 1.1.1
14901  * Copyright(c) 2006-2007, Ext JS, LLC.
14902  *
14903  * Originally Released Under LGPL - original licence link has changed is not relivant.
14904  *
14905  * Fork - LGPL
14906  * <script type="text/javascript">
14907  */
14908 /**
14909  * @class Roo.state.Manager
14910  * This is the global state manager. By default all components that are "state aware" check this class
14911  * for state information if you don't pass them a custom state provider. In order for this class
14912  * to be useful, it must be initialized with a provider when your application initializes.
14913  <pre><code>
14914 // in your initialization function
14915 init : function(){
14916    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14917    ...
14918    // supposed you have a {@link Roo.BorderLayout}
14919    var layout = new Roo.BorderLayout(...);
14920    layout.restoreState();
14921    // or a {Roo.BasicDialog}
14922    var dialog = new Roo.BasicDialog(...);
14923    dialog.restoreState();
14924  </code></pre>
14925  * @singleton
14926  */
14927 Roo.state.Manager = function(){
14928     var provider = new Roo.state.Provider();
14929     
14930     return {
14931         /**
14932          * Configures the default state provider for your application
14933          * @param {Provider} stateProvider The state provider to set
14934          */
14935         setProvider : function(stateProvider){
14936             provider = stateProvider;
14937         },
14938         
14939         /**
14940          * Returns the current value for a key
14941          * @param {String} name The key name
14942          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14943          * @return {Mixed} The state data
14944          */
14945         get : function(key, defaultValue){
14946             return provider.get(key, defaultValue);
14947         },
14948         
14949         /**
14950          * Sets the value for a key
14951          * @param {String} name The key name
14952          * @param {Mixed} value The state data
14953          */
14954          set : function(key, value){
14955             provider.set(key, value);
14956         },
14957         
14958         /**
14959          * Clears a value from the state
14960          * @param {String} name The key name
14961          */
14962         clear : function(key){
14963             provider.clear(key);
14964         },
14965         
14966         /**
14967          * Gets the currently configured state provider
14968          * @return {Provider} The state provider
14969          */
14970         getProvider : function(){
14971             return provider;
14972         }
14973     };
14974 }();
14975 /*
14976  * Based on:
14977  * Ext JS Library 1.1.1
14978  * Copyright(c) 2006-2007, Ext JS, LLC.
14979  *
14980  * Originally Released Under LGPL - original licence link has changed is not relivant.
14981  *
14982  * Fork - LGPL
14983  * <script type="text/javascript">
14984  */
14985 /**
14986  * @class Roo.state.CookieProvider
14987  * @extends Roo.state.Provider
14988  * The default Provider implementation which saves state via cookies.
14989  * <br />Usage:
14990  <pre><code>
14991    var cp = new Roo.state.CookieProvider({
14992        path: "/cgi-bin/",
14993        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14994        domain: "roojs.com"
14995    })
14996    Roo.state.Manager.setProvider(cp);
14997  </code></pre>
14998  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14999  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15000  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15001  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15002  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15003  * domain the page is running on including the 'www' like 'www.roojs.com')
15004  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15005  * @constructor
15006  * Create a new CookieProvider
15007  * @param {Object} config The configuration object
15008  */
15009 Roo.state.CookieProvider = function(config){
15010     Roo.state.CookieProvider.superclass.constructor.call(this);
15011     this.path = "/";
15012     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15013     this.domain = null;
15014     this.secure = false;
15015     Roo.apply(this, config);
15016     this.state = this.readCookies();
15017 };
15018
15019 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15020     // private
15021     set : function(name, value){
15022         if(typeof value == "undefined" || value === null){
15023             this.clear(name);
15024             return;
15025         }
15026         this.setCookie(name, value);
15027         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15028     },
15029
15030     // private
15031     clear : function(name){
15032         this.clearCookie(name);
15033         Roo.state.CookieProvider.superclass.clear.call(this, name);
15034     },
15035
15036     // private
15037     readCookies : function(){
15038         var cookies = {};
15039         var c = document.cookie + ";";
15040         var re = /\s?(.*?)=(.*?);/g;
15041         var matches;
15042         while((matches = re.exec(c)) != null){
15043             var name = matches[1];
15044             var value = matches[2];
15045             if(name && name.substring(0,3) == "ys-"){
15046                 cookies[name.substr(3)] = this.decodeValue(value);
15047             }
15048         }
15049         return cookies;
15050     },
15051
15052     // private
15053     setCookie : function(name, value){
15054         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15055            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15056            ((this.path == null) ? "" : ("; path=" + this.path)) +
15057            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15058            ((this.secure == true) ? "; secure" : "");
15059     },
15060
15061     // private
15062     clearCookie : function(name){
15063         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15064            ((this.path == null) ? "" : ("; path=" + this.path)) +
15065            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15066            ((this.secure == true) ? "; secure" : "");
15067     }
15068 });