roojs-debug.js
[roojs1] / roojs-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         /**
90          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
91          * @type Boolean
92          */
93         enableGarbageCollector : true,
94
95         /**
96          * True to automatically purge event listeners after uncaching an element (defaults to false).
97          * Note: this only happens if enableGarbageCollector is true.
98          * @type Boolean
99          */
100         enableListenerCollection:false,
101
102         /**
103          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
104          * the IE insecure content warning (defaults to javascript:false).
105          * @type String
106          */
107         SSL_SECURE_URL : "javascript:false",
108
109         /**
110          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
111          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
112          * @type String
113          */
114         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
115
116         emptyFn : function(){},
117
118         /**
119          * Copies all the properties of config to obj if they don't already exist.
120          * @param {Object} obj The receiver of the properties
121          * @param {Object} config The source of the properties
122          * @return {Object} returns obj
123          */
124         applyIf : function(o, c){
125             if(o && c){
126                 for(var p in c){
127                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
128                 }
129             }
130             return o;
131         },
132
133         /**
134          * Applies event listeners to elements by selectors when the document is ready.
135          * The event name is specified with an @ suffix.
136 <pre><code>
137 Roo.addBehaviors({
138    // add a listener for click on all anchors in element with id foo
139    '#foo a@click' : function(e, t){
140        // do something
141    },
142
143    // add the same listener to multiple selectors (separated by comma BEFORE the @)
144    '#foo a, #bar span.some-class@mouseover' : function(){
145        // do something
146    }
147 });
148 </code></pre>
149          * @param {Object} obj The list of behaviors to apply
150          */
151         addBehaviors : function(o){
152             if(!Roo.isReady){
153                 Roo.onReady(function(){
154                     Roo.addBehaviors(o);
155                 });
156                 return;
157             }
158             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
159             for(var b in o){
160                 var parts = b.split('@');
161                 if(parts[1]){ // for Object prototype breakers
162                     var s = parts[0];
163                     if(!cache[s]){
164                         cache[s] = Roo.select(s);
165                     }
166                     cache[s].on(parts[1], o[b]);
167                 }
168             }
169             cache = null;
170         },
171
172         /**
173          * Generates unique ids. If the element already has an id, it is unchanged
174          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
175          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
176          * @return {String} The generated Id.
177          */
178         id : function(el, prefix){
179             prefix = prefix || "roo-gen";
180             el = Roo.getDom(el);
181             var id = prefix + (++idSeed);
182             return el ? (el.id ? el.id : (el.id = id)) : id;
183         },
184          
185        
186         /**
187          * Extends one class with another class and optionally overrides members with the passed literal. This class
188          * also adds the function "override()" to the class that can be used to override
189          * members on an instance.
190          * @param {Object} subclass The class inheriting the functionality
191          * @param {Object} superclass The class being extended
192          * @param {Object} overrides (optional) A literal with members
193          * @method extend
194          */
195         extend : function(){
196             // inline overrides
197             var io = function(o){
198                 for(var m in o){
199                     this[m] = o[m];
200                 }
201             };
202             return function(sb, sp, overrides){
203                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
204                     overrides = sp;
205                     sp = sb;
206                     sb = function(){sp.apply(this, arguments);};
207                 }
208                 var F = function(){}, sbp, spp = sp.prototype;
209                 F.prototype = spp;
210                 sbp = sb.prototype = new F();
211                 sbp.constructor=sb;
212                 sb.superclass=spp;
213                 
214                 if(spp.constructor == Object.prototype.constructor){
215                     spp.constructor=sp;
216                    
217                 }
218                 
219                 sb.override = function(o){
220                     Roo.override(sb, o);
221                 };
222                 sbp.override = io;
223                 Roo.override(sb, overrides);
224                 return sb;
225             };
226         }(),
227
228         /**
229          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
230          * Usage:<pre><code>
231 Roo.override(MyClass, {
232     newMethod1: function(){
233         // etc.
234     },
235     newMethod2: function(foo){
236         // etc.
237     }
238 });
239  </code></pre>
240          * @param {Object} origclass The class to override
241          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
242          * containing one or more methods.
243          * @method override
244          */
245         override : function(origclass, overrides){
246             if(overrides){
247                 var p = origclass.prototype;
248                 for(var method in overrides){
249                     p[method] = overrides[method];
250                 }
251             }
252         },
253         /**
254          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
255          * <pre><code>
256 Roo.namespace('Company', 'Company.data');
257 Company.Widget = function() { ... }
258 Company.data.CustomStore = function(config) { ... }
259 </code></pre>
260          * @param {String} namespace1
261          * @param {String} namespace2
262          * @param {String} etc
263          * @method namespace
264          */
265         namespace : function(){
266             var a=arguments, o=null, i, j, d, rt;
267             for (i=0; i<a.length; ++i) {
268                 d=a[i].split(".");
269                 rt = d[0];
270                 /** eval:var:o */
271                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
272                 for (j=1; j<d.length; ++j) {
273                     o[d[j]]=o[d[j]] || {};
274                     o=o[d[j]];
275                 }
276             }
277         },
278         /**
279          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
280          * <pre><code>
281 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
282 Roo.factory(conf, Roo.data);
283 </code></pre>
284          * @param {String} classname
285          * @param {String} namespace (optional)
286          * @method factory
287          */
288          
289         factory : function(c, ns)
290         {
291             // no xtype, no ns or c.xns - or forced off by c.xns
292             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
293                 return c;
294             }
295             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
296             if (c.constructor == ns[c.xtype]) {// already created...
297                 return c;
298             }
299             if (ns[c.xtype]) {
300                 console.log("Roo.Factory(" + c.xtype + ")");
301                 var ret = new ns[c.xtype](c);
302                 ret.xns = false;
303                 return ret;
304             }
305             c.xns = false; // prevent recursion..
306             return c;
307         },
308          
309         /**
310          * 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.
311          * @param {Object} o
312          * @return {String}
313          */
314         urlEncode : function(o){
315             if(!o){
316                 return "";
317             }
318             var buf = [];
319             for(var key in o){
320                 var ov = o[key], k = encodeURIComponent(key);
321                 var type = typeof ov;
322                 if(type == 'undefined'){
323                     buf.push(k, "=&");
324                 }else if(type != "function" && type != "object"){
325                     buf.push(k, "=", encodeURIComponent(ov), "&");
326                 }else if(ov instanceof Array){
327                     if (ov.length) {
328                             for(var i = 0, len = ov.length; i < len; i++) {
329                                 buf.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
330                             }
331                         } else {
332                             buf.push(k, "=&");
333                         }
334                 }
335             }
336             buf.pop();
337             return buf.join("");
338         },
339
340         /**
341          * 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]}.
342          * @param {String} string
343          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
344          * @return {Object} A literal with members
345          */
346         urlDecode : function(string, overwrite){
347             if(!string || !string.length){
348                 return {};
349             }
350             var obj = {};
351             var pairs = string.split('&');
352             var pair, name, value;
353             for(var i = 0, len = pairs.length; i < len; i++){
354                 pair = pairs[i].split('=');
355                 name = decodeURIComponent(pair[0]);
356                 value = decodeURIComponent(pair[1]);
357                 if(overwrite !== true){
358                     if(typeof obj[name] == "undefined"){
359                         obj[name] = value;
360                     }else if(typeof obj[name] == "string"){
361                         obj[name] = [obj[name]];
362                         obj[name].push(value);
363                     }else{
364                         obj[name].push(value);
365                     }
366                 }else{
367                     obj[name] = value;
368                 }
369             }
370             return obj;
371         },
372
373         /**
374          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
375          * passed array is not really an array, your function is called once with it.
376          * The supplied function is called with (Object item, Number index, Array allItems).
377          * @param {Array/NodeList/Mixed} array
378          * @param {Function} fn
379          * @param {Object} scope
380          */
381         each : function(array, fn, scope){
382             if(typeof array.length == "undefined" || typeof array == "string"){
383                 array = [array];
384             }
385             for(var i = 0, len = array.length; i < len; i++){
386                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
387             }
388         },
389
390         // deprecated
391         combine : function(){
392             var as = arguments, l = as.length, r = [];
393             for(var i = 0; i < l; i++){
394                 var a = as[i];
395                 if(a instanceof Array){
396                     r = r.concat(a);
397                 }else if(a.length !== undefined && !a.substr){
398                     r = r.concat(Array.prototype.slice.call(a, 0));
399                 }else{
400                     r.push(a);
401                 }
402             }
403             return r;
404         },
405
406         /**
407          * Escapes the passed string for use in a regular expression
408          * @param {String} str
409          * @return {String}
410          */
411         escapeRe : function(s) {
412             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
413         },
414
415         // internal
416         callback : function(cb, scope, args, delay){
417             if(typeof cb == "function"){
418                 if(delay){
419                     cb.defer(delay, scope, args || []);
420                 }else{
421                     cb.apply(scope, args || []);
422                 }
423             }
424         },
425
426         /**
427          * Return the dom node for the passed string (id), dom node, or Roo.Element
428          * @param {String/HTMLElement/Roo.Element} el
429          * @return HTMLElement
430          */
431         getDom : function(el){
432             if(!el){
433                 return null;
434             }
435             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
436         },
437
438         /**
439         * Shorthand for {@link Roo.ComponentMgr#get}
440         * @param {String} id
441         * @return Roo.Component
442         */
443         getCmp : function(id){
444             return Roo.ComponentMgr.get(id);
445         },
446          
447         num : function(v, defaultValue){
448             if(typeof v != 'number'){
449                 return defaultValue;
450             }
451             return v;
452         },
453
454         destroy : function(){
455             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
456                 var as = a[i];
457                 if(as){
458                     if(as.dom){
459                         as.removeAllListeners();
460                         as.remove();
461                         continue;
462                     }
463                     if(typeof as.purgeListeners == 'function'){
464                         as.purgeListeners();
465                     }
466                     if(typeof as.destroy == 'function'){
467                         as.destroy();
468                     }
469                 }
470             }
471         },
472
473         // inpired by a similar function in mootools library
474         /**
475          * Returns the type of object that is passed in. If the object passed in is null or undefined it
476          * return false otherwise it returns one of the following values:<ul>
477          * <li><b>string</b>: If the object passed is a string</li>
478          * <li><b>number</b>: If the object passed is a number</li>
479          * <li><b>boolean</b>: If the object passed is a boolean value</li>
480          * <li><b>function</b>: If the object passed is a function reference</li>
481          * <li><b>object</b>: If the object passed is an object</li>
482          * <li><b>array</b>: If the object passed is an array</li>
483          * <li><b>regexp</b>: If the object passed is a regular expression</li>
484          * <li><b>element</b>: If the object passed is a DOM Element</li>
485          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
486          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
487          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
488          * @param {Mixed} object
489          * @return {String}
490          */
491         type : function(o){
492             if(o === undefined || o === null){
493                 return false;
494             }
495             if(o.htmlElement){
496                 return 'element';
497             }
498             var t = typeof o;
499             if(t == 'object' && o.nodeName) {
500                 switch(o.nodeType) {
501                     case 1: return 'element';
502                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
503                 }
504             }
505             if(t == 'object' || t == 'function') {
506                 switch(o.constructor) {
507                     case Array: return 'array';
508                     case RegExp: return 'regexp';
509                 }
510                 if(typeof o.length == 'number' && typeof o.item == 'function') {
511                     return 'nodelist';
512                 }
513             }
514             return t;
515         },
516
517         /**
518          * Returns true if the passed value is null, undefined or an empty string (optional).
519          * @param {Mixed} value The value to test
520          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
521          * @return {Boolean}
522          */
523         isEmpty : function(v, allowBlank){
524             return v === null || v === undefined || (!allowBlank ? v === '' : false);
525         },
526         
527         /** @type Boolean */
528         isOpera : isOpera,
529         /** @type Boolean */
530         isSafari : isSafari,
531         /** @type Boolean */
532         isIE : isIE,
533         /** @type Boolean */
534         isIE7 : isIE7,
535         /** @type Boolean */
536         isGecko : isGecko,
537         /** @type Boolean */
538         isBorderBox : isBorderBox,
539         /** @type Boolean */
540         isWindows : isWindows,
541         /** @type Boolean */
542         isLinux : isLinux,
543         /** @type Boolean */
544         isMac : isMac,
545
546         /**
547          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
548          * you may want to set this to true.
549          * @type Boolean
550          */
551         useShims : ((isIE && !isIE7) || (isGecko && isMac))
552     });
553
554
555 })();
556
557 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
558                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
559 /*
560  * Based on:
561  * Ext JS Library 1.1.1
562  * Copyright(c) 2006-2007, Ext JS, LLC.
563  *
564  * Originally Released Under LGPL - original licence link has changed is not relivant.
565  *
566  * Fork - LGPL
567  * <script type="text/javascript">
568  */
569
570 (function() {    
571     // wrappedn so fnCleanup is not in global scope...
572     if(Roo.isIE) {
573         function fnCleanUp() {
574             var p = Function.prototype;
575             delete p.createSequence;
576             delete p.defer;
577             delete p.createDelegate;
578             delete p.createCallback;
579             delete p.createInterceptor;
580
581             window.detachEvent("onunload", fnCleanUp);
582         }
583         window.attachEvent("onunload", fnCleanUp);
584     }
585 })();
586
587
588 /**
589  * @class Function
590  * These functions are available on every Function object (any JavaScript function).
591  */
592 Roo.apply(Function.prototype, {
593      /**
594      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
595      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
596      * Will create a function that is bound to those 2 args.
597      * @return {Function} The new function
598     */
599     createCallback : function(/*args...*/){
600         // make args available, in function below
601         var args = arguments;
602         var method = this;
603         return function() {
604             return method.apply(window, args);
605         };
606     },
607
608     /**
609      * Creates a delegate (callback) that sets the scope to obj.
610      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
611      * Will create a function that is automatically scoped to this.
612      * @param {Object} obj (optional) The object for which the scope is set
613      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
614      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
615      *                                             if a number the args are inserted at the specified position
616      * @return {Function} The new function
617      */
618     createDelegate : function(obj, args, appendArgs){
619         var method = this;
620         return function() {
621             var callArgs = args || arguments;
622             if(appendArgs === true){
623                 callArgs = Array.prototype.slice.call(arguments, 0);
624                 callArgs = callArgs.concat(args);
625             }else if(typeof appendArgs == "number"){
626                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
627                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
628                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
629             }
630             return method.apply(obj || window, callArgs);
631         };
632     },
633
634     /**
635      * Calls this function after the number of millseconds specified.
636      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
637      * @param {Object} obj (optional) The object for which the scope is set
638      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
639      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
640      *                                             if a number the args are inserted at the specified position
641      * @return {Number} The timeout id that can be used with clearTimeout
642      */
643     defer : function(millis, obj, args, appendArgs){
644         var fn = this.createDelegate(obj, args, appendArgs);
645         if(millis){
646             return setTimeout(fn, millis);
647         }
648         fn();
649         return 0;
650     },
651     /**
652      * Create a combined function call sequence of the original function + the passed function.
653      * The resulting function returns the results of the original function.
654      * The passed fcn is called with the parameters of the original function
655      * @param {Function} fcn The function to sequence
656      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
657      * @return {Function} The new function
658      */
659     createSequence : function(fcn, scope){
660         if(typeof fcn != "function"){
661             return this;
662         }
663         var method = this;
664         return function() {
665             var retval = method.apply(this || window, arguments);
666             fcn.apply(scope || this || window, arguments);
667             return retval;
668         };
669     },
670
671     /**
672      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
673      * The resulting function returns the results of the original function.
674      * The passed fcn is called with the parameters of the original function.
675      * @addon
676      * @param {Function} fcn The function to call before the original
677      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
678      * @return {Function} The new function
679      */
680     createInterceptor : function(fcn, scope){
681         if(typeof fcn != "function"){
682             return this;
683         }
684         var method = this;
685         return function() {
686             fcn.target = this;
687             fcn.method = method;
688             if(fcn.apply(scope || this || window, arguments) === false){
689                 return;
690             }
691             return method.apply(this || window, arguments);
692         };
693     }
694 });
695 /*
696  * Based on:
697  * Ext JS Library 1.1.1
698  * Copyright(c) 2006-2007, Ext JS, LLC.
699  *
700  * Originally Released Under LGPL - original licence link has changed is not relivant.
701  *
702  * Fork - LGPL
703  * <script type="text/javascript">
704  */
705
706 Roo.applyIf(String, {
707     
708     /** @scope String */
709     
710     /**
711      * Escapes the passed string for ' and \
712      * @param {String} string The string to escape
713      * @return {String} The escaped string
714      * @static
715      */
716     escape : function(string) {
717         return string.replace(/('|\\)/g, "\\$1");
718     },
719
720     /**
721      * Pads the left side of a string with a specified character.  This is especially useful
722      * for normalizing number and date strings.  Example usage:
723      * <pre><code>
724 var s = String.leftPad('123', 5, '0');
725 // s now contains the string: '00123'
726 </code></pre>
727      * @param {String} string The original string
728      * @param {Number} size The total length of the output string
729      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
730      * @return {String} The padded string
731      * @static
732      */
733     leftPad : function (val, size, ch) {
734         var result = new String(val);
735         if(ch === null || ch === undefined || ch === '') {
736             ch = " ";
737         }
738         while (result.length < size) {
739             result = ch + result;
740         }
741         return result;
742     },
743
744     /**
745      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
746      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
747      * <pre><code>
748 var cls = 'my-class', text = 'Some text';
749 var s = String.format('<div class="{0}">{1}</div>', cls, text);
750 // s now contains the string: '<div class="my-class">Some text</div>'
751 </code></pre>
752      * @param {String} string The tokenized string to be formatted
753      * @param {String} value1 The value to replace token {0}
754      * @param {String} value2 Etc...
755      * @return {String} The formatted string
756      * @static
757      */
758     format : function(format){
759         var args = Array.prototype.slice.call(arguments, 1);
760         return format.replace(/\{(\d+)\}/g, function(m, i){
761             return Roo.util.Format.htmlEncode(args[i]);
762         });
763     }
764 });
765
766 /**
767  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
768  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
769  * they are already different, the first value passed in is returned.  Note that this method returns the new value
770  * but does not change the current string.
771  * <pre><code>
772 // alternate sort directions
773 sort = sort.toggle('ASC', 'DESC');
774
775 // instead of conditional logic:
776 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
777 </code></pre>
778  * @param {String} value The value to compare to the current string
779  * @param {String} other The new value to use if the string already equals the first value passed in
780  * @return {String} The new value
781  */
782  
783 String.prototype.toggle = function(value, other){
784     return this == value ? other : value;
785 };/*
786  * Based on:
787  * Ext JS Library 1.1.1
788  * Copyright(c) 2006-2007, Ext JS, LLC.
789  *
790  * Originally Released Under LGPL - original licence link has changed is not relivant.
791  *
792  * Fork - LGPL
793  * <script type="text/javascript">
794  */
795
796  /**
797  * @class Number
798  */
799 Roo.applyIf(Number.prototype, {
800     /**
801      * Checks whether or not the current number is within a desired range.  If the number is already within the
802      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
803      * exceeded.  Note that this method returns the constrained value but does not change the current number.
804      * @param {Number} min The minimum number in the range
805      * @param {Number} max The maximum number in the range
806      * @return {Number} The constrained value if outside the range, otherwise the current value
807      */
808     constrain : function(min, max){
809         return Math.min(Math.max(this, min), max);
810     }
811 });/*
812  * Based on:
813  * Ext JS Library 1.1.1
814  * Copyright(c) 2006-2007, Ext JS, LLC.
815  *
816  * Originally Released Under LGPL - original licence link has changed is not relivant.
817  *
818  * Fork - LGPL
819  * <script type="text/javascript">
820  */
821  /**
822  * @class Array
823  */
824 Roo.applyIf(Array.prototype, {
825     /**
826      * Checks whether or not the specified object exists in the array.
827      * @param {Object} o The object to check for
828      * @return {Number} The index of o in the array (or -1 if it is not found)
829      */
830     indexOf : function(o){
831        for (var i = 0, len = this.length; i < len; i++){
832               if(this[i] == o) return i;
833        }
834            return -1;
835     },
836
837     /**
838      * Removes the specified object from the array.  If the object is not found nothing happens.
839      * @param {Object} o The object to remove
840      */
841     remove : function(o){
842        var index = this.indexOf(o);
843        if(index != -1){
844            this.splice(index, 1);
845        }
846     }
847 });/*
848  * Based on:
849  * Ext JS Library 1.1.1
850  * Copyright(c) 2006-2007, Ext JS, LLC.
851  *
852  * Originally Released Under LGPL - original licence link has changed is not relivant.
853  *
854  * Fork - LGPL
855  * <script type="text/javascript">
856  */
857
858 /**
859  * @class Date
860  *
861  * The date parsing and format syntax is a subset of
862  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
863  * supported will provide results equivalent to their PHP versions.
864  *
865  * Following is the list of all currently supported formats:
866  *<pre>
867 Sample date:
868 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
869
870 Format  Output      Description
871 ------  ----------  --------------------------------------------------------------
872   d      10         Day of the month, 2 digits with leading zeros
873   D      Wed        A textual representation of a day, three letters
874   j      10         Day of the month without leading zeros
875   l      Wednesday  A full textual representation of the day of the week
876   S      th         English ordinal day of month suffix, 2 chars (use with j)
877   w      3          Numeric representation of the day of the week
878   z      9          The julian date, or day of the year (0-365)
879   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
880   F      January    A full textual representation of the month
881   m      01         Numeric representation of a month, with leading zeros
882   M      Jan        Month name abbreviation, three letters
883   n      1          Numeric representation of a month, without leading zeros
884   t      31         Number of days in the given month
885   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
886   Y      2007       A full numeric representation of a year, 4 digits
887   y      07         A two digit representation of a year
888   a      pm         Lowercase Ante meridiem and Post meridiem
889   A      PM         Uppercase Ante meridiem and Post meridiem
890   g      3          12-hour format of an hour without leading zeros
891   G      15         24-hour format of an hour without leading zeros
892   h      03         12-hour format of an hour with leading zeros
893   H      15         24-hour format of an hour with leading zeros
894   i      05         Minutes with leading zeros
895   s      01         Seconds, with leading zeros
896   O      -0600      Difference to Greenwich time (GMT) in hours
897   T      CST        Timezone setting of the machine running the code
898   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
899 </pre>
900  *
901  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
902  * <pre><code>
903 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
904 document.write(dt.format('Y-m-d'));                         //2007-01-10
905 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
906 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
907  </code></pre>
908  *
909  * Here are some standard date/time patterns that you might find helpful.  They
910  * are not part of the source of Date.js, but to use them you can simply copy this
911  * block of code into any script that is included after Date.js and they will also become
912  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
913  * <pre><code>
914 Date.patterns = {
915     ISO8601Long:"Y-m-d H:i:s",
916     ISO8601Short:"Y-m-d",
917     ShortDate: "n/j/Y",
918     LongDate: "l, F d, Y",
919     FullDateTime: "l, F d, Y g:i:s A",
920     MonthDay: "F d",
921     ShortTime: "g:i A",
922     LongTime: "g:i:s A",
923     SortableDateTime: "Y-m-d\\TH:i:s",
924     UniversalSortableDateTime: "Y-m-d H:i:sO",
925     YearMonth: "F, Y"
926 };
927 </code></pre>
928  *
929  * Example usage:
930  * <pre><code>
931 var dt = new Date();
932 document.write(dt.format(Date.patterns.ShortDate));
933  </code></pre>
934  */
935
936 /*
937  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
938  * They generate precompiled functions from date formats instead of parsing and
939  * processing the pattern every time you format a date.  These functions are available
940  * on every Date object (any javascript function).
941  *
942  * The original article and download are here:
943  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
944  *
945  */
946  
947  
948  // was in core
949 /**
950  Returns the number of milliseconds between this date and date
951  @param {Date} date (optional) Defaults to now
952  @return {Number} The diff in milliseconds
953  @member Date getElapsed
954  */
955 Date.prototype.getElapsed = function(date) {
956         return Math.abs((date || new Date()).getTime()-this.getTime());
957 };
958 // was in date file..
959
960
961 // private
962 Date.parseFunctions = {count:0};
963 // private
964 Date.parseRegexes = [];
965 // private
966 Date.formatFunctions = {count:0};
967
968 // private
969 Date.prototype.dateFormat = function(format) {
970     if (Date.formatFunctions[format] == null) {
971         Date.createNewFormat(format);
972     }
973     var func = Date.formatFunctions[format];
974     return this[func]();
975 };
976
977
978 /**
979  * Formats a date given the supplied format string
980  * @param {String} format The format string
981  * @return {String} The formatted date
982  * @method
983  */
984 Date.prototype.format = Date.prototype.dateFormat;
985
986 // private
987 Date.createNewFormat = function(format) {
988     var funcName = "format" + Date.formatFunctions.count++;
989     Date.formatFunctions[format] = funcName;
990     var code = "Date.prototype." + funcName + " = function(){return ";
991     var special = false;
992     var ch = '';
993     for (var i = 0; i < format.length; ++i) {
994         ch = format.charAt(i);
995         if (!special && ch == "\\") {
996             special = true;
997         }
998         else if (special) {
999             special = false;
1000             code += "'" + String.escape(ch) + "' + ";
1001         }
1002         else {
1003             code += Date.getFormatCode(ch);
1004         }
1005     }
1006     /** eval:var:zzzzzzzzzzzzz */
1007     eval(code.substring(0, code.length - 3) + ";}");
1008 };
1009
1010 // private
1011 Date.getFormatCode = function(character) {
1012     switch (character) {
1013     case "d":
1014         return "String.leftPad(this.getDate(), 2, '0') + ";
1015     case "D":
1016         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1017     case "j":
1018         return "this.getDate() + ";
1019     case "l":
1020         return "Date.dayNames[this.getDay()] + ";
1021     case "S":
1022         return "this.getSuffix() + ";
1023     case "w":
1024         return "this.getDay() + ";
1025     case "z":
1026         return "this.getDayOfYear() + ";
1027     case "W":
1028         return "this.getWeekOfYear() + ";
1029     case "F":
1030         return "Date.monthNames[this.getMonth()] + ";
1031     case "m":
1032         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1033     case "M":
1034         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1035     case "n":
1036         return "(this.getMonth() + 1) + ";
1037     case "t":
1038         return "this.getDaysInMonth() + ";
1039     case "L":
1040         return "(this.isLeapYear() ? 1 : 0) + ";
1041     case "Y":
1042         return "this.getFullYear() + ";
1043     case "y":
1044         return "('' + this.getFullYear()).substring(2, 4) + ";
1045     case "a":
1046         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1047     case "A":
1048         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1049     case "g":
1050         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1051     case "G":
1052         return "this.getHours() + ";
1053     case "h":
1054         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1055     case "H":
1056         return "String.leftPad(this.getHours(), 2, '0') + ";
1057     case "i":
1058         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1059     case "s":
1060         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1061     case "O":
1062         return "this.getGMTOffset() + ";
1063     case "T":
1064         return "this.getTimezone() + ";
1065     case "Z":
1066         return "(this.getTimezoneOffset() * -60) + ";
1067     default:
1068         return "'" + String.escape(character) + "' + ";
1069     }
1070 };
1071
1072 /**
1073  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1074  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1075  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1076  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1077  * string or the parse operation will fail.
1078  * Example Usage:
1079 <pre><code>
1080 //dt = Fri May 25 2007 (current date)
1081 var dt = new Date();
1082
1083 //dt = Thu May 25 2006 (today's month/day in 2006)
1084 dt = Date.parseDate("2006", "Y");
1085
1086 //dt = Sun Jan 15 2006 (all date parts specified)
1087 dt = Date.parseDate("2006-1-15", "Y-m-d");
1088
1089 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1090 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1091 </code></pre>
1092  * @param {String} input The unparsed date as a string
1093  * @param {String} format The format the date is in
1094  * @return {Date} The parsed date
1095  * @static
1096  */
1097 Date.parseDate = function(input, format) {
1098     if (Date.parseFunctions[format] == null) {
1099         Date.createParser(format);
1100     }
1101     var func = Date.parseFunctions[format];
1102     return Date[func](input);
1103 };
1104
1105 // private
1106 Date.createParser = function(format) {
1107     var funcName = "parse" + Date.parseFunctions.count++;
1108     var regexNum = Date.parseRegexes.length;
1109     var currentGroup = 1;
1110     Date.parseFunctions[format] = funcName;
1111
1112     var code = "Date." + funcName + " = function(input){\n"
1113         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1114         + "var d = new Date();\n"
1115         + "y = d.getFullYear();\n"
1116         + "m = d.getMonth();\n"
1117         + "d = d.getDate();\n"
1118         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1119         + "if (results && results.length > 0) {";
1120     var regex = "";
1121
1122     var special = false;
1123     var ch = '';
1124     for (var i = 0; i < format.length; ++i) {
1125         ch = format.charAt(i);
1126         if (!special && ch == "\\") {
1127             special = true;
1128         }
1129         else if (special) {
1130             special = false;
1131             regex += String.escape(ch);
1132         }
1133         else {
1134             var obj = Date.formatCodeToRegex(ch, currentGroup);
1135             currentGroup += obj.g;
1136             regex += obj.s;
1137             if (obj.g && obj.c) {
1138                 code += obj.c;
1139             }
1140         }
1141     }
1142
1143     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1144         + "{v = new Date(y, m, d, h, i, s);}\n"
1145         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1146         + "{v = new Date(y, m, d, h, i);}\n"
1147         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1148         + "{v = new Date(y, m, d, h);}\n"
1149         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1150         + "{v = new Date(y, m, d);}\n"
1151         + "else if (y >= 0 && m >= 0)\n"
1152         + "{v = new Date(y, m);}\n"
1153         + "else if (y >= 0)\n"
1154         + "{v = new Date(y);}\n"
1155         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1156         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1157         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1158         + ";}";
1159
1160     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1161      /** eval:var:zzzzzzzzzzzzz */
1162     eval(code);
1163 };
1164
1165 // private
1166 Date.formatCodeToRegex = function(character, currentGroup) {
1167     switch (character) {
1168     case "D":
1169         return {g:0,
1170         c:null,
1171         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1172     case "j":
1173         return {g:1,
1174             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1175             s:"(\\d{1,2})"}; // day of month without leading zeroes
1176     case "d":
1177         return {g:1,
1178             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1179             s:"(\\d{2})"}; // day of month with leading zeroes
1180     case "l":
1181         return {g:0,
1182             c:null,
1183             s:"(?:" + Date.dayNames.join("|") + ")"};
1184     case "S":
1185         return {g:0,
1186             c:null,
1187             s:"(?:st|nd|rd|th)"};
1188     case "w":
1189         return {g:0,
1190             c:null,
1191             s:"\\d"};
1192     case "z":
1193         return {g:0,
1194             c:null,
1195             s:"(?:\\d{1,3})"};
1196     case "W":
1197         return {g:0,
1198             c:null,
1199             s:"(?:\\d{2})"};
1200     case "F":
1201         return {g:1,
1202             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1203             s:"(" + Date.monthNames.join("|") + ")"};
1204     case "M":
1205         return {g:1,
1206             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1207             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1208     case "n":
1209         return {g:1,
1210             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1211             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1212     case "m":
1213         return {g:1,
1214             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1215             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1216     case "t":
1217         return {g:0,
1218             c:null,
1219             s:"\\d{1,2}"};
1220     case "L":
1221         return {g:0,
1222             c:null,
1223             s:"(?:1|0)"};
1224     case "Y":
1225         return {g:1,
1226             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1227             s:"(\\d{4})"};
1228     case "y":
1229         return {g:1,
1230             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1231                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1232             s:"(\\d{1,2})"};
1233     case "a":
1234         return {g:1,
1235             c:"if (results[" + currentGroup + "] == 'am') {\n"
1236                 + "if (h == 12) { h = 0; }\n"
1237                 + "} else { if (h < 12) { h += 12; }}",
1238             s:"(am|pm)"};
1239     case "A":
1240         return {g:1,
1241             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1242                 + "if (h == 12) { h = 0; }\n"
1243                 + "} else { if (h < 12) { h += 12; }}",
1244             s:"(AM|PM)"};
1245     case "g":
1246     case "G":
1247         return {g:1,
1248             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1249             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1250     case "h":
1251     case "H":
1252         return {g:1,
1253             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1254             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1255     case "i":
1256         return {g:1,
1257             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1258             s:"(\\d{2})"};
1259     case "s":
1260         return {g:1,
1261             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1262             s:"(\\d{2})"};
1263     case "O":
1264         return {g:1,
1265             c:[
1266                 "o = results[", currentGroup, "];\n",
1267                 "var sn = o.substring(0,1);\n", // get + / - sign
1268                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1269                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1270                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1271                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1272             ].join(""),
1273             s:"([+\-]\\d{4})"};
1274     case "T":
1275         return {g:0,
1276             c:null,
1277             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1278     case "Z":
1279         return {g:1,
1280             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1281                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1282             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1283     default:
1284         return {g:0,
1285             c:null,
1286             s:String.escape(character)};
1287     }
1288 };
1289
1290 /**
1291  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1292  * @return {String} The abbreviated timezone name (e.g. 'CST')
1293  */
1294 Date.prototype.getTimezone = function() {
1295     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1296 };
1297
1298 /**
1299  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1300  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1301  */
1302 Date.prototype.getGMTOffset = function() {
1303     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1304         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1305         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1306 };
1307
1308 /**
1309  * Get the numeric day number of the year, adjusted for leap year.
1310  * @return {Number} 0 through 364 (365 in leap years)
1311  */
1312 Date.prototype.getDayOfYear = function() {
1313     var num = 0;
1314     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1315     for (var i = 0; i < this.getMonth(); ++i) {
1316         num += Date.daysInMonth[i];
1317     }
1318     return num + this.getDate() - 1;
1319 };
1320
1321 /**
1322  * Get the string representation of the numeric week number of the year
1323  * (equivalent to the format specifier 'W').
1324  * @return {String} '00' through '52'
1325  */
1326 Date.prototype.getWeekOfYear = function() {
1327     // Skip to Thursday of this week
1328     var now = this.getDayOfYear() + (4 - this.getDay());
1329     // Find the first Thursday of the year
1330     var jan1 = new Date(this.getFullYear(), 0, 1);
1331     var then = (7 - jan1.getDay() + 4);
1332     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1333 };
1334
1335 /**
1336  * Whether or not the current date is in a leap year.
1337  * @return {Boolean} True if the current date is in a leap year, else false
1338  */
1339 Date.prototype.isLeapYear = function() {
1340     var year = this.getFullYear();
1341     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1342 };
1343
1344 /**
1345  * Get the first day of the current month, adjusted for leap year.  The returned value
1346  * is the numeric day index within the week (0-6) which can be used in conjunction with
1347  * the {@link #monthNames} array to retrieve the textual day name.
1348  * Example:
1349  *<pre><code>
1350 var dt = new Date('1/10/2007');
1351 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1352 </code></pre>
1353  * @return {Number} The day number (0-6)
1354  */
1355 Date.prototype.getFirstDayOfMonth = function() {
1356     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1357     return (day < 0) ? (day + 7) : day;
1358 };
1359
1360 /**
1361  * Get the last day of the current month, adjusted for leap year.  The returned value
1362  * is the numeric day index within the week (0-6) which can be used in conjunction with
1363  * the {@link #monthNames} array to retrieve the textual day name.
1364  * Example:
1365  *<pre><code>
1366 var dt = new Date('1/10/2007');
1367 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1368 </code></pre>
1369  * @return {Number} The day number (0-6)
1370  */
1371 Date.prototype.getLastDayOfMonth = function() {
1372     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1373     return (day < 0) ? (day + 7) : day;
1374 };
1375
1376
1377 /**
1378  * Get the first date of this date's month
1379  * @return {Date}
1380  */
1381 Date.prototype.getFirstDateOfMonth = function() {
1382     return new Date(this.getFullYear(), this.getMonth(), 1);
1383 };
1384
1385 /**
1386  * Get the last date of this date's month
1387  * @return {Date}
1388  */
1389 Date.prototype.getLastDateOfMonth = function() {
1390     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1391 };
1392 /**
1393  * Get the number of days in the current month, adjusted for leap year.
1394  * @return {Number} The number of days in the month
1395  */
1396 Date.prototype.getDaysInMonth = function() {
1397     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1398     return Date.daysInMonth[this.getMonth()];
1399 };
1400
1401 /**
1402  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1403  * @return {String} 'st, 'nd', 'rd' or 'th'
1404  */
1405 Date.prototype.getSuffix = function() {
1406     switch (this.getDate()) {
1407         case 1:
1408         case 21:
1409         case 31:
1410             return "st";
1411         case 2:
1412         case 22:
1413             return "nd";
1414         case 3:
1415         case 23:
1416             return "rd";
1417         default:
1418             return "th";
1419     }
1420 };
1421
1422 // private
1423 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1424
1425 /**
1426  * An array of textual month names.
1427  * Override these values for international dates, for example...
1428  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1429  * @type Array
1430  * @static
1431  */
1432 Date.monthNames =
1433    ["January",
1434     "February",
1435     "March",
1436     "April",
1437     "May",
1438     "June",
1439     "July",
1440     "August",
1441     "September",
1442     "October",
1443     "November",
1444     "December"];
1445
1446 /**
1447  * An array of textual day names.
1448  * Override these values for international dates, for example...
1449  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1450  * @type Array
1451  * @static
1452  */
1453 Date.dayNames =
1454    ["Sunday",
1455     "Monday",
1456     "Tuesday",
1457     "Wednesday",
1458     "Thursday",
1459     "Friday",
1460     "Saturday"];
1461
1462 // private
1463 Date.y2kYear = 50;
1464 // private
1465 Date.monthNumbers = {
1466     Jan:0,
1467     Feb:1,
1468     Mar:2,
1469     Apr:3,
1470     May:4,
1471     Jun:5,
1472     Jul:6,
1473     Aug:7,
1474     Sep:8,
1475     Oct:9,
1476     Nov:10,
1477     Dec:11};
1478
1479 /**
1480  * Creates and returns a new Date instance with the exact same date value as the called instance.
1481  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1482  * variable will also be changed.  When the intention is to create a new variable that will not
1483  * modify the original instance, you should create a clone.
1484  *
1485  * Example of correctly cloning a date:
1486  * <pre><code>
1487 //wrong way:
1488 var orig = new Date('10/1/2006');
1489 var copy = orig;
1490 copy.setDate(5);
1491 document.write(orig);  //returns 'Thu Oct 05 2006'!
1492
1493 //correct way:
1494 var orig = new Date('10/1/2006');
1495 var copy = orig.clone();
1496 copy.setDate(5);
1497 document.write(orig);  //returns 'Thu Oct 01 2006'
1498 </code></pre>
1499  * @return {Date} The new Date instance
1500  */
1501 Date.prototype.clone = function() {
1502         return new Date(this.getTime());
1503 };
1504
1505 /**
1506  * Clears any time information from this date
1507  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1508  @return {Date} this or the clone
1509  */
1510 Date.prototype.clearTime = function(clone){
1511     if(clone){
1512         return this.clone().clearTime();
1513     }
1514     this.setHours(0);
1515     this.setMinutes(0);
1516     this.setSeconds(0);
1517     this.setMilliseconds(0);
1518     return this;
1519 };
1520
1521 // private
1522 // safari setMonth is broken
1523 if(Roo.isSafari){
1524     Date.brokenSetMonth = Date.prototype.setMonth;
1525         Date.prototype.setMonth = function(num){
1526                 if(num <= -1){
1527                         var n = Math.ceil(-num);
1528                         var back_year = Math.ceil(n/12);
1529                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1530                         this.setFullYear(this.getFullYear() - back_year);
1531                         return Date.brokenSetMonth.call(this, month);
1532                 } else {
1533                         return Date.brokenSetMonth.apply(this, arguments);
1534                 }
1535         };
1536 }
1537
1538 /** Date interval constant 
1539 * @static 
1540 * @type String */
1541 Date.MILLI = "ms";
1542 /** Date interval constant 
1543 * @static 
1544 * @type String */
1545 Date.SECOND = "s";
1546 /** Date interval constant 
1547 * @static 
1548 * @type String */
1549 Date.MINUTE = "mi";
1550 /** Date interval constant 
1551 * @static 
1552 * @type String */
1553 Date.HOUR = "h";
1554 /** Date interval constant 
1555 * @static 
1556 * @type String */
1557 Date.DAY = "d";
1558 /** Date interval constant 
1559 * @static 
1560 * @type String */
1561 Date.MONTH = "mo";
1562 /** Date interval constant 
1563 * @static 
1564 * @type String */
1565 Date.YEAR = "y";
1566
1567 /**
1568  * Provides a convenient method of performing basic date arithmetic.  This method
1569  * does not modify the Date instance being called - it creates and returns
1570  * a new Date instance containing the resulting date value.
1571  *
1572  * Examples:
1573  * <pre><code>
1574 //Basic usage:
1575 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1576 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1577
1578 //Negative values will subtract correctly:
1579 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1580 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1581
1582 //You can even chain several calls together in one line!
1583 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1584 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1585  </code></pre>
1586  *
1587  * @param {String} interval   A valid date interval enum value
1588  * @param {Number} value      The amount to add to the current date
1589  * @return {Date} The new Date instance
1590  */
1591 Date.prototype.add = function(interval, value){
1592   var d = this.clone();
1593   if (!interval || value === 0) return d;
1594   switch(interval.toLowerCase()){
1595     case Date.MILLI:
1596       d.setMilliseconds(this.getMilliseconds() + value);
1597       break;
1598     case Date.SECOND:
1599       d.setSeconds(this.getSeconds() + value);
1600       break;
1601     case Date.MINUTE:
1602       d.setMinutes(this.getMinutes() + value);
1603       break;
1604     case Date.HOUR:
1605       d.setHours(this.getHours() + value);
1606       break;
1607     case Date.DAY:
1608       d.setDate(this.getDate() + value);
1609       break;
1610     case Date.MONTH:
1611       var day = this.getDate();
1612       if(day > 28){
1613           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1614       }
1615       d.setDate(day);
1616       d.setMonth(this.getMonth() + value);
1617       break;
1618     case Date.YEAR:
1619       d.setFullYear(this.getFullYear() + value);
1620       break;
1621   }
1622   return d;
1623 };/*
1624  * Based on:
1625  * Ext JS Library 1.1.1
1626  * Copyright(c) 2006-2007, Ext JS, LLC.
1627  *
1628  * Originally Released Under LGPL - original licence link has changed is not relivant.
1629  *
1630  * Fork - LGPL
1631  * <script type="text/javascript">
1632  */
1633
1634 Roo.lib.Dom = {
1635     getViewWidth : function(full) {
1636         return full ? this.getDocumentWidth() : this.getViewportWidth();
1637     },
1638
1639     getViewHeight : function(full) {
1640         return full ? this.getDocumentHeight() : this.getViewportHeight();
1641     },
1642
1643     getDocumentHeight: function() {
1644         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1645         return Math.max(scrollHeight, this.getViewportHeight());
1646     },
1647
1648     getDocumentWidth: function() {
1649         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1650         return Math.max(scrollWidth, this.getViewportWidth());
1651     },
1652
1653     getViewportHeight: function() {
1654         var height = self.innerHeight;
1655         var mode = document.compatMode;
1656
1657         if ((mode || Roo.isIE) && !Roo.isOpera) {
1658             height = (mode == "CSS1Compat") ?
1659                      document.documentElement.clientHeight :
1660                      document.body.clientHeight;
1661         }
1662
1663         return height;
1664     },
1665
1666     getViewportWidth: function() {
1667         var width = self.innerWidth;
1668         var mode = document.compatMode;
1669
1670         if (mode || Roo.isIE) {
1671             width = (mode == "CSS1Compat") ?
1672                     document.documentElement.clientWidth :
1673                     document.body.clientWidth;
1674         }
1675         return width;
1676     },
1677
1678     isAncestor : function(p, c) {
1679         p = Roo.getDom(p);
1680         c = Roo.getDom(c);
1681         if (!p || !c) {
1682             return false;
1683         }
1684
1685         if (p.contains && !Roo.isSafari) {
1686             return p.contains(c);
1687         } else if (p.compareDocumentPosition) {
1688             return !!(p.compareDocumentPosition(c) & 16);
1689         } else {
1690             var parent = c.parentNode;
1691             while (parent) {
1692                 if (parent == p) {
1693                     return true;
1694                 }
1695                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1696                     return false;
1697                 }
1698                 parent = parent.parentNode;
1699             }
1700             return false;
1701         }
1702     },
1703
1704     getRegion : function(el) {
1705         return Roo.lib.Region.getRegion(el);
1706     },
1707
1708     getY : function(el) {
1709         return this.getXY(el)[1];
1710     },
1711
1712     getX : function(el) {
1713         return this.getXY(el)[0];
1714     },
1715
1716     getXY : function(el) {
1717         var p, pe, b, scroll, bd = document.body;
1718         el = Roo.getDom(el);
1719         var fly = Roo.lib.AnimBase.fly;
1720         if (el.getBoundingClientRect) {
1721             b = el.getBoundingClientRect();
1722             scroll = fly(document).getScroll();
1723             return [b.left + scroll.left, b.top + scroll.top];
1724         }
1725         var x = 0, y = 0;
1726
1727         p = el;
1728
1729         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1730
1731         while (p) {
1732
1733             x += p.offsetLeft;
1734             y += p.offsetTop;
1735
1736             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1737                 hasAbsolute = true;
1738             }
1739
1740             if (Roo.isGecko) {
1741                 pe = fly(p);
1742
1743                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1744                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1745
1746
1747                 x += bl;
1748                 y += bt;
1749
1750
1751                 if (p != el && pe.getStyle('overflow') != 'visible') {
1752                     x += bl;
1753                     y += bt;
1754                 }
1755             }
1756             p = p.offsetParent;
1757         }
1758
1759         if (Roo.isSafari && hasAbsolute) {
1760             x -= bd.offsetLeft;
1761             y -= bd.offsetTop;
1762         }
1763
1764         if (Roo.isGecko && !hasAbsolute) {
1765             var dbd = fly(bd);
1766             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1767             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1768         }
1769
1770         p = el.parentNode;
1771         while (p && p != bd) {
1772             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1773                 x -= p.scrollLeft;
1774                 y -= p.scrollTop;
1775             }
1776             p = p.parentNode;
1777         }
1778         return [x, y];
1779     },
1780  
1781   
1782
1783
1784     setXY : function(el, xy) {
1785         el = Roo.fly(el, '_setXY');
1786         el.position();
1787         var pts = el.translatePoints(xy);
1788         if (xy[0] !== false) {
1789             el.dom.style.left = pts.left + "px";
1790         }
1791         if (xy[1] !== false) {
1792             el.dom.style.top = pts.top + "px";
1793         }
1794     },
1795
1796     setX : function(el, x) {
1797         this.setXY(el, [x, false]);
1798     },
1799
1800     setY : function(el, y) {
1801         this.setXY(el, [false, y]);
1802     }
1803 };
1804 /*
1805  * Portions of this file are based on pieces of Yahoo User Interface Library
1806  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1807  * YUI licensed under the BSD License:
1808  * http://developer.yahoo.net/yui/license.txt
1809  * <script type="text/javascript">
1810  *
1811  */
1812
1813 Roo.lib.Event = function() {
1814     var loadComplete = false;
1815     var listeners = [];
1816     var unloadListeners = [];
1817     var retryCount = 0;
1818     var onAvailStack = [];
1819     var counter = 0;
1820     var lastError = null;
1821
1822     return {
1823         POLL_RETRYS: 200,
1824         POLL_INTERVAL: 20,
1825         EL: 0,
1826         TYPE: 1,
1827         FN: 2,
1828         WFN: 3,
1829         OBJ: 3,
1830         ADJ_SCOPE: 4,
1831         _interval: null,
1832
1833         startInterval: function() {
1834             if (!this._interval) {
1835                 var self = this;
1836                 var callback = function() {
1837                     self._tryPreloadAttach();
1838                 };
1839                 this._interval = setInterval(callback, this.POLL_INTERVAL);
1840
1841             }
1842         },
1843
1844         onAvailable: function(p_id, p_fn, p_obj, p_override) {
1845             onAvailStack.push({ id:         p_id,
1846                 fn:         p_fn,
1847                 obj:        p_obj,
1848                 override:   p_override,
1849                 checkReady: false    });
1850
1851             retryCount = this.POLL_RETRYS;
1852             this.startInterval();
1853         },
1854
1855
1856         addListener: function(el, eventName, fn) {
1857             el = Roo.getDom(el);
1858             if (!el || !fn) {
1859                 return false;
1860             }
1861
1862             if ("unload" == eventName) {
1863                 unloadListeners[unloadListeners.length] =
1864                 [el, eventName, fn];
1865                 return true;
1866             }
1867
1868             var wrappedFn = function(e) {
1869                 return fn(Roo.lib.Event.getEvent(e));
1870             };
1871
1872             var li = [el, eventName, fn, wrappedFn];
1873
1874             var index = listeners.length;
1875             listeners[index] = li;
1876
1877             this.doAdd(el, eventName, wrappedFn, false);
1878             return true;
1879
1880         },
1881
1882
1883         removeListener: function(el, eventName, fn) {
1884             var i, len;
1885
1886             el = Roo.getDom(el);
1887
1888             if(!fn) {
1889                 return this.purgeElement(el, false, eventName);
1890             }
1891
1892
1893             if ("unload" == eventName) {
1894
1895                 for (i = 0,len = unloadListeners.length; i < len; i++) {
1896                     var li = unloadListeners[i];
1897                     if (li &&
1898                         li[0] == el &&
1899                         li[1] == eventName &&
1900                         li[2] == fn) {
1901                         unloadListeners.splice(i, 1);
1902                         return true;
1903                     }
1904                 }
1905
1906                 return false;
1907             }
1908
1909             var cacheItem = null;
1910
1911
1912             var index = arguments[3];
1913
1914             if ("undefined" == typeof index) {
1915                 index = this._getCacheIndex(el, eventName, fn);
1916             }
1917
1918             if (index >= 0) {
1919                 cacheItem = listeners[index];
1920             }
1921
1922             if (!el || !cacheItem) {
1923                 return false;
1924             }
1925
1926             this.doRemove(el, eventName, cacheItem[this.WFN], false);
1927
1928             delete listeners[index][this.WFN];
1929             delete listeners[index][this.FN];
1930             listeners.splice(index, 1);
1931
1932             return true;
1933
1934         },
1935
1936
1937         getTarget: function(ev, resolveTextNode) {
1938             ev = ev.browserEvent || ev;
1939             var t = ev.target || ev.srcElement;
1940             return this.resolveTextNode(t);
1941         },
1942
1943
1944         resolveTextNode: function(node) {
1945             if (Roo.isSafari && node && 3 == node.nodeType) {
1946                 return node.parentNode;
1947             } else {
1948                 return node;
1949             }
1950         },
1951
1952
1953         getPageX: function(ev) {
1954             ev = ev.browserEvent || ev;
1955             var x = ev.pageX;
1956             if (!x && 0 !== x) {
1957                 x = ev.clientX || 0;
1958
1959                 if (Roo.isIE) {
1960                     x += this.getScroll()[1];
1961                 }
1962             }
1963
1964             return x;
1965         },
1966
1967
1968         getPageY: function(ev) {
1969             ev = ev.browserEvent || ev;
1970             var y = ev.pageY;
1971             if (!y && 0 !== y) {
1972                 y = ev.clientY || 0;
1973
1974                 if (Roo.isIE) {
1975                     y += this.getScroll()[0];
1976                 }
1977             }
1978
1979
1980             return y;
1981         },
1982
1983
1984         getXY: function(ev) {
1985             ev = ev.browserEvent || ev;
1986             return [this.getPageX(ev), this.getPageY(ev)];
1987         },
1988
1989
1990         getRelatedTarget: function(ev) {
1991             ev = ev.browserEvent || ev;
1992             var t = ev.relatedTarget;
1993             if (!t) {
1994                 if (ev.type == "mouseout") {
1995                     t = ev.toElement;
1996                 } else if (ev.type == "mouseover") {
1997                     t = ev.fromElement;
1998                 }
1999             }
2000
2001             return this.resolveTextNode(t);
2002         },
2003
2004
2005         getTime: function(ev) {
2006             ev = ev.browserEvent || ev;
2007             if (!ev.time) {
2008                 var t = new Date().getTime();
2009                 try {
2010                     ev.time = t;
2011                 } catch(ex) {
2012                     this.lastError = ex;
2013                     return t;
2014                 }
2015             }
2016
2017             return ev.time;
2018         },
2019
2020
2021         stopEvent: function(ev) {
2022             this.stopPropagation(ev);
2023             this.preventDefault(ev);
2024         },
2025
2026
2027         stopPropagation: function(ev) {
2028             ev = ev.browserEvent || ev;
2029             if (ev.stopPropagation) {
2030                 ev.stopPropagation();
2031             } else {
2032                 ev.cancelBubble = true;
2033             }
2034         },
2035
2036
2037         preventDefault: function(ev) {
2038             ev = ev.browserEvent || ev;
2039             if(ev.preventDefault) {
2040                 ev.preventDefault();
2041             } else {
2042                 ev.returnValue = false;
2043             }
2044         },
2045
2046
2047         getEvent: function(e) {
2048             var ev = e || window.event;
2049             if (!ev) {
2050                 var c = this.getEvent.caller;
2051                 while (c) {
2052                     ev = c.arguments[0];
2053                     if (ev && Event == ev.constructor) {
2054                         break;
2055                     }
2056                     c = c.caller;
2057                 }
2058             }
2059             return ev;
2060         },
2061
2062
2063         getCharCode: function(ev) {
2064             ev = ev.browserEvent || ev;
2065             return ev.charCode || ev.keyCode || 0;
2066         },
2067
2068
2069         _getCacheIndex: function(el, eventName, fn) {
2070             for (var i = 0,len = listeners.length; i < len; ++i) {
2071                 var li = listeners[i];
2072                 if (li &&
2073                     li[this.FN] == fn &&
2074                     li[this.EL] == el &&
2075                     li[this.TYPE] == eventName) {
2076                     return i;
2077                 }
2078             }
2079
2080             return -1;
2081         },
2082
2083
2084         elCache: {},
2085
2086
2087         getEl: function(id) {
2088             return document.getElementById(id);
2089         },
2090
2091
2092         clearCache: function() {
2093         },
2094
2095
2096         _load: function(e) {
2097             loadComplete = true;
2098             var EU = Roo.lib.Event;
2099
2100
2101             if (Roo.isIE) {
2102                 EU.doRemove(window, "load", EU._load);
2103             }
2104         },
2105
2106
2107         _tryPreloadAttach: function() {
2108
2109             if (this.locked) {
2110                 return false;
2111             }
2112
2113             this.locked = true;
2114
2115
2116             var tryAgain = !loadComplete;
2117             if (!tryAgain) {
2118                 tryAgain = (retryCount > 0);
2119             }
2120
2121
2122             var notAvail = [];
2123             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2124                 var item = onAvailStack[i];
2125                 if (item) {
2126                     var el = this.getEl(item.id);
2127
2128                     if (el) {
2129                         if (!item.checkReady ||
2130                             loadComplete ||
2131                             el.nextSibling ||
2132                             (document && document.body)) {
2133
2134                             var scope = el;
2135                             if (item.override) {
2136                                 if (item.override === true) {
2137                                     scope = item.obj;
2138                                 } else {
2139                                     scope = item.override;
2140                                 }
2141                             }
2142                             item.fn.call(scope, item.obj);
2143                             onAvailStack[i] = null;
2144                         }
2145                     } else {
2146                         notAvail.push(item);
2147                     }
2148                 }
2149             }
2150
2151             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2152
2153             if (tryAgain) {
2154
2155                 this.startInterval();
2156             } else {
2157                 clearInterval(this._interval);
2158                 this._interval = null;
2159             }
2160
2161             this.locked = false;
2162
2163             return true;
2164
2165         },
2166
2167
2168         purgeElement: function(el, recurse, eventName) {
2169             var elListeners = this.getListeners(el, eventName);
2170             if (elListeners) {
2171                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2172                     var l = elListeners[i];
2173                     this.removeListener(el, l.type, l.fn);
2174                 }
2175             }
2176
2177             if (recurse && el && el.childNodes) {
2178                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2179                     this.purgeElement(el.childNodes[i], recurse, eventName);
2180                 }
2181             }
2182         },
2183
2184
2185         getListeners: function(el, eventName) {
2186             var results = [], searchLists;
2187             if (!eventName) {
2188                 searchLists = [listeners, unloadListeners];
2189             } else if (eventName == "unload") {
2190                 searchLists = [unloadListeners];
2191             } else {
2192                 searchLists = [listeners];
2193             }
2194
2195             for (var j = 0; j < searchLists.length; ++j) {
2196                 var searchList = searchLists[j];
2197                 if (searchList && searchList.length > 0) {
2198                     for (var i = 0,len = searchList.length; i < len; ++i) {
2199                         var l = searchList[i];
2200                         if (l && l[this.EL] === el &&
2201                             (!eventName || eventName === l[this.TYPE])) {
2202                             results.push({
2203                                 type:   l[this.TYPE],
2204                                 fn:     l[this.FN],
2205                                 obj:    l[this.OBJ],
2206                                 adjust: l[this.ADJ_SCOPE],
2207                                 index:  i
2208                             });
2209                         }
2210                     }
2211                 }
2212             }
2213
2214             return (results.length) ? results : null;
2215         },
2216
2217
2218         _unload: function(e) {
2219
2220             var EU = Roo.lib.Event, i, j, l, len, index;
2221
2222             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2223                 l = unloadListeners[i];
2224                 if (l) {
2225                     var scope = window;
2226                     if (l[EU.ADJ_SCOPE]) {
2227                         if (l[EU.ADJ_SCOPE] === true) {
2228                             scope = l[EU.OBJ];
2229                         } else {
2230                             scope = l[EU.ADJ_SCOPE];
2231                         }
2232                     }
2233                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2234                     unloadListeners[i] = null;
2235                     l = null;
2236                     scope = null;
2237                 }
2238             }
2239
2240             unloadListeners = null;
2241
2242             if (listeners && listeners.length > 0) {
2243                 j = listeners.length;
2244                 while (j) {
2245                     index = j - 1;
2246                     l = listeners[index];
2247                     if (l) {
2248                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2249                                 l[EU.FN], index);
2250                     }
2251                     j = j - 1;
2252                 }
2253                 l = null;
2254
2255                 EU.clearCache();
2256             }
2257
2258             EU.doRemove(window, "unload", EU._unload);
2259
2260         },
2261
2262
2263         getScroll: function() {
2264             var dd = document.documentElement, db = document.body;
2265             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2266                 return [dd.scrollTop, dd.scrollLeft];
2267             } else if (db) {
2268                 return [db.scrollTop, db.scrollLeft];
2269             } else {
2270                 return [0, 0];
2271             }
2272         },
2273
2274
2275         doAdd: function () {
2276             if (window.addEventListener) {
2277                 return function(el, eventName, fn, capture) {
2278                     el.addEventListener(eventName, fn, (capture));
2279                 };
2280             } else if (window.attachEvent) {
2281                 return function(el, eventName, fn, capture) {
2282                     el.attachEvent("on" + eventName, fn);
2283                 };
2284             } else {
2285                 return function() {
2286                 };
2287             }
2288         }(),
2289
2290
2291         doRemove: function() {
2292             if (window.removeEventListener) {
2293                 return function (el, eventName, fn, capture) {
2294                     el.removeEventListener(eventName, fn, (capture));
2295                 };
2296             } else if (window.detachEvent) {
2297                 return function (el, eventName, fn) {
2298                     el.detachEvent("on" + eventName, fn);
2299                 };
2300             } else {
2301                 return function() {
2302                 };
2303             }
2304         }()
2305     };
2306     
2307 }();
2308 (function() {     
2309    
2310     var E = Roo.lib.Event;
2311     E.on = E.addListener;
2312     E.un = E.removeListener;
2313
2314     if (document && document.body) {
2315         E._load();
2316     } else {
2317         E.doAdd(window, "load", E._load);
2318     }
2319     E.doAdd(window, "unload", E._unload);
2320     E._tryPreloadAttach();
2321 })();
2322
2323 /*
2324  * Portions of this file are based on pieces of Yahoo User Interface Library
2325  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2326  * YUI licensed under the BSD License:
2327  * http://developer.yahoo.net/yui/license.txt
2328  * <script type="text/javascript">
2329  *
2330  */
2331
2332 (function() {
2333     
2334     Roo.lib.Ajax = {
2335         request : function(method, uri, cb, data, options) {
2336             if(options){
2337                 var hs = options.headers;
2338                 if(hs){
2339                     for(var h in hs){
2340                         if(hs.hasOwnProperty(h)){
2341                             this.initHeader(h, hs[h], false);
2342                         }
2343                     }
2344                 }
2345                 if(options.xmlData){
2346                     this.initHeader('Content-Type', 'text/xml', false);
2347                     method = 'POST';
2348                     data = options.xmlData;
2349                 }
2350             }
2351
2352             return this.asyncRequest(method, uri, cb, data);
2353         },
2354
2355         serializeForm : function(form) {
2356             if(typeof form == 'string') {
2357                 form = (document.getElementById(form) || document.forms[form]);
2358             }
2359
2360             var el, name, val, disabled, data = '', hasSubmit = false;
2361             for (var i = 0; i < form.elements.length; i++) {
2362                 el = form.elements[i];
2363                 disabled = form.elements[i].disabled;
2364                 name = form.elements[i].name;
2365                 val = form.elements[i].value;
2366
2367                 if (!disabled && name){
2368                     switch (el.type)
2369                             {
2370                         case 'select-one':
2371                         case 'select-multiple':
2372                             for (var j = 0; j < el.options.length; j++) {
2373                                 if (el.options[j].selected) {
2374                                     if (Roo.isIE) {
2375                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2376                                     }
2377                                     else {
2378                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2379                                     }
2380                                 }
2381                             }
2382                             break;
2383                         case 'radio':
2384                         case 'checkbox':
2385                             if (el.checked) {
2386                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2387                             }
2388                             break;
2389                         case 'file':
2390
2391                         case undefined:
2392
2393                         case 'reset':
2394
2395                         case 'button':
2396
2397                             break;
2398                         case 'submit':
2399                             if(hasSubmit == false) {
2400                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2401                                 hasSubmit = true;
2402                             }
2403                             break;
2404                         default:
2405                             data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2406                             break;
2407                     }
2408                 }
2409             }
2410             data = data.substr(0, data.length - 1);
2411             return data;
2412         },
2413
2414         headers:{},
2415
2416         hasHeaders:false,
2417
2418         useDefaultHeader:true,
2419
2420         defaultPostHeader:'application/x-www-form-urlencoded',
2421
2422         useDefaultXhrHeader:true,
2423
2424         defaultXhrHeader:'XMLHttpRequest',
2425
2426         hasDefaultHeaders:true,
2427
2428         defaultHeaders:{},
2429
2430         poll:{},
2431
2432         timeout:{},
2433
2434         pollInterval:50,
2435
2436         transactionId:0,
2437
2438         setProgId:function(id)
2439         {
2440             this.activeX.unshift(id);
2441         },
2442
2443         setDefaultPostHeader:function(b)
2444         {
2445             this.useDefaultHeader = b;
2446         },
2447
2448         setDefaultXhrHeader:function(b)
2449         {
2450             this.useDefaultXhrHeader = b;
2451         },
2452
2453         setPollingInterval:function(i)
2454         {
2455             if (typeof i == 'number' && isFinite(i)) {
2456                 this.pollInterval = i;
2457             }
2458         },
2459
2460         createXhrObject:function(transactionId)
2461         {
2462             var obj,http;
2463             try
2464             {
2465
2466                 http = new XMLHttpRequest();
2467
2468                 obj = { conn:http, tId:transactionId };
2469             }
2470             catch(e)
2471             {
2472                 for (var i = 0; i < this.activeX.length; ++i) {
2473                     try
2474                     {
2475
2476                         http = new ActiveXObject(this.activeX[i]);
2477
2478                         obj = { conn:http, tId:transactionId };
2479                         break;
2480                     }
2481                     catch(e) {
2482                     }
2483                 }
2484             }
2485             finally
2486             {
2487                 return obj;
2488             }
2489         },
2490
2491         getConnectionObject:function()
2492         {
2493             var o;
2494             var tId = this.transactionId;
2495
2496             try
2497             {
2498                 o = this.createXhrObject(tId);
2499                 if (o) {
2500                     this.transactionId++;
2501                 }
2502             }
2503             catch(e) {
2504             }
2505             finally
2506             {
2507                 return o;
2508             }
2509         },
2510
2511         asyncRequest:function(method, uri, callback, postData)
2512         {
2513             var o = this.getConnectionObject();
2514
2515             if (!o) {
2516                 return null;
2517             }
2518             else {
2519                 o.conn.open(method, uri, true);
2520
2521                 if (this.useDefaultXhrHeader) {
2522                     if (!this.defaultHeaders['X-Requested-With']) {
2523                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2524                     }
2525                 }
2526
2527                 if(postData && this.useDefaultHeader){
2528                     this.initHeader('Content-Type', this.defaultPostHeader);
2529                 }
2530
2531                  if (this.hasDefaultHeaders || this.hasHeaders) {
2532                     this.setHeader(o);
2533                 }
2534
2535                 this.handleReadyState(o, callback);
2536                 o.conn.send(postData || null);
2537
2538                 return o;
2539             }
2540         },
2541
2542         handleReadyState:function(o, callback)
2543         {
2544             var oConn = this;
2545
2546             if (callback && callback.timeout) {
2547                 this.timeout[o.tId] = window.setTimeout(function() {
2548                     oConn.abort(o, callback, true);
2549                 }, callback.timeout);
2550             }
2551
2552             this.poll[o.tId] = window.setInterval(
2553                     function() {
2554                         if (o.conn && o.conn.readyState == 4) {
2555                             window.clearInterval(oConn.poll[o.tId]);
2556                             delete oConn.poll[o.tId];
2557
2558                             if(callback && callback.timeout) {
2559                                 window.clearTimeout(oConn.timeout[o.tId]);
2560                                 delete oConn.timeout[o.tId];
2561                             }
2562
2563                             oConn.handleTransactionResponse(o, callback);
2564                         }
2565                     }
2566                     , this.pollInterval);
2567         },
2568
2569         handleTransactionResponse:function(o, callback, isAbort)
2570         {
2571
2572             if (!callback) {
2573                 this.releaseObject(o);
2574                 return;
2575             }
2576
2577             var httpStatus, responseObject;
2578
2579             try
2580             {
2581                 if (o.conn.status !== undefined && o.conn.status != 0) {
2582                     httpStatus = o.conn.status;
2583                 }
2584                 else {
2585                     httpStatus = 13030;
2586                 }
2587             }
2588             catch(e) {
2589
2590
2591                 httpStatus = 13030;
2592             }
2593
2594             if (httpStatus >= 200 && httpStatus < 300) {
2595                 responseObject = this.createResponseObject(o, callback.argument);
2596                 if (callback.success) {
2597                     if (!callback.scope) {
2598                         callback.success(responseObject);
2599                     }
2600                     else {
2601
2602
2603                         callback.success.apply(callback.scope, [responseObject]);
2604                     }
2605                 }
2606             }
2607             else {
2608                 switch (httpStatus) {
2609
2610                     case 12002:
2611                     case 12029:
2612                     case 12030:
2613                     case 12031:
2614                     case 12152:
2615                     case 13030:
2616                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2617                         if (callback.failure) {
2618                             if (!callback.scope) {
2619                                 callback.failure(responseObject);
2620                             }
2621                             else {
2622                                 callback.failure.apply(callback.scope, [responseObject]);
2623                             }
2624                         }
2625                         break;
2626                     default:
2627                         responseObject = this.createResponseObject(o, callback.argument);
2628                         if (callback.failure) {
2629                             if (!callback.scope) {
2630                                 callback.failure(responseObject);
2631                             }
2632                             else {
2633                                 callback.failure.apply(callback.scope, [responseObject]);
2634                             }
2635                         }
2636                 }
2637             }
2638
2639             this.releaseObject(o);
2640             responseObject = null;
2641         },
2642
2643         createResponseObject:function(o, callbackArg)
2644         {
2645             var obj = {};
2646             var headerObj = {};
2647
2648             try
2649             {
2650                 var headerStr = o.conn.getAllResponseHeaders();
2651                 var header = headerStr.split('\n');
2652                 for (var i = 0; i < header.length; i++) {
2653                     var delimitPos = header[i].indexOf(':');
2654                     if (delimitPos != -1) {
2655                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2656                     }
2657                 }
2658             }
2659             catch(e) {
2660             }
2661
2662             obj.tId = o.tId;
2663             obj.status = o.conn.status;
2664             obj.statusText = o.conn.statusText;
2665             obj.getResponseHeader = headerObj;
2666             obj.getAllResponseHeaders = headerStr;
2667             obj.responseText = o.conn.responseText;
2668             obj.responseXML = o.conn.responseXML;
2669
2670             if (typeof callbackArg !== undefined) {
2671                 obj.argument = callbackArg;
2672             }
2673
2674             return obj;
2675         },
2676
2677         createExceptionObject:function(tId, callbackArg, isAbort)
2678         {
2679             var COMM_CODE = 0;
2680             var COMM_ERROR = 'communication failure';
2681             var ABORT_CODE = -1;
2682             var ABORT_ERROR = 'transaction aborted';
2683
2684             var obj = {};
2685
2686             obj.tId = tId;
2687             if (isAbort) {
2688                 obj.status = ABORT_CODE;
2689                 obj.statusText = ABORT_ERROR;
2690             }
2691             else {
2692                 obj.status = COMM_CODE;
2693                 obj.statusText = COMM_ERROR;
2694             }
2695
2696             if (callbackArg) {
2697                 obj.argument = callbackArg;
2698             }
2699
2700             return obj;
2701         },
2702
2703         initHeader:function(label, value, isDefault)
2704         {
2705             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2706
2707             if (headerObj[label] === undefined) {
2708                 headerObj[label] = value;
2709             }
2710             else {
2711
2712
2713                 headerObj[label] = value + "," + headerObj[label];
2714             }
2715
2716             if (isDefault) {
2717                 this.hasDefaultHeaders = true;
2718             }
2719             else {
2720                 this.hasHeaders = true;
2721             }
2722         },
2723
2724
2725         setHeader:function(o)
2726         {
2727             if (this.hasDefaultHeaders) {
2728                 for (var prop in this.defaultHeaders) {
2729                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2730                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2731                     }
2732                 }
2733             }
2734
2735             if (this.hasHeaders) {
2736                 for (var prop in this.headers) {
2737                     if (this.headers.hasOwnProperty(prop)) {
2738                         o.conn.setRequestHeader(prop, this.headers[prop]);
2739                     }
2740                 }
2741                 this.headers = {};
2742                 this.hasHeaders = false;
2743             }
2744         },
2745
2746         resetDefaultHeaders:function() {
2747             delete this.defaultHeaders;
2748             this.defaultHeaders = {};
2749             this.hasDefaultHeaders = false;
2750         },
2751
2752         abort:function(o, callback, isTimeout)
2753         {
2754             if(this.isCallInProgress(o)) {
2755                 o.conn.abort();
2756                 window.clearInterval(this.poll[o.tId]);
2757                 delete this.poll[o.tId];
2758                 if (isTimeout) {
2759                     delete this.timeout[o.tId];
2760                 }
2761
2762                 this.handleTransactionResponse(o, callback, true);
2763
2764                 return true;
2765             }
2766             else {
2767                 return false;
2768             }
2769         },
2770
2771
2772         isCallInProgress:function(o)
2773         {
2774             if (o && o.conn) {
2775                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2776             }
2777             else {
2778
2779                 return false;
2780             }
2781         },
2782
2783
2784         releaseObject:function(o)
2785         {
2786
2787             o.conn = null;
2788
2789             o = null;
2790         },
2791
2792         activeX:[
2793         'MSXML2.XMLHTTP.3.0',
2794         'MSXML2.XMLHTTP',
2795         'Microsoft.XMLHTTP'
2796         ]
2797
2798
2799     };
2800 })();