roojs-core-debug.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
64
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                 if (Roo.debug) 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      * Map (JS 1.6 compatibility)
849      * @param {Function} function  to call
850      */
851     map : function(fun )
852     {
853         var len = this.length >>> 0;
854         if (typeof fun != "function")
855             throw new TypeError();
856
857         var res = new Array(len);
858         var thisp = arguments[1];
859         for (var i = 0; i < len; i++)
860         {
861             if (i in this)
862                 res[i] = fun.call(thisp, this[i], i, this);
863         }
864
865         return res;
866     }
867     
868 });
869
870
871  /*
872  * Based on:
873  * Ext JS Library 1.1.1
874  * Copyright(c) 2006-2007, Ext JS, LLC.
875  *
876  * Originally Released Under LGPL - original licence link has changed is not relivant.
877  *
878  * Fork - LGPL
879  * <script type="text/javascript">
880  */
881
882 /**
883  * @class Date
884  *
885  * The date parsing and format syntax is a subset of
886  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
887  * supported will provide results equivalent to their PHP versions.
888  *
889  * Following is the list of all currently supported formats:
890  *<pre>
891 Sample date:
892 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
893
894 Format  Output      Description
895 ------  ----------  --------------------------------------------------------------
896   d      10         Day of the month, 2 digits with leading zeros
897   D      Wed        A textual representation of a day, three letters
898   j      10         Day of the month without leading zeros
899   l      Wednesday  A full textual representation of the day of the week
900   S      th         English ordinal day of month suffix, 2 chars (use with j)
901   w      3          Numeric representation of the day of the week
902   z      9          The julian date, or day of the year (0-365)
903   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
904   F      January    A full textual representation of the month
905   m      01         Numeric representation of a month, with leading zeros
906   M      Jan        Month name abbreviation, three letters
907   n      1          Numeric representation of a month, without leading zeros
908   t      31         Number of days in the given month
909   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
910   Y      2007       A full numeric representation of a year, 4 digits
911   y      07         A two digit representation of a year
912   a      pm         Lowercase Ante meridiem and Post meridiem
913   A      PM         Uppercase Ante meridiem and Post meridiem
914   g      3          12-hour format of an hour without leading zeros
915   G      15         24-hour format of an hour without leading zeros
916   h      03         12-hour format of an hour with leading zeros
917   H      15         24-hour format of an hour with leading zeros
918   i      05         Minutes with leading zeros
919   s      01         Seconds, with leading zeros
920   O      -0600      Difference to Greenwich time (GMT) in hours
921   T      CST        Timezone setting of the machine running the code
922   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
923 </pre>
924  *
925  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
926  * <pre><code>
927 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
928 document.write(dt.format('Y-m-d'));                         //2007-01-10
929 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
930 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
931  </code></pre>
932  *
933  * Here are some standard date/time patterns that you might find helpful.  They
934  * are not part of the source of Date.js, but to use them you can simply copy this
935  * block of code into any script that is included after Date.js and they will also become
936  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
937  * <pre><code>
938 Date.patterns = {
939     ISO8601Long:"Y-m-d H:i:s",
940     ISO8601Short:"Y-m-d",
941     ShortDate: "n/j/Y",
942     LongDate: "l, F d, Y",
943     FullDateTime: "l, F d, Y g:i:s A",
944     MonthDay: "F d",
945     ShortTime: "g:i A",
946     LongTime: "g:i:s A",
947     SortableDateTime: "Y-m-d\\TH:i:s",
948     UniversalSortableDateTime: "Y-m-d H:i:sO",
949     YearMonth: "F, Y"
950 };
951 </code></pre>
952  *
953  * Example usage:
954  * <pre><code>
955 var dt = new Date();
956 document.write(dt.format(Date.patterns.ShortDate));
957  </code></pre>
958  */
959
960 /*
961  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
962  * They generate precompiled functions from date formats instead of parsing and
963  * processing the pattern every time you format a date.  These functions are available
964  * on every Date object (any javascript function).
965  *
966  * The original article and download are here:
967  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
968  *
969  */
970  
971  
972  // was in core
973 /**
974  Returns the number of milliseconds between this date and date
975  @param {Date} date (optional) Defaults to now
976  @return {Number} The diff in milliseconds
977  @member Date getElapsed
978  */
979 Date.prototype.getElapsed = function(date) {
980         return Math.abs((date || new Date()).getTime()-this.getTime());
981 };
982 // was in date file..
983
984
985 // private
986 Date.parseFunctions = {count:0};
987 // private
988 Date.parseRegexes = [];
989 // private
990 Date.formatFunctions = {count:0};
991
992 // private
993 Date.prototype.dateFormat = function(format) {
994     if (Date.formatFunctions[format] == null) {
995         Date.createNewFormat(format);
996     }
997     var func = Date.formatFunctions[format];
998     return this[func]();
999 };
1000
1001
1002 /**
1003  * Formats a date given the supplied format string
1004  * @param {String} format The format string
1005  * @return {String} The formatted date
1006  * @method
1007  */
1008 Date.prototype.format = Date.prototype.dateFormat;
1009
1010 // private
1011 Date.createNewFormat = function(format) {
1012     var funcName = "format" + Date.formatFunctions.count++;
1013     Date.formatFunctions[format] = funcName;
1014     var code = "Date.prototype." + funcName + " = function(){return ";
1015     var special = false;
1016     var ch = '';
1017     for (var i = 0; i < format.length; ++i) {
1018         ch = format.charAt(i);
1019         if (!special && ch == "\\") {
1020             special = true;
1021         }
1022         else if (special) {
1023             special = false;
1024             code += "'" + String.escape(ch) + "' + ";
1025         }
1026         else {
1027             code += Date.getFormatCode(ch);
1028         }
1029     }
1030     /** eval:var:zzzzzzzzzzzzz */
1031     eval(code.substring(0, code.length - 3) + ";}");
1032 };
1033
1034 // private
1035 Date.getFormatCode = function(character) {
1036     switch (character) {
1037     case "d":
1038         return "String.leftPad(this.getDate(), 2, '0') + ";
1039     case "D":
1040         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1041     case "j":
1042         return "this.getDate() + ";
1043     case "l":
1044         return "Date.dayNames[this.getDay()] + ";
1045     case "S":
1046         return "this.getSuffix() + ";
1047     case "w":
1048         return "this.getDay() + ";
1049     case "z":
1050         return "this.getDayOfYear() + ";
1051     case "W":
1052         return "this.getWeekOfYear() + ";
1053     case "F":
1054         return "Date.monthNames[this.getMonth()] + ";
1055     case "m":
1056         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1057     case "M":
1058         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1059     case "n":
1060         return "(this.getMonth() + 1) + ";
1061     case "t":
1062         return "this.getDaysInMonth() + ";
1063     case "L":
1064         return "(this.isLeapYear() ? 1 : 0) + ";
1065     case "Y":
1066         return "this.getFullYear() + ";
1067     case "y":
1068         return "('' + this.getFullYear()).substring(2, 4) + ";
1069     case "a":
1070         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1071     case "A":
1072         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1073     case "g":
1074         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1075     case "G":
1076         return "this.getHours() + ";
1077     case "h":
1078         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1079     case "H":
1080         return "String.leftPad(this.getHours(), 2, '0') + ";
1081     case "i":
1082         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1083     case "s":
1084         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1085     case "O":
1086         return "this.getGMTOffset() + ";
1087     case "T":
1088         return "this.getTimezone() + ";
1089     case "Z":
1090         return "(this.getTimezoneOffset() * -60) + ";
1091     default:
1092         return "'" + String.escape(character) + "' + ";
1093     }
1094 };
1095
1096 /**
1097  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1098  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1099  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1100  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1101  * string or the parse operation will fail.
1102  * Example Usage:
1103 <pre><code>
1104 //dt = Fri May 25 2007 (current date)
1105 var dt = new Date();
1106
1107 //dt = Thu May 25 2006 (today's month/day in 2006)
1108 dt = Date.parseDate("2006", "Y");
1109
1110 //dt = Sun Jan 15 2006 (all date parts specified)
1111 dt = Date.parseDate("2006-1-15", "Y-m-d");
1112
1113 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1114 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1115 </code></pre>
1116  * @param {String} input The unparsed date as a string
1117  * @param {String} format The format the date is in
1118  * @return {Date} The parsed date
1119  * @static
1120  */
1121 Date.parseDate = function(input, format) {
1122     if (Date.parseFunctions[format] == null) {
1123         Date.createParser(format);
1124     }
1125     var func = Date.parseFunctions[format];
1126     return Date[func](input);
1127 };
1128 /**
1129  * @private
1130  */
1131 Date.createParser = function(format) {
1132     var funcName = "parse" + Date.parseFunctions.count++;
1133     var regexNum = Date.parseRegexes.length;
1134     var currentGroup = 1;
1135     Date.parseFunctions[format] = funcName;
1136
1137     var code = "Date." + funcName + " = function(input){\n"
1138         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1139         + "var d = new Date();\n"
1140         + "y = d.getFullYear();\n"
1141         + "m = d.getMonth();\n"
1142         + "d = d.getDate();\n"
1143         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1144         + "if (results && results.length > 0) {";
1145     var regex = "";
1146
1147     var special = false;
1148     var ch = '';
1149     for (var i = 0; i < format.length; ++i) {
1150         ch = format.charAt(i);
1151         if (!special && ch == "\\") {
1152             special = true;
1153         }
1154         else if (special) {
1155             special = false;
1156             regex += String.escape(ch);
1157         }
1158         else {
1159             var obj = Date.formatCodeToRegex(ch, currentGroup);
1160             currentGroup += obj.g;
1161             regex += obj.s;
1162             if (obj.g && obj.c) {
1163                 code += obj.c;
1164             }
1165         }
1166     }
1167
1168     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1169         + "{v = new Date(y, m, d, h, i, s);}\n"
1170         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1171         + "{v = new Date(y, m, d, h, i);}\n"
1172         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1173         + "{v = new Date(y, m, d, h);}\n"
1174         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1175         + "{v = new Date(y, m, d);}\n"
1176         + "else if (y >= 0 && m >= 0)\n"
1177         + "{v = new Date(y, m);}\n"
1178         + "else if (y >= 0)\n"
1179         + "{v = new Date(y);}\n"
1180         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1181         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1182         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1183         + ";}";
1184
1185     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1186     /** eval:var:zzzzzzzzzzzzz */
1187     eval(code);
1188 };
1189
1190 // private
1191 Date.formatCodeToRegex = function(character, currentGroup) {
1192     switch (character) {
1193     case "D":
1194         return {g:0,
1195         c:null,
1196         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1197     case "j":
1198         return {g:1,
1199             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1200             s:"(\\d{1,2})"}; // day of month without leading zeroes
1201     case "d":
1202         return {g:1,
1203             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1204             s:"(\\d{2})"}; // day of month with leading zeroes
1205     case "l":
1206         return {g:0,
1207             c:null,
1208             s:"(?:" + Date.dayNames.join("|") + ")"};
1209     case "S":
1210         return {g:0,
1211             c:null,
1212             s:"(?:st|nd|rd|th)"};
1213     case "w":
1214         return {g:0,
1215             c:null,
1216             s:"\\d"};
1217     case "z":
1218         return {g:0,
1219             c:null,
1220             s:"(?:\\d{1,3})"};
1221     case "W":
1222         return {g:0,
1223             c:null,
1224             s:"(?:\\d{2})"};
1225     case "F":
1226         return {g:1,
1227             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1228             s:"(" + Date.monthNames.join("|") + ")"};
1229     case "M":
1230         return {g:1,
1231             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1232             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1233     case "n":
1234         return {g:1,
1235             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1236             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1237     case "m":
1238         return {g:1,
1239             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1240             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1241     case "t":
1242         return {g:0,
1243             c:null,
1244             s:"\\d{1,2}"};
1245     case "L":
1246         return {g:0,
1247             c:null,
1248             s:"(?:1|0)"};
1249     case "Y":
1250         return {g:1,
1251             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1252             s:"(\\d{4})"};
1253     case "y":
1254         return {g:1,
1255             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1256                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1257             s:"(\\d{1,2})"};
1258     case "a":
1259         return {g:1,
1260             c:"if (results[" + currentGroup + "] == 'am') {\n"
1261                 + "if (h == 12) { h = 0; }\n"
1262                 + "} else { if (h < 12) { h += 12; }}",
1263             s:"(am|pm)"};
1264     case "A":
1265         return {g:1,
1266             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1267                 + "if (h == 12) { h = 0; }\n"
1268                 + "} else { if (h < 12) { h += 12; }}",
1269             s:"(AM|PM)"};
1270     case "g":
1271     case "G":
1272         return {g:1,
1273             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1274             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1275     case "h":
1276     case "H":
1277         return {g:1,
1278             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1279             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1280     case "i":
1281         return {g:1,
1282             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1283             s:"(\\d{2})"};
1284     case "s":
1285         return {g:1,
1286             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1287             s:"(\\d{2})"};
1288     case "O":
1289         return {g:1,
1290             c:[
1291                 "o = results[", currentGroup, "];\n",
1292                 "var sn = o.substring(0,1);\n", // get + / - sign
1293                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1294                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1295                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1296                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1297             ].join(""),
1298             s:"([+\-]\\d{4})"};
1299     case "T":
1300         return {g:0,
1301             c:null,
1302             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1303     case "Z":
1304         return {g:1,
1305             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1306                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1307             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1308     default:
1309         return {g:0,
1310             c:null,
1311             s:String.escape(character)};
1312     }
1313 };
1314
1315 /**
1316  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1317  * @return {String} The abbreviated timezone name (e.g. 'CST')
1318  */
1319 Date.prototype.getTimezone = function() {
1320     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1321 };
1322
1323 /**
1324  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1325  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1326  */
1327 Date.prototype.getGMTOffset = function() {
1328     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1329         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1330         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1331 };
1332
1333 /**
1334  * Get the numeric day number of the year, adjusted for leap year.
1335  * @return {Number} 0 through 364 (365 in leap years)
1336  */
1337 Date.prototype.getDayOfYear = function() {
1338     var num = 0;
1339     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1340     for (var i = 0; i < this.getMonth(); ++i) {
1341         num += Date.daysInMonth[i];
1342     }
1343     return num + this.getDate() - 1;
1344 };
1345
1346 /**
1347  * Get the string representation of the numeric week number of the year
1348  * (equivalent to the format specifier 'W').
1349  * @return {String} '00' through '52'
1350  */
1351 Date.prototype.getWeekOfYear = function() {
1352     // Skip to Thursday of this week
1353     var now = this.getDayOfYear() + (4 - this.getDay());
1354     // Find the first Thursday of the year
1355     var jan1 = new Date(this.getFullYear(), 0, 1);
1356     var then = (7 - jan1.getDay() + 4);
1357     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1358 };
1359
1360 /**
1361  * Whether or not the current date is in a leap year.
1362  * @return {Boolean} True if the current date is in a leap year, else false
1363  */
1364 Date.prototype.isLeapYear = function() {
1365     var year = this.getFullYear();
1366     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1367 };
1368
1369 /**
1370  * Get the first day of the current month, adjusted for leap year.  The returned value
1371  * is the numeric day index within the week (0-6) which can be used in conjunction with
1372  * the {@link #monthNames} array to retrieve the textual day name.
1373  * Example:
1374  *<pre><code>
1375 var dt = new Date('1/10/2007');
1376 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1377 </code></pre>
1378  * @return {Number} The day number (0-6)
1379  */
1380 Date.prototype.getFirstDayOfMonth = function() {
1381     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1382     return (day < 0) ? (day + 7) : day;
1383 };
1384
1385 /**
1386  * Get the last day of the current month, adjusted for leap year.  The returned value
1387  * is the numeric day index within the week (0-6) which can be used in conjunction with
1388  * the {@link #monthNames} array to retrieve the textual day name.
1389  * Example:
1390  *<pre><code>
1391 var dt = new Date('1/10/2007');
1392 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1393 </code></pre>
1394  * @return {Number} The day number (0-6)
1395  */
1396 Date.prototype.getLastDayOfMonth = function() {
1397     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1398     return (day < 0) ? (day + 7) : day;
1399 };
1400
1401
1402 /**
1403  * Get the first date of this date's month
1404  * @return {Date}
1405  */
1406 Date.prototype.getFirstDateOfMonth = function() {
1407     return new Date(this.getFullYear(), this.getMonth(), 1);
1408 };
1409
1410 /**
1411  * Get the last date of this date's month
1412  * @return {Date}
1413  */
1414 Date.prototype.getLastDateOfMonth = function() {
1415     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1416 };
1417 /**
1418  * Get the number of days in the current month, adjusted for leap year.
1419  * @return {Number} The number of days in the month
1420  */
1421 Date.prototype.getDaysInMonth = function() {
1422     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1423     return Date.daysInMonth[this.getMonth()];
1424 };
1425
1426 /**
1427  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1428  * @return {String} 'st, 'nd', 'rd' or 'th'
1429  */
1430 Date.prototype.getSuffix = function() {
1431     switch (this.getDate()) {
1432         case 1:
1433         case 21:
1434         case 31:
1435             return "st";
1436         case 2:
1437         case 22:
1438             return "nd";
1439         case 3:
1440         case 23:
1441             return "rd";
1442         default:
1443             return "th";
1444     }
1445 };
1446
1447 // private
1448 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1449
1450 /**
1451  * An array of textual month names.
1452  * Override these values for international dates, for example...
1453  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1454  * @type Array
1455  * @static
1456  */
1457 Date.monthNames =
1458    ["January",
1459     "February",
1460     "March",
1461     "April",
1462     "May",
1463     "June",
1464     "July",
1465     "August",
1466     "September",
1467     "October",
1468     "November",
1469     "December"];
1470
1471 /**
1472  * An array of textual day names.
1473  * Override these values for international dates, for example...
1474  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1475  * @type Array
1476  * @static
1477  */
1478 Date.dayNames =
1479    ["Sunday",
1480     "Monday",
1481     "Tuesday",
1482     "Wednesday",
1483     "Thursday",
1484     "Friday",
1485     "Saturday"];
1486
1487 // private
1488 Date.y2kYear = 50;
1489 // private
1490 Date.monthNumbers = {
1491     Jan:0,
1492     Feb:1,
1493     Mar:2,
1494     Apr:3,
1495     May:4,
1496     Jun:5,
1497     Jul:6,
1498     Aug:7,
1499     Sep:8,
1500     Oct:9,
1501     Nov:10,
1502     Dec:11};
1503
1504 /**
1505  * Creates and returns a new Date instance with the exact same date value as the called instance.
1506  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1507  * variable will also be changed.  When the intention is to create a new variable that will not
1508  * modify the original instance, you should create a clone.
1509  *
1510  * Example of correctly cloning a date:
1511  * <pre><code>
1512 //wrong way:
1513 var orig = new Date('10/1/2006');
1514 var copy = orig;
1515 copy.setDate(5);
1516 document.write(orig);  //returns 'Thu Oct 05 2006'!
1517
1518 //correct way:
1519 var orig = new Date('10/1/2006');
1520 var copy = orig.clone();
1521 copy.setDate(5);
1522 document.write(orig);  //returns 'Thu Oct 01 2006'
1523 </code></pre>
1524  * @return {Date} The new Date instance
1525  */
1526 Date.prototype.clone = function() {
1527         return new Date(this.getTime());
1528 };
1529
1530 /**
1531  * Clears any time information from this date
1532  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1533  @return {Date} this or the clone
1534  */
1535 Date.prototype.clearTime = function(clone){
1536     if(clone){
1537         return this.clone().clearTime();
1538     }
1539     this.setHours(0);
1540     this.setMinutes(0);
1541     this.setSeconds(0);
1542     this.setMilliseconds(0);
1543     return this;
1544 };
1545
1546 // private
1547 // safari setMonth is broken
1548 if(Roo.isSafari){
1549     Date.brokenSetMonth = Date.prototype.setMonth;
1550         Date.prototype.setMonth = function(num){
1551                 if(num <= -1){
1552                         var n = Math.ceil(-num);
1553                         var back_year = Math.ceil(n/12);
1554                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1555                         this.setFullYear(this.getFullYear() - back_year);
1556                         return Date.brokenSetMonth.call(this, month);
1557                 } else {
1558                         return Date.brokenSetMonth.apply(this, arguments);
1559                 }
1560         };
1561 }
1562
1563 /** Date interval constant 
1564 * @static 
1565 * @type String */
1566 Date.MILLI = "ms";
1567 /** Date interval constant 
1568 * @static 
1569 * @type String */
1570 Date.SECOND = "s";
1571 /** Date interval constant 
1572 * @static 
1573 * @type String */
1574 Date.MINUTE = "mi";
1575 /** Date interval constant 
1576 * @static 
1577 * @type String */
1578 Date.HOUR = "h";
1579 /** Date interval constant 
1580 * @static 
1581 * @type String */
1582 Date.DAY = "d";
1583 /** Date interval constant 
1584 * @static 
1585 * @type String */
1586 Date.MONTH = "mo";
1587 /** Date interval constant 
1588 * @static 
1589 * @type String */
1590 Date.YEAR = "y";
1591
1592 /**
1593  * Provides a convenient method of performing basic date arithmetic.  This method
1594  * does not modify the Date instance being called - it creates and returns
1595  * a new Date instance containing the resulting date value.
1596  *
1597  * Examples:
1598  * <pre><code>
1599 //Basic usage:
1600 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1601 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1602
1603 //Negative values will subtract correctly:
1604 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1605 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1606
1607 //You can even chain several calls together in one line!
1608 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1609 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1610  </code></pre>
1611  *
1612  * @param {String} interval   A valid date interval enum value
1613  * @param {Number} value      The amount to add to the current date
1614  * @return {Date} The new Date instance
1615  */
1616 Date.prototype.add = function(interval, value){
1617   var d = this.clone();
1618   if (!interval || value === 0) return d;
1619   switch(interval.toLowerCase()){
1620     case Date.MILLI:
1621       d.setMilliseconds(this.getMilliseconds() + value);
1622       break;
1623     case Date.SECOND:
1624       d.setSeconds(this.getSeconds() + value);
1625       break;
1626     case Date.MINUTE:
1627       d.setMinutes(this.getMinutes() + value);
1628       break;
1629     case Date.HOUR:
1630       d.setHours(this.getHours() + value);
1631       break;
1632     case Date.DAY:
1633       d.setDate(this.getDate() + value);
1634       break;
1635     case Date.MONTH:
1636       var day = this.getDate();
1637       if(day > 28){
1638           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1639       }
1640       d.setDate(day);
1641       d.setMonth(this.getMonth() + value);
1642       break;
1643     case Date.YEAR:
1644       d.setFullYear(this.getFullYear() + value);
1645       break;
1646   }
1647   return d;
1648 };/*
1649  * Based on:
1650  * Ext JS Library 1.1.1
1651  * Copyright(c) 2006-2007, Ext JS, LLC.
1652  *
1653  * Originally Released Under LGPL - original licence link has changed is not relivant.
1654  *
1655  * Fork - LGPL
1656  * <script type="text/javascript">
1657  */
1658
1659 Roo.lib.Dom = {
1660     getViewWidth : function(full) {
1661         return full ? this.getDocumentWidth() : this.getViewportWidth();
1662     },
1663
1664     getViewHeight : function(full) {
1665         return full ? this.getDocumentHeight() : this.getViewportHeight();
1666     },
1667
1668     getDocumentHeight: function() {
1669         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1670         return Math.max(scrollHeight, this.getViewportHeight());
1671     },
1672
1673     getDocumentWidth: function() {
1674         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1675         return Math.max(scrollWidth, this.getViewportWidth());
1676     },
1677
1678     getViewportHeight: function() {
1679         var height = self.innerHeight;
1680         var mode = document.compatMode;
1681
1682         if ((mode || Roo.isIE) && !Roo.isOpera) {
1683             height = (mode == "CSS1Compat") ?
1684                      document.documentElement.clientHeight :
1685                      document.body.clientHeight;
1686         }
1687
1688         return height;
1689     },
1690
1691     getViewportWidth: function() {
1692         var width = self.innerWidth;
1693         var mode = document.compatMode;
1694
1695         if (mode || Roo.isIE) {
1696             width = (mode == "CSS1Compat") ?
1697                     document.documentElement.clientWidth :
1698                     document.body.clientWidth;
1699         }
1700         return width;
1701     },
1702
1703     isAncestor : function(p, c) {
1704         p = Roo.getDom(p);
1705         c = Roo.getDom(c);
1706         if (!p || !c) {
1707             return false;
1708         }
1709
1710         if (p.contains && !Roo.isSafari) {
1711             return p.contains(c);
1712         } else if (p.compareDocumentPosition) {
1713             return !!(p.compareDocumentPosition(c) & 16);
1714         } else {
1715             var parent = c.parentNode;
1716             while (parent) {
1717                 if (parent == p) {
1718                     return true;
1719                 }
1720                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1721                     return false;
1722                 }
1723                 parent = parent.parentNode;
1724             }
1725             return false;
1726         }
1727     },
1728
1729     getRegion : function(el) {
1730         return Roo.lib.Region.getRegion(el);
1731     },
1732
1733     getY : function(el) {
1734         return this.getXY(el)[1];
1735     },
1736
1737     getX : function(el) {
1738         return this.getXY(el)[0];
1739     },
1740
1741     getXY : function(el) {
1742         var p, pe, b, scroll, bd = document.body;
1743         el = Roo.getDom(el);
1744         var fly = Roo.lib.AnimBase.fly;
1745         if (el.getBoundingClientRect) {
1746             b = el.getBoundingClientRect();
1747             scroll = fly(document).getScroll();
1748             return [b.left + scroll.left, b.top + scroll.top];
1749         }
1750         var x = 0, y = 0;
1751
1752         p = el;
1753
1754         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1755
1756         while (p) {
1757
1758             x += p.offsetLeft;
1759             y += p.offsetTop;
1760
1761             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1762                 hasAbsolute = true;
1763             }
1764
1765             if (Roo.isGecko) {
1766                 pe = fly(p);
1767
1768                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1769                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1770
1771
1772                 x += bl;
1773                 y += bt;
1774
1775
1776                 if (p != el && pe.getStyle('overflow') != 'visible') {
1777                     x += bl;
1778                     y += bt;
1779                 }
1780             }
1781             p = p.offsetParent;
1782         }
1783
1784         if (Roo.isSafari && hasAbsolute) {
1785             x -= bd.offsetLeft;
1786             y -= bd.offsetTop;
1787         }
1788
1789         if (Roo.isGecko && !hasAbsolute) {
1790             var dbd = fly(bd);
1791             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1792             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1793         }
1794
1795         p = el.parentNode;
1796         while (p && p != bd) {
1797             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1798                 x -= p.scrollLeft;
1799                 y -= p.scrollTop;
1800             }
1801             p = p.parentNode;
1802         }
1803         return [x, y];
1804     },
1805  
1806   
1807
1808
1809     setXY : function(el, xy) {
1810         el = Roo.fly(el, '_setXY');
1811         el.position();
1812         var pts = el.translatePoints(xy);
1813         if (xy[0] !== false) {
1814             el.dom.style.left = pts.left + "px";
1815         }
1816         if (xy[1] !== false) {
1817             el.dom.style.top = pts.top + "px";
1818         }
1819     },
1820
1821     setX : function(el, x) {
1822         this.setXY(el, [x, false]);
1823     },
1824
1825     setY : function(el, y) {
1826         this.setXY(el, [false, y]);
1827     }
1828 };
1829 /*
1830  * Portions of this file are based on pieces of Yahoo User Interface Library
1831  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1832  * YUI licensed under the BSD License:
1833  * http://developer.yahoo.net/yui/license.txt
1834  * <script type="text/javascript">
1835  *
1836  */
1837
1838 Roo.lib.Event = function() {
1839     var loadComplete = false;
1840     var listeners = [];
1841     var unloadListeners = [];
1842     var retryCount = 0;
1843     var onAvailStack = [];
1844     var counter = 0;
1845     var lastError = null;
1846
1847     return {
1848         POLL_RETRYS: 200,
1849         POLL_INTERVAL: 20,
1850         EL: 0,
1851         TYPE: 1,
1852         FN: 2,
1853         WFN: 3,
1854         OBJ: 3,
1855         ADJ_SCOPE: 4,
1856         _interval: null,
1857
1858         startInterval: function() {
1859             if (!this._interval) {
1860                 var self = this;
1861                 var callback = function() {
1862                     self._tryPreloadAttach();
1863                 };
1864                 this._interval = setInterval(callback, this.POLL_INTERVAL);
1865
1866             }
1867         },
1868
1869         onAvailable: function(p_id, p_fn, p_obj, p_override) {
1870             onAvailStack.push({ id:         p_id,
1871                 fn:         p_fn,
1872                 obj:        p_obj,
1873                 override:   p_override,
1874                 checkReady: false    });
1875
1876             retryCount = this.POLL_RETRYS;
1877             this.startInterval();
1878         },
1879
1880
1881         addListener: function(el, eventName, fn) {
1882             el = Roo.getDom(el);
1883             if (!el || !fn) {
1884                 return false;
1885             }
1886
1887             if ("unload" == eventName) {
1888                 unloadListeners[unloadListeners.length] =
1889                 [el, eventName, fn];
1890                 return true;
1891             }
1892
1893             var wrappedFn = function(e) {
1894                 return fn(Roo.lib.Event.getEvent(e));
1895             };
1896
1897             var li = [el, eventName, fn, wrappedFn];
1898
1899             var index = listeners.length;
1900             listeners[index] = li;
1901
1902             this.doAdd(el, eventName, wrappedFn, false);
1903             return true;
1904
1905         },
1906
1907
1908         removeListener: function(el, eventName, fn) {
1909             var i, len;
1910
1911             el = Roo.getDom(el);
1912
1913             if(!fn) {
1914                 return this.purgeElement(el, false, eventName);
1915             }
1916
1917
1918             if ("unload" == eventName) {
1919
1920                 for (i = 0,len = unloadListeners.length; i < len; i++) {
1921                     var li = unloadListeners[i];
1922                     if (li &&
1923                         li[0] == el &&
1924                         li[1] == eventName &&
1925                         li[2] == fn) {
1926                         unloadListeners.splice(i, 1);
1927                         return true;
1928                     }
1929                 }
1930
1931                 return false;
1932             }
1933
1934             var cacheItem = null;
1935
1936
1937             var index = arguments[3];
1938
1939             if ("undefined" == typeof index) {
1940                 index = this._getCacheIndex(el, eventName, fn);
1941             }
1942
1943             if (index >= 0) {
1944                 cacheItem = listeners[index];
1945             }
1946
1947             if (!el || !cacheItem) {
1948                 return false;
1949             }
1950
1951             this.doRemove(el, eventName, cacheItem[this.WFN], false);
1952
1953             delete listeners[index][this.WFN];
1954             delete listeners[index][this.FN];
1955             listeners.splice(index, 1);
1956
1957             return true;
1958
1959         },
1960
1961
1962         getTarget: function(ev, resolveTextNode) {
1963             ev = ev.browserEvent || ev;
1964             var t = ev.target || ev.srcElement;
1965             return this.resolveTextNode(t);
1966         },
1967
1968
1969         resolveTextNode: function(node) {
1970             if (Roo.isSafari && node && 3 == node.nodeType) {
1971                 return node.parentNode;
1972             } else {
1973                 return node;
1974             }
1975         },
1976
1977
1978         getPageX: function(ev) {
1979             ev = ev.browserEvent || ev;
1980             var x = ev.pageX;
1981             if (!x && 0 !== x) {
1982                 x = ev.clientX || 0;
1983
1984                 if (Roo.isIE) {
1985                     x += this.getScroll()[1];
1986                 }
1987             }
1988
1989             return x;
1990         },
1991
1992
1993         getPageY: function(ev) {
1994             ev = ev.browserEvent || ev;
1995             var y = ev.pageY;
1996             if (!y && 0 !== y) {
1997                 y = ev.clientY || 0;
1998
1999                 if (Roo.isIE) {
2000                     y += this.getScroll()[0];
2001                 }
2002             }
2003
2004
2005             return y;
2006         },
2007
2008
2009         getXY: function(ev) {
2010             ev = ev.browserEvent || ev;
2011             return [this.getPageX(ev), this.getPageY(ev)];
2012         },
2013
2014
2015         getRelatedTarget: function(ev) {
2016             ev = ev.browserEvent || ev;
2017             var t = ev.relatedTarget;
2018             if (!t) {
2019                 if (ev.type == "mouseout") {
2020                     t = ev.toElement;
2021                 } else if (ev.type == "mouseover") {
2022                     t = ev.fromElement;
2023                 }
2024             }
2025
2026             return this.resolveTextNode(t);
2027         },
2028
2029
2030         getTime: function(ev) {
2031             ev = ev.browserEvent || ev;
2032             if (!ev.time) {
2033                 var t = new Date().getTime();
2034                 try {
2035                     ev.time = t;
2036                 } catch(ex) {
2037                     this.lastError = ex;
2038                     return t;
2039                 }
2040             }
2041
2042             return ev.time;
2043         },
2044
2045
2046         stopEvent: function(ev) {
2047             this.stopPropagation(ev);
2048             this.preventDefault(ev);
2049         },
2050
2051
2052         stopPropagation: function(ev) {
2053             ev = ev.browserEvent || ev;
2054             if (ev.stopPropagation) {
2055                 ev.stopPropagation();
2056             } else {
2057                 ev.cancelBubble = true;
2058             }
2059         },
2060
2061
2062         preventDefault: function(ev) {
2063             ev = ev.browserEvent || ev;
2064             if(ev.preventDefault) {
2065                 ev.preventDefault();
2066             } else {
2067                 ev.returnValue = false;
2068             }
2069         },
2070
2071
2072         getEvent: function(e) {
2073             var ev = e || window.event;
2074             if (!ev) {
2075                 var c = this.getEvent.caller;
2076                 while (c) {
2077                     ev = c.arguments[0];
2078                     if (ev && Event == ev.constructor) {
2079                         break;
2080                     }
2081                     c = c.caller;
2082                 }
2083             }
2084             return ev;
2085         },
2086
2087
2088         getCharCode: function(ev) {
2089             ev = ev.browserEvent || ev;
2090             return ev.charCode || ev.keyCode || 0;
2091         },
2092
2093
2094         _getCacheIndex: function(el, eventName, fn) {
2095             for (var i = 0,len = listeners.length; i < len; ++i) {
2096                 var li = listeners[i];
2097                 if (li &&
2098                     li[this.FN] == fn &&
2099                     li[this.EL] == el &&
2100                     li[this.TYPE] == eventName) {
2101                     return i;
2102                 }
2103             }
2104
2105             return -1;
2106         },
2107
2108
2109         elCache: {},
2110
2111
2112         getEl: function(id) {
2113             return document.getElementById(id);
2114         },
2115
2116
2117         clearCache: function() {
2118         },
2119
2120
2121         _load: function(e) {
2122             loadComplete = true;
2123             var EU = Roo.lib.Event;
2124
2125
2126             if (Roo.isIE) {
2127                 EU.doRemove(window, "load", EU._load);
2128             }
2129         },
2130
2131
2132         _tryPreloadAttach: function() {
2133
2134             if (this.locked) {
2135                 return false;
2136             }
2137
2138             this.locked = true;
2139
2140
2141             var tryAgain = !loadComplete;
2142             if (!tryAgain) {
2143                 tryAgain = (retryCount > 0);
2144             }
2145
2146
2147             var notAvail = [];
2148             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2149                 var item = onAvailStack[i];
2150                 if (item) {
2151                     var el = this.getEl(item.id);
2152
2153                     if (el) {
2154                         if (!item.checkReady ||
2155                             loadComplete ||
2156                             el.nextSibling ||
2157                             (document && document.body)) {
2158
2159                             var scope = el;
2160                             if (item.override) {
2161                                 if (item.override === true) {
2162                                     scope = item.obj;
2163                                 } else {
2164                                     scope = item.override;
2165                                 }
2166                             }
2167                             item.fn.call(scope, item.obj);
2168                             onAvailStack[i] = null;
2169                         }
2170                     } else {
2171                         notAvail.push(item);
2172                     }
2173                 }
2174             }
2175
2176             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2177
2178             if (tryAgain) {
2179
2180                 this.startInterval();
2181             } else {
2182                 clearInterval(this._interval);
2183                 this._interval = null;
2184             }
2185
2186             this.locked = false;
2187
2188             return true;
2189
2190         },
2191
2192
2193         purgeElement: function(el, recurse, eventName) {
2194             var elListeners = this.getListeners(el, eventName);
2195             if (elListeners) {
2196                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2197                     var l = elListeners[i];
2198                     this.removeListener(el, l.type, l.fn);
2199                 }
2200             }
2201
2202             if (recurse && el && el.childNodes) {
2203                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2204                     this.purgeElement(el.childNodes[i], recurse, eventName);
2205                 }
2206             }
2207         },
2208
2209
2210         getListeners: function(el, eventName) {
2211             var results = [], searchLists;
2212             if (!eventName) {
2213                 searchLists = [listeners, unloadListeners];
2214             } else if (eventName == "unload") {
2215                 searchLists = [unloadListeners];
2216             } else {
2217                 searchLists = [listeners];
2218             }
2219
2220             for (var j = 0; j < searchLists.length; ++j) {
2221                 var searchList = searchLists[j];
2222                 if (searchList && searchList.length > 0) {
2223                     for (var i = 0,len = searchList.length; i < len; ++i) {
2224                         var l = searchList[i];
2225                         if (l && l[this.EL] === el &&
2226                             (!eventName || eventName === l[this.TYPE])) {
2227                             results.push({
2228                                 type:   l[this.TYPE],
2229                                 fn:     l[this.FN],
2230                                 obj:    l[this.OBJ],
2231                                 adjust: l[this.ADJ_SCOPE],
2232                                 index:  i
2233                             });
2234                         }
2235                     }
2236                 }
2237             }
2238
2239             return (results.length) ? results : null;
2240         },
2241
2242
2243         _unload: function(e) {
2244
2245             var EU = Roo.lib.Event, i, j, l, len, index;
2246
2247             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2248                 l = unloadListeners[i];
2249                 if (l) {
2250                     var scope = window;
2251                     if (l[EU.ADJ_SCOPE]) {
2252                         if (l[EU.ADJ_SCOPE] === true) {
2253                             scope = l[EU.OBJ];
2254                         } else {
2255                             scope = l[EU.ADJ_SCOPE];
2256                         }
2257                     }
2258                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2259                     unloadListeners[i] = null;
2260                     l = null;
2261                     scope = null;
2262                 }
2263             }
2264
2265             unloadListeners = null;
2266
2267             if (listeners && listeners.length > 0) {
2268                 j = listeners.length;
2269                 while (j) {
2270                     index = j - 1;
2271                     l = listeners[index];
2272                     if (l) {
2273                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2274                                 l[EU.FN], index);
2275                     }
2276                     j = j - 1;
2277                 }
2278                 l = null;
2279
2280                 EU.clearCache();
2281             }
2282
2283             EU.doRemove(window, "unload", EU._unload);
2284
2285         },
2286
2287
2288         getScroll: function() {
2289             var dd = document.documentElement, db = document.body;
2290             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2291                 return [dd.scrollTop, dd.scrollLeft];
2292             } else if (db) {
2293                 return [db.scrollTop, db.scrollLeft];
2294             } else {
2295                 return [0, 0];
2296             }
2297         },
2298
2299
2300         doAdd: function () {
2301             if (window.addEventListener) {
2302                 return function(el, eventName, fn, capture) {
2303                     el.addEventListener(eventName, fn, (capture));
2304                 };
2305             } else if (window.attachEvent) {
2306                 return function(el, eventName, fn, capture) {
2307                     el.attachEvent("on" + eventName, fn);
2308                 };
2309             } else {
2310                 return function() {
2311                 };
2312             }
2313         }(),
2314
2315
2316         doRemove: function() {
2317             if (window.removeEventListener) {
2318                 return function (el, eventName, fn, capture) {
2319                     el.removeEventListener(eventName, fn, (capture));
2320                 };
2321             } else if (window.detachEvent) {
2322                 return function (el, eventName, fn) {
2323                     el.detachEvent("on" + eventName, fn);
2324                 };
2325             } else {
2326                 return function() {
2327                 };
2328             }
2329         }()
2330     };
2331     
2332 }();
2333 (function() {     
2334    
2335     var E = Roo.lib.Event;
2336     E.on = E.addListener;
2337     E.un = E.removeListener;
2338
2339     if (document && document.body) {
2340         E._load();
2341     } else {
2342         E.doAdd(window, "load", E._load);
2343     }
2344     E.doAdd(window, "unload", E._unload);
2345     E._tryPreloadAttach();
2346 })();
2347
2348 /*
2349  * Portions of this file are based on pieces of Yahoo User Interface Library
2350  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2351  * YUI licensed under the BSD License:
2352  * http://developer.yahoo.net/yui/license.txt
2353  * <script type="text/javascript">
2354  *
2355  */
2356
2357 (function() {
2358     
2359     Roo.lib.Ajax = {
2360         request : function(method, uri, cb, data, options) {
2361             if(options){
2362                 var hs = options.headers;
2363                 if(hs){
2364                     for(var h in hs){
2365                         if(hs.hasOwnProperty(h)){
2366                             this.initHeader(h, hs[h], false);
2367                         }
2368                     }
2369                 }
2370                 if(options.xmlData){
2371                     this.initHeader('Content-Type', 'text/xml', false);
2372                     method = 'POST';
2373                     data = options.xmlData;
2374                 }
2375             }
2376
2377             return this.asyncRequest(method, uri, cb, data);
2378         },
2379
2380         serializeForm : function(form) {
2381             if(typeof form == 'string') {
2382                 form = (document.getElementById(form) || document.forms[form]);
2383             }
2384
2385             var el, name, val, disabled, data = '', hasSubmit = false;
2386             for (var i = 0; i < form.elements.length; i++) {
2387                 el = form.elements[i];
2388                 disabled = form.elements[i].disabled;
2389                 name = form.elements[i].name;
2390                 val = form.elements[i].value;
2391
2392                 if (!disabled && name){
2393                     switch (el.type)
2394                             {
2395                         case 'select-one':
2396                         case 'select-multiple':
2397                             for (var j = 0; j < el.options.length; j++) {
2398                                 if (el.options[j].selected) {
2399                                     if (Roo.isIE) {
2400                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2401                                     }
2402                                     else {
2403                                         data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2404                                     }
2405                                 }
2406                             }
2407                             break;
2408                         case 'radio':
2409                         case 'checkbox':
2410                             if (el.checked) {
2411                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2412                             }
2413                             break;
2414                         case 'file':
2415
2416                         case undefined:
2417
2418                         case 'reset':
2419
2420                         case 'button':
2421
2422                             break;
2423                         case 'submit':
2424                             if(hasSubmit == false) {
2425                                 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2426                                 hasSubmit = true;
2427                             }
2428                             break;
2429                         default:
2430                             data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2431                             break;
2432                     }
2433                 }
2434             }
2435             data = data.substr(0, data.length - 1);
2436             return data;
2437         },
2438
2439         headers:{},
2440
2441         hasHeaders:false,
2442
2443         useDefaultHeader:true,
2444
2445         defaultPostHeader:'application/x-www-form-urlencoded',
2446
2447         useDefaultXhrHeader:true,
2448
2449         defaultXhrHeader:'XMLHttpRequest',
2450
2451         hasDefaultHeaders:true,
2452
2453         defaultHeaders:{},
2454
2455         poll:{},
2456
2457         timeout:{},
2458
2459         pollInterval:50,
2460
2461         transactionId:0,
2462
2463         setProgId:function(id)
2464         {
2465             this.activeX.unshift(id);
2466         },
2467
2468         setDefaultPostHeader:function(b)
2469         {
2470             this.useDefaultHeader = b;
2471         },
2472
2473         setDefaultXhrHeader:function(b)
2474         {
2475             this.useDefaultXhrHeader = b;
2476         },
2477
2478         setPollingInterval:function(i)
2479         {
2480             if (typeof i == 'number' && isFinite(i)) {
2481                 this.pollInterval = i;
2482             }
2483         },
2484
2485         createXhrObject:function(transactionId)
2486         {
2487             var obj,http;
2488             try
2489             {
2490
2491                 http = new XMLHttpRequest();
2492
2493                 obj = { conn:http, tId:transactionId };
2494             }
2495             catch(e)
2496             {
2497                 for (var i = 0; i < this.activeX.length; ++i) {
2498                     try
2499                     {
2500
2501                         http = new ActiveXObject(this.activeX[i]);
2502
2503                         obj = { conn:http, tId:transactionId };
2504                         break;
2505                     }
2506                     catch(e) {
2507                     }
2508                 }
2509             }
2510             finally
2511             {
2512                 return obj;
2513             }
2514         },
2515
2516         getConnectionObject:function()
2517         {
2518             var o;
2519             var tId = this.transactionId;
2520
2521             try
2522             {
2523                 o = this.createXhrObject(tId);
2524                 if (o) {
2525                     this.transactionId++;
2526                 }
2527             }
2528             catch(e) {
2529             }
2530             finally
2531             {
2532                 return o;
2533             }
2534         },
2535
2536         asyncRequest:function(method, uri, callback, postData)
2537         {
2538             var o = this.getConnectionObject();
2539
2540             if (!o) {
2541                 return null;
2542             }
2543             else {
2544                 o.conn.open(method, uri, true);
2545
2546                 if (this.useDefaultXhrHeader) {
2547                     if (!this.defaultHeaders['X-Requested-With']) {
2548                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2549                     }
2550                 }
2551
2552                 if(postData && this.useDefaultHeader){
2553                     this.initHeader('Content-Type', this.defaultPostHeader);
2554                 }
2555
2556                  if (this.hasDefaultHeaders || this.hasHeaders) {
2557                     this.setHeader(o);
2558                 }
2559
2560                 this.handleReadyState(o, callback);
2561                 o.conn.send(postData || null);
2562
2563                 return o;
2564             }
2565         },
2566
2567         handleReadyState:function(o, callback)
2568         {
2569             var oConn = this;
2570
2571             if (callback && callback.timeout) {
2572                 this.timeout[o.tId] = window.setTimeout(function() {
2573                     oConn.abort(o, callback, true);
2574                 }, callback.timeout);
2575             }
2576
2577             this.poll[o.tId] = window.setInterval(
2578                     function() {
2579                         if (o.conn && o.conn.readyState == 4) {
2580                             window.clearInterval(oConn.poll[o.tId]);
2581                             delete oConn.poll[o.tId];
2582
2583                             if(callback && callback.timeout) {
2584                                 window.clearTimeout(oConn.timeout[o.tId]);
2585                                 delete oConn.timeout[o.tId];
2586                             }
2587
2588                             oConn.handleTransactionResponse(o, callback);
2589                         }
2590                     }
2591                     , this.pollInterval);
2592         },
2593
2594         handleTransactionResponse:function(o, callback, isAbort)
2595         {
2596
2597             if (!callback) {
2598                 this.releaseObject(o);
2599                 return;
2600             }
2601
2602             var httpStatus, responseObject;
2603
2604             try
2605             {
2606                 if (o.conn.status !== undefined && o.conn.status != 0) {
2607                     httpStatus = o.conn.status;
2608                 }
2609                 else {
2610                     httpStatus = 13030;
2611                 }
2612             }
2613             catch(e) {
2614
2615
2616                 httpStatus = 13030;
2617             }
2618
2619             if (httpStatus >= 200 && httpStatus < 300) {
2620                 responseObject = this.createResponseObject(o, callback.argument);
2621                 if (callback.success) {
2622                     if (!callback.scope) {
2623                         callback.success(responseObject);
2624                     }
2625                     else {
2626
2627
2628                         callback.success.apply(callback.scope, [responseObject]);
2629                     }
2630                 }
2631             }
2632             else {
2633                 switch (httpStatus) {
2634
2635                     case 12002:
2636                     case 12029:
2637                     case 12030:
2638                     case 12031:
2639                     case 12152:
2640                     case 13030:
2641                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2642                         if (callback.failure) {
2643                             if (!callback.scope) {
2644                                 callback.failure(responseObject);
2645                             }
2646                             else {
2647                                 callback.failure.apply(callback.scope, [responseObject]);
2648                             }
2649                         }
2650                         break;
2651                     default:
2652                         responseObject = this.createResponseObject(o, callback.argument);
2653                         if (callback.failure) {
2654                             if (!callback.scope) {
2655                                 callback.failure(responseObject);
2656                             }
2657                             else {
2658                                 callback.failure.apply(callback.scope, [responseObject]);
2659                             }
2660                         }
2661                 }
2662             }
2663
2664             this.releaseObject(o);
2665             responseObject = null;
2666         },
2667
2668         createResponseObject:function(o, callbackArg)
2669         {
2670             var obj = {};
2671             var headerObj = {};
2672
2673             try
2674             {
2675                 var headerStr = o.conn.getAllResponseHeaders();
2676                 var header = headerStr.split('\n');
2677                 for (var i = 0; i < header.length; i++) {
2678                     var delimitPos = header[i].indexOf(':');
2679                     if (delimitPos != -1) {
2680                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2681                     }
2682                 }
2683             }
2684             catch(e) {
2685             }
2686
2687             obj.tId = o.tId;
2688             obj.status = o.conn.status;
2689             obj.statusText = o.conn.statusText;
2690             obj.getResponseHeader = headerObj;
2691             obj.getAllResponseHeaders = headerStr;
2692             obj.responseText = o.conn.responseText;
2693             obj.responseXML = o.conn.responseXML;
2694
2695             if (typeof callbackArg !== undefined) {
2696                 obj.argument = callbackArg;
2697             }
2698
2699             return obj;
2700         },
2701
2702         createExceptionObject:function(tId, callbackArg, isAbort)
2703         {
2704             var COMM_CODE = 0;
2705             var COMM_ERROR = 'communication failure';
2706             var ABORT_CODE = -1;
2707             var ABORT_ERROR = 'transaction aborted';
2708
2709             var obj = {};
2710
2711             obj.tId = tId;
2712             if (isAbort) {
2713                 obj.status = ABORT_CODE;
2714                 obj.statusText = ABORT_ERROR;
2715             }
2716             else {
2717                 obj.status = COMM_CODE;
2718                 obj.statusText = COMM_ERROR;
2719             }
2720
2721             if (callbackArg) {
2722                 obj.argument = callbackArg;
2723             }
2724
2725             return obj;
2726         },
2727
2728         initHeader:function(label, value, isDefault)
2729         {
2730             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2731
2732             if (headerObj[label] === undefined) {
2733                 headerObj[label] = value;
2734             }
2735             else {
2736
2737
2738                 headerObj[label] = value + "," + headerObj[label];
2739             }
2740
2741             if (isDefault) {
2742                 this.hasDefaultHeaders = true;
2743             }
2744             else {
2745                 this.hasHeaders = true;
2746             }
2747         },
2748
2749
2750         setHeader:function(o)
2751         {
2752             if (this.hasDefaultHeaders) {
2753                 for (var prop in this.defaultHeaders) {
2754                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2755                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2756                     }
2757                 }
2758             }
2759
2760             if (this.hasHeaders) {
2761                 for (var prop in this.headers) {
2762                     if (this.headers.hasOwnProperty(prop)) {
2763                         o.conn.setRequestHeader(prop, this.headers[prop]);
2764                     }
2765                 }
2766                 this.headers = {};
2767                 this.hasHeaders = false;
2768             }
2769         },
2770
2771         resetDefaultHeaders:function() {
2772             delete this.defaultHeaders;
2773             this.defaultHeaders = {};
2774             this.hasDefaultHeaders = false;
2775         },
2776
2777         abort:function(o, callback, isTimeout)
2778         {
2779             if(this.isCallInProgress(o)) {
2780                 o.conn.abort();
2781                 window.clearInterval(this.poll[o.tId]);
2782                 delete this.poll[o.tId];
2783                 if (isTimeout) {
2784                     delete this.timeout[o.tId];
2785                 }
2786
2787                 this.handleTransactionResponse(o, callback, true);
2788
2789                 return true;
2790             }
2791             else {
2792                 return false;
2793             }
2794         },
2795
2796
2797         isCallInProgress:function(o)
2798         {
2799             if (o && o.conn) {
2800                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2801             }
2802             else {
2803
2804                 return false;
2805             }
2806         },
2807
2808
2809         releaseObject:function(o)
2810         {
2811
2812             o.conn = null;
2813
2814             o = null;
2815         },
2816
2817         activeX:[
2818         'MSXML2.XMLHTTP.3.0',
2819         'MSXML2.XMLHTTP',
2820         'Microsoft.XMLHTTP'
2821         ]
2822
2823
2824     };
2825 })();/*
2826  * Portions of this file are based on pieces of Yahoo User Interface Library
2827  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2828  * YUI licensed under the BSD License:
2829  * http://developer.yahoo.net/yui/license.txt
2830  * <script type="text/javascript">
2831  *
2832  */
2833
2834 Roo.lib.Region = function(t, r, b, l) {
2835     this.top = t;
2836     this[1] = t;
2837     this.right = r;
2838     this.bottom = b;
2839     this.left = l;
2840     this[0] = l;
2841 };
2842
2843
2844 Roo.lib.Region.prototype = {
2845     contains : function(region) {
2846         return ( region.left >= this.left &&
2847                  region.right <= this.right &&
2848                  region.top >= this.top &&
2849                  region.bottom <= this.bottom    );
2850
2851     },
2852
2853     getArea : function() {
2854         return ( (this.bottom - this.top) * (this.right - this.left) );
2855     },
2856
2857     intersect : function(region) {
2858         var t = Math.max(this.top, region.top);
2859         var r = Math.min(this.right, region.right);
2860         var b = Math.min(this.bottom, region.bottom);
2861         var l = Math.max(this.left, region.left);
2862
2863         if (b >= t && r >= l) {
2864             return new Roo.lib.Region(t, r, b, l);
2865         } else {
2866             return null;
2867         }
2868     },
2869     union : function(region) {
2870         var t = Math.min(this.top, region.top);
2871         var r = Math.max(this.right, region.right);
2872         var b = Math.max(this.bottom, region.bottom);
2873         var l = Math.min(this.left, region.left);
2874
2875         return new Roo.lib.Region(t, r, b, l);
2876     },
2877
2878     adjust : function(t, l, b, r) {
2879         this.top += t;
2880         this.left += l;
2881         this.right += r;
2882         this.bottom += b;
2883         return this;
2884     }
2885 };
2886
2887 Roo.lib.Region.getRegion = function(el) {
2888     var p = Roo.lib.Dom.getXY(el);
2889
2890     var t = p[1];
2891     var r = p[0] + el.offsetWidth;
2892     var b = p[1] + el.offsetHeight;
2893     var l = p[0];
2894
2895     return new Roo.lib.Region(t, r, b, l);
2896 };
2897 /*
2898  * Portions of this file are based on pieces of Yahoo User Interface Library
2899  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2900  * YUI licensed under the BSD License:
2901  * http://developer.yahoo.net/yui/license.txt
2902  * <script type="text/javascript">
2903  *
2904  */
2905 //@@dep Roo.lib.Region
2906
2907
2908 Roo.lib.Point = function(x, y) {
2909     if (x instanceof Array) {
2910         y = x[1];
2911         x = x[0];
2912     }
2913     this.x = this.right = this.left = this[0] = x;
2914     this.y = this.top = this.bottom = this[1] = y;
2915 };
2916
2917 Roo.lib.Point.prototype = new Roo.lib.Region();
2918 /*
2919  * Portions of this file are based on pieces of Yahoo User Interface Library
2920  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2921  * YUI licensed under the BSD License:
2922  * http://developer.yahoo.net/yui/license.txt
2923  * <script type="text/javascript">
2924  *
2925  */
2926  
2927 (function() {   
2928
2929     Roo.lib.Anim = {
2930         scroll : function(el, args, duration, easing, cb, scope) {
2931             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2932         },
2933
2934         motion : function(el, args, duration, easing, cb, scope) {
2935             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2936         },
2937
2938         color : function(el, args, duration, easing, cb, scope) {
2939             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2940         },
2941
2942         run : function(el, args, duration, easing, cb, scope, type) {
2943             type = type || Roo.lib.AnimBase;
2944             if (typeof easing == "string") {
2945                 easing = Roo.lib.Easing[easing];
2946             }
2947             var anim = new type(el, args, duration, easing);
2948             anim.animateX(function() {
2949                 Roo.callback(cb, scope);
2950             });
2951             return anim;
2952         }
2953     };
2954 })();/*
2955  * Portions of this file are based on pieces of Yahoo User Interface Library
2956  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2957  * YUI licensed under the BSD License:
2958  * http://developer.yahoo.net/yui/license.txt
2959  * <script type="text/javascript">
2960  *
2961  */
2962
2963 (function() {    
2964     var libFlyweight;
2965     
2966     function fly(el) {
2967         if (!libFlyweight) {
2968             libFlyweight = new Roo.Element.Flyweight();
2969         }
2970         libFlyweight.dom = el;
2971         return libFlyweight;
2972     }
2973
2974     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2975     
2976    
2977     
2978     Roo.lib.AnimBase = function(el, attributes, duration, method) {
2979         if (el) {
2980             this.init(el, attributes, duration, method);
2981         }
2982     };
2983
2984     Roo.lib.AnimBase.fly = fly;
2985     
2986     
2987     
2988     Roo.lib.AnimBase.prototype = {
2989
2990         toString: function() {
2991             var el = this.getEl();
2992             var id = el.id || el.tagName;
2993             return ("Anim " + id);
2994         },
2995
2996         patterns: {
2997             noNegatives:        /width|height|opacity|padding/i,
2998             offsetAttribute:  /^((width|height)|(top|left))$/,
2999             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3000             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3001         },
3002
3003
3004         doMethod: function(attr, start, end) {
3005             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3006         },
3007
3008
3009         setAttribute: function(attr, val, unit) {
3010             if (this.patterns.noNegatives.test(attr)) {
3011                 val = (val > 0) ? val : 0;
3012             }
3013
3014             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3015         },
3016
3017
3018         getAttribute: function(attr) {
3019             var el = this.getEl();
3020             var val = fly(el).getStyle(attr);
3021
3022             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3023                 return parseFloat(val);
3024             }
3025
3026             var a = this.patterns.offsetAttribute.exec(attr) || [];
3027             var pos = !!( a[3] );
3028             var box = !!( a[2] );
3029
3030
3031             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3032                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3033             } else {
3034                 val = 0;
3035             }
3036
3037             return val;
3038         },
3039
3040
3041         getDefaultUnit: function(attr) {
3042             if (this.patterns.defaultUnit.test(attr)) {
3043                 return 'px';
3044             }
3045
3046             return '';
3047         },
3048
3049         animateX : function(callback, scope) {
3050             var f = function() {
3051                 this.onComplete.removeListener(f);
3052                 if (typeof callback == "function") {
3053                     callback.call(scope || this, this);
3054                 }
3055             };
3056             this.onComplete.addListener(f, this);
3057             this.animate();
3058         },
3059
3060
3061         setRuntimeAttribute: function(attr) {
3062             var start;
3063             var end;
3064             var attributes = this.attributes;
3065
3066             this.runtimeAttributes[attr] = {};
3067
3068             var isset = function(prop) {
3069                 return (typeof prop !== 'undefined');
3070             };
3071
3072             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3073                 return false;
3074             }
3075
3076             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3077
3078
3079             if (isset(attributes[attr]['to'])) {
3080                 end = attributes[attr]['to'];
3081             } else if (isset(attributes[attr]['by'])) {
3082                 if (start.constructor == Array) {
3083                     end = [];
3084                     for (var i = 0, len = start.length; i < len; ++i) {
3085                         end[i] = start[i] + attributes[attr]['by'][i];
3086                     }
3087                 } else {
3088                     end = start + attributes[attr]['by'];
3089                 }
3090             }
3091
3092             this.runtimeAttributes[attr].start = start;
3093             this.runtimeAttributes[attr].end = end;
3094
3095
3096             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3097         },
3098
3099
3100         init: function(el, attributes, duration, method) {
3101
3102             var isAnimated = false;
3103
3104
3105             var startTime = null;
3106
3107
3108             var actualFrames = 0;
3109
3110
3111             el = Roo.getDom(el);
3112
3113
3114             this.attributes = attributes || {};
3115
3116
3117             this.duration = duration || 1;
3118
3119
3120             this.method = method || Roo.lib.Easing.easeNone;
3121
3122
3123             this.useSeconds = true;
3124
3125
3126             this.currentFrame = 0;
3127
3128
3129             this.totalFrames = Roo.lib.AnimMgr.fps;
3130
3131
3132             this.getEl = function() {
3133                 return el;
3134             };
3135
3136
3137             this.isAnimated = function() {
3138                 return isAnimated;
3139             };
3140
3141
3142             this.getStartTime = function() {
3143                 return startTime;
3144             };
3145
3146             this.runtimeAttributes = {};
3147
3148
3149             this.animate = function() {
3150                 if (this.isAnimated()) {
3151                     return false;
3152                 }
3153
3154                 this.currentFrame = 0;
3155
3156                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3157
3158                 Roo.lib.AnimMgr.registerElement(this);
3159             };
3160
3161
3162             this.stop = function(finish) {
3163                 if (finish) {
3164                     this.currentFrame = this.totalFrames;
3165                     this._onTween.fire();
3166                 }
3167                 Roo.lib.AnimMgr.stop(this);
3168             };
3169
3170             var onStart = function() {
3171                 this.onStart.fire();
3172
3173                 this.runtimeAttributes = {};
3174                 for (var attr in this.attributes) {
3175                     this.setRuntimeAttribute(attr);
3176                 }
3177
3178                 isAnimated = true;
3179                 actualFrames = 0;
3180                 startTime = new Date();
3181             };
3182
3183
3184             var onTween = function() {
3185                 var data = {
3186                     duration: new Date() - this.getStartTime(),
3187                     currentFrame: this.currentFrame
3188                 };
3189
3190                 data.toString = function() {
3191                     return (
3192                             'duration: ' + data.duration +
3193                             ', currentFrame: ' + data.currentFrame
3194                             );
3195                 };
3196
3197                 this.onTween.fire(data);
3198
3199                 var runtimeAttributes = this.runtimeAttributes;
3200
3201                 for (var attr in runtimeAttributes) {
3202                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3203                 }
3204
3205                 actualFrames += 1;
3206             };
3207
3208             var onComplete = function() {
3209                 var actual_duration = (new Date() - startTime) / 1000 ;
3210
3211                 var data = {
3212                     duration: actual_duration,
3213                     frames: actualFrames,
3214                     fps: actualFrames / actual_duration
3215                 };
3216
3217                 data.toString = function() {
3218                     return (
3219                             'duration: ' + data.duration +
3220                             ', frames: ' + data.frames +
3221                             ', fps: ' + data.fps
3222                             );
3223                 };
3224
3225                 isAnimated = false;
3226                 actualFrames = 0;
3227                 this.onComplete.fire(data);
3228             };
3229
3230
3231             this._onStart = new Roo.util.Event(this);
3232             this.onStart = new Roo.util.Event(this);
3233             this.onTween = new Roo.util.Event(this);
3234             this._onTween = new Roo.util.Event(this);
3235             this.onComplete = new Roo.util.Event(this);
3236             this._onComplete = new Roo.util.Event(this);
3237             this._onStart.addListener(onStart);
3238             this._onTween.addListener(onTween);
3239             this._onComplete.addListener(onComplete);
3240         }
3241     };
3242 })();
3243 /*
3244  * Portions of this file are based on pieces of Yahoo User Interface Library
3245  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3246  * YUI licensed under the BSD License:
3247  * http://developer.yahoo.net/yui/license.txt
3248  * <script type="text/javascript">
3249  *
3250  */
3251
3252 Roo.lib.AnimMgr = new function() {
3253
3254         var thread = null;
3255
3256
3257         var queue = [];
3258
3259
3260         var tweenCount = 0;
3261
3262
3263         this.fps = 1000;
3264
3265
3266         this.delay = 1;
3267
3268
3269         this.registerElement = function(tween) {
3270             queue[queue.length] = tween;
3271             tweenCount += 1;
3272             tween._onStart.fire();
3273             this.start();
3274         };
3275
3276
3277         this.unRegister = function(tween, index) {
3278             tween._onComplete.fire();
3279             index = index || getIndex(tween);
3280             if (index != -1) {
3281                 queue.splice(index, 1);
3282             }
3283
3284             tweenCount -= 1;
3285             if (tweenCount <= 0) {
3286                 this.stop();
3287             }
3288         };
3289
3290
3291         this.start = function() {
3292             if (thread === null) {
3293                 thread = setInterval(this.run, this.delay);
3294             }
3295         };
3296
3297
3298         this.stop = function(tween) {
3299             if (!tween) {
3300                 clearInterval(thread);
3301
3302                 for (var i = 0, len = queue.length; i < len; ++i) {
3303                     if (queue[0].isAnimated()) {
3304                         this.unRegister(queue[0], 0);
3305                     }
3306                 }
3307
3308                 queue = [];
3309                 thread = null;
3310                 tweenCount = 0;
3311             }
3312             else {
3313                 this.unRegister(tween);
3314             }
3315         };
3316
3317
3318         this.run = function() {
3319             for (var i = 0, len = queue.length; i < len; ++i) {
3320                 var tween = queue[i];
3321                 if (!tween || !tween.isAnimated()) {
3322                     continue;
3323                 }
3324
3325                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3326                 {
3327                     tween.currentFrame += 1;
3328
3329                     if (tween.useSeconds) {
3330                         correctFrame(tween);
3331                     }
3332                     tween._onTween.fire();
3333                 }
3334                 else {
3335                     Roo.lib.AnimMgr.stop(tween, i);
3336                 }
3337             }
3338         };
3339
3340         var getIndex = function(anim) {
3341             for (var i = 0, len = queue.length; i < len; ++i) {
3342                 if (queue[i] == anim) {
3343                     return i;
3344                 }
3345             }
3346             return -1;
3347         };
3348
3349
3350         var correctFrame = function(tween) {
3351             var frames = tween.totalFrames;
3352             var frame = tween.currentFrame;
3353             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3354             var elapsed = (new Date() - tween.getStartTime());
3355             var tweak = 0;
3356
3357             if (elapsed < tween.duration * 1000) {
3358                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3359             } else {
3360                 tweak = frames - (frame + 1);
3361             }
3362             if (tweak > 0 && isFinite(tweak)) {
3363                 if (tween.currentFrame + tweak >= frames) {
3364                     tweak = frames - (frame + 1);
3365                 }
3366
3367                 tween.currentFrame += tweak;
3368             }
3369         };
3370     };/*
3371  * Portions of this file are based on pieces of Yahoo User Interface Library
3372  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3373  * YUI licensed under the BSD License:
3374  * http://developer.yahoo.net/yui/license.txt
3375  * <script type="text/javascript">
3376  *
3377  */
3378 Roo.lib.Bezier = new function() {
3379
3380         this.getPosition = function(points, t) {
3381             var n = points.length;
3382             var tmp = [];
3383
3384             for (var i = 0; i < n; ++i) {
3385                 tmp[i] = [points[i][0], points[i][1]];
3386             }
3387
3388             for (var j = 1; j < n; ++j) {
3389                 for (i = 0; i < n - j; ++i) {
3390                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3391                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3392                 }
3393             }
3394
3395             return [ tmp[0][0], tmp[0][1] ];
3396
3397         };
3398     };/*
3399  * Portions of this file are based on pieces of Yahoo User Interface Library
3400  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3401  * YUI licensed under the BSD License:
3402  * http://developer.yahoo.net/yui/license.txt
3403  * <script type="text/javascript">
3404  *
3405  */
3406 (function() {
3407
3408     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3409         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3410     };
3411
3412     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3413
3414     var fly = Roo.lib.AnimBase.fly;
3415     var Y = Roo.lib;
3416     var superclass = Y.ColorAnim.superclass;
3417     var proto = Y.ColorAnim.prototype;
3418
3419     proto.toString = function() {
3420         var el = this.getEl();
3421         var id = el.id || el.tagName;
3422         return ("ColorAnim " + id);
3423     };
3424
3425     proto.patterns.color = /color$/i;
3426     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3427     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3428     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3429     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3430
3431
3432     proto.parseColor = function(s) {
3433         if (s.length == 3) {
3434             return s;
3435         }
3436
3437         var c = this.patterns.hex.exec(s);
3438         if (c && c.length == 4) {
3439             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3440         }
3441
3442         c = this.patterns.rgb.exec(s);
3443         if (c && c.length == 4) {
3444             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3445         }
3446
3447         c = this.patterns.hex3.exec(s);
3448         if (c && c.length == 4) {
3449             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3450         }
3451
3452         return null;
3453     };
3454     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3455     proto.getAttribute = function(attr) {
3456         var el = this.getEl();
3457         if (this.patterns.color.test(attr)) {
3458             var val = fly(el).getStyle(attr);
3459
3460             if (this.patterns.transparent.test(val)) {
3461                 var parent = el.parentNode;
3462                 val = fly(parent).getStyle(attr);
3463
3464                 while (parent && this.patterns.transparent.test(val)) {
3465                     parent = parent.parentNode;
3466                     val = fly(parent).getStyle(attr);
3467                     if (parent.tagName.toUpperCase() == 'HTML') {
3468                         val = '#fff';
3469                     }
3470                 }
3471             }
3472         } else {
3473             val = superclass.getAttribute.call(this, attr);
3474         }
3475
3476         return val;
3477     };
3478     proto.getAttribute = function(attr) {
3479         var el = this.getEl();
3480         if (this.patterns.color.test(attr)) {
3481             var val = fly(el).getStyle(attr);
3482
3483             if (this.patterns.transparent.test(val)) {
3484                 var parent = el.parentNode;
3485                 val = fly(parent).getStyle(attr);
3486
3487                 while (parent && this.patterns.transparent.test(val)) {
3488                     parent = parent.parentNode;
3489                     val = fly(parent).getStyle(attr);
3490                     if (parent.tagName.toUpperCase() == 'HTML') {
3491                         val = '#fff';
3492                     }
3493                 }
3494             }
3495         } else {
3496             val = superclass.getAttribute.call(this, attr);
3497         }
3498
3499         return val;
3500     };
3501
3502     proto.doMethod = function(attr, start, end) {
3503         var val;
3504
3505         if (this.patterns.color.test(attr)) {
3506             val = [];
3507             for (var i = 0, len = start.length; i < len; ++i) {
3508                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3509             }
3510
3511             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3512         }
3513         else {
3514             val = superclass.doMethod.call(this, attr, start, end);
3515         }
3516
3517         return val;
3518     };
3519
3520     proto.setRuntimeAttribute = function(attr) {
3521         superclass.setRuntimeAttribute.call(this, attr);
3522
3523         if (this.patterns.color.test(attr)) {
3524             var attributes = this.attributes;
3525             var start = this.parseColor(this.runtimeAttributes[attr].start);
3526             var end = this.parseColor(this.runtimeAttributes[attr].end);
3527
3528             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3529                 end = this.parseColor(attributes[attr].by);
3530
3531                 for (var i = 0, len = start.length; i < len; ++i) {
3532                     end[i] = start[i] + end[i];
3533                 }
3534             }
3535
3536             this.runtimeAttributes[attr].start = start;
3537             this.runtimeAttributes[attr].end = end;
3538         }
3539     };
3540 })();
3541
3542 /*
3543  * Portions of this file are based on pieces of Yahoo User Interface Library
3544  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3545  * YUI licensed under the BSD License:
3546  * http://developer.yahoo.net/yui/license.txt
3547  * <script type="text/javascript">
3548  *
3549  */
3550 Roo.lib.Easing = {
3551
3552
3553     easeNone: function (t, b, c, d) {
3554         return c * t / d + b;
3555     },
3556
3557
3558     easeIn: function (t, b, c, d) {
3559         return c * (t /= d) * t + b;
3560     },
3561
3562
3563     easeOut: function (t, b, c, d) {
3564         return -c * (t /= d) * (t - 2) + b;
3565     },
3566
3567
3568     easeBoth: function (t, b, c, d) {
3569         if ((t /= d / 2) < 1) {
3570             return c / 2 * t * t + b;
3571         }
3572
3573         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3574     },
3575
3576
3577     easeInStrong: function (t, b, c, d) {
3578         return c * (t /= d) * t * t * t + b;
3579     },
3580
3581
3582     easeOutStrong: function (t, b, c, d) {
3583         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3584     },
3585
3586
3587     easeBothStrong: function (t, b, c, d) {
3588         if ((t /= d / 2) < 1) {
3589             return c / 2 * t * t * t * t + b;
3590         }
3591
3592         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3593     },
3594
3595
3596
3597     elasticIn: function (t, b, c, d, a, p) {
3598         if (t == 0) {
3599             return b;
3600         }
3601         if ((t /= d) == 1) {
3602             return b + c;
3603         }
3604         if (!p) {
3605             p = d * .3;
3606         }
3607
3608         if (!a || a < Math.abs(c)) {
3609             a = c;
3610             var s = p / 4;
3611         }
3612         else {
3613             var s = p / (2 * Math.PI) * Math.asin(c / a);
3614         }
3615
3616         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3617     },
3618
3619
3620     elasticOut: function (t, b, c, d, a, p) {
3621         if (t == 0) {
3622             return b;
3623         }
3624         if ((t /= d) == 1) {
3625             return b + c;
3626         }
3627         if (!p) {
3628             p = d * .3;
3629         }
3630
3631         if (!a || a < Math.abs(c)) {
3632             a = c;
3633             var s = p / 4;
3634         }
3635         else {
3636             var s = p / (2 * Math.PI) * Math.asin(c / a);
3637         }
3638
3639         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3640     },
3641
3642
3643     elasticBoth: function (t, b, c, d, a, p) {
3644         if (t == 0) {
3645             return b;
3646         }
3647
3648         if ((t /= d / 2) == 2) {
3649             return b + c;
3650         }
3651
3652         if (!p) {
3653             p = d * (.3 * 1.5);
3654         }
3655
3656         if (!a || a < Math.abs(c)) {
3657             a = c;
3658             var s = p / 4;
3659         }
3660         else {
3661             var s = p / (2 * Math.PI) * Math.asin(c / a);
3662         }
3663
3664         if (t < 1) {
3665             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3666                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3667         }
3668         return a * Math.pow(2, -10 * (t -= 1)) *
3669                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3670     },
3671
3672
3673
3674     backIn: function (t, b, c, d, s) {
3675         if (typeof s == 'undefined') {
3676             s = 1.70158;
3677         }
3678         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3679     },
3680
3681
3682     backOut: function (t, b, c, d, s) {
3683         if (typeof s == 'undefined') {
3684             s = 1.70158;
3685         }
3686         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3687     },
3688
3689
3690     backBoth: function (t, b, c, d, s) {
3691         if (typeof s == 'undefined') {
3692             s = 1.70158;
3693         }
3694
3695         if ((t /= d / 2 ) < 1) {
3696             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3697         }
3698         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3699     },
3700
3701
3702     bounceIn: function (t, b, c, d) {
3703         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3704     },
3705
3706
3707     bounceOut: function (t, b, c, d) {
3708         if ((t /= d) < (1 / 2.75)) {
3709             return c * (7.5625 * t * t) + b;
3710         } else if (t < (2 / 2.75)) {
3711             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3712         } else if (t < (2.5 / 2.75)) {
3713             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3714         }
3715         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3716     },
3717
3718
3719     bounceBoth: function (t, b, c, d) {
3720         if (t < d / 2) {
3721             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3722         }
3723         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3724     }
3725 };/*
3726  * Portions of this file are based on pieces of Yahoo User Interface Library
3727  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3728  * YUI licensed under the BSD License:
3729  * http://developer.yahoo.net/yui/license.txt
3730  * <script type="text/javascript">
3731  *
3732  */
3733     (function() {
3734         Roo.lib.Motion = function(el, attributes, duration, method) {
3735             if (el) {
3736                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3737             }
3738         };
3739
3740         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3741
3742
3743         var Y = Roo.lib;
3744         var superclass = Y.Motion.superclass;
3745         var proto = Y.Motion.prototype;
3746
3747         proto.toString = function() {
3748             var el = this.getEl();
3749             var id = el.id || el.tagName;
3750             return ("Motion " + id);
3751         };
3752
3753         proto.patterns.points = /^points$/i;
3754
3755         proto.setAttribute = function(attr, val, unit) {
3756             if (this.patterns.points.test(attr)) {
3757                 unit = unit || 'px';
3758                 superclass.setAttribute.call(this, 'left', val[0], unit);
3759                 superclass.setAttribute.call(this, 'top', val[1], unit);
3760             } else {
3761                 superclass.setAttribute.call(this, attr, val, unit);
3762             }
3763         };
3764
3765         proto.getAttribute = function(attr) {
3766             if (this.patterns.points.test(attr)) {
3767                 var val = [
3768                         superclass.getAttribute.call(this, 'left'),
3769                         superclass.getAttribute.call(this, 'top')
3770                         ];
3771             } else {
3772                 val = superclass.getAttribute.call(this, attr);
3773             }
3774
3775             return val;
3776         };
3777
3778         proto.doMethod = function(attr, start, end) {
3779             var val = null;
3780
3781             if (this.patterns.points.test(attr)) {
3782                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3783                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3784             } else {
3785                 val = superclass.doMethod.call(this, attr, start, end);
3786             }
3787             return val;
3788         };
3789
3790         proto.setRuntimeAttribute = function(attr) {
3791             if (this.patterns.points.test(attr)) {
3792                 var el = this.getEl();
3793                 var attributes = this.attributes;
3794                 var start;
3795                 var control = attributes['points']['control'] || [];
3796                 var end;
3797                 var i, len;
3798
3799                 if (control.length > 0 && !(control[0] instanceof Array)) {
3800                     control = [control];
3801                 } else {
3802                     var tmp = [];
3803                     for (i = 0,len = control.length; i < len; ++i) {
3804                         tmp[i] = control[i];
3805                     }
3806                     control = tmp;
3807                 }
3808
3809                 Roo.fly(el).position();
3810
3811                 if (isset(attributes['points']['from'])) {
3812                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3813                 }
3814                 else {
3815                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3816                 }
3817
3818                 start = this.getAttribute('points');
3819
3820
3821                 if (isset(attributes['points']['to'])) {
3822                     end = translateValues.call(this, attributes['points']['to'], start);
3823
3824                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3825                     for (i = 0,len = control.length; i < len; ++i) {
3826                         control[i] = translateValues.call(this, control[i], start);
3827                     }
3828
3829
3830                 } else if (isset(attributes['points']['by'])) {
3831                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3832
3833                     for (i = 0,len = control.length; i < len; ++i) {
3834                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3835                     }
3836                 }
3837
3838                 this.runtimeAttributes[attr] = [start];
3839
3840                 if (control.length > 0) {
3841                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3842                 }
3843
3844                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3845             }
3846             else {
3847                 superclass.setRuntimeAttribute.call(this, attr);
3848             }
3849         };
3850
3851         var translateValues = function(val, start) {
3852             var pageXY = Roo.lib.Dom.getXY(this.getEl());
3853             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3854
3855             return val;
3856         };
3857
3858         var isset = function(prop) {
3859             return (typeof prop !== 'undefined');
3860         };
3861     })();
3862 /*
3863  * Portions of this file are based on pieces of Yahoo User Interface Library
3864  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3865  * YUI licensed under the BSD License:
3866  * http://developer.yahoo.net/yui/license.txt
3867  * <script type="text/javascript">
3868  *
3869  */
3870     (function() {
3871         Roo.lib.Scroll = function(el, attributes, duration, method) {
3872             if (el) {
3873                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3874             }
3875         };
3876
3877         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3878
3879
3880         var Y = Roo.lib;
3881         var superclass = Y.Scroll.superclass;
3882         var proto = Y.Scroll.prototype;
3883
3884         proto.toString = function() {
3885             var el = this.getEl();
3886             var id = el.id || el.tagName;
3887             return ("Scroll " + id);
3888         };
3889
3890         proto.doMethod = function(attr, start, end) {
3891             var val = null;
3892
3893             if (attr == 'scroll') {
3894                 val = [
3895                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3896                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3897                         ];
3898
3899             } else {
3900                 val = superclass.doMethod.call(this, attr, start, end);
3901             }
3902             return val;
3903         };
3904
3905         proto.getAttribute = function(attr) {
3906             var val = null;
3907             var el = this.getEl();
3908
3909             if (attr == 'scroll') {
3910                 val = [ el.scrollLeft, el.scrollTop ];
3911             } else {
3912                 val = superclass.getAttribute.call(this, attr);
3913             }
3914
3915             return val;
3916         };
3917
3918         proto.setAttribute = function(attr, val, unit) {
3919             var el = this.getEl();
3920
3921             if (attr == 'scroll') {
3922                 el.scrollLeft = val[0];
3923                 el.scrollTop = val[1];
3924             } else {
3925                 superclass.setAttribute.call(this, attr, val, unit);
3926             }
3927         };
3928     })();
3929 /*
3930  * Based on:
3931  * Ext JS Library 1.1.1
3932  * Copyright(c) 2006-2007, Ext JS, LLC.
3933  *
3934  * Originally Released Under LGPL - original licence link has changed is not relivant.
3935  *
3936  * Fork - LGPL
3937  * <script type="text/javascript">
3938  */
3939  
3940
3941 /**
3942  * @class Roo.DomHelper
3943  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3944  * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
3945  * @singleton
3946  */
3947 Roo.DomHelper = function(){
3948     var tempTableEl = null;
3949     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3950     var tableRe = /^table|tbody|tr|td$/i;
3951     var xmlns = {};
3952     // build as innerHTML where available
3953     /** @ignore */
3954     var createHtml = function(o){
3955         if(typeof o == 'string'){
3956             return o;
3957         }
3958         var b = "";
3959         if(!o.tag){
3960             o.tag = "div";
3961         }
3962         b += "<" + o.tag;
3963         for(var attr in o){
3964             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3965             if(attr == "style"){
3966                 var s = o["style"];
3967                 if(typeof s == "function"){
3968                     s = s.call();
3969                 }
3970                 if(typeof s == "string"){
3971                     b += ' style="' + s + '"';
3972                 }else if(typeof s == "object"){
3973                     b += ' style="';
3974                     for(var key in s){
3975                         if(typeof s[key] != "function"){
3976                             b += key + ":" + s[key] + ";";
3977                         }
3978                     }
3979                     b += '"';
3980                 }
3981             }else{
3982                 if(attr == "cls"){
3983                     b += ' class="' + o["cls"] + '"';
3984                 }else if(attr == "htmlFor"){
3985                     b += ' for="' + o["htmlFor"] + '"';
3986                 }else{
3987                     b += " " + attr + '="' + o[attr] + '"';
3988                 }
3989             }
3990         }
3991         if(emptyTags.test(o.tag)){
3992             b += "/>";
3993         }else{
3994             b += ">";
3995             var cn = o.children || o.cn;
3996             if(cn){
3997                 //http://bugs.kde.org/show_bug.cgi?id=71506
3998                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
3999                     for(var i = 0, len = cn.length; i < len; i++) {
4000                         b += createHtml(cn[i], b);
4001                     }
4002                 }else{
4003                     b += createHtml(cn, b);
4004                 }
4005             }
4006             if(o.html){
4007                 b += o.html;
4008             }
4009             b += "</" + o.tag + ">";
4010         }
4011         return b;
4012     };
4013
4014     // build as dom
4015     /** @ignore */
4016     var createDom = function(o, parentNode){
4017          
4018         // defininition craeted..
4019         var ns = false;
4020         if (o.ns && o.ns != 'html') {
4021                
4022             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4023                 xmlns[o.ns] = o.xmlns;
4024                 ns = o.xmlns;
4025             }
4026             if (typeof(xmlns[o.ns]) == 'undefined') {
4027                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4028             }
4029             ns = xmlns[o.ns];
4030         }
4031         
4032         
4033         if (typeof(o) == 'string') {
4034             return parentNode.appendChild(document.createTextNode(o));
4035         }
4036         o.tag = o.tag || div;
4037         if (o.ns && Roo.isIE) {
4038             ns = false;
4039             o.tag = o.ns + ':' + o.tag;
4040             
4041         }
4042         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4043         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4044         for(var attr in o){
4045             
4046             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4047                     attr == "style" || typeof o[attr] == "function") continue;
4048                     
4049             if(attr=="cls" && Roo.isIE){
4050                 el.className = o["cls"];
4051             }else{
4052                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4053                 else el[attr] = o[attr];
4054             }
4055         }
4056         Roo.DomHelper.applyStyles(el, o.style);
4057         var cn = o.children || o.cn;
4058         if(cn){
4059             //http://bugs.kde.org/show_bug.cgi?id=71506
4060              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4061                 for(var i = 0, len = cn.length; i < len; i++) {
4062                     createDom(cn[i], el);
4063                 }
4064             }else{
4065                 createDom(cn, el);
4066             }
4067         }
4068         if(o.html){
4069             el.innerHTML = o.html;
4070         }
4071         if(parentNode){
4072            parentNode.appendChild(el);
4073         }
4074         return el;
4075     };
4076
4077     var ieTable = function(depth, s, h, e){
4078         tempTableEl.innerHTML = [s, h, e].join('');
4079         var i = -1, el = tempTableEl;
4080         while(++i < depth){
4081             el = el.firstChild;
4082         }
4083         return el;
4084     };
4085
4086     // kill repeat to save bytes
4087     var ts = '<table>',
4088         te = '</table>',
4089         tbs = ts+'<tbody>',
4090         tbe = '</tbody>'+te,
4091         trs = tbs + '<tr>',
4092         tre = '</tr>'+tbe;
4093
4094     /**
4095      * @ignore
4096      * Nasty code for IE's broken table implementation
4097      */
4098     var insertIntoTable = function(tag, where, el, html){
4099         if(!tempTableEl){
4100             tempTableEl = document.createElement('div');
4101         }
4102         var node;
4103         var before = null;
4104         if(tag == 'td'){
4105             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4106                 return;
4107             }
4108             if(where == 'beforebegin'){
4109                 before = el;
4110                 el = el.parentNode;
4111             } else{
4112                 before = el.nextSibling;
4113                 el = el.parentNode;
4114             }
4115             node = ieTable(4, trs, html, tre);
4116         }
4117         else if(tag == 'tr'){
4118             if(where == 'beforebegin'){
4119                 before = el;
4120                 el = el.parentNode;
4121                 node = ieTable(3, tbs, html, tbe);
4122             } else if(where == 'afterend'){
4123                 before = el.nextSibling;
4124                 el = el.parentNode;
4125                 node = ieTable(3, tbs, html, tbe);
4126             } else{ // INTO a TR
4127                 if(where == 'afterbegin'){
4128                     before = el.firstChild;
4129                 }
4130                 node = ieTable(4, trs, html, tre);
4131             }
4132         } else if(tag == 'tbody'){
4133             if(where == 'beforebegin'){
4134                 before = el;
4135                 el = el.parentNode;
4136                 node = ieTable(2, ts, html, te);
4137             } else if(where == 'afterend'){
4138                 before = el.nextSibling;
4139                 el = el.parentNode;
4140                 node = ieTable(2, ts, html, te);
4141             } else{
4142                 if(where == 'afterbegin'){
4143                     before = el.firstChild;
4144                 }
4145                 node = ieTable(3, tbs, html, tbe);
4146             }
4147         } else{ // TABLE
4148             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4149                 return;
4150             }
4151             if(where == 'afterbegin'){
4152                 before = el.firstChild;
4153             }
4154             node = ieTable(2, ts, html, te);
4155         }
4156         el.insertBefore(node, before);
4157         return node;
4158     };
4159
4160     return {
4161     /** True to force the use of DOM instead of html fragments @type Boolean */
4162     useDom : false,
4163
4164     /**
4165      * Returns the markup for the passed Element(s) config
4166      * @param {Object} o The Dom object spec (and children)
4167      * @return {String}
4168      */
4169     markup : function(o){
4170         return createHtml(o);
4171     },
4172
4173     /**
4174      * Applies a style specification to an element
4175      * @param {String/HTMLElement} el The element to apply styles to
4176      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4177      * a function which returns such a specification.
4178      */
4179     applyStyles : function(el, styles){
4180         if(styles){
4181            el = Roo.fly(el);
4182            if(typeof styles == "string"){
4183                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4184                var matches;
4185                while ((matches = re.exec(styles)) != null){
4186                    el.setStyle(matches[1], matches[2]);
4187                }
4188            }else if (typeof styles == "object"){
4189                for (var style in styles){
4190                   el.setStyle(style, styles[style]);
4191                }
4192            }else if (typeof styles == "function"){
4193                 Roo.DomHelper.applyStyles(el, styles.call());
4194            }
4195         }
4196     },
4197
4198     /**
4199      * Inserts an HTML fragment into the Dom
4200      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4201      * @param {HTMLElement} el The context element
4202      * @param {String} html The HTML fragmenet
4203      * @return {HTMLElement} The new node
4204      */
4205     insertHtml : function(where, el, html){
4206         where = where.toLowerCase();
4207         if(el.insertAdjacentHTML){
4208             if(tableRe.test(el.tagName)){
4209                 var rs;
4210                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4211                     return rs;
4212                 }
4213             }
4214             switch(where){
4215                 case "beforebegin":
4216                     el.insertAdjacentHTML('BeforeBegin', html);
4217                     return el.previousSibling;
4218                 case "afterbegin":
4219                     el.insertAdjacentHTML('AfterBegin', html);
4220                     return el.firstChild;
4221                 case "beforeend":
4222                     el.insertAdjacentHTML('BeforeEnd', html);
4223                     return el.lastChild;
4224                 case "afterend":
4225                     el.insertAdjacentHTML('AfterEnd', html);
4226                     return el.nextSibling;
4227             }
4228             throw 'Illegal insertion point -> "' + where + '"';
4229         }
4230         var range = el.ownerDocument.createRange();
4231         var frag;
4232         switch(where){
4233              case "beforebegin":
4234                 range.setStartBefore(el);
4235                 frag = range.createContextualFragment(html);
4236                 el.parentNode.insertBefore(frag, el);
4237                 return el.previousSibling;
4238              case "afterbegin":
4239                 if(el.firstChild){
4240                     range.setStartBefore(el.firstChild);
4241                     frag = range.createContextualFragment(html);
4242                     el.insertBefore(frag, el.firstChild);
4243                     return el.firstChild;
4244                 }else{
4245                     el.innerHTML = html;
4246                     return el.firstChild;
4247                 }
4248             case "beforeend":
4249                 if(el.lastChild){
4250                     range.setStartAfter(el.lastChild);
4251                     frag = range.createContextualFragment(html);
4252                     el.appendChild(frag);
4253                     return el.lastChild;
4254                 }else{
4255                     el.innerHTML = html;
4256                     return el.lastChild;
4257                 }
4258             case "afterend":
4259                 range.setStartAfter(el);
4260                 frag = range.createContextualFragment(html);
4261                 el.parentNode.insertBefore(frag, el.nextSibling);
4262                 return el.nextSibling;
4263             }
4264             throw 'Illegal insertion point -> "' + where + '"';
4265     },
4266
4267     /**
4268      * Creates new Dom element(s) and inserts them before el
4269      * @param {String/HTMLElement/Element} el The context element
4270      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4271      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4272      * @return {HTMLElement/Roo.Element} The new node
4273      */
4274     insertBefore : function(el, o, returnElement){
4275         return this.doInsert(el, o, returnElement, "beforeBegin");
4276     },
4277
4278     /**
4279      * Creates new Dom element(s) and inserts them after el
4280      * @param {String/HTMLElement/Element} el The context element
4281      * @param {Object} o The Dom object spec (and children)
4282      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4283      * @return {HTMLElement/Roo.Element} The new node
4284      */
4285     insertAfter : function(el, o, returnElement){
4286         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4287     },
4288
4289     /**
4290      * Creates new Dom element(s) and inserts them as the first child of el
4291      * @param {String/HTMLElement/Element} el The context element
4292      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4293      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4294      * @return {HTMLElement/Roo.Element} The new node
4295      */
4296     insertFirst : function(el, o, returnElement){
4297         return this.doInsert(el, o, returnElement, "afterBegin");
4298     },
4299
4300     // private
4301     doInsert : function(el, o, returnElement, pos, sibling){
4302         el = Roo.getDom(el);
4303         var newNode;
4304         if(this.useDom || o.ns){
4305             newNode = createDom(o, null);
4306             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4307         }else{
4308             var html = createHtml(o);
4309             newNode = this.insertHtml(pos, el, html);
4310         }
4311         return returnElement ? Roo.get(newNode, true) : newNode;
4312     },
4313
4314     /**
4315      * Creates new Dom element(s) and appends them to el
4316      * @param {String/HTMLElement/Element} el The context element
4317      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4318      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4319      * @return {HTMLElement/Roo.Element} The new node
4320      */
4321     append : function(el, o, returnElement){
4322         el = Roo.getDom(el);
4323         var newNode;
4324         if(this.useDom || o.ns){
4325             newNode = createDom(o, null);
4326             el.appendChild(newNode);
4327         }else{
4328             var html = createHtml(o);
4329             newNode = this.insertHtml("beforeEnd", el, html);
4330         }
4331         return returnElement ? Roo.get(newNode, true) : newNode;
4332     },
4333
4334     /**
4335      * Creates new Dom element(s) and overwrites the contents of el with them
4336      * @param {String/HTMLElement/Element} el The context element
4337      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4338      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4339      * @return {HTMLElement/Roo.Element} The new node
4340      */
4341     overwrite : function(el, o, returnElement){
4342         el = Roo.getDom(el);
4343         if (o.ns) {
4344           
4345             while (el.childNodes.length) {
4346                 el.removeChild(el.firstChild);
4347             }
4348             createDom(o, el);
4349         } else {
4350             el.innerHTML = createHtml(o);   
4351         }
4352         
4353         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4354     },
4355
4356     /**
4357      * Creates a new Roo.DomHelper.Template from the Dom object spec
4358      * @param {Object} o The Dom object spec (and children)
4359      * @return {Roo.DomHelper.Template} The new template
4360      */
4361     createTemplate : function(o){
4362         var html = createHtml(o);
4363         return new Roo.Template(html);
4364     }
4365     };
4366 }();
4367 /*
4368  * Based on:
4369  * Ext JS Library 1.1.1
4370  * Copyright(c) 2006-2007, Ext JS, LLC.
4371  *
4372  * Originally Released Under LGPL - original licence link has changed is not relivant.
4373  *
4374  * Fork - LGPL
4375  * <script type="text/javascript">
4376  */
4377  
4378 /**
4379 * @class Roo.Template
4380 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4381 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4382 * Usage:
4383 <pre><code>
4384 var t = new Roo.Template(
4385     '&lt;div name="{id}"&gt;',
4386         '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
4387     '&lt;/div&gt;'
4388 );
4389 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4390 </code></pre>
4391 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>. 
4392 * @constructor
4393 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4394 */
4395 Roo.Template = function(html){
4396     if(html instanceof Array){
4397         html = html.join("");
4398     }else if(arguments.length > 1){
4399         html = Array.prototype.join.call(arguments, "");
4400     }
4401     /**@private*/
4402     this.html = html;
4403     
4404 };
4405 Roo.Template.prototype = {
4406     /**
4407      * Returns an HTML fragment of this template with the specified values applied.
4408      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4409      * @return {String} The HTML fragment
4410      */
4411     applyTemplate : function(values){
4412         if(this.compiled){
4413             return this.compiled(values);
4414         }
4415         var useF = this.disableFormats !== true;
4416         var fm = Roo.util.Format, tpl = this;
4417         var fn = function(m, name, format, args){
4418             if(format && useF){
4419                 if(format.substr(0, 5) == "this."){
4420                     return tpl.call(format.substr(5), values[name], values);
4421                 }else{
4422                     if(args){
4423                         // quoted values are required for strings in compiled templates, 
4424                         // but for non compiled we need to strip them
4425                         // quoted reversed for jsmin
4426                         var re = /^\s*['"](.*)["']\s*$/;
4427                         args = args.split(',');
4428                         for(var i = 0, len = args.length; i < len; i++){
4429                             args[i] = args[i].replace(re, "$1");
4430                         }
4431                         args = [values[name]].concat(args);
4432                     }else{
4433                         args = [values[name]];
4434                     }
4435                     return fm[format].apply(fm, args);
4436                 }
4437             }else{
4438                 return values[name] !== undefined ? values[name] : "";
4439             }
4440         };
4441         return this.html.replace(this.re, fn);
4442     },
4443     
4444     /**
4445      * Sets the HTML used as the template and optionally compiles it.
4446      * @param {String} html
4447      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4448      * @return {Roo.Template} this
4449      */
4450     set : function(html, compile){
4451         this.html = html;
4452         this.compiled = null;
4453         if(compile){
4454             this.compile();
4455         }
4456         return this;
4457     },
4458     
4459     /**
4460      * True to disable format functions (defaults to false)
4461      * @type Boolean
4462      */
4463     disableFormats : false,
4464     
4465     /**
4466     * The regular expression used to match template variables 
4467     * @type RegExp
4468     * @property 
4469     */
4470     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4471     
4472     /**
4473      * Compiles the template into an internal function, eliminating the RegEx overhead.
4474      * @return {Roo.Template} this
4475      */
4476     compile : function(){
4477         var fm = Roo.util.Format;
4478         var useF = this.disableFormats !== true;
4479         var sep = Roo.isGecko ? "+" : ",";
4480         var fn = function(m, name, format, args){
4481             if(format && useF){
4482                 args = args ? ',' + args : "";
4483                 if(format.substr(0, 5) != "this."){
4484                     format = "fm." + format + '(';
4485                 }else{
4486                     format = 'this.call("'+ format.substr(5) + '", ';
4487                     args = ", values";
4488                 }
4489             }else{
4490                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4491             }
4492             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4493         };
4494         var body;
4495         // branched to use + in gecko and [].join() in others
4496         if(Roo.isGecko){
4497             body = "this.compiled = function(values){ return '" +
4498                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4499                     "';};";
4500         }else{
4501             body = ["this.compiled = function(values){ return ['"];
4502             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4503             body.push("'].join('');};");
4504             body = body.join('');
4505         }
4506         /**
4507          * eval:var:values
4508          * eval:var:fm
4509          */
4510         eval(body);
4511         return this;
4512     },
4513     
4514     // private function used to call members
4515     call : function(fnName, value, allValues){
4516         return this[fnName](value, allValues);
4517     },
4518     
4519     /**
4520      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4521      * @param {String/HTMLElement/Roo.Element} el The context element
4522      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4523      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4524      * @return {HTMLElement/Roo.Element} The new node or Element
4525      */
4526     insertFirst: function(el, values, returnElement){
4527         return this.doInsert('afterBegin', el, values, returnElement);
4528     },
4529
4530     /**
4531      * Applies the supplied values to the template and inserts the new node(s) before el.
4532      * @param {String/HTMLElement/Roo.Element} el The context element
4533      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4534      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4535      * @return {HTMLElement/Roo.Element} The new node or Element
4536      */
4537     insertBefore: function(el, values, returnElement){
4538         return this.doInsert('beforeBegin', el, values, returnElement);
4539     },
4540
4541     /**
4542      * Applies the supplied values to the template and inserts the new node(s) after el.
4543      * @param {String/HTMLElement/Roo.Element} el The context element
4544      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4545      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4546      * @return {HTMLElement/Roo.Element} The new node or Element
4547      */
4548     insertAfter : function(el, values, returnElement){
4549         return this.doInsert('afterEnd', el, values, returnElement);
4550     },
4551     
4552     /**
4553      * Applies the supplied values to the template and appends the new node(s) to el.
4554      * @param {String/HTMLElement/Roo.Element} el The context element
4555      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4556      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4557      * @return {HTMLElement/Roo.Element} The new node or Element
4558      */
4559     append : function(el, values, returnElement){
4560         return this.doInsert('beforeEnd', el, values, returnElement);
4561     },
4562
4563     doInsert : function(where, el, values, returnEl){
4564         el = Roo.getDom(el);
4565         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4566         return returnEl ? Roo.get(newNode, true) : newNode;
4567     },
4568
4569     /**
4570      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4571      * @param {String/HTMLElement/Roo.Element} el The context element
4572      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4573      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4574      * @return {HTMLElement/Roo.Element} The new node or Element
4575      */
4576     overwrite : function(el, values, returnElement){
4577         el = Roo.getDom(el);
4578         el.innerHTML = this.applyTemplate(values);
4579         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4580     }
4581 };
4582 /**
4583  * Alias for {@link #applyTemplate}
4584  * @method
4585  */
4586 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4587
4588 // backwards compat
4589 Roo.DomHelper.Template = Roo.Template;
4590
4591 /**
4592  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4593  * @param {String/HTMLElement} el A DOM element or its id
4594  * @returns {Roo.Template} The created template
4595  * @static
4596  */
4597 Roo.Template.from = function(el){
4598     el = Roo.getDom(el);
4599     return new Roo.Template(el.value || el.innerHTML);
4600 };/*
4601  * Based on:
4602  * Ext JS Library 1.1.1
4603  * Copyright(c) 2006-2007, Ext JS, LLC.
4604  *
4605  * Originally Released Under LGPL - original licence link has changed is not relivant.
4606  *
4607  * Fork - LGPL
4608  * <script type="text/javascript">
4609  */
4610  
4611
4612 /*
4613  * This is code is also distributed under MIT license for use
4614  * with jQuery and prototype JavaScript libraries.
4615  */
4616 /**
4617  * @class Roo.DomQuery
4618 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4619 <p>
4620 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4621
4622 <p>
4623 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4624 </p>
4625 <h4>Element Selectors:</h4>
4626 <ul class="list">
4627     <li> <b>*</b> any element</li>
4628     <li> <b>E</b> an element with the tag E</li>
4629     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4630     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4631     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4632     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4633 </ul>
4634 <h4>Attribute Selectors:</h4>
4635 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4636 <ul class="list">
4637     <li> <b>E[foo]</b> has an attribute "foo"</li>
4638     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4639     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4640     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4641     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4642     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4643     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4644 </ul>
4645 <h4>Pseudo Classes:</h4>
4646 <ul class="list">
4647     <li> <b>E:first-child</b> E is the first child of its parent</li>
4648     <li> <b>E:last-child</b> E is the last child of its parent</li>
4649     <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4650     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4651     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4652     <li> <b>E:only-child</b> E is the only child of its parent</li>
4653     <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4654     <li> <b>E:first</b> the first E in the resultset</li>
4655     <li> <b>E:last</b> the last E in the resultset</li>
4656     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4657     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4658     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4659     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4660     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4661     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4662     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4663     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4664     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4665 </ul>
4666 <h4>CSS Value Selectors:</h4>
4667 <ul class="list">
4668     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4669     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4670     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4671     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4672     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4673     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4674 </ul>
4675  * @singleton
4676  */
4677 Roo.DomQuery = function(){
4678     var cache = {}, simpleCache = {}, valueCache = {};
4679     var nonSpace = /\S/;
4680     var trimRe = /^\s+|\s+$/g;
4681     var tplRe = /\{(\d+)\}/g;
4682     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4683     var tagTokenRe = /^(#)?([\w-\*]+)/;
4684     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4685
4686     function child(p, index){
4687         var i = 0;
4688         var n = p.firstChild;
4689         while(n){
4690             if(n.nodeType == 1){
4691                if(++i == index){
4692                    return n;
4693                }
4694             }
4695             n = n.nextSibling;
4696         }
4697         return null;
4698     };
4699
4700     function next(n){
4701         while((n = n.nextSibling) && n.nodeType != 1);
4702         return n;
4703     };
4704
4705     function prev(n){
4706         while((n = n.previousSibling) && n.nodeType != 1);
4707         return n;
4708     };
4709
4710     function children(d){
4711         var n = d.firstChild, ni = -1;
4712             while(n){
4713                 var nx = n.nextSibling;
4714                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4715                     d.removeChild(n);
4716                 }else{
4717                     n.nodeIndex = ++ni;
4718                 }
4719                 n = nx;
4720             }
4721             return this;
4722         };
4723
4724     function byClassName(c, a, v){
4725         if(!v){
4726             return c;
4727         }
4728         var r = [], ri = -1, cn;
4729         for(var i = 0, ci; ci = c[i]; i++){
4730             if((' '+ci.className+' ').indexOf(v) != -1){
4731                 r[++ri] = ci;
4732             }
4733         }
4734         return r;
4735     };
4736
4737     function attrValue(n, attr){
4738         if(!n.tagName && typeof n.length != "undefined"){
4739             n = n[0];
4740         }
4741         if(!n){
4742             return null;
4743         }
4744         if(attr == "for"){
4745             return n.htmlFor;
4746         }
4747         if(attr == "class" || attr == "className"){
4748             return n.className;
4749         }
4750         return n.getAttribute(attr) || n[attr];
4751
4752     };
4753
4754     function getNodes(ns, mode, tagName){
4755         var result = [], ri = -1, cs;
4756         if(!ns){
4757             return result;
4758         }
4759         tagName = tagName || "*";
4760         if(typeof ns.getElementsByTagName != "undefined"){
4761             ns = [ns];
4762         }
4763         if(!mode){
4764             for(var i = 0, ni; ni = ns[i]; i++){
4765                 cs = ni.getElementsByTagName(tagName);
4766                 for(var j = 0, ci; ci = cs[j]; j++){
4767                     result[++ri] = ci;
4768                 }
4769             }
4770         }else if(mode == "/" || mode == ">"){
4771             var utag = tagName.toUpperCase();
4772             for(var i = 0, ni, cn; ni = ns[i]; i++){
4773                 cn = ni.children || ni.childNodes;
4774                 for(var j = 0, cj; cj = cn[j]; j++){
4775                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
4776                         result[++ri] = cj;
4777                     }
4778                 }
4779             }
4780         }else if(mode == "+"){
4781             var utag = tagName.toUpperCase();
4782             for(var i = 0, n; n = ns[i]; i++){
4783                 while((n = n.nextSibling) && n.nodeType != 1);
4784                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4785                     result[++ri] = n;
4786                 }
4787             }
4788         }else if(mode == "~"){
4789             for(var i = 0, n; n = ns[i]; i++){
4790                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4791                 if(n){
4792                     result[++ri] = n;
4793                 }
4794             }
4795         }
4796         return result;
4797     };
4798
4799     function concat(a, b){
4800         if(b.slice){
4801             return a.concat(b);
4802         }
4803         for(var i = 0, l = b.length; i < l; i++){
4804             a[a.length] = b[i];
4805         }
4806         return a;
4807     }
4808
4809     function byTag(cs, tagName){
4810         if(cs.tagName || cs == document){
4811             cs = [cs];
4812         }
4813         if(!tagName){
4814             return cs;
4815         }
4816         var r = [], ri = -1;
4817         tagName = tagName.toLowerCase();
4818         for(var i = 0, ci; ci = cs[i]; i++){
4819             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4820                 r[++ri] = ci;
4821             }
4822         }
4823         return r;
4824     };
4825
4826     function byId(cs, attr, id){
4827         if(cs.tagName || cs == document){
4828             cs = [cs];
4829         }
4830         if(!id){
4831             return cs;
4832         }
4833         var r = [], ri = -1;
4834         for(var i = 0,ci; ci = cs[i]; i++){
4835             if(ci && ci.id == id){
4836                 r[++ri] = ci;
4837                 return r;
4838             }
4839         }
4840         return r;
4841     };
4842
4843     function byAttribute(cs, attr, value, op, custom){
4844         var r = [], ri = -1, st = custom=="{";
4845         var f = Roo.DomQuery.operators[op];
4846         for(var i = 0, ci; ci = cs[i]; i++){
4847             var a;
4848             if(st){
4849                 a = Roo.DomQuery.getStyle(ci, attr);
4850             }
4851             else if(attr == "class" || attr == "className"){
4852                 a = ci.className;
4853             }else if(attr == "for"){
4854                 a = ci.htmlFor;
4855             }else if(attr == "href"){
4856                 a = ci.getAttribute("href", 2);
4857             }else{
4858                 a = ci.getAttribute(attr);
4859             }
4860             if((f && f(a, value)) || (!f && a)){
4861                 r[++ri] = ci;
4862             }
4863         }
4864         return r;
4865     };
4866
4867     function byPseudo(cs, name, value){
4868         return Roo.DomQuery.pseudos[name](cs, value);
4869     };
4870
4871     // This is for IE MSXML which does not support expandos.
4872     // IE runs the same speed using setAttribute, however FF slows way down
4873     // and Safari completely fails so they need to continue to use expandos.
4874     var isIE = window.ActiveXObject ? true : false;
4875
4876     // this eval is stop the compressor from
4877     // renaming the variable to something shorter
4878     
4879     /** eval:var:batch */
4880     var batch = 30803; 
4881
4882     var key = 30803;
4883
4884     function nodupIEXml(cs){
4885         var d = ++key;
4886         cs[0].setAttribute("_nodup", d);
4887         var r = [cs[0]];
4888         for(var i = 1, len = cs.length; i < len; i++){
4889             var c = cs[i];
4890             if(!c.getAttribute("_nodup") != d){
4891                 c.setAttribute("_nodup", d);
4892                 r[r.length] = c;
4893             }
4894         }
4895         for(var i = 0, len = cs.length; i < len; i++){
4896             cs[i].removeAttribute("_nodup");
4897         }
4898         return r;
4899     }
4900
4901     function nodup(cs){
4902         if(!cs){
4903             return [];
4904         }
4905         var len = cs.length, c, i, r = cs, cj, ri = -1;
4906         if(!len || typeof cs.nodeType != "undefined" || len == 1){
4907             return cs;
4908         }
4909         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4910             return nodupIEXml(cs);
4911         }
4912         var d = ++key;
4913         cs[0]._nodup = d;
4914         for(i = 1; c = cs[i]; i++){
4915             if(c._nodup != d){
4916                 c._nodup = d;
4917             }else{
4918                 r = [];
4919                 for(var j = 0; j < i; j++){
4920                     r[++ri] = cs[j];
4921                 }
4922                 for(j = i+1; cj = cs[j]; j++){
4923                     if(cj._nodup != d){
4924                         cj._nodup = d;
4925                         r[++ri] = cj;
4926                     }
4927                 }
4928                 return r;
4929             }
4930         }
4931         return r;
4932     }
4933
4934     function quickDiffIEXml(c1, c2){
4935         var d = ++key;
4936         for(var i = 0, len = c1.length; i < len; i++){
4937             c1[i].setAttribute("_qdiff", d);
4938         }
4939         var r = [];
4940         for(var i = 0, len = c2.length; i < len; i++){
4941             if(c2[i].getAttribute("_qdiff") != d){
4942                 r[r.length] = c2[i];
4943             }
4944         }
4945         for(var i = 0, len = c1.length; i < len; i++){
4946            c1[i].removeAttribute("_qdiff");
4947         }
4948         return r;
4949     }
4950
4951     function quickDiff(c1, c2){
4952         var len1 = c1.length;
4953         if(!len1){
4954             return c2;
4955         }
4956         if(isIE && c1[0].selectSingleNode){
4957             return quickDiffIEXml(c1, c2);
4958         }
4959         var d = ++key;
4960         for(var i = 0; i < len1; i++){
4961             c1[i]._qdiff = d;
4962         }
4963         var r = [];
4964         for(var i = 0, len = c2.length; i < len; i++){
4965             if(c2[i]._qdiff != d){
4966                 r[r.length] = c2[i];
4967             }
4968         }
4969         return r;
4970     }
4971
4972     function quickId(ns, mode, root, id){
4973         if(ns == root){
4974            var d = root.ownerDocument || root;
4975            return d.getElementById(id);
4976         }
4977         ns = getNodes(ns, mode, "*");
4978         return byId(ns, null, id);
4979     }
4980
4981     return {
4982         getStyle : function(el, name){
4983             return Roo.fly(el).getStyle(name);
4984         },
4985         /**
4986          * Compiles a selector/xpath query into a reusable function. The returned function
4987          * takes one parameter "root" (optional), which is the context node from where the query should start.
4988          * @param {String} selector The selector/xpath query
4989          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
4990          * @return {Function}
4991          */
4992         compile : function(path, type){
4993             type = type || "select";
4994             
4995             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
4996             var q = path, mode, lq;
4997             var tk = Roo.DomQuery.matchers;
4998             var tklen = tk.length;
4999             var mm;
5000
5001             // accept leading mode switch
5002             var lmode = q.match(modeRe);
5003             if(lmode && lmode[1]){
5004                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5005                 q = q.replace(lmode[1], "");
5006             }
5007             // strip leading slashes
5008             while(path.substr(0, 1)=="/"){
5009                 path = path.substr(1);
5010             }
5011
5012             while(q && lq != q){
5013                 lq = q;
5014                 var tm = q.match(tagTokenRe);
5015                 if(type == "select"){
5016                     if(tm){
5017                         if(tm[1] == "#"){
5018                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5019                         }else{
5020                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5021                         }
5022                         q = q.replace(tm[0], "");
5023                     }else if(q.substr(0, 1) != '@'){
5024                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5025                     }
5026                 }else{
5027                     if(tm){
5028                         if(tm[1] == "#"){
5029                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5030                         }else{
5031                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5032                         }
5033                         q = q.replace(tm[0], "");
5034                     }
5035                 }
5036                 while(!(mm = q.match(modeRe))){
5037                     var matched = false;
5038                     for(var j = 0; j < tklen; j++){
5039                         var t = tk[j];
5040                         var m = q.match(t.re);
5041                         if(m){
5042                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5043                                                     return m[i];
5044                                                 });
5045                             q = q.replace(m[0], "");
5046                             matched = true;
5047                             break;
5048                         }
5049                     }
5050                     // prevent infinite loop on bad selector
5051                     if(!matched){
5052                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5053                     }
5054                 }
5055                 if(mm[1]){
5056                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5057                     q = q.replace(mm[1], "");
5058                 }
5059             }
5060             fn[fn.length] = "return nodup(n);\n}";
5061             
5062              /** 
5063               * list of variables that need from compression as they are used by eval.
5064              *  eval:var:batch 
5065              *  eval:var:nodup
5066              *  eval:var:byTag
5067              *  eval:var:ById
5068              *  eval:var:getNodes
5069              *  eval:var:quickId
5070              *  eval:var:mode
5071              *  eval:var:root
5072              *  eval:var:n
5073              *  eval:var:byClassName
5074              *  eval:var:byPseudo
5075              *  eval:var:byAttribute
5076              *  eval:var:attrValue
5077              * 
5078              **/ 
5079             eval(fn.join(""));
5080             return f;
5081         },
5082
5083         /**
5084          * Selects a group of elements.
5085          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5086          * @param {Node} root (optional) The start of the query (defaults to document).
5087          * @return {Array}
5088          */
5089         select : function(path, root, type){
5090             if(!root || root == document){
5091                 root = document;
5092             }
5093             if(typeof root == "string"){
5094                 root = document.getElementById(root);
5095             }
5096             var paths = path.split(",");
5097             var results = [];
5098             for(var i = 0, len = paths.length; i < len; i++){
5099                 var p = paths[i].replace(trimRe, "");
5100                 if(!cache[p]){
5101                     cache[p] = Roo.DomQuery.compile(p);
5102                     if(!cache[p]){
5103                         throw p + " is not a valid selector";
5104                     }
5105                 }
5106                 var result = cache[p](root);
5107                 if(result && result != document){
5108                     results = results.concat(result);
5109                 }
5110             }
5111             if(paths.length > 1){
5112                 return nodup(results);
5113             }
5114             return results;
5115         },
5116
5117         /**
5118          * Selects a single element.
5119          * @param {String} selector The selector/xpath query
5120          * @param {Node} root (optional) The start of the query (defaults to document).
5121          * @return {Element}
5122          */
5123         selectNode : function(path, root){
5124             return Roo.DomQuery.select(path, root)[0];
5125         },
5126
5127         /**
5128          * Selects the value of a node, optionally replacing null with the defaultValue.
5129          * @param {String} selector The selector/xpath query
5130          * @param {Node} root (optional) The start of the query (defaults to document).
5131          * @param {String} defaultValue
5132          */
5133         selectValue : function(path, root, defaultValue){
5134             path = path.replace(trimRe, "");
5135             if(!valueCache[path]){
5136                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5137             }
5138             var n = valueCache[path](root);
5139             n = n[0] ? n[0] : n;
5140             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5141             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5142         },
5143
5144         /**
5145          * Selects the value of a node, parsing integers and floats.
5146          * @param {String} selector The selector/xpath query
5147          * @param {Node} root (optional) The start of the query (defaults to document).
5148          * @param {Number} defaultValue
5149          * @return {Number}
5150          */
5151         selectNumber : function(path, root, defaultValue){
5152             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5153             return parseFloat(v);
5154         },
5155
5156         /**
5157          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5158          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5159          * @param {String} selector The simple selector to test
5160          * @return {Boolean}
5161          */
5162         is : function(el, ss){
5163             if(typeof el == "string"){
5164                 el = document.getElementById(el);
5165             }
5166             var isArray = (el instanceof Array);
5167             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5168             return isArray ? (result.length == el.length) : (result.length > 0);
5169         },
5170
5171         /**
5172          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5173          * @param {Array} el An array of elements to filter
5174          * @param {String} selector The simple selector to test
5175          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5176          * the selector instead of the ones that match
5177          * @return {Array}
5178          */
5179         filter : function(els, ss, nonMatches){
5180             ss = ss.replace(trimRe, "");
5181             if(!simpleCache[ss]){
5182                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5183             }
5184             var result = simpleCache[ss](els);
5185             return nonMatches ? quickDiff(result, els) : result;
5186         },
5187
5188         /**
5189          * Collection of matching regular expressions and code snippets.
5190          */
5191         matchers : [{
5192                 re: /^\.([\w-]+)/,
5193                 select: 'n = byClassName(n, null, " {1} ");'
5194             }, {
5195                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5196                 select: 'n = byPseudo(n, "{1}", "{2}");'
5197             },{
5198                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5199                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5200             }, {
5201                 re: /^#([\w-]+)/,
5202                 select: 'n = byId(n, null, "{1}");'
5203             },{
5204                 re: /^@([\w-]+)/,
5205                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5206             }
5207         ],
5208
5209         /**
5210          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5211          * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, &gt; &lt;.
5212          */
5213         operators : {
5214             "=" : function(a, v){
5215                 return a == v;
5216             },
5217             "!=" : function(a, v){
5218                 return a != v;
5219             },
5220             "^=" : function(a, v){
5221                 return a && a.substr(0, v.length) == v;
5222             },
5223             "$=" : function(a, v){
5224                 return a && a.substr(a.length-v.length) == v;
5225             },
5226             "*=" : function(a, v){
5227                 return a && a.indexOf(v) !== -1;
5228             },
5229             "%=" : function(a, v){
5230                 return (a % v) == 0;
5231             },
5232             "|=" : function(a, v){
5233                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5234             },
5235             "~=" : function(a, v){
5236                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5237             }
5238         },
5239
5240         /**
5241          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5242          * and the argument (if any) supplied in the selector.
5243          */
5244         pseudos : {
5245             "first-child" : function(c){
5246                 var r = [], ri = -1, n;
5247                 for(var i = 0, ci; ci = n = c[i]; i++){
5248                     while((n = n.previousSibling) && n.nodeType != 1);
5249                     if(!n){
5250                         r[++ri] = ci;
5251                     }
5252                 }
5253                 return r;
5254             },
5255
5256             "last-child" : function(c){
5257                 var r = [], ri = -1, n;
5258                 for(var i = 0, ci; ci = n = c[i]; i++){
5259                     while((n = n.nextSibling) && n.nodeType != 1);
5260                     if(!n){
5261                         r[++ri] = ci;
5262                     }
5263                 }
5264                 return r;
5265             },
5266
5267             "nth-child" : function(c, a) {
5268                 var r = [], ri = -1;
5269                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5270                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5271                 for(var i = 0, n; n = c[i]; i++){
5272                     var pn = n.parentNode;
5273                     if (batch != pn._batch) {
5274                         var j = 0;
5275                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5276                             if(cn.nodeType == 1){
5277                                cn.nodeIndex = ++j;
5278                             }
5279                         }
5280                         pn._batch = batch;
5281                     }
5282                     if (f == 1) {
5283                         if (l == 0 || n.nodeIndex == l){
5284                             r[++ri] = n;
5285                         }
5286                     } else if ((n.nodeIndex + l) % f == 0){
5287                         r[++ri] = n;
5288                     }
5289                 }
5290
5291                 return r;
5292             },
5293
5294             "only-child" : function(c){
5295                 var r = [], ri = -1;;
5296                 for(var i = 0, ci; ci = c[i]; i++){
5297                     if(!prev(ci) && !next(ci)){
5298                         r[++ri] = ci;
5299                     }
5300                 }
5301                 return r;
5302             },
5303
5304             "empty" : function(c){
5305                 var r = [], ri = -1;
5306                 for(var i = 0, ci; ci = c[i]; i++){
5307                     var cns = ci.childNodes, j = 0, cn, empty = true;
5308                     while(cn = cns[j]){
5309                         ++j;
5310                         if(cn.nodeType == 1 || cn.nodeType == 3){
5311                             empty = false;
5312                             break;
5313                         }
5314                     }
5315                     if(empty){
5316                         r[++ri] = ci;
5317                     }
5318                 }
5319                 return r;
5320             },
5321
5322             "contains" : function(c, v){
5323                 var r = [], ri = -1;
5324                 for(var i = 0, ci; ci = c[i]; i++){
5325                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5326                         r[++ri] = ci;
5327                     }
5328                 }
5329                 return r;
5330             },
5331
5332             "nodeValue" : function(c, v){
5333                 var r = [], ri = -1;
5334                 for(var i = 0, ci; ci = c[i]; i++){
5335                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5336                         r[++ri] = ci;
5337                     }
5338                 }
5339                 return r;
5340             },
5341
5342             "checked" : function(c){
5343                 var r = [], ri = -1;
5344                 for(var i = 0, ci; ci = c[i]; i++){
5345                     if(ci.checked == true){
5346                         r[++ri] = ci;
5347                     }
5348                 }
5349                 return r;
5350             },
5351
5352             "not" : function(c, ss){
5353                 return Roo.DomQuery.filter(c, ss, true);
5354             },
5355
5356             "odd" : function(c){
5357                 return this["nth-child"](c, "odd");
5358             },
5359
5360             "even" : function(c){
5361                 return this["nth-child"](c, "even");
5362             },
5363
5364             "nth" : function(c, a){
5365                 return c[a-1] || [];
5366             },
5367
5368             "first" : function(c){
5369                 return c[0] || [];
5370             },
5371
5372             "last" : function(c){
5373                 return c[c.length-1] || [];
5374             },
5375
5376             "has" : function(c, ss){
5377                 var s = Roo.DomQuery.select;
5378                 var r = [], ri = -1;
5379                 for(var i = 0, ci; ci = c[i]; i++){
5380                     if(s(ss, ci).length > 0){
5381                         r[++ri] = ci;
5382                     }
5383                 }
5384                 return r;
5385             },
5386
5387             "next" : function(c, ss){
5388                 var is = Roo.DomQuery.is;
5389                 var r = [], ri = -1;
5390                 for(var i = 0, ci; ci = c[i]; i++){
5391                     var n = next(ci);
5392                     if(n && is(n, ss)){
5393                         r[++ri] = ci;
5394                     }
5395                 }
5396                 return r;
5397             },
5398
5399             "prev" : function(c, ss){
5400                 var is = Roo.DomQuery.is;
5401                 var r = [], ri = -1;
5402                 for(var i = 0, ci; ci = c[i]; i++){
5403                     var n = prev(ci);
5404                     if(n && is(n, ss)){
5405                         r[++ri] = ci;
5406                     }
5407                 }
5408                 return r;
5409             }
5410         }
5411     };
5412 }();
5413
5414 /**
5415  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5416  * @param {String} path The selector/xpath query
5417  * @param {Node} root (optional) The start of the query (defaults to document).
5418  * @return {Array}
5419  * @member Roo
5420  * @method query
5421  */
5422 Roo.query = Roo.DomQuery.select;
5423 /*
5424  * Based on:
5425  * Ext JS Library 1.1.1
5426  * Copyright(c) 2006-2007, Ext JS, LLC.
5427  *
5428  * Originally Released Under LGPL - original licence link has changed is not relivant.
5429  *
5430  * Fork - LGPL
5431  * <script type="text/javascript">
5432  */
5433
5434 /**
5435  * @class Roo.util.Observable
5436  * Base class that provides a common interface for publishing events. Subclasses are expected to
5437  * to have a property "events" with all the events defined.<br>
5438  * For example:
5439  * <pre><code>
5440  Employee = function(name){
5441     this.name = name;
5442     this.addEvents({
5443         "fired" : true,
5444         "quit" : true
5445     });
5446  }
5447  Roo.extend(Employee, Roo.util.Observable);
5448 </code></pre>
5449  * @param {Object} config properties to use (incuding events / listeners)
5450  */
5451
5452 Roo.util.Observable = function(cfg){
5453     
5454     cfg = cfg|| {};
5455     this.addEvents(cfg.events || {});
5456     if (cfg.events) {
5457         delete cfg.events; // make sure
5458     }
5459      
5460     Roo.apply(this, cfg);
5461     
5462     if(this.listeners){
5463         this.on(this.listeners);
5464         delete this.listeners;
5465     }
5466 };
5467 Roo.util.Observable.prototype = {
5468     /** 
5469  * @cfg {Object} listeners  list of events and functions to call for this object, 
5470  * For example :
5471  * <pre><code>
5472     listeners :  { 
5473        'click' : function(e) {
5474            ..... 
5475         } ,
5476         .... 
5477     } 
5478   </code></pre>
5479  */
5480     
5481     
5482     /**
5483      * Fires the specified event with the passed parameters (minus the event name).
5484      * @param {String} eventName
5485      * @param {Object...} args Variable number of parameters are passed to handlers
5486      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5487      */
5488     fireEvent : function(){
5489         var ce = this.events[arguments[0].toLowerCase()];
5490         if(typeof ce == "object"){
5491             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5492         }else{
5493             return true;
5494         }
5495     },
5496
5497     // private
5498     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5499
5500     /**
5501      * Appends an event handler to this component
5502      * @param {String}   eventName The type of event to listen for
5503      * @param {Function} handler The method the event invokes
5504      * @param {Object}   scope (optional) The scope in which to execute the handler
5505      * function. The handler function's "this" context.
5506      * @param {Object}   options (optional) An object containing handler configuration
5507      * properties. This may contain any of the following properties:<ul>
5508      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5509      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5510      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5511      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5512      * by the specified number of milliseconds. If the event fires again within that time, the original
5513      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5514      * </ul><br>
5515      * <p>
5516      * <b>Combining Options</b><br>
5517      * Using the options argument, it is possible to combine different types of listeners:<br>
5518      * <br>
5519      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5520                 <pre><code>
5521                 el.on('click', this.onClick, this, {
5522                         single: true,
5523                 delay: 100,
5524                 forumId: 4
5525                 });
5526                 </code></pre>
5527      * <p>
5528      * <b>Attaching multiple handlers in 1 call</b><br>
5529      * The method also allows for a single argument to be passed which is a config object containing properties
5530      * which specify multiple handlers.
5531      * <pre><code>
5532                 el.on({
5533                         'click': {
5534                         fn: this.onClick,
5535                         scope: this,
5536                         delay: 100
5537                 }, 
5538                 'mouseover': {
5539                         fn: this.onMouseOver,
5540                         scope: this
5541                 },
5542                 'mouseout': {
5543                         fn: this.onMouseOut,
5544                         scope: this
5545                 }
5546                 });
5547                 </code></pre>
5548      * <p>
5549      * Or a shorthand syntax which passes the same scope object to all handlers:
5550         <pre><code>
5551                 el.on({
5552                         'click': this.onClick,
5553                 'mouseover': this.onMouseOver,
5554                 'mouseout': this.onMouseOut,
5555                 scope: this
5556                 });
5557                 </code></pre>
5558      */
5559     addListener : function(eventName, fn, scope, o){
5560         if(typeof eventName == "object"){
5561             o = eventName;
5562             for(var e in o){
5563                 if(this.filterOptRe.test(e)){
5564                     continue;
5565                 }
5566                 if(typeof o[e] == "function"){
5567                     // shared options
5568                     this.addListener(e, o[e], o.scope,  o);
5569                 }else{
5570                     // individual options
5571                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5572                 }
5573             }
5574             return;
5575         }
5576         o = (!o || typeof o == "boolean") ? {} : o;
5577         eventName = eventName.toLowerCase();
5578         var ce = this.events[eventName] || true;
5579         if(typeof ce == "boolean"){
5580             ce = new Roo.util.Event(this, eventName);
5581             this.events[eventName] = ce;
5582         }
5583         ce.addListener(fn, scope, o);
5584     },
5585
5586     /**
5587      * Removes a listener
5588      * @param {String}   eventName     The type of event to listen for
5589      * @param {Function} handler        The handler to remove
5590      * @param {Object}   scope  (optional) The scope (this object) for the handler
5591      */
5592     removeListener : function(eventName, fn, scope){
5593         var ce = this.events[eventName.toLowerCase()];
5594         if(typeof ce == "object"){
5595             ce.removeListener(fn, scope);
5596         }
5597     },
5598
5599     /**
5600      * Removes all listeners for this object
5601      */
5602     purgeListeners : function(){
5603         for(var evt in this.events){
5604             if(typeof this.events[evt] == "object"){
5605                  this.events[evt].clearListeners();
5606             }
5607         }
5608     },
5609
5610     relayEvents : function(o, events){
5611         var createHandler = function(ename){
5612             return function(){
5613                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5614             };
5615         };
5616         for(var i = 0, len = events.length; i < len; i++){
5617             var ename = events[i];
5618             if(!this.events[ename]){ this.events[ename] = true; };
5619             o.on(ename, createHandler(ename), this);
5620         }
5621     },
5622
5623     /**
5624      * Used to define events on this Observable
5625      * @param {Object} object The object with the events defined
5626      */
5627     addEvents : function(o){
5628         if(!this.events){
5629             this.events = {};
5630         }
5631         Roo.applyIf(this.events, o);
5632     },
5633
5634     /**
5635      * Checks to see if this object has any listeners for a specified event
5636      * @param {String} eventName The name of the event to check for
5637      * @return {Boolean} True if the event is being listened for, else false
5638      */
5639     hasListener : function(eventName){
5640         var e = this.events[eventName];
5641         return typeof e == "object" && e.listeners.length > 0;
5642     }
5643 };
5644 /**
5645  * Appends an event handler to this element (shorthand for addListener)
5646  * @param {String}   eventName     The type of event to listen for
5647  * @param {Function} handler        The method the event invokes
5648  * @param {Object}   scope (optional) The scope in which to execute the handler
5649  * function. The handler function's "this" context.
5650  * @param {Object}   options  (optional)
5651  * @method
5652  */
5653 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5654 /**
5655  * Removes a listener (shorthand for removeListener)
5656  * @param {String}   eventName     The type of event to listen for
5657  * @param {Function} handler        The handler to remove
5658  * @param {Object}   scope  (optional) The scope (this object) for the handler
5659  * @method
5660  */
5661 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5662
5663 /**
5664  * Starts capture on the specified Observable. All events will be passed
5665  * to the supplied function with the event name + standard signature of the event
5666  * <b>before</b> the event is fired. If the supplied function returns false,
5667  * the event will not fire.
5668  * @param {Observable} o The Observable to capture
5669  * @param {Function} fn The function to call
5670  * @param {Object} scope (optional) The scope (this object) for the fn
5671  * @static
5672  */
5673 Roo.util.Observable.capture = function(o, fn, scope){
5674     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5675 };
5676
5677 /**
5678  * Removes <b>all</b> added captures from the Observable.
5679  * @param {Observable} o The Observable to release
5680  * @static
5681  */
5682 Roo.util.Observable.releaseCapture = function(o){
5683     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5684 };
5685
5686 (function(){
5687
5688     var createBuffered = function(h, o, scope){
5689         var task = new Roo.util.DelayedTask();
5690         return function(){
5691             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5692         };
5693     };
5694
5695     var createSingle = function(h, e, fn, scope){
5696         return function(){
5697             e.removeListener(fn, scope);
5698             return h.apply(scope, arguments);
5699         };
5700     };
5701
5702     var createDelayed = function(h, o, scope){
5703         return function(){
5704             var args = Array.prototype.slice.call(arguments, 0);
5705             setTimeout(function(){
5706                 h.apply(scope, args);
5707             }, o.delay || 10);
5708         };
5709     };
5710
5711     Roo.util.Event = function(obj, name){
5712         this.name = name;
5713         this.obj = obj;
5714         this.listeners = [];
5715     };
5716
5717     Roo.util.Event.prototype = {
5718         addListener : function(fn, scope, options){
5719             var o = options || {};
5720             scope = scope || this.obj;
5721             if(!this.isListening(fn, scope)){
5722                 var l = {fn: fn, scope: scope, options: o};
5723                 var h = fn;
5724                 if(o.delay){
5725                     h = createDelayed(h, o, scope);
5726                 }
5727                 if(o.single){
5728                     h = createSingle(h, this, fn, scope);
5729                 }
5730                 if(o.buffer){
5731                     h = createBuffered(h, o, scope);
5732                 }
5733                 l.fireFn = h;
5734                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5735                     this.listeners.push(l);
5736                 }else{
5737                     this.listeners = this.listeners.slice(0);
5738                     this.listeners.push(l);
5739                 }
5740             }
5741         },
5742
5743         findListener : function(fn, scope){
5744             scope = scope || this.obj;
5745             var ls = this.listeners;
5746             for(var i = 0, len = ls.length; i < len; i++){
5747                 var l = ls[i];
5748                 if(l.fn == fn && l.scope == scope){
5749                     return i;
5750                 }
5751             }
5752             return -1;
5753         },
5754
5755         isListening : function(fn, scope){
5756             return this.findListener(fn, scope) != -1;
5757         },
5758
5759         removeListener : function(fn, scope){
5760             var index;
5761             if((index = this.findListener(fn, scope)) != -1){
5762                 if(!this.firing){
5763                     this.listeners.splice(index, 1);
5764                 }else{
5765                     this.listeners = this.listeners.slice(0);
5766                     this.listeners.splice(index, 1);
5767                 }
5768                 return true;
5769             }
5770             return false;
5771         },
5772
5773         clearListeners : function(){
5774             this.listeners = [];
5775         },
5776
5777         fire : function(){
5778             var ls = this.listeners, scope, len = ls.length;
5779             if(len > 0){
5780                 this.firing = true;
5781                 var args = Array.prototype.slice.call(arguments, 0);
5782                 for(var i = 0; i < len; i++){
5783                     var l = ls[i];
5784                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5785                         this.firing = false;
5786                         return false;
5787                     }
5788                 }
5789                 this.firing = false;
5790             }
5791             return true;
5792         }
5793     };
5794 })();/*
5795  * Based on:
5796  * Ext JS Library 1.1.1
5797  * Copyright(c) 2006-2007, Ext JS, LLC.
5798  *
5799  * Originally Released Under LGPL - original licence link has changed is not relivant.
5800  *
5801  * Fork - LGPL
5802  * <script type="text/javascript">
5803  */
5804
5805 /**
5806  * @class Roo.EventManager
5807  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
5808  * several useful events directly.
5809  * See {@link Roo.EventObject} for more details on normalized event objects.
5810  * @singleton
5811  */
5812 Roo.EventManager = function(){
5813     var docReadyEvent, docReadyProcId, docReadyState = false;
5814     var resizeEvent, resizeTask, textEvent, textSize;
5815     var E = Roo.lib.Event;
5816     var D = Roo.lib.Dom;
5817
5818
5819     var fireDocReady = function(){
5820         if(!docReadyState){
5821             docReadyState = true;
5822             Roo.isReady = true;
5823             if(docReadyProcId){
5824                 clearInterval(docReadyProcId);
5825             }
5826             if(Roo.isGecko || Roo.isOpera) {
5827                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5828             }
5829             if(Roo.isIE){
5830                 var defer = document.getElementById("ie-deferred-loader");
5831                 if(defer){
5832                     defer.onreadystatechange = null;
5833                     defer.parentNode.removeChild(defer);
5834                 }
5835             }
5836             if(docReadyEvent){
5837                 docReadyEvent.fire();
5838                 docReadyEvent.clearListeners();
5839             }
5840         }
5841     };
5842     
5843     var initDocReady = function(){
5844         docReadyEvent = new Roo.util.Event();
5845         if(Roo.isGecko || Roo.isOpera) {
5846             document.addEventListener("DOMContentLoaded", fireDocReady, false);
5847         }else if(Roo.isIE){
5848             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5849             var defer = document.getElementById("ie-deferred-loader");
5850             defer.onreadystatechange = function(){
5851                 if(this.readyState == "complete"){
5852                     fireDocReady();
5853                 }
5854             };
5855         }else if(Roo.isSafari){ 
5856             docReadyProcId = setInterval(function(){
5857                 var rs = document.readyState;
5858                 if(rs == "complete") {
5859                     fireDocReady();     
5860                  }
5861             }, 10);
5862         }
5863         // no matter what, make sure it fires on load
5864         E.on(window, "load", fireDocReady);
5865     };
5866
5867     var createBuffered = function(h, o){
5868         var task = new Roo.util.DelayedTask(h);
5869         return function(e){
5870             // create new event object impl so new events don't wipe out properties
5871             e = new Roo.EventObjectImpl(e);
5872             task.delay(o.buffer, h, null, [e]);
5873         };
5874     };
5875
5876     var createSingle = function(h, el, ename, fn){
5877         return function(e){
5878             Roo.EventManager.removeListener(el, ename, fn);
5879             h(e);
5880         };
5881     };
5882
5883     var createDelayed = function(h, o){
5884         return function(e){
5885             // create new event object impl so new events don't wipe out properties
5886             e = new Roo.EventObjectImpl(e);
5887             setTimeout(function(){
5888                 h(e);
5889             }, o.delay || 10);
5890         };
5891     };
5892
5893     var listen = function(element, ename, opt, fn, scope){
5894         var o = (!opt || typeof opt == "boolean") ? {} : opt;
5895         fn = fn || o.fn; scope = scope || o.scope;
5896         var el = Roo.getDom(element);
5897         if(!el){
5898             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5899         }
5900         var h = function(e){
5901             e = Roo.EventObject.setEvent(e);
5902             var t;
5903             if(o.delegate){
5904                 t = e.getTarget(o.delegate, el);
5905                 if(!t){
5906                     return;
5907                 }
5908             }else{
5909                 t = e.target;
5910             }
5911             if(o.stopEvent === true){
5912                 e.stopEvent();
5913             }
5914             if(o.preventDefault === true){
5915                e.preventDefault();
5916             }
5917             if(o.stopPropagation === true){
5918                 e.stopPropagation();
5919             }
5920
5921             if(o.normalized === false){
5922                 e = e.browserEvent;
5923             }
5924
5925             fn.call(scope || el, e, t, o);
5926         };
5927         if(o.delay){
5928             h = createDelayed(h, o);
5929         }
5930         if(o.single){
5931             h = createSingle(h, el, ename, fn);
5932         }
5933         if(o.buffer){
5934             h = createBuffered(h, o);
5935         }
5936         fn._handlers = fn._handlers || [];
5937         fn._handlers.push([Roo.id(el), ename, h]);
5938
5939         E.on(el, ename, h);
5940         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5941             el.addEventListener("DOMMouseScroll", h, false);
5942             E.on(window, 'unload', function(){
5943                 el.removeEventListener("DOMMouseScroll", h, false);
5944             });
5945         }
5946         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5947             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5948         }
5949         return h;
5950     };
5951
5952     var stopListening = function(el, ename, fn){
5953         var id = Roo.id(el), hds = fn._handlers, hd = fn;
5954         if(hds){
5955             for(var i = 0, len = hds.length; i < len; i++){
5956                 var h = hds[i];
5957                 if(h[0] == id && h[1] == ename){
5958                     hd = h[2];
5959                     hds.splice(i, 1);
5960                     break;
5961                 }
5962             }
5963         }
5964         E.un(el, ename, hd);
5965         el = Roo.getDom(el);
5966         if(ename == "mousewheel" && el.addEventListener){
5967             el.removeEventListener("DOMMouseScroll", hd, false);
5968         }
5969         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5970             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5971         }
5972     };
5973
5974     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
5975     
5976     var pub = {
5977         
5978         
5979         /** 
5980          * Fix for doc tools
5981          * @scope Roo.EventManager
5982          */
5983         
5984         
5985         /** 
5986          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
5987          * object with a Roo.EventObject
5988          * @param {Function} fn        The method the event invokes
5989          * @param {Object}   scope    An object that becomes the scope of the handler
5990          * @param {boolean}  override If true, the obj passed in becomes
5991          *                             the execution scope of the listener
5992          * @return {Function} The wrapped function
5993          * @deprecated
5994          */
5995         wrap : function(fn, scope, override){
5996             return function(e){
5997                 Roo.EventObject.setEvent(e);
5998                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
5999             };
6000         },
6001         
6002         /**
6003      * Appends an event handler to an element (shorthand for addListener)
6004      * @param {String/HTMLElement}   element        The html element or id to assign the
6005      * @param {String}   eventName The type of event to listen for
6006      * @param {Function} handler The method the event invokes
6007      * @param {Object}   scope (optional) The scope in which to execute the handler
6008      * function. The handler function's "this" context.
6009      * @param {Object}   options (optional) An object containing handler configuration
6010      * properties. This may contain any of the following properties:<ul>
6011      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6012      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6013      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6014      * <li>preventDefault {Boolean} True to prevent the default action</li>
6015      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6016      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6017      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6018      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6019      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6020      * by the specified number of milliseconds. If the event fires again within that time, the original
6021      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6022      * </ul><br>
6023      * <p>
6024      * <b>Combining Options</b><br>
6025      * Using the options argument, it is possible to combine different types of listeners:<br>
6026      * <br>
6027      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6028      * Code:<pre><code>
6029 el.on('click', this.onClick, this, {
6030     single: true,
6031     delay: 100,
6032     stopEvent : true,
6033     forumId: 4
6034 });</code></pre>
6035      * <p>
6036      * <b>Attaching multiple handlers in 1 call</b><br>
6037       * The method also allows for a single argument to be passed which is a config object containing properties
6038      * which specify multiple handlers.
6039      * <p>
6040      * Code:<pre><code>
6041 el.on({
6042     'click' : {
6043         fn: this.onClick
6044         scope: this,
6045         delay: 100
6046     },
6047     'mouseover' : {
6048         fn: this.onMouseOver
6049         scope: this
6050     },
6051     'mouseout' : {
6052         fn: this.onMouseOut
6053         scope: this
6054     }
6055 });</code></pre>
6056      * <p>
6057      * Or a shorthand syntax:<br>
6058      * Code:<pre><code>
6059 el.on({
6060     'click' : this.onClick,
6061     'mouseover' : this.onMouseOver,
6062     'mouseout' : this.onMouseOut
6063     scope: this
6064 });</code></pre>
6065      */
6066         addListener : function(element, eventName, fn, scope, options){
6067             if(typeof eventName == "object"){
6068                 var o = eventName;
6069                 for(var e in o){
6070                     if(propRe.test(e)){
6071                         continue;
6072                     }
6073                     if(typeof o[e] == "function"){
6074                         // shared options
6075                         listen(element, e, o, o[e], o.scope);
6076                     }else{
6077                         // individual options
6078                         listen(element, e, o[e]);
6079                     }
6080                 }
6081                 return;
6082             }
6083             return listen(element, eventName, options, fn, scope);
6084         },
6085         
6086         /**
6087          * Removes an event handler
6088          *
6089          * @param {String/HTMLElement}   element        The id or html element to remove the 
6090          *                             event from
6091          * @param {String}   eventName     The type of event
6092          * @param {Function} fn
6093          * @return {Boolean} True if a listener was actually removed
6094          */
6095         removeListener : function(element, eventName, fn){
6096             return stopListening(element, eventName, fn);
6097         },
6098         
6099         /**
6100          * Fires when the document is ready (before onload and before images are loaded). Can be 
6101          * accessed shorthanded Roo.onReady().
6102          * @param {Function} fn        The method the event invokes
6103          * @param {Object}   scope    An  object that becomes the scope of the handler
6104          * @param {boolean}  options
6105          */
6106         onDocumentReady : function(fn, scope, options){
6107             if(docReadyState){ // if it already fired
6108                 docReadyEvent.addListener(fn, scope, options);
6109                 docReadyEvent.fire();
6110                 docReadyEvent.clearListeners();
6111                 return;
6112             }
6113             if(!docReadyEvent){
6114                 initDocReady();
6115             }
6116             docReadyEvent.addListener(fn, scope, options);
6117         },
6118         
6119         /**
6120          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6121          * @param {Function} fn        The method the event invokes
6122          * @param {Object}   scope    An object that becomes the scope of the handler
6123          * @param {boolean}  options
6124          */
6125         onWindowResize : function(fn, scope, options){
6126             if(!resizeEvent){
6127                 resizeEvent = new Roo.util.Event();
6128                 resizeTask = new Roo.util.DelayedTask(function(){
6129                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6130                 });
6131                 E.on(window, "resize", function(){
6132                     if(Roo.isIE){
6133                         resizeTask.delay(50);
6134                     }else{
6135                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6136                     }
6137                 });
6138             }
6139             resizeEvent.addListener(fn, scope, options);
6140         },
6141
6142         /**
6143          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6144          * @param {Function} fn        The method the event invokes
6145          * @param {Object}   scope    An object that becomes the scope of the handler
6146          * @param {boolean}  options
6147          */
6148         onTextResize : function(fn, scope, options){
6149             if(!textEvent){
6150                 textEvent = new Roo.util.Event();
6151                 var textEl = new Roo.Element(document.createElement('div'));
6152                 textEl.dom.className = 'x-text-resize';
6153                 textEl.dom.innerHTML = 'X';
6154                 textEl.appendTo(document.body);
6155                 textSize = textEl.dom.offsetHeight;
6156                 setInterval(function(){
6157                     if(textEl.dom.offsetHeight != textSize){
6158                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6159                     }
6160                 }, this.textResizeInterval);
6161             }
6162             textEvent.addListener(fn, scope, options);
6163         },
6164
6165         /**
6166          * Removes the passed window resize listener.
6167          * @param {Function} fn        The method the event invokes
6168          * @param {Object}   scope    The scope of handler
6169          */
6170         removeResizeListener : function(fn, scope){
6171             if(resizeEvent){
6172                 resizeEvent.removeListener(fn, scope);
6173             }
6174         },
6175
6176         // private
6177         fireResize : function(){
6178             if(resizeEvent){
6179                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6180             }   
6181         },
6182         /**
6183          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6184          */
6185         ieDeferSrc : false,
6186         /**
6187          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6188          */
6189         textResizeInterval : 50
6190     };
6191     
6192     /**
6193      * Fix for doc tools
6194      * @scopeAlias pub=Roo.EventManager
6195      */
6196     
6197      /**
6198      * Appends an event handler to an element (shorthand for addListener)
6199      * @param {String/HTMLElement}   element        The html element or id to assign the
6200      * @param {String}   eventName The type of event to listen for
6201      * @param {Function} handler The method the event invokes
6202      * @param {Object}   scope (optional) The scope in which to execute the handler
6203      * function. The handler function's "this" context.
6204      * @param {Object}   options (optional) An object containing handler configuration
6205      * properties. This may contain any of the following properties:<ul>
6206      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6207      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6208      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6209      * <li>preventDefault {Boolean} True to prevent the default action</li>
6210      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6211      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6212      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6213      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6214      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6215      * by the specified number of milliseconds. If the event fires again within that time, the original
6216      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6217      * </ul><br>
6218      * <p>
6219      * <b>Combining Options</b><br>
6220      * Using the options argument, it is possible to combine different types of listeners:<br>
6221      * <br>
6222      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6223      * Code:<pre><code>
6224 el.on('click', this.onClick, this, {
6225     single: true,
6226     delay: 100,
6227     stopEvent : true,
6228     forumId: 4
6229 });</code></pre>
6230      * <p>
6231      * <b>Attaching multiple handlers in 1 call</b><br>
6232       * The method also allows for a single argument to be passed which is a config object containing properties
6233      * which specify multiple handlers.
6234      * <p>
6235      * Code:<pre><code>
6236 el.on({
6237     'click' : {
6238         fn: this.onClick
6239         scope: this,
6240         delay: 100
6241     },
6242     'mouseover' : {
6243         fn: this.onMouseOver
6244         scope: this
6245     },
6246     'mouseout' : {
6247         fn: this.onMouseOut
6248         scope: this
6249     }
6250 });</code></pre>
6251      * <p>
6252      * Or a shorthand syntax:<br>
6253      * Code:<pre><code>
6254 el.on({
6255     'click' : this.onClick,
6256     'mouseover' : this.onMouseOver,
6257     'mouseout' : this.onMouseOut
6258     scope: this
6259 });</code></pre>
6260      */
6261     pub.on = pub.addListener;
6262     pub.un = pub.removeListener;
6263
6264     pub.stoppedMouseDownEvent = new Roo.util.Event();
6265     return pub;
6266 }();
6267 /**
6268   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6269   * @param {Function} fn        The method the event invokes
6270   * @param {Object}   scope    An  object that becomes the scope of the handler
6271   * @param {boolean}  override If true, the obj passed in becomes
6272   *                             the execution scope of the listener
6273   * @member Roo
6274   * @method onReady
6275  */
6276 Roo.onReady = Roo.EventManager.onDocumentReady;
6277
6278 Roo.onReady(function(){
6279     var bd = Roo.get(document.body);
6280     if(!bd){ return; }
6281
6282     var cls = [
6283             Roo.isIE ? "roo-ie"
6284             : Roo.isGecko ? "roo-gecko"
6285             : Roo.isOpera ? "roo-opera"
6286             : Roo.isSafari ? "roo-safari" : ""];
6287
6288     if(Roo.isMac){
6289         cls.push("roo-mac");
6290     }
6291     if(Roo.isLinux){
6292         cls.push("roo-linux");
6293     }
6294     if(Roo.isBorderBox){
6295         cls.push('roo-border-box');
6296     }
6297     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6298         var p = bd.dom.parentNode;
6299         if(p){
6300             p.className += ' roo-strict';
6301         }
6302     }
6303     bd.addClass(cls.join(' '));
6304 });
6305
6306 /**
6307  * @class Roo.EventObject
6308  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6309  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6310  * Example:
6311  * <pre><code>
6312  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6313     e.preventDefault();
6314     var target = e.getTarget();
6315     ...
6316  }
6317  var myDiv = Roo.get("myDiv");
6318  myDiv.on("click", handleClick);
6319  //or
6320  Roo.EventManager.on("myDiv", 'click', handleClick);
6321  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6322  </code></pre>
6323  * @singleton
6324  */
6325 Roo.EventObject = function(){
6326     
6327     var E = Roo.lib.Event;
6328     
6329     // safari keypress events for special keys return bad keycodes
6330     var safariKeys = {
6331         63234 : 37, // left
6332         63235 : 39, // right
6333         63232 : 38, // up
6334         63233 : 40, // down
6335         63276 : 33, // page up
6336         63277 : 34, // page down
6337         63272 : 46, // delete
6338         63273 : 36, // home
6339         63275 : 35  // end
6340     };
6341
6342     // normalize button clicks
6343     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6344                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6345
6346     Roo.EventObjectImpl = function(e){
6347         if(e){
6348             this.setEvent(e.browserEvent || e);
6349         }
6350     };
6351     Roo.EventObjectImpl.prototype = {
6352         /**
6353          * Used to fix doc tools.
6354          * @scope Roo.EventObject.prototype
6355          */
6356             
6357
6358         
6359         
6360         /** The normal browser event */
6361         browserEvent : null,
6362         /** The button pressed in a mouse event */
6363         button : -1,
6364         /** True if the shift key was down during the event */
6365         shiftKey : false,
6366         /** True if the control key was down during the event */
6367         ctrlKey : false,
6368         /** True if the alt key was down during the event */
6369         altKey : false,
6370
6371         /** Key constant 
6372         * @type Number */
6373         BACKSPACE : 8,
6374         /** Key constant 
6375         * @type Number */
6376         TAB : 9,
6377         /** Key constant 
6378         * @type Number */
6379         RETURN : 13,
6380         /** Key constant 
6381         * @type Number */
6382         ENTER : 13,
6383         /** Key constant 
6384         * @type Number */
6385         SHIFT : 16,
6386         /** Key constant 
6387         * @type Number */
6388         CONTROL : 17,
6389         /** Key constant 
6390         * @type Number */
6391         ESC : 27,
6392         /** Key constant 
6393         * @type Number */
6394         SPACE : 32,
6395         /** Key constant 
6396         * @type Number */
6397         PAGEUP : 33,
6398         /** Key constant 
6399         * @type Number */
6400         PAGEDOWN : 34,
6401         /** Key constant 
6402         * @type Number */
6403         END : 35,
6404         /** Key constant 
6405         * @type Number */
6406         HOME : 36,
6407         /** Key constant 
6408         * @type Number */
6409         LEFT : 37,
6410         /** Key constant 
6411         * @type Number */
6412         UP : 38,
6413         /** Key constant 
6414         * @type Number */
6415         RIGHT : 39,
6416         /** Key constant 
6417         * @type Number */
6418         DOWN : 40,
6419         /** Key constant 
6420         * @type Number */
6421         DELETE : 46,
6422         /** Key constant 
6423         * @type Number */
6424         F5 : 116,
6425
6426            /** @private */
6427         setEvent : function(e){
6428             if(e == this || (e && e.browserEvent)){ // already wrapped
6429                 return e;
6430             }
6431             this.browserEvent = e;
6432             if(e){
6433                 // normalize buttons
6434                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6435                 if(e.type == 'click' && this.button == -1){
6436                     this.button = 0;
6437                 }
6438                 this.type = e.type;
6439                 this.shiftKey = e.shiftKey;
6440                 // mac metaKey behaves like ctrlKey
6441                 this.ctrlKey = e.ctrlKey || e.metaKey;
6442                 this.altKey = e.altKey;
6443                 // in getKey these will be normalized for the mac
6444                 this.keyCode = e.keyCode;
6445                 // keyup warnings on firefox.
6446                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6447                 // cache the target for the delayed and or buffered events
6448                 this.target = E.getTarget(e);
6449                 // same for XY
6450                 this.xy = E.getXY(e);
6451             }else{
6452                 this.button = -1;
6453                 this.shiftKey = false;
6454                 this.ctrlKey = false;
6455                 this.altKey = false;
6456                 this.keyCode = 0;
6457                 this.charCode =0;
6458                 this.target = null;
6459                 this.xy = [0, 0];
6460             }
6461             return this;
6462         },
6463
6464         /**
6465          * Stop the event (preventDefault and stopPropagation)
6466          */
6467         stopEvent : function(){
6468             if(this.browserEvent){
6469                 if(this.browserEvent.type == 'mousedown'){
6470                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6471                 }
6472                 E.stopEvent(this.browserEvent);
6473             }
6474         },
6475
6476         /**
6477          * Prevents the browsers default handling of the event.
6478          */
6479         preventDefault : function(){
6480             if(this.browserEvent){
6481                 E.preventDefault(this.browserEvent);
6482             }
6483         },
6484
6485         /** @private */
6486         isNavKeyPress : function(){
6487             var k = this.keyCode;
6488             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6489             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6490         },
6491
6492         isSpecialKey : function(){
6493             var k = this.keyCode;
6494             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6495             (k == 16) || (k == 17) ||
6496             (k >= 18 && k <= 20) ||
6497             (k >= 33 && k <= 35) ||
6498             (k >= 36 && k <= 39) ||
6499             (k >= 44 && k <= 45);
6500         },
6501         /**
6502          * Cancels bubbling of the event.
6503          */
6504         stopPropagation : function(){
6505             if(this.browserEvent){
6506                 if(this.type == 'mousedown'){
6507                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6508                 }
6509                 E.stopPropagation(this.browserEvent);
6510             }
6511         },
6512
6513         /**
6514          * Gets the key code for the event.
6515          * @return {Number}
6516          */
6517         getCharCode : function(){
6518             return this.charCode || this.keyCode;
6519         },
6520
6521         /**
6522          * Returns a normalized keyCode for the event.
6523          * @return {Number} The key code
6524          */
6525         getKey : function(){
6526             var k = this.keyCode || this.charCode;
6527             return Roo.isSafari ? (safariKeys[k] || k) : k;
6528         },
6529
6530         /**
6531          * Gets the x coordinate of the event.
6532          * @return {Number}
6533          */
6534         getPageX : function(){
6535             return this.xy[0];
6536         },
6537
6538         /**
6539          * Gets the y coordinate of the event.
6540          * @return {Number}
6541          */
6542         getPageY : function(){
6543             return this.xy[1];
6544         },
6545
6546         /**
6547          * Gets the time of the event.
6548          * @return {Number}
6549          */
6550         getTime : function(){
6551             if(this.browserEvent){
6552                 return E.getTime(this.browserEvent);
6553             }
6554             return null;
6555         },
6556
6557         /**
6558          * Gets the page coordinates of the event.
6559          * @return {Array} The xy values like [x, y]
6560          */
6561         getXY : function(){
6562             return this.xy;
6563         },
6564
6565         /**
6566          * Gets the target for the event.
6567          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6568          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6569                 search as a number or element (defaults to 10 || document.body)
6570          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6571          * @return {HTMLelement}
6572          */
6573         getTarget : function(selector, maxDepth, returnEl){
6574             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6575         },
6576         /**
6577          * Gets the related target.
6578          * @return {HTMLElement}
6579          */
6580         getRelatedTarget : function(){
6581             if(this.browserEvent){
6582                 return E.getRelatedTarget(this.browserEvent);
6583             }
6584             return null;
6585         },
6586
6587         /**
6588          * Normalizes mouse wheel delta across browsers
6589          * @return {Number} The delta
6590          */
6591         getWheelDelta : function(){
6592             var e = this.browserEvent;
6593             var delta = 0;
6594             if(e.wheelDelta){ /* IE/Opera. */
6595                 delta = e.wheelDelta/120;
6596             }else if(e.detail){ /* Mozilla case. */
6597                 delta = -e.detail/3;
6598             }
6599             return delta;
6600         },
6601
6602         /**
6603          * Returns true if the control, meta, shift or alt key was pressed during this event.
6604          * @return {Boolean}
6605          */
6606         hasModifier : function(){
6607             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6608         },
6609
6610         /**
6611          * Returns true if the target of this event equals el or is a child of el
6612          * @param {String/HTMLElement/Element} el
6613          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6614          * @return {Boolean}
6615          */
6616         within : function(el, related){
6617             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6618             return t && Roo.fly(el).contains(t);
6619         },
6620
6621         getPoint : function(){
6622             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6623         }
6624     };
6625
6626     return new Roo.EventObjectImpl();
6627 }();
6628             
6629     /*
6630  * Based on:
6631  * Ext JS Library 1.1.1
6632  * Copyright(c) 2006-2007, Ext JS, LLC.
6633  *
6634  * Originally Released Under LGPL - original licence link has changed is not relivant.
6635  *
6636  * Fork - LGPL
6637  * <script type="text/javascript">
6638  */
6639
6640  
6641 // was in Composite Element!??!?!
6642  
6643 (function(){
6644     var D = Roo.lib.Dom;
6645     var E = Roo.lib.Event;
6646     var A = Roo.lib.Anim;
6647
6648     // local style camelizing for speed
6649     var propCache = {};
6650     var camelRe = /(-[a-z])/gi;
6651     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6652     var view = document.defaultView;
6653
6654 /**
6655  * @class Roo.Element
6656  * Represents an Element in the DOM.<br><br>
6657  * Usage:<br>
6658 <pre><code>
6659 var el = Roo.get("my-div");
6660
6661 // or with getEl
6662 var el = getEl("my-div");
6663
6664 // or with a DOM element
6665 var el = Roo.get(myDivElement);
6666 </code></pre>
6667  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6668  * each call instead of constructing a new one.<br><br>
6669  * <b>Animations</b><br />
6670  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6671  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6672 <pre>
6673 Option    Default   Description
6674 --------- --------  ---------------------------------------------
6675 duration  .35       The duration of the animation in seconds
6676 easing    easeOut   The YUI easing method
6677 callback  none      A function to execute when the anim completes
6678 scope     this      The scope (this) of the callback function
6679 </pre>
6680 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6681 * manipulate the animation. Here's an example:
6682 <pre><code>
6683 var el = Roo.get("my-div");
6684
6685 // no animation
6686 el.setWidth(100);
6687
6688 // default animation
6689 el.setWidth(100, true);
6690
6691 // animation with some options set
6692 el.setWidth(100, {
6693     duration: 1,
6694     callback: this.foo,
6695     scope: this
6696 });
6697
6698 // using the "anim" property to get the Anim object
6699 var opt = {
6700     duration: 1,
6701     callback: this.foo,
6702     scope: this
6703 };
6704 el.setWidth(100, opt);
6705 ...
6706 if(opt.anim.isAnimated()){
6707     opt.anim.stop();
6708 }
6709 </code></pre>
6710 * <b> Composite (Collections of) Elements</b><br />
6711  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6712  * @constructor Create a new Element directly.
6713  * @param {String/HTMLElement} element
6714  * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6715  */
6716     Roo.Element = function(element, forceNew){
6717         var dom = typeof element == "string" ?
6718                 document.getElementById(element) : element;
6719         if(!dom){ // invalid id/element
6720             return null;
6721         }
6722         var id = dom.id;
6723         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6724             return Roo.Element.cache[id];
6725         }
6726
6727         /**
6728          * The DOM element
6729          * @type HTMLElement
6730          */
6731         this.dom = dom;
6732
6733         /**
6734          * The DOM element ID
6735          * @type String
6736          */
6737         this.id = id || Roo.id(dom);
6738     };
6739
6740     var El = Roo.Element;
6741
6742     El.prototype = {
6743         /**
6744          * The element's default display mode  (defaults to "")
6745          * @type String
6746          */
6747         originalDisplay : "",
6748
6749         visibilityMode : 1,
6750         /**
6751          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6752          * @type String
6753          */
6754         defaultUnit : "px",
6755         /**
6756          * Sets the element's visibility mode. When setVisible() is called it
6757          * will use this to determine whether to set the visibility or the display property.
6758          * @param visMode Element.VISIBILITY or Element.DISPLAY
6759          * @return {Roo.Element} this
6760          */
6761         setVisibilityMode : function(visMode){
6762             this.visibilityMode = visMode;
6763             return this;
6764         },
6765         /**
6766          * Convenience method for setVisibilityMode(Element.DISPLAY)
6767          * @param {String} display (optional) What to set display to when visible
6768          * @return {Roo.Element} this
6769          */
6770         enableDisplayMode : function(display){
6771             this.setVisibilityMode(El.DISPLAY);
6772             if(typeof display != "undefined") this.originalDisplay = display;
6773             return this;
6774         },
6775
6776         /**
6777          * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6778          * @param {String} selector The simple selector to test
6779          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6780                 search as a number or element (defaults to 10 || document.body)
6781          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6782          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6783          */
6784         findParent : function(simpleSelector, maxDepth, returnEl){
6785             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6786             maxDepth = maxDepth || 50;
6787             if(typeof maxDepth != "number"){
6788                 stopEl = Roo.getDom(maxDepth);
6789                 maxDepth = 10;
6790             }
6791             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6792                 if(dq.is(p, simpleSelector)){
6793                     return returnEl ? Roo.get(p) : p;
6794                 }
6795                 depth++;
6796                 p = p.parentNode;
6797             }
6798             return null;
6799         },
6800
6801
6802         /**
6803          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6804          * @param {String} selector The simple selector to test
6805          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6806                 search as a number or element (defaults to 10 || document.body)
6807          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6808          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6809          */
6810         findParentNode : function(simpleSelector, maxDepth, returnEl){
6811             var p = Roo.fly(this.dom.parentNode, '_internal');
6812             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6813         },
6814
6815         /**
6816          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6817          * This is a shortcut for findParentNode() that always returns an Roo.Element.
6818          * @param {String} selector The simple selector to test
6819          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6820                 search as a number or element (defaults to 10 || document.body)
6821          * @return {Roo.Element} The matching DOM node (or null if no match was found)
6822          */
6823         up : function(simpleSelector, maxDepth){
6824             return this.findParentNode(simpleSelector, maxDepth, true);
6825         },
6826
6827
6828
6829         /**
6830          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6831          * @param {String} selector The simple selector to test
6832          * @return {Boolean} True if this element matches the selector, else false
6833          */
6834         is : function(simpleSelector){
6835             return Roo.DomQuery.is(this.dom, simpleSelector);
6836         },
6837
6838         /**
6839          * Perform animation on this element.
6840          * @param {Object} args The YUI animation control args
6841          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6842          * @param {Function} onComplete (optional) Function to call when animation completes
6843          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6844          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6845          * @return {Roo.Element} this
6846          */
6847         animate : function(args, duration, onComplete, easing, animType){
6848             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6849             return this;
6850         },
6851
6852         /*
6853          * @private Internal animation call
6854          */
6855         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6856             animType = animType || 'run';
6857             opt = opt || {};
6858             var anim = Roo.lib.Anim[animType](
6859                 this.dom, args,
6860                 (opt.duration || defaultDur) || .35,
6861                 (opt.easing || defaultEase) || 'easeOut',
6862                 function(){
6863                     Roo.callback(cb, this);
6864                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6865                 },
6866                 this
6867             );
6868             opt.anim = anim;
6869             return anim;
6870         },
6871
6872         // private legacy anim prep
6873         preanim : function(a, i){
6874             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6875         },
6876
6877         /**
6878          * Removes worthless text nodes
6879          * @param {Boolean} forceReclean (optional) By default the element
6880          * keeps track if it has been cleaned already so
6881          * you can call this over and over. However, if you update the element and
6882          * need to force a reclean, you can pass true.
6883          */
6884         clean : function(forceReclean){
6885             if(this.isCleaned && forceReclean !== true){
6886                 return this;
6887             }
6888             var ns = /\S/;
6889             var d = this.dom, n = d.firstChild, ni = -1;
6890             while(n){
6891                 var nx = n.nextSibling;
6892                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6893                     d.removeChild(n);
6894                 }else{
6895                     n.nodeIndex = ++ni;
6896                 }
6897                 n = nx;
6898             }
6899             this.isCleaned = true;
6900             return this;
6901         },
6902
6903         // private
6904         calcOffsetsTo : function(el){
6905             el = Roo.get(el);
6906             var d = el.dom;
6907             var restorePos = false;
6908             if(el.getStyle('position') == 'static'){
6909                 el.position('relative');
6910                 restorePos = true;
6911             }
6912             var x = 0, y =0;
6913             var op = this.dom;
6914             while(op && op != d && op.tagName != 'HTML'){
6915                 x+= op.offsetLeft;
6916                 y+= op.offsetTop;
6917                 op = op.offsetParent;
6918             }
6919             if(restorePos){
6920                 el.position('static');
6921             }
6922             return [x, y];
6923         },
6924
6925         /**
6926          * Scrolls this element into view within the passed container.
6927          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6928          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6929          * @return {Roo.Element} this
6930          */
6931         scrollIntoView : function(container, hscroll){
6932             var c = Roo.getDom(container) || document.body;
6933             var el = this.dom;
6934
6935             var o = this.calcOffsetsTo(c),
6936                 l = o[0],
6937                 t = o[1],
6938                 b = t+el.offsetHeight,
6939                 r = l+el.offsetWidth;
6940
6941             var ch = c.clientHeight;
6942             var ct = parseInt(c.scrollTop, 10);
6943             var cl = parseInt(c.scrollLeft, 10);
6944             var cb = ct + ch;
6945             var cr = cl + c.clientWidth;
6946
6947             if(t < ct){
6948                 c.scrollTop = t;
6949             }else if(b > cb){
6950                 c.scrollTop = b-ch;
6951             }
6952
6953             if(hscroll !== false){
6954                 if(l < cl){
6955                     c.scrollLeft = l;
6956                 }else if(r > cr){
6957                     c.scrollLeft = r-c.clientWidth;
6958                 }
6959             }
6960             return this;
6961         },
6962
6963         // private
6964         scrollChildIntoView : function(child, hscroll){
6965             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6966         },
6967
6968         /**
6969          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6970          * the new height may not be available immediately.
6971          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6972          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6973          * @param {Function} onComplete (optional) Function to call when animation completes
6974          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
6975          * @return {Roo.Element} this
6976          */
6977         autoHeight : function(animate, duration, onComplete, easing){
6978             var oldHeight = this.getHeight();
6979             this.clip();
6980             this.setHeight(1); // force clipping
6981             setTimeout(function(){
6982                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
6983                 if(!animate){
6984                     this.setHeight(height);
6985                     this.unclip();
6986                     if(typeof onComplete == "function"){
6987                         onComplete();
6988                     }
6989                 }else{
6990                     this.setHeight(oldHeight); // restore original height
6991                     this.setHeight(height, animate, duration, function(){
6992                         this.unclip();
6993                         if(typeof onComplete == "function") onComplete();
6994                     }.createDelegate(this), easing);
6995                 }
6996             }.createDelegate(this), 0);
6997             return this;
6998         },
6999
7000         /**
7001          * Returns true if this element is an ancestor of the passed element
7002          * @param {HTMLElement/String} el The element to check
7003          * @return {Boolean} True if this element is an ancestor of el, else false
7004          */
7005         contains : function(el){
7006             if(!el){return false;}
7007             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7008         },
7009
7010         /**
7011          * Checks whether the element is currently visible using both visibility and display properties.
7012          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7013          * @return {Boolean} True if the element is currently visible, else false
7014          */
7015         isVisible : function(deep) {
7016             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7017             if(deep !== true || !vis){
7018                 return vis;
7019             }
7020             var p = this.dom.parentNode;
7021             while(p && p.tagName.toLowerCase() != "body"){
7022                 if(!Roo.fly(p, '_isVisible').isVisible()){
7023                     return false;
7024                 }
7025                 p = p.parentNode;
7026             }
7027             return true;
7028         },
7029
7030         /**
7031          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7032          * @param {String} selector The CSS selector
7033          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7034          * @return {CompositeElement/CompositeElementLite} The composite element
7035          */
7036         select : function(selector, unique){
7037             return El.select(selector, unique, this.dom);
7038         },
7039
7040         /**
7041          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7042          * @param {String} selector The CSS selector
7043          * @return {Array} An array of the matched nodes
7044          */
7045         query : function(selector, unique){
7046             return Roo.DomQuery.select(selector, this.dom);
7047         },
7048
7049         /**
7050          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7051          * @param {String} selector The CSS selector
7052          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7053          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7054          */
7055         child : function(selector, returnDom){
7056             var n = Roo.DomQuery.selectNode(selector, this.dom);
7057             return returnDom ? n : Roo.get(n);
7058         },
7059
7060         /**
7061          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7062          * @param {String} selector The CSS selector
7063          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7064          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7065          */
7066         down : function(selector, returnDom){
7067             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7068             return returnDom ? n : Roo.get(n);
7069         },
7070
7071         /**
7072          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7073          * @param {String} group The group the DD object is member of
7074          * @param {Object} config The DD config object
7075          * @param {Object} overrides An object containing methods to override/implement on the DD object
7076          * @return {Roo.dd.DD} The DD object
7077          */
7078         initDD : function(group, config, overrides){
7079             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7080             return Roo.apply(dd, overrides);
7081         },
7082
7083         /**
7084          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7085          * @param {String} group The group the DDProxy object is member of
7086          * @param {Object} config The DDProxy config object
7087          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7088          * @return {Roo.dd.DDProxy} The DDProxy object
7089          */
7090         initDDProxy : function(group, config, overrides){
7091             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7092             return Roo.apply(dd, overrides);
7093         },
7094
7095         /**
7096          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7097          * @param {String} group The group the DDTarget object is member of
7098          * @param {Object} config The DDTarget config object
7099          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7100          * @return {Roo.dd.DDTarget} The DDTarget object
7101          */
7102         initDDTarget : function(group, config, overrides){
7103             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7104             return Roo.apply(dd, overrides);
7105         },
7106
7107         /**
7108          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7109          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7110          * @param {Boolean} visible Whether the element is visible
7111          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7112          * @return {Roo.Element} this
7113          */
7114          setVisible : function(visible, animate){
7115             if(!animate || !A){
7116                 if(this.visibilityMode == El.DISPLAY){
7117                     this.setDisplayed(visible);
7118                 }else{
7119                     this.fixDisplay();
7120                     this.dom.style.visibility = visible ? "visible" : "hidden";
7121                 }
7122             }else{
7123                 // closure for composites
7124                 var dom = this.dom;
7125                 var visMode = this.visibilityMode;
7126                 if(visible){
7127                     this.setOpacity(.01);
7128                     this.setVisible(true);
7129                 }
7130                 this.anim({opacity: { to: (visible?1:0) }},
7131                       this.preanim(arguments, 1),
7132                       null, .35, 'easeIn', function(){
7133                          if(!visible){
7134                              if(visMode == El.DISPLAY){
7135                                  dom.style.display = "none";
7136                              }else{
7137                                  dom.style.visibility = "hidden";
7138                              }
7139                              Roo.get(dom).setOpacity(1);
7140                          }
7141                      });
7142             }
7143             return this;
7144         },
7145
7146         /**
7147          * Returns true if display is not "none"
7148          * @return {Boolean}
7149          */
7150         isDisplayed : function() {
7151             return this.getStyle("display") != "none";
7152         },
7153
7154         /**
7155          * Toggles the element's visibility or display, depending on visibility mode.
7156          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7157          * @return {Roo.Element} this
7158          */
7159         toggle : function(animate){
7160             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7161             return this;
7162         },
7163
7164         /**
7165          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7166          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7167          * @return {Roo.Element} this
7168          */
7169         setDisplayed : function(value) {
7170             if(typeof value == "boolean"){
7171                value = value ? this.originalDisplay : "none";
7172             }
7173             this.setStyle("display", value);
7174             return this;
7175         },
7176
7177         /**
7178          * Tries to focus the element. Any exceptions are caught and ignored.
7179          * @return {Roo.Element} this
7180          */
7181         focus : function() {
7182             try{
7183                 this.dom.focus();
7184             }catch(e){}
7185             return this;
7186         },
7187
7188         /**
7189          * Tries to blur the element. Any exceptions are caught and ignored.
7190          * @return {Roo.Element} this
7191          */
7192         blur : function() {
7193             try{
7194                 this.dom.blur();
7195             }catch(e){}
7196             return this;
7197         },
7198
7199         /**
7200          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7201          * @param {String/Array} className The CSS class to add, or an array of classes
7202          * @return {Roo.Element} this
7203          */
7204         addClass : function(className){
7205             if(className instanceof Array){
7206                 for(var i = 0, len = className.length; i < len; i++) {
7207                     this.addClass(className[i]);
7208                 }
7209             }else{
7210                 if(className && !this.hasClass(className)){
7211                     this.dom.className = this.dom.className + " " + className;
7212                 }
7213             }
7214             return this;
7215         },
7216
7217         /**
7218          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7219          * @param {String/Array} className The CSS class to add, or an array of classes
7220          * @return {Roo.Element} this
7221          */
7222         radioClass : function(className){
7223             var siblings = this.dom.parentNode.childNodes;
7224             for(var i = 0; i < siblings.length; i++) {
7225                 var s = siblings[i];
7226                 if(s.nodeType == 1){
7227                     Roo.get(s).removeClass(className);
7228                 }
7229             }
7230             this.addClass(className);
7231             return this;
7232         },
7233
7234         /**
7235          * Removes one or more CSS classes from the element.
7236          * @param {String/Array} className The CSS class to remove, or an array of classes
7237          * @return {Roo.Element} this
7238          */
7239         removeClass : function(className){
7240             if(!className || !this.dom.className){
7241                 return this;
7242             }
7243             if(className instanceof Array){
7244                 for(var i = 0, len = className.length; i < len; i++) {
7245                     this.removeClass(className[i]);
7246                 }
7247             }else{
7248                 if(this.hasClass(className)){
7249                     var re = this.classReCache[className];
7250                     if (!re) {
7251                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7252                        this.classReCache[className] = re;
7253                     }
7254                     this.dom.className =
7255                         this.dom.className.replace(re, " ");
7256                 }
7257             }
7258             return this;
7259         },
7260
7261         // private
7262         classReCache: {},
7263
7264         /**
7265          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7266          * @param {String} className The CSS class to toggle
7267          * @return {Roo.Element} this
7268          */
7269         toggleClass : function(className){
7270             if(this.hasClass(className)){
7271                 this.removeClass(className);
7272             }else{
7273                 this.addClass(className);
7274             }
7275             return this;
7276         },
7277
7278         /**
7279          * Checks if the specified CSS class exists on this element's DOM node.
7280          * @param {String} className The CSS class to check for
7281          * @return {Boolean} True if the class exists, else false
7282          */
7283         hasClass : function(className){
7284             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7285         },
7286
7287         /**
7288          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7289          * @param {String} oldClassName The CSS class to replace
7290          * @param {String} newClassName The replacement CSS class
7291          * @return {Roo.Element} this
7292          */
7293         replaceClass : function(oldClassName, newClassName){
7294             this.removeClass(oldClassName);
7295             this.addClass(newClassName);
7296             return this;
7297         },
7298
7299         /**
7300          * Returns an object with properties matching the styles requested.
7301          * For example, el.getStyles('color', 'font-size', 'width') might return
7302          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7303          * @param {String} style1 A style name
7304          * @param {String} style2 A style name
7305          * @param {String} etc.
7306          * @return {Object} The style object
7307          */
7308         getStyles : function(){
7309             var a = arguments, len = a.length, r = {};
7310             for(var i = 0; i < len; i++){
7311                 r[a[i]] = this.getStyle(a[i]);
7312             }
7313             return r;
7314         },
7315
7316         /**
7317          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7318          * @param {String} property The style property whose value is returned.
7319          * @return {String} The current value of the style property for this element.
7320          */
7321         getStyle : function(){
7322             return view && view.getComputedStyle ?
7323                 function(prop){
7324                     var el = this.dom, v, cs, camel;
7325                     if(prop == 'float'){
7326                         prop = "cssFloat";
7327                     }
7328                     if(el.style && (v = el.style[prop])){
7329                         return v;
7330                     }
7331                     if(cs = view.getComputedStyle(el, "")){
7332                         if(!(camel = propCache[prop])){
7333                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7334                         }
7335                         return cs[camel];
7336                     }
7337                     return null;
7338                 } :
7339                 function(prop){
7340                     var el = this.dom, v, cs, camel;
7341                     if(prop == 'opacity'){
7342                         if(typeof el.style.filter == 'string'){
7343                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7344                             if(m){
7345                                 var fv = parseFloat(m[1]);
7346                                 if(!isNaN(fv)){
7347                                     return fv ? fv / 100 : 0;
7348                                 }
7349                             }
7350                         }
7351                         return 1;
7352                     }else if(prop == 'float'){
7353                         prop = "styleFloat";
7354                     }
7355                     if(!(camel = propCache[prop])){
7356                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7357                     }
7358                     if(v = el.style[camel]){
7359                         return v;
7360                     }
7361                     if(cs = el.currentStyle){
7362                         return cs[camel];
7363                     }
7364                     return null;
7365                 };
7366         }(),
7367
7368         /**
7369          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7370          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7371          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7372          * @return {Roo.Element} this
7373          */
7374         setStyle : function(prop, value){
7375             if(typeof prop == "string"){
7376                 var camel;
7377                 if(!(camel = propCache[prop])){
7378                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7379                 }
7380                 if(camel == 'opacity') {
7381                     this.setOpacity(value);
7382                 }else{
7383                     this.dom.style[camel] = value;
7384                 }
7385             }else{
7386                 for(var style in prop){
7387                     if(typeof prop[style] != "function"){
7388                        this.setStyle(style, prop[style]);
7389                     }
7390                 }
7391             }
7392             return this;
7393         },
7394
7395         /**
7396          * More flexible version of {@link #setStyle} for setting style properties.
7397          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7398          * a function which returns such a specification.
7399          * @return {Roo.Element} this
7400          */
7401         applyStyles : function(style){
7402             Roo.DomHelper.applyStyles(this.dom, style);
7403             return this;
7404         },
7405
7406         /**
7407           * Gets the current X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7408           * @return {Number} The X position of the element
7409           */
7410         getX : function(){
7411             return D.getX(this.dom);
7412         },
7413
7414         /**
7415           * Gets the current Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7416           * @return {Number} The Y position of the element
7417           */
7418         getY : function(){
7419             return D.getY(this.dom);
7420         },
7421
7422         /**
7423           * Gets the current position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7424           * @return {Array} The XY position of the element
7425           */
7426         getXY : function(){
7427             return D.getXY(this.dom);
7428         },
7429
7430         /**
7431          * Sets the X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7432          * @param {Number} The X position of the element
7433          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7434          * @return {Roo.Element} this
7435          */
7436         setX : function(x, animate){
7437             if(!animate || !A){
7438                 D.setX(this.dom, x);
7439             }else{
7440                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7441             }
7442             return this;
7443         },
7444
7445         /**
7446          * Sets the Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7447          * @param {Number} The Y position of the element
7448          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7449          * @return {Roo.Element} this
7450          */
7451         setY : function(y, animate){
7452             if(!animate || !A){
7453                 D.setY(this.dom, y);
7454             }else{
7455                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7456             }
7457             return this;
7458         },
7459
7460         /**
7461          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7462          * @param {String} left The left CSS property value
7463          * @return {Roo.Element} this
7464          */
7465         setLeft : function(left){
7466             this.setStyle("left", this.addUnits(left));
7467             return this;
7468         },
7469
7470         /**
7471          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7472          * @param {String} top The top CSS property value
7473          * @return {Roo.Element} this
7474          */
7475         setTop : function(top){
7476             this.setStyle("top", this.addUnits(top));
7477             return this;
7478         },
7479
7480         /**
7481          * Sets the element's CSS right style.
7482          * @param {String} right The right CSS property value
7483          * @return {Roo.Element} this
7484          */
7485         setRight : function(right){
7486             this.setStyle("right", this.addUnits(right));
7487             return this;
7488         },
7489
7490         /**
7491          * Sets the element's CSS bottom style.
7492          * @param {String} bottom The bottom CSS property value
7493          * @return {Roo.Element} this
7494          */
7495         setBottom : function(bottom){
7496             this.setStyle("bottom", this.addUnits(bottom));
7497             return this;
7498         },
7499
7500         /**
7501          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7502          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7503          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7504          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7505          * @return {Roo.Element} this
7506          */
7507         setXY : function(pos, animate){
7508             if(!animate || !A){
7509                 D.setXY(this.dom, pos);
7510             }else{
7511                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7512             }
7513             return this;
7514         },
7515
7516         /**
7517          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7518          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7519          * @param {Number} x X value for new position (coordinates are page-based)
7520          * @param {Number} y Y value for new position (coordinates are page-based)
7521          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7522          * @return {Roo.Element} this
7523          */
7524         setLocation : function(x, y, animate){
7525             this.setXY([x, y], this.preanim(arguments, 2));
7526             return this;
7527         },
7528
7529         /**
7530          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7531          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7532          * @param {Number} x X value for new position (coordinates are page-based)
7533          * @param {Number} y Y value for new position (coordinates are page-based)
7534          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7535          * @return {Roo.Element} this
7536          */
7537         moveTo : function(x, y, animate){
7538             this.setXY([x, y], this.preanim(arguments, 2));
7539             return this;
7540         },
7541
7542         /**
7543          * Returns the region of the given element.
7544          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7545          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7546          */
7547         getRegion : function(){
7548             return D.getRegion(this.dom);
7549         },
7550
7551         /**
7552          * Returns the offset height of the element
7553          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7554          * @return {Number} The element's height
7555          */
7556         getHeight : function(contentHeight){
7557             var h = this.dom.offsetHeight || 0;
7558             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7559         },
7560
7561         /**
7562          * Returns the offset width of the element
7563          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7564          * @return {Number} The element's width
7565          */
7566         getWidth : function(contentWidth){
7567             var w = this.dom.offsetWidth || 0;
7568             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7569         },
7570
7571         /**
7572          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7573          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7574          * if a height has not been set using CSS.
7575          * @return {Number}
7576          */
7577         getComputedHeight : function(){
7578             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7579             if(!h){
7580                 h = parseInt(this.getStyle('height'), 10) || 0;
7581                 if(!this.isBorderBox()){
7582                     h += this.getFrameWidth('tb');
7583                 }
7584             }
7585             return h;
7586         },
7587
7588         /**
7589          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7590          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7591          * if a width has not been set using CSS.
7592          * @return {Number}
7593          */
7594         getComputedWidth : function(){
7595             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7596             if(!w){
7597                 w = parseInt(this.getStyle('width'), 10) || 0;
7598                 if(!this.isBorderBox()){
7599                     w += this.getFrameWidth('lr');
7600                 }
7601             }
7602             return w;
7603         },
7604
7605         /**
7606          * Returns the size of the element.
7607          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7608          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7609          */
7610         getSize : function(contentSize){
7611             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7612         },
7613
7614         /**
7615          * Returns the width and height of the viewport.
7616          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7617          */
7618         getViewSize : function(){
7619             var d = this.dom, doc = document, aw = 0, ah = 0;
7620             if(d == doc || d == doc.body){
7621                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7622             }else{
7623                 return {
7624                     width : d.clientWidth,
7625                     height: d.clientHeight
7626                 };
7627             }
7628         },
7629
7630         /**
7631          * Returns the value of the "value" attribute
7632          * @param {Boolean} asNumber true to parse the value as a number
7633          * @return {String/Number}
7634          */
7635         getValue : function(asNumber){
7636             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7637         },
7638
7639         // private
7640         adjustWidth : function(width){
7641             if(typeof width == "number"){
7642                 if(this.autoBoxAdjust && !this.isBorderBox()){
7643                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7644                 }
7645                 if(width < 0){
7646                     width = 0;
7647                 }
7648             }
7649             return width;
7650         },
7651
7652         // private
7653         adjustHeight : function(height){
7654             if(typeof height == "number"){
7655                if(this.autoBoxAdjust && !this.isBorderBox()){
7656                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7657                }
7658                if(height < 0){
7659                    height = 0;
7660                }
7661             }
7662             return height;
7663         },
7664
7665         /**
7666          * Set the width of the element
7667          * @param {Number} width The new width
7668          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7669          * @return {Roo.Element} this
7670          */
7671         setWidth : function(width, animate){
7672             width = this.adjustWidth(width);
7673             if(!animate || !A){
7674                 this.dom.style.width = this.addUnits(width);
7675             }else{
7676                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7677             }
7678             return this;
7679         },
7680
7681         /**
7682          * Set the height of the element
7683          * @param {Number} height The new height
7684          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7685          * @return {Roo.Element} this
7686          */
7687          setHeight : function(height, animate){
7688             height = this.adjustHeight(height);
7689             if(!animate || !A){
7690                 this.dom.style.height = this.addUnits(height);
7691             }else{
7692                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7693             }
7694             return this;
7695         },
7696
7697         /**
7698          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7699          * @param {Number} width The new width
7700          * @param {Number} height The new height
7701          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7702          * @return {Roo.Element} this
7703          */
7704          setSize : function(width, height, animate){
7705             if(typeof width == "object"){ // in case of object from getSize()
7706                 height = width.height; width = width.width;
7707             }
7708             width = this.adjustWidth(width); height = this.adjustHeight(height);
7709             if(!animate || !A){
7710                 this.dom.style.width = this.addUnits(width);
7711                 this.dom.style.height = this.addUnits(height);
7712             }else{
7713                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7714             }
7715             return this;
7716         },
7717
7718         /**
7719          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7720          * @param {Number} x X value for new position (coordinates are page-based)
7721          * @param {Number} y Y value for new position (coordinates are page-based)
7722          * @param {Number} width The new width
7723          * @param {Number} height The new height
7724          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7725          * @return {Roo.Element} this
7726          */
7727         setBounds : function(x, y, width, height, animate){
7728             if(!animate || !A){
7729                 this.setSize(width, height);
7730                 this.setLocation(x, y);
7731             }else{
7732                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7733                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7734                               this.preanim(arguments, 4), 'motion');
7735             }
7736             return this;
7737         },
7738
7739         /**
7740          * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7741          * @param {Roo.lib.Region} region The region to fill
7742          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7743          * @return {Roo.Element} this
7744          */
7745         setRegion : function(region, animate){
7746             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7747             return this;
7748         },
7749
7750         /**
7751          * Appends an event handler
7752          *
7753          * @param {String}   eventName     The type of event to append
7754          * @param {Function} fn        The method the event invokes
7755          * @param {Object} scope       (optional) The scope (this object) of the fn
7756          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7757          */
7758         addListener : function(eventName, fn, scope, options){
7759             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
7760         },
7761
7762         /**
7763          * Removes an event handler from this element
7764          * @param {String} eventName the type of event to remove
7765          * @param {Function} fn the method the event invokes
7766          * @return {Roo.Element} this
7767          */
7768         removeListener : function(eventName, fn){
7769             Roo.EventManager.removeListener(this.dom,  eventName, fn);
7770             return this;
7771         },
7772
7773         /**
7774          * Removes all previous added listeners from this element
7775          * @return {Roo.Element} this
7776          */
7777         removeAllListeners : function(){
7778             E.purgeElement(this.dom);
7779             return this;
7780         },
7781
7782         relayEvent : function(eventName, observable){
7783             this.on(eventName, function(e){
7784                 observable.fireEvent(eventName, e);
7785             });
7786         },
7787
7788         /**
7789          * Set the opacity of the element
7790          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7791          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7792          * @return {Roo.Element} this
7793          */
7794          setOpacity : function(opacity, animate){
7795             if(!animate || !A){
7796                 var s = this.dom.style;
7797                 if(Roo.isIE){
7798                     s.zoom = 1;
7799                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7800                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7801                 }else{
7802                     s.opacity = opacity;
7803                 }
7804             }else{
7805                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7806             }
7807             return this;
7808         },
7809
7810         /**
7811          * Gets the left X coordinate
7812          * @param {Boolean} local True to get the local css position instead of page coordinate
7813          * @return {Number}
7814          */
7815         getLeft : function(local){
7816             if(!local){
7817                 return this.getX();
7818             }else{
7819                 return parseInt(this.getStyle("left"), 10) || 0;
7820             }
7821         },
7822
7823         /**
7824          * Gets the right X coordinate of the element (element X position + element width)
7825          * @param {Boolean} local True to get the local css position instead of page coordinate
7826          * @return {Number}
7827          */
7828         getRight : function(local){
7829             if(!local){
7830                 return this.getX() + this.getWidth();
7831             }else{
7832                 return (this.getLeft(true) + this.getWidth()) || 0;
7833             }
7834         },
7835
7836         /**
7837          * Gets the top Y coordinate
7838          * @param {Boolean} local True to get the local css position instead of page coordinate
7839          * @return {Number}
7840          */
7841         getTop : function(local) {
7842             if(!local){
7843                 return this.getY();
7844             }else{
7845                 return parseInt(this.getStyle("top"), 10) || 0;
7846             }
7847         },
7848
7849         /**
7850          * Gets the bottom Y coordinate of the element (element Y position + element height)
7851          * @param {Boolean} local True to get the local css position instead of page coordinate
7852          * @return {Number}
7853          */
7854         getBottom : function(local){
7855             if(!local){
7856                 return this.getY() + this.getHeight();
7857             }else{
7858                 return (this.getTop(true) + this.getHeight()) || 0;
7859             }
7860         },
7861
7862         /**
7863         * Initializes positioning on this element. If a desired position is not passed, it will make the
7864         * the element positioned relative IF it is not already positioned.
7865         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7866         * @param {Number} zIndex (optional) The zIndex to apply
7867         * @param {Number} x (optional) Set the page X position
7868         * @param {Number} y (optional) Set the page Y position
7869         */
7870         position : function(pos, zIndex, x, y){
7871             if(!pos){
7872                if(this.getStyle('position') == 'static'){
7873                    this.setStyle('position', 'relative');
7874                }
7875             }else{
7876                 this.setStyle("position", pos);
7877             }
7878             if(zIndex){
7879                 this.setStyle("z-index", zIndex);
7880             }
7881             if(x !== undefined && y !== undefined){
7882                 this.setXY([x, y]);
7883             }else if(x !== undefined){
7884                 this.setX(x);
7885             }else if(y !== undefined){
7886                 this.setY(y);
7887             }
7888         },
7889
7890         /**
7891         * Clear positioning back to the default when the document was loaded
7892         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7893         * @return {Roo.Element} this
7894          */
7895         clearPositioning : function(value){
7896             value = value ||'';
7897             this.setStyle({
7898                 "left": value,
7899                 "right": value,
7900                 "top": value,
7901                 "bottom": value,
7902                 "z-index": "",
7903                 "position" : "static"
7904             });
7905             return this;
7906         },
7907
7908         /**
7909         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7910         * snapshot before performing an update and then restoring the element.
7911         * @return {Object}
7912         */
7913         getPositioning : function(){
7914             var l = this.getStyle("left");
7915             var t = this.getStyle("top");
7916             return {
7917                 "position" : this.getStyle("position"),
7918                 "left" : l,
7919                 "right" : l ? "" : this.getStyle("right"),
7920                 "top" : t,
7921                 "bottom" : t ? "" : this.getStyle("bottom"),
7922                 "z-index" : this.getStyle("z-index")
7923             };
7924         },
7925
7926         /**
7927          * Gets the width of the border(s) for the specified side(s)
7928          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7929          * passing lr would get the border (l)eft width + the border (r)ight width.
7930          * @return {Number} The width of the sides passed added together
7931          */
7932         getBorderWidth : function(side){
7933             return this.addStyles(side, El.borders);
7934         },
7935
7936         /**
7937          * Gets the width of the padding(s) for the specified side(s)
7938          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7939          * passing lr would get the padding (l)eft + the padding (r)ight.
7940          * @return {Number} The padding of the sides passed added together
7941          */
7942         getPadding : function(side){
7943             return this.addStyles(side, El.paddings);
7944         },
7945
7946         /**
7947         * Set positioning with an object returned by getPositioning().
7948         * @param {Object} posCfg
7949         * @return {Roo.Element} this
7950          */
7951         setPositioning : function(pc){
7952             this.applyStyles(pc);
7953             if(pc.right == "auto"){
7954                 this.dom.style.right = "";
7955             }
7956             if(pc.bottom == "auto"){
7957                 this.dom.style.bottom = "";
7958             }
7959             return this;
7960         },
7961
7962         // private
7963         fixDisplay : function(){
7964             if(this.getStyle("display") == "none"){
7965                 this.setStyle("visibility", "hidden");
7966                 this.setStyle("display", this.originalDisplay); // first try reverting to default
7967                 if(this.getStyle("display") == "none"){ // if that fails, default to block
7968                     this.setStyle("display", "block");
7969                 }
7970             }
7971         },
7972
7973         /**
7974          * Quick set left and top adding default units
7975          * @param {String} left The left CSS property value
7976          * @param {String} top The top CSS property value
7977          * @return {Roo.Element} this
7978          */
7979          setLeftTop : function(left, top){
7980             this.dom.style.left = this.addUnits(left);
7981             this.dom.style.top = this.addUnits(top);
7982             return this;
7983         },
7984
7985         /**
7986          * Move this element relative to its current position.
7987          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
7988          * @param {Number} distance How far to move the element in pixels
7989          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7990          * @return {Roo.Element} this
7991          */
7992          move : function(direction, distance, animate){
7993             var xy = this.getXY();
7994             direction = direction.toLowerCase();
7995             switch(direction){
7996                 case "l":
7997                 case "left":
7998                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
7999                     break;
8000                case "r":
8001                case "right":
8002                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8003                     break;
8004                case "t":
8005                case "top":
8006                case "up":
8007                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8008                     break;
8009                case "b":
8010                case "bottom":
8011                case "down":
8012                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8013                     break;
8014             }
8015             return this;
8016         },
8017
8018         /**
8019          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8020          * @return {Roo.Element} this
8021          */
8022         clip : function(){
8023             if(!this.isClipped){
8024                this.isClipped = true;
8025                this.originalClip = {
8026                    "o": this.getStyle("overflow"),
8027                    "x": this.getStyle("overflow-x"),
8028                    "y": this.getStyle("overflow-y")
8029                };
8030                this.setStyle("overflow", "hidden");
8031                this.setStyle("overflow-x", "hidden");
8032                this.setStyle("overflow-y", "hidden");
8033             }
8034             return this;
8035         },
8036
8037         /**
8038          *  Return clipping (overflow) to original clipping before clip() was called
8039          * @return {Roo.Element} this
8040          */
8041         unclip : function(){
8042             if(this.isClipped){
8043                 this.isClipped = false;
8044                 var o = this.originalClip;
8045                 if(o.o){this.setStyle("overflow", o.o);}
8046                 if(o.x){this.setStyle("overflow-x", o.x);}
8047                 if(o.y){this.setStyle("overflow-y", o.y);}
8048             }
8049             return this;
8050         },
8051
8052
8053         /**
8054          * Gets the x,y coordinates specified by the anchor position on the element.
8055          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8056          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8057          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8058          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8059          * @return {Array} [x, y] An array containing the element's x and y coordinates
8060          */
8061         getAnchorXY : function(anchor, local, s){
8062             //Passing a different size is useful for pre-calculating anchors,
8063             //especially for anchored animations that change the el size.
8064
8065             var w, h, vp = false;
8066             if(!s){
8067                 var d = this.dom;
8068                 if(d == document.body || d == document){
8069                     vp = true;
8070                     w = D.getViewWidth(); h = D.getViewHeight();
8071                 }else{
8072                     w = this.getWidth(); h = this.getHeight();
8073                 }
8074             }else{
8075                 w = s.width;  h = s.height;
8076             }
8077             var x = 0, y = 0, r = Math.round;
8078             switch((anchor || "tl").toLowerCase()){
8079                 case "c":
8080                     x = r(w*.5);
8081                     y = r(h*.5);
8082                 break;
8083                 case "t":
8084                     x = r(w*.5);
8085                     y = 0;
8086                 break;
8087                 case "l":
8088                     x = 0;
8089                     y = r(h*.5);
8090                 break;
8091                 case "r":
8092                     x = w;
8093                     y = r(h*.5);
8094                 break;
8095                 case "b":
8096                     x = r(w*.5);
8097                     y = h;
8098                 break;
8099                 case "tl":
8100                     x = 0;
8101                     y = 0;
8102                 break;
8103                 case "bl":
8104                     x = 0;
8105                     y = h;
8106                 break;
8107                 case "br":
8108                     x = w;
8109                     y = h;
8110                 break;
8111                 case "tr":
8112                     x = w;
8113                     y = 0;
8114                 break;
8115             }
8116             if(local === true){
8117                 return [x, y];
8118             }
8119             if(vp){
8120                 var sc = this.getScroll();
8121                 return [x + sc.left, y + sc.top];
8122             }
8123             //Add the element's offset xy
8124             var o = this.getXY();
8125             return [x+o[0], y+o[1]];
8126         },
8127
8128         /**
8129          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8130          * supported position values.
8131          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8132          * @param {String} position The position to align to.
8133          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8134          * @return {Array} [x, y]
8135          */
8136         getAlignToXY : function(el, p, o){
8137             el = Roo.get(el);
8138             var d = this.dom;
8139             if(!el.dom){
8140                 throw "Element.alignTo with an element that doesn't exist";
8141             }
8142             var c = false; //constrain to viewport
8143             var p1 = "", p2 = "";
8144             o = o || [0,0];
8145
8146             if(!p){
8147                 p = "tl-bl";
8148             }else if(p == "?"){
8149                 p = "tl-bl?";
8150             }else if(p.indexOf("-") == -1){
8151                 p = "tl-" + p;
8152             }
8153             p = p.toLowerCase();
8154             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8155             if(!m){
8156                throw "Element.alignTo with an invalid alignment " + p;
8157             }
8158             p1 = m[1]; p2 = m[2]; c = !!m[3];
8159
8160             //Subtract the aligned el's internal xy from the target's offset xy
8161             //plus custom offset to get the aligned el's new offset xy
8162             var a1 = this.getAnchorXY(p1, true);
8163             var a2 = el.getAnchorXY(p2, false);
8164             var x = a2[0] - a1[0] + o[0];
8165             var y = a2[1] - a1[1] + o[1];
8166             if(c){
8167                 //constrain the aligned el to viewport if necessary
8168                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8169                 // 5px of margin for ie
8170                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8171
8172                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8173                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8174                 //otherwise swap the aligned el to the opposite border of the target.
8175                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8176                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8177                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8178                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8179
8180                var doc = document;
8181                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8182                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8183
8184                if((x+w) > dw + scrollX){
8185                     x = swapX ? r.left-w : dw+scrollX-w;
8186                 }
8187                if(x < scrollX){
8188                    x = swapX ? r.right : scrollX;
8189                }
8190                if((y+h) > dh + scrollY){
8191                     y = swapY ? r.top-h : dh+scrollY-h;
8192                 }
8193                if (y < scrollY){
8194                    y = swapY ? r.bottom : scrollY;
8195                }
8196             }
8197             return [x,y];
8198         },
8199
8200         // private
8201         getConstrainToXY : function(){
8202             var os = {top:0, left:0, bottom:0, right: 0};
8203
8204             return function(el, local, offsets, proposedXY){
8205                 el = Roo.get(el);
8206                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8207
8208                 var vw, vh, vx = 0, vy = 0;
8209                 if(el.dom == document.body || el.dom == document){
8210                     vw = Roo.lib.Dom.getViewWidth();
8211                     vh = Roo.lib.Dom.getViewHeight();
8212                 }else{
8213                     vw = el.dom.clientWidth;
8214                     vh = el.dom.clientHeight;
8215                     if(!local){
8216                         var vxy = el.getXY();
8217                         vx = vxy[0];
8218                         vy = vxy[1];
8219                     }
8220                 }
8221
8222                 var s = el.getScroll();
8223
8224                 vx += offsets.left + s.left;
8225                 vy += offsets.top + s.top;
8226
8227                 vw -= offsets.right;
8228                 vh -= offsets.bottom;
8229
8230                 var vr = vx+vw;
8231                 var vb = vy+vh;
8232
8233                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8234                 var x = xy[0], y = xy[1];
8235                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8236
8237                 // only move it if it needs it
8238                 var moved = false;
8239
8240                 // first validate right/bottom
8241                 if((x + w) > vr){
8242                     x = vr - w;
8243                     moved = true;
8244                 }
8245                 if((y + h) > vb){
8246                     y = vb - h;
8247                     moved = true;
8248                 }
8249                 // then make sure top/left isn't negative
8250                 if(x < vx){
8251                     x = vx;
8252                     moved = true;
8253                 }
8254                 if(y < vy){
8255                     y = vy;
8256                     moved = true;
8257                 }
8258                 return moved ? [x, y] : false;
8259             };
8260         }(),
8261
8262         // private
8263         adjustForConstraints : function(xy, parent, offsets){
8264             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8265         },
8266
8267         /**
8268          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8269          * document it aligns it to the viewport.
8270          * The position parameter is optional, and can be specified in any one of the following formats:
8271          * <ul>
8272          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8273          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8274          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8275          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8276          *   <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8277          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8278          * </ul>
8279          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8280          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8281          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8282          * that specified in order to enforce the viewport constraints.
8283          * Following are all of the supported anchor positions:
8284     <pre>
8285     Value  Description
8286     -----  -----------------------------
8287     tl     The top left corner (default)
8288     t      The center of the top edge
8289     tr     The top right corner
8290     l      The center of the left edge
8291     c      In the center of the element
8292     r      The center of the right edge
8293     bl     The bottom left corner
8294     b      The center of the bottom edge
8295     br     The bottom right corner
8296     </pre>
8297     Example Usage:
8298     <pre><code>
8299     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8300     el.alignTo("other-el");
8301
8302     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8303     el.alignTo("other-el", "tr?");
8304
8305     // align the bottom right corner of el with the center left edge of other-el
8306     el.alignTo("other-el", "br-l?");
8307
8308     // align the center of el with the bottom left corner of other-el and
8309     // adjust the x position by -6 pixels (and the y position by 0)
8310     el.alignTo("other-el", "c-bl", [-6, 0]);
8311     </code></pre>
8312          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8313          * @param {String} position The position to align to.
8314          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8315          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8316          * @return {Roo.Element} this
8317          */
8318         alignTo : function(element, position, offsets, animate){
8319             var xy = this.getAlignToXY(element, position, offsets);
8320             this.setXY(xy, this.preanim(arguments, 3));
8321             return this;
8322         },
8323
8324         /**
8325          * Anchors an element to another element and realigns it when the window is resized.
8326          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8327          * @param {String} position The position to align to.
8328          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8329          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8330          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8331          * is a number, it is used as the buffer delay (defaults to 50ms).
8332          * @param {Function} callback The function to call after the animation finishes
8333          * @return {Roo.Element} this
8334          */
8335         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8336             var action = function(){
8337                 this.alignTo(el, alignment, offsets, animate);
8338                 Roo.callback(callback, this);
8339             };
8340             Roo.EventManager.onWindowResize(action, this);
8341             var tm = typeof monitorScroll;
8342             if(tm != 'undefined'){
8343                 Roo.EventManager.on(window, 'scroll', action, this,
8344                     {buffer: tm == 'number' ? monitorScroll : 50});
8345             }
8346             action.call(this); // align immediately
8347             return this;
8348         },
8349         /**
8350          * Clears any opacity settings from this element. Required in some cases for IE.
8351          * @return {Roo.Element} this
8352          */
8353         clearOpacity : function(){
8354             if (window.ActiveXObject) {
8355                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8356                     this.dom.style.filter = "";
8357                 }
8358             } else {
8359                 this.dom.style.opacity = "";
8360                 this.dom.style["-moz-opacity"] = "";
8361                 this.dom.style["-khtml-opacity"] = "";
8362             }
8363             return this;
8364         },
8365
8366         /**
8367          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8368          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8369          * @return {Roo.Element} this
8370          */
8371         hide : function(animate){
8372             this.setVisible(false, this.preanim(arguments, 0));
8373             return this;
8374         },
8375
8376         /**
8377         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8378         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8379          * @return {Roo.Element} this
8380          */
8381         show : function(animate){
8382             this.setVisible(true, this.preanim(arguments, 0));
8383             return this;
8384         },
8385
8386         /**
8387          * @private Test if size has a unit, otherwise appends the default
8388          */
8389         addUnits : function(size){
8390             return Roo.Element.addUnits(size, this.defaultUnit);
8391         },
8392
8393         /**
8394          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8395          * @return {Roo.Element} this
8396          */
8397         beginMeasure : function(){
8398             var el = this.dom;
8399             if(el.offsetWidth || el.offsetHeight){
8400                 return this; // offsets work already
8401             }
8402             var changed = [];
8403             var p = this.dom, b = document.body; // start with this element
8404             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8405                 var pe = Roo.get(p);
8406                 if(pe.getStyle('display') == 'none'){
8407                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8408                     p.style.visibility = "hidden";
8409                     p.style.display = "block";
8410                 }
8411                 p = p.parentNode;
8412             }
8413             this._measureChanged = changed;
8414             return this;
8415
8416         },
8417
8418         /**
8419          * Restores displays to before beginMeasure was called
8420          * @return {Roo.Element} this
8421          */
8422         endMeasure : function(){
8423             var changed = this._measureChanged;
8424             if(changed){
8425                 for(var i = 0, len = changed.length; i < len; i++) {
8426                     var r = changed[i];
8427                     r.el.style.visibility = r.visibility;
8428                     r.el.style.display = "none";
8429                 }
8430                 this._measureChanged = null;
8431             }
8432             return this;
8433         },
8434
8435         /**
8436         * Update the innerHTML of this element, optionally searching for and processing scripts
8437         * @param {String} html The new HTML
8438         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8439         * @param {Function} callback For async script loading you can be noticed when the update completes
8440         * @return {Roo.Element} this
8441          */
8442         update : function(html, loadScripts, callback){
8443             if(typeof html == "undefined"){
8444                 html = "";
8445             }
8446             if(loadScripts !== true){
8447                 this.dom.innerHTML = html;
8448                 if(typeof callback == "function"){
8449                     callback();
8450                 }
8451                 return this;
8452             }
8453             var id = Roo.id();
8454             var dom = this.dom;
8455
8456             html += '<span id="' + id + '"></span>';
8457
8458             E.onAvailable(id, function(){
8459                 var hd = document.getElementsByTagName("head")[0];
8460                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8461                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8462                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8463
8464                 var match;
8465                 while(match = re.exec(html)){
8466                     var attrs = match[1];
8467                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8468                     if(srcMatch && srcMatch[2]){
8469                        var s = document.createElement("script");
8470                        s.src = srcMatch[2];
8471                        var typeMatch = attrs.match(typeRe);
8472                        if(typeMatch && typeMatch[2]){
8473                            s.type = typeMatch[2];
8474                        }
8475                        hd.appendChild(s);
8476                     }else if(match[2] && match[2].length > 0){
8477                         if(window.execScript) {
8478                            window.execScript(match[2]);
8479                         } else {
8480                             /**
8481                              * eval:var:id
8482                              * eval:var:dom
8483                              * eval:var:html
8484                              * 
8485                              */
8486                            window.eval(match[2]);
8487                         }
8488                     }
8489                 }
8490                 var el = document.getElementById(id);
8491                 if(el){el.parentNode.removeChild(el);}
8492                 if(typeof callback == "function"){
8493                     callback();
8494                 }
8495             });
8496             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8497             return this;
8498         },
8499
8500         /**
8501          * Direct access to the UpdateManager update() method (takes the same parameters).
8502          * @param {String/Function} url The url for this request or a function to call to get the url
8503          * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
8504          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8505          * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8506          * @return {Roo.Element} this
8507          */
8508         load : function(){
8509             var um = this.getUpdateManager();
8510             um.update.apply(um, arguments);
8511             return this;
8512         },
8513
8514         /**
8515         * Gets this element's UpdateManager
8516         * @return {Roo.UpdateManager} The UpdateManager
8517         */
8518         getUpdateManager : function(){
8519             if(!this.updateManager){
8520                 this.updateManager = new Roo.UpdateManager(this);
8521             }
8522             return this.updateManager;
8523         },
8524
8525         /**
8526          * Disables text selection for this element (normalized across browsers)
8527          * @return {Roo.Element} this
8528          */
8529         unselectable : function(){
8530             this.dom.unselectable = "on";
8531             this.swallowEvent("selectstart", true);
8532             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8533             this.addClass("x-unselectable");
8534             return this;
8535         },
8536
8537         /**
8538         * Calculates the x, y to center this element on the screen
8539         * @return {Array} The x, y values [x, y]
8540         */
8541         getCenterXY : function(){
8542             return this.getAlignToXY(document, 'c-c');
8543         },
8544
8545         /**
8546         * Centers the Element in either the viewport, or another Element.
8547         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8548         */
8549         center : function(centerIn){
8550             this.alignTo(centerIn || document, 'c-c');
8551             return this;
8552         },
8553
8554         /**
8555          * Tests various css rules/browsers to determine if this element uses a border box
8556          * @return {Boolean}
8557          */
8558         isBorderBox : function(){
8559             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8560         },
8561
8562         /**
8563          * Return a box {x, y, width, height} that can be used to set another elements
8564          * size/location to match this element.
8565          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8566          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8567          * @return {Object} box An object in the format {x, y, width, height}
8568          */
8569         getBox : function(contentBox, local){
8570             var xy;
8571             if(!local){
8572                 xy = this.getXY();
8573             }else{
8574                 var left = parseInt(this.getStyle("left"), 10) || 0;
8575                 var top = parseInt(this.getStyle("top"), 10) || 0;
8576                 xy = [left, top];
8577             }
8578             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8579             if(!contentBox){
8580                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8581             }else{
8582                 var l = this.getBorderWidth("l")+this.getPadding("l");
8583                 var r = this.getBorderWidth("r")+this.getPadding("r");
8584                 var t = this.getBorderWidth("t")+this.getPadding("t");
8585                 var b = this.getBorderWidth("b")+this.getPadding("b");
8586                 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8587             }
8588             bx.right = bx.x + bx.width;
8589             bx.bottom = bx.y + bx.height;
8590             return bx;
8591         },
8592
8593         /**
8594          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8595          for more information about the sides.
8596          * @param {String} sides
8597          * @return {Number}
8598          */
8599         getFrameWidth : function(sides, onlyContentBox){
8600             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8601         },
8602
8603         /**
8604          * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8605          * @param {Object} box The box to fill {x, y, width, height}
8606          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8607          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8608          * @return {Roo.Element} this
8609          */
8610         setBox : function(box, adjust, animate){
8611             var w = box.width, h = box.height;
8612             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8613                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8614                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8615             }
8616             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8617             return this;
8618         },
8619
8620         /**
8621          * Forces the browser to repaint this element
8622          * @return {Roo.Element} this
8623          */
8624          repaint : function(){
8625             var dom = this.dom;
8626             this.addClass("x-repaint");
8627             setTimeout(function(){
8628                 Roo.get(dom).removeClass("x-repaint");
8629             }, 1);
8630             return this;
8631         },
8632
8633         /**
8634          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8635          * then it returns the calculated width of the sides (see getPadding)
8636          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8637          * @return {Object/Number}
8638          */
8639         getMargins : function(side){
8640             if(!side){
8641                 return {
8642                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8643                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8644                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8645                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8646                 };
8647             }else{
8648                 return this.addStyles(side, El.margins);
8649              }
8650         },
8651
8652         // private
8653         addStyles : function(sides, styles){
8654             var val = 0, v, w;
8655             for(var i = 0, len = sides.length; i < len; i++){
8656                 v = this.getStyle(styles[sides.charAt(i)]);
8657                 if(v){
8658                      w = parseInt(v, 10);
8659                      if(w){ val += w; }
8660                 }
8661             }
8662             return val;
8663         },
8664
8665         /**
8666          * Creates a proxy element of this element
8667          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8668          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8669          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8670          * @return {Roo.Element} The new proxy element
8671          */
8672         createProxy : function(config, renderTo, matchBox){
8673             if(renderTo){
8674                 renderTo = Roo.getDom(renderTo);
8675             }else{
8676                 renderTo = document.body;
8677             }
8678             config = typeof config == "object" ?
8679                 config : {tag : "div", cls: config};
8680             var proxy = Roo.DomHelper.append(renderTo, config, true);
8681             if(matchBox){
8682                proxy.setBox(this.getBox());
8683             }
8684             return proxy;
8685         },
8686
8687         /**
8688          * Puts a mask over this element to disable user interaction. Requires core.css.
8689          * This method can only be applied to elements which accept child nodes.
8690          * @param {String} msg (optional) A message to display in the mask
8691          * @param {String} msgCls (optional) A css class to apply to the msg element
8692          * @return {Element} The mask  element
8693          */
8694         mask : function(msg, msgCls){
8695             if(this.getStyle("position") == "static"){
8696                 this.setStyle("position", "relative");
8697             }
8698             if(!this._mask){
8699                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8700             }
8701             this.addClass("x-masked");
8702             this._mask.setDisplayed(true);
8703             if(typeof msg == 'string'){
8704                 if(!this._maskMsg){
8705                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8706                 }
8707                 var mm = this._maskMsg;
8708                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8709                 mm.dom.firstChild.innerHTML = msg;
8710                 mm.setDisplayed(true);
8711                 mm.center(this);
8712             }
8713             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8714                 this._mask.setHeight(this.getHeight());
8715             }
8716             return this._mask;
8717         },
8718
8719         /**
8720          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8721          * it is cached for reuse.
8722          */
8723         unmask : function(removeEl){
8724             if(this._mask){
8725                 if(removeEl === true){
8726                     this._mask.remove();
8727                     delete this._mask;
8728                     if(this._maskMsg){
8729                         this._maskMsg.remove();
8730                         delete this._maskMsg;
8731                     }
8732                 }else{
8733                     this._mask.setDisplayed(false);
8734                     if(this._maskMsg){
8735                         this._maskMsg.setDisplayed(false);
8736                     }
8737                 }
8738             }
8739             this.removeClass("x-masked");
8740         },
8741
8742         /**
8743          * Returns true if this element is masked
8744          * @return {Boolean}
8745          */
8746         isMasked : function(){
8747             return this._mask && this._mask.isVisible();
8748         },
8749
8750         /**
8751          * Creates an iframe shim for this element to keep selects and other windowed objects from
8752          * showing through.
8753          * @return {Roo.Element} The new shim element
8754          */
8755         createShim : function(){
8756             var el = document.createElement('iframe');
8757             el.frameBorder = 'no';
8758             el.className = 'roo-shim';
8759             if(Roo.isIE && Roo.isSecure){
8760                 el.src = Roo.SSL_SECURE_URL;
8761             }
8762             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8763             shim.autoBoxAdjust = false;
8764             return shim;
8765         },
8766
8767         /**
8768          * Removes this element from the DOM and deletes it from the cache
8769          */
8770         remove : function(){
8771             if(this.dom.parentNode){
8772                 this.dom.parentNode.removeChild(this.dom);
8773             }
8774             delete El.cache[this.dom.id];
8775         },
8776
8777         /**
8778          * Sets up event handlers to add and remove a css class when the mouse is over this element
8779          * @param {String} className
8780          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8781          * mouseout events for children elements
8782          * @return {Roo.Element} this
8783          */
8784         addClassOnOver : function(className, preventFlicker){
8785             this.on("mouseover", function(){
8786                 Roo.fly(this, '_internal').addClass(className);
8787             }, this.dom);
8788             var removeFn = function(e){
8789                 if(preventFlicker !== true || !e.within(this, true)){
8790                     Roo.fly(this, '_internal').removeClass(className);
8791                 }
8792             };
8793             this.on("mouseout", removeFn, this.dom);
8794             return this;
8795         },
8796
8797         /**
8798          * Sets up event handlers to add and remove a css class when this element has the focus
8799          * @param {String} className
8800          * @return {Roo.Element} this
8801          */
8802         addClassOnFocus : function(className){
8803             this.on("focus", function(){
8804                 Roo.fly(this, '_internal').addClass(className);
8805             }, this.dom);
8806             this.on("blur", function(){
8807                 Roo.fly(this, '_internal').removeClass(className);
8808             }, this.dom);
8809             return this;
8810         },
8811         /**
8812          * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
8813          * @param {String} className
8814          * @return {Roo.Element} this
8815          */
8816         addClassOnClick : function(className){
8817             var dom = this.dom;
8818             this.on("mousedown", function(){
8819                 Roo.fly(dom, '_internal').addClass(className);
8820                 var d = Roo.get(document);
8821                 var fn = function(){
8822                     Roo.fly(dom, '_internal').removeClass(className);
8823                     d.removeListener("mouseup", fn);
8824                 };
8825                 d.on("mouseup", fn);
8826             });
8827             return this;
8828         },
8829
8830         /**
8831          * Stops the specified event from bubbling and optionally prevents the default action
8832          * @param {String} eventName
8833          * @param {Boolean} preventDefault (optional) true to prevent the default action too
8834          * @return {Roo.Element} this
8835          */
8836         swallowEvent : function(eventName, preventDefault){
8837             var fn = function(e){
8838                 e.stopPropagation();
8839                 if(preventDefault){
8840                     e.preventDefault();
8841                 }
8842             };
8843             if(eventName instanceof Array){
8844                 for(var i = 0, len = eventName.length; i < len; i++){
8845                      this.on(eventName[i], fn);
8846                 }
8847                 return this;
8848             }
8849             this.on(eventName, fn);
8850             return this;
8851         },
8852
8853         /**
8854          * @private
8855          */
8856       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8857
8858         /**
8859          * Sizes this element to its parent element's dimensions performing
8860          * neccessary box adjustments.
8861          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8862          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8863          * @return {Roo.Element} this
8864          */
8865         fitToParent : function(monitorResize, targetParent) {
8866           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8867           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8868           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8869             return;
8870           }
8871           var p = Roo.get(targetParent || this.dom.parentNode);
8872           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8873           if (monitorResize === true) {
8874             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8875             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8876           }
8877           return this;
8878         },
8879
8880         /**
8881          * Gets the next sibling, skipping text nodes
8882          * @return {HTMLElement} The next sibling or null
8883          */
8884         getNextSibling : function(){
8885             var n = this.dom.nextSibling;
8886             while(n && n.nodeType != 1){
8887                 n = n.nextSibling;
8888             }
8889             return n;
8890         },
8891
8892         /**
8893          * Gets the previous sibling, skipping text nodes
8894          * @return {HTMLElement} The previous sibling or null
8895          */
8896         getPrevSibling : function(){
8897             var n = this.dom.previousSibling;
8898             while(n && n.nodeType != 1){
8899                 n = n.previousSibling;
8900             }
8901             return n;
8902         },
8903
8904
8905         /**
8906          * Appends the passed element(s) to this element
8907          * @param {String/HTMLElement/Array/Element/CompositeElement} el
8908          * @return {Roo.Element} this
8909          */
8910         appendChild: function(el){
8911             el = Roo.get(el);
8912             el.appendTo(this);
8913             return this;
8914         },
8915
8916         /**
8917          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8918          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
8919          * automatically generated with the specified attributes.
8920          * @param {HTMLElement} insertBefore (optional) a child element of this element
8921          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8922          * @return {Roo.Element} The new child element
8923          */
8924         createChild: function(config, insertBefore, returnDom){
8925             config = config || {tag:'div'};
8926             if(insertBefore){
8927                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8928             }
8929             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
8930         },
8931
8932         /**
8933          * Appends this element to the passed element
8934          * @param {String/HTMLElement/Element} el The new parent element
8935          * @return {Roo.Element} this
8936          */
8937         appendTo: function(el){
8938             el = Roo.getDom(el);
8939             el.appendChild(this.dom);
8940             return this;
8941         },
8942
8943         /**
8944          * Inserts this element before the passed element in the DOM
8945          * @param {String/HTMLElement/Element} el The element to insert before
8946          * @return {Roo.Element} this
8947          */
8948         insertBefore: function(el){
8949             el = Roo.getDom(el);
8950             el.parentNode.insertBefore(this.dom, el);
8951             return this;
8952         },
8953
8954         /**
8955          * Inserts this element after the passed element in the DOM
8956          * @param {String/HTMLElement/Element} el The element to insert after
8957          * @return {Roo.Element} this
8958          */
8959         insertAfter: function(el){
8960             el = Roo.getDom(el);
8961             el.parentNode.insertBefore(this.dom, el.nextSibling);
8962             return this;
8963         },
8964
8965         /**
8966          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8967          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8968          * @return {Roo.Element} The new child
8969          */
8970         insertFirst: function(el, returnDom){
8971             el = el || {};
8972             if(typeof el == 'object' && !el.nodeType){ // dh config
8973                 return this.createChild(el, this.dom.firstChild, returnDom);
8974             }else{
8975                 el = Roo.getDom(el);
8976                 this.dom.insertBefore(el, this.dom.firstChild);
8977                 return !returnDom ? Roo.get(el) : el;
8978             }
8979         },
8980
8981         /**
8982          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
8983          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8984          * @param {String} where (optional) 'before' or 'after' defaults to before
8985          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8986          * @return {Roo.Element} the inserted Element
8987          */
8988         insertSibling: function(el, where, returnDom){
8989             where = where ? where.toLowerCase() : 'before';
8990             el = el || {};
8991             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
8992
8993             if(typeof el == 'object' && !el.nodeType){ // dh config
8994                 if(where == 'after' && !this.dom.nextSibling){
8995                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
8996                 }else{
8997                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
8998                 }
8999
9000             }else{
9001                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9002                             where == 'before' ? this.dom : this.dom.nextSibling);
9003                 if(!returnDom){
9004                     rt = Roo.get(rt);
9005                 }
9006             }
9007             return rt;
9008         },
9009
9010         /**
9011          * Creates and wraps this element with another element
9012          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9013          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9014          * @return {HTMLElement/Element} The newly created wrapper element
9015          */
9016         wrap: function(config, returnDom){
9017             if(!config){
9018                 config = {tag: "div"};
9019             }
9020             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9021             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9022             return newEl;
9023         },
9024
9025         /**
9026          * Replaces the passed element with this element
9027          * @param {String/HTMLElement/Element} el The element to replace
9028          * @return {Roo.Element} this
9029          */
9030         replace: function(el){
9031             el = Roo.get(el);
9032             this.insertBefore(el);
9033             el.remove();
9034             return this;
9035         },
9036
9037         /**
9038          * Inserts an html fragment into this element
9039          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9040          * @param {String} html The HTML fragment
9041          * @param {Boolean} returnEl True to return an Roo.Element
9042          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9043          */
9044         insertHtml : function(where, html, returnEl){
9045             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9046             return returnEl ? Roo.get(el) : el;
9047         },
9048
9049         /**
9050          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9051          * @param {Object} o The object with the attributes
9052          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9053          * @return {Roo.Element} this
9054          */
9055         set : function(o, useSet){
9056             var el = this.dom;
9057             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9058             for(var attr in o){
9059                 if(attr == "style" || typeof o[attr] == "function") continue;
9060                 if(attr=="cls"){
9061                     el.className = o["cls"];
9062                 }else{
9063                     if(useSet) el.setAttribute(attr, o[attr]);
9064                     else el[attr] = o[attr];
9065                 }
9066             }
9067             if(o.style){
9068                 Roo.DomHelper.applyStyles(el, o.style);
9069             }
9070             return this;
9071         },
9072
9073         /**
9074          * Convenience method for constructing a KeyMap
9075          * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9076          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9077          * @param {Function} fn The function to call
9078          * @param {Object} scope (optional) The scope of the function
9079          * @return {Roo.KeyMap} The KeyMap created
9080          */
9081         addKeyListener : function(key, fn, scope){
9082             var config;
9083             if(typeof key != "object" || key instanceof Array){
9084                 config = {
9085                     key: key,
9086                     fn: fn,
9087                     scope: scope
9088                 };
9089             }else{
9090                 config = {
9091                     key : key.key,
9092                     shift : key.shift,
9093                     ctrl : key.ctrl,
9094                     alt : key.alt,
9095                     fn: fn,
9096                     scope: scope
9097                 };
9098             }
9099             return new Roo.KeyMap(this, config);
9100         },
9101
9102         /**
9103          * Creates a KeyMap for this element
9104          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9105          * @return {Roo.KeyMap} The KeyMap created
9106          */
9107         addKeyMap : function(config){
9108             return new Roo.KeyMap(this, config);
9109         },
9110
9111         /**
9112          * Returns true if this element is scrollable.
9113          * @return {Boolean}
9114          */
9115          isScrollable : function(){
9116             var dom = this.dom;
9117             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9118         },
9119
9120         /**
9121          * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9122          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9123          * @param {Number} value The new scroll value
9124          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9125          * @return {Element} this
9126          */
9127
9128         scrollTo : function(side, value, animate){
9129             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9130             if(!animate || !A){
9131                 this.dom[prop] = value;
9132             }else{
9133                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9134                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9135             }
9136             return this;
9137         },
9138
9139         /**
9140          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9141          * within this element's scrollable range.
9142          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9143          * @param {Number} distance How far to scroll the element in pixels
9144          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9145          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9146          * was scrolled as far as it could go.
9147          */
9148          scroll : function(direction, distance, animate){
9149              if(!this.isScrollable()){
9150                  return;
9151              }
9152              var el = this.dom;
9153              var l = el.scrollLeft, t = el.scrollTop;
9154              var w = el.scrollWidth, h = el.scrollHeight;
9155              var cw = el.clientWidth, ch = el.clientHeight;
9156              direction = direction.toLowerCase();
9157              var scrolled = false;
9158              var a = this.preanim(arguments, 2);
9159              switch(direction){
9160                  case "l":
9161                  case "left":
9162                      if(w - l > cw){
9163                          var v = Math.min(l + distance, w-cw);
9164                          this.scrollTo("left", v, a);
9165                          scrolled = true;
9166                      }
9167                      break;
9168                 case "r":
9169                 case "right":
9170                      if(l > 0){
9171                          var v = Math.max(l - distance, 0);
9172                          this.scrollTo("left", v, a);
9173                          scrolled = true;
9174                      }
9175                      break;
9176                 case "t":
9177                 case "top":
9178                 case "up":
9179                      if(t > 0){
9180                          var v = Math.max(t - distance, 0);
9181                          this.scrollTo("top", v, a);
9182                          scrolled = true;
9183                      }
9184                      break;
9185                 case "b":
9186                 case "bottom":
9187                 case "down":
9188                      if(h - t > ch){
9189                          var v = Math.min(t + distance, h-ch);
9190                          this.scrollTo("top", v, a);
9191                          scrolled = true;
9192                      }
9193                      break;
9194              }
9195              return scrolled;
9196         },
9197
9198         /**
9199          * Translates the passed page coordinates into left/top css values for this element
9200          * @param {Number/Array} x The page x or an array containing [x, y]
9201          * @param {Number} y The page y
9202          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9203          */
9204         translatePoints : function(x, y){
9205             if(typeof x == 'object' || x instanceof Array){
9206                 y = x[1]; x = x[0];
9207             }
9208             var p = this.getStyle('position');
9209             var o = this.getXY();
9210
9211             var l = parseInt(this.getStyle('left'), 10);
9212             var t = parseInt(this.getStyle('top'), 10);
9213
9214             if(isNaN(l)){
9215                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9216             }
9217             if(isNaN(t)){
9218                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9219             }
9220
9221             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9222         },
9223
9224         /**
9225          * Returns the current scroll position of the element.
9226          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9227          */
9228         getScroll : function(){
9229             var d = this.dom, doc = document;
9230             if(d == doc || d == doc.body){
9231                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9232                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9233                 return {left: l, top: t};
9234             }else{
9235                 return {left: d.scrollLeft, top: d.scrollTop};
9236             }
9237         },
9238
9239         /**
9240          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9241          * are convert to standard 6 digit hex color.
9242          * @param {String} attr The css attribute
9243          * @param {String} defaultValue The default value to use when a valid color isn't found
9244          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9245          * YUI color anims.
9246          */
9247         getColor : function(attr, defaultValue, prefix){
9248             var v = this.getStyle(attr);
9249             if(!v || v == "transparent" || v == "inherit") {
9250                 return defaultValue;
9251             }
9252             var color = typeof prefix == "undefined" ? "#" : prefix;
9253             if(v.substr(0, 4) == "rgb("){
9254                 var rvs = v.slice(4, v.length -1).split(",");
9255                 for(var i = 0; i < 3; i++){
9256                     var h = parseInt(rvs[i]).toString(16);
9257                     if(h < 16){
9258                         h = "0" + h;
9259                     }
9260                     color += h;
9261                 }
9262             } else {
9263                 if(v.substr(0, 1) == "#"){
9264                     if(v.length == 4) {
9265                         for(var i = 1; i < 4; i++){
9266                             var c = v.charAt(i);
9267                             color +=  c + c;
9268                         }
9269                     }else if(v.length == 7){
9270                         color += v.substr(1);
9271                     }
9272                 }
9273             }
9274             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9275         },
9276
9277         /**
9278          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9279          * gradient background, rounded corners and a 4-way shadow.
9280          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9281          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9282          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9283          * @return {Roo.Element} this
9284          */
9285         boxWrap : function(cls){
9286             cls = cls || 'x-box';
9287             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9288             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9289             return el;
9290         },
9291
9292         /**
9293          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9294          * @param {String} namespace The namespace in which to look for the attribute
9295          * @param {String} name The attribute name
9296          * @return {String} The attribute value
9297          */
9298         getAttributeNS : Roo.isIE ? function(ns, name){
9299             var d = this.dom;
9300             var type = typeof d[ns+":"+name];
9301             if(type != 'undefined' && type != 'unknown'){
9302                 return d[ns+":"+name];
9303             }
9304             return d[name];
9305         } : function(ns, name){
9306             var d = this.dom;
9307             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9308         }
9309     };
9310
9311     var ep = El.prototype;
9312
9313     /**
9314      * Appends an event handler (Shorthand for addListener)
9315      * @param {String}   eventName     The type of event to append
9316      * @param {Function} fn        The method the event invokes
9317      * @param {Object} scope       (optional) The scope (this object) of the fn
9318      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9319      * @method
9320      */
9321     ep.on = ep.addListener;
9322         // backwards compat
9323     ep.mon = ep.addListener;
9324
9325     /**
9326      * Removes an event handler from this element (shorthand for removeListener)
9327      * @param {String} eventName the type of event to remove
9328      * @param {Function} fn the method the event invokes
9329      * @return {Roo.Element} this
9330      * @method
9331      */
9332     ep.un = ep.removeListener;
9333
9334     /**
9335      * true to automatically adjust width and height settings for box-model issues (default to true)
9336      */
9337     ep.autoBoxAdjust = true;
9338
9339     // private
9340     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9341
9342     // private
9343     El.addUnits = function(v, defaultUnit){
9344         if(v === "" || v == "auto"){
9345             return v;
9346         }
9347         if(v === undefined){
9348             return '';
9349         }
9350         if(typeof v == "number" || !El.unitPattern.test(v)){
9351             return v + (defaultUnit || 'px');
9352         }
9353         return v;
9354     };
9355
9356     // special markup used throughout Roo when box wrapping elements
9357     El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9358     /**
9359      * Visibility mode constant - Use visibility to hide element
9360      * @static
9361      * @type Number
9362      */
9363     El.VISIBILITY = 1;
9364     /**
9365      * Visibility mode constant - Use display to hide element
9366      * @static
9367      * @type Number
9368      */
9369     El.DISPLAY = 2;
9370
9371     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9372     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9373     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9374
9375
9376
9377     /**
9378      * @private
9379      */
9380     El.cache = {};
9381
9382     var docEl;
9383
9384     /**
9385      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9386      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9387      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9388      * @return {Element} The Element object
9389      * @static
9390      */
9391     El.get = function(el){
9392         var ex, elm, id;
9393         if(!el){ return null; }
9394         if(typeof el == "string"){ // element id
9395             if(!(elm = document.getElementById(el))){
9396                 return null;
9397             }
9398             if(ex = El.cache[el]){
9399                 ex.dom = elm;
9400             }else{
9401                 ex = El.cache[el] = new El(elm);
9402             }
9403             return ex;
9404         }else if(el.tagName){ // dom element
9405             if(!(id = el.id)){
9406                 id = Roo.id(el);
9407             }
9408             if(ex = El.cache[id]){
9409                 ex.dom = el;
9410             }else{
9411                 ex = El.cache[id] = new El(el);
9412             }
9413             return ex;
9414         }else if(el instanceof El){
9415             if(el != docEl){
9416                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9417                                                               // catch case where it hasn't been appended
9418                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9419             }
9420             return el;
9421         }else if(el.isComposite){
9422             return el;
9423         }else if(el instanceof Array){
9424             return El.select(el);
9425         }else if(el == document){
9426             // create a bogus element object representing the document object
9427             if(!docEl){
9428                 var f = function(){};
9429                 f.prototype = El.prototype;
9430                 docEl = new f();
9431                 docEl.dom = document;
9432             }
9433             return docEl;
9434         }
9435         return null;
9436     };
9437
9438     // private
9439     El.uncache = function(el){
9440         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9441             if(a[i]){
9442                 delete El.cache[a[i].id || a[i]];
9443             }
9444         }
9445     };
9446
9447     // private
9448     // Garbage collection - uncache elements/purge listeners on orphaned elements
9449     // so we don't hold a reference and cause the browser to retain them
9450     El.garbageCollect = function(){
9451         if(!Roo.enableGarbageCollector){
9452             clearInterval(El.collectorThread);
9453             return;
9454         }
9455         for(var eid in El.cache){
9456             var el = El.cache[eid], d = el.dom;
9457             // -------------------------------------------------------
9458             // Determining what is garbage:
9459             // -------------------------------------------------------
9460             // !d
9461             // dom node is null, definitely garbage
9462             // -------------------------------------------------------
9463             // !d.parentNode
9464             // no parentNode == direct orphan, definitely garbage
9465             // -------------------------------------------------------
9466             // !d.offsetParent && !document.getElementById(eid)
9467             // display none elements have no offsetParent so we will
9468             // also try to look it up by it's id. However, check
9469             // offsetParent first so we don't do unneeded lookups.
9470             // This enables collection of elements that are not orphans
9471             // directly, but somewhere up the line they have an orphan
9472             // parent.
9473             // -------------------------------------------------------
9474             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9475                 delete El.cache[eid];
9476                 if(d && Roo.enableListenerCollection){
9477                     E.purgeElement(d);
9478                 }
9479             }
9480         }
9481     }
9482     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9483
9484
9485     // dom is optional
9486     El.Flyweight = function(dom){
9487         this.dom = dom;
9488     };
9489     El.Flyweight.prototype = El.prototype;
9490
9491     El._flyweights = {};
9492     /**
9493      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9494      * the dom node can be overwritten by other code.
9495      * @param {String/HTMLElement} el The dom node or id
9496      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9497      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9498      * @static
9499      * @return {Element} The shared Element object
9500      */
9501     El.fly = function(el, named){
9502         named = named || '_global';
9503         el = Roo.getDom(el);
9504         if(!el){
9505             return null;
9506         }
9507         if(!El._flyweights[named]){
9508             El._flyweights[named] = new El.Flyweight();
9509         }
9510         El._flyweights[named].dom = el;
9511         return El._flyweights[named];
9512     };
9513
9514     /**
9515      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9516      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9517      * Shorthand of {@link Roo.Element#get}
9518      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9519      * @return {Element} The Element object
9520      * @member Roo
9521      * @method get
9522      */
9523     Roo.get = El.get;
9524     /**
9525      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9526      * the dom node can be overwritten by other code.
9527      * Shorthand of {@link Roo.Element#fly}
9528      * @param {String/HTMLElement} el The dom node or id
9529      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9530      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9531      * @static
9532      * @return {Element} The shared Element object
9533      * @member Roo
9534      * @method fly
9535      */
9536     Roo.fly = El.fly;
9537
9538     // speedy lookup for elements never to box adjust
9539     var noBoxAdjust = Roo.isStrict ? {
9540         select:1
9541     } : {
9542         input:1, select:1, textarea:1
9543     };
9544     if(Roo.isIE || Roo.isGecko){
9545         noBoxAdjust['button'] = 1;
9546     }
9547
9548
9549     Roo.EventManager.on(window, 'unload', function(){
9550         delete El.cache;
9551         delete El._flyweights;
9552     });
9553 })();
9554
9555
9556
9557
9558 if(Roo.DomQuery){
9559     Roo.Element.selectorFunction = Roo.DomQuery.select;
9560 }
9561
9562 Roo.Element.select = function(selector, unique, root){
9563     var els;
9564     if(typeof selector == "string"){
9565         els = Roo.Element.selectorFunction(selector, root);
9566     }else if(selector.length !== undefined){
9567         els = selector;
9568     }else{
9569         throw "Invalid selector";
9570     }
9571     if(unique === true){
9572         return new Roo.CompositeElement(els);
9573     }else{
9574         return new Roo.CompositeElementLite(els);
9575     }
9576 };
9577 /**
9578  * Selects elements based on the passed CSS selector to enable working on them as 1.
9579  * @param {String/Array} selector The CSS selector or an array of elements
9580  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9581  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9582  * @return {CompositeElementLite/CompositeElement}
9583  * @member Roo
9584  * @method select
9585  */
9586 Roo.select = Roo.Element.select;
9587
9588
9589
9590
9591
9592
9593
9594
9595
9596
9597
9598
9599
9600
9601 /*
9602  * Based on:
9603  * Ext JS Library 1.1.1
9604  * Copyright(c) 2006-2007, Ext JS, LLC.
9605  *
9606  * Originally Released Under LGPL - original licence link has changed is not relivant.
9607  *
9608  * Fork - LGPL
9609  * <script type="text/javascript">
9610  */
9611
9612
9613
9614 //Notifies Element that fx methods are available
9615 Roo.enableFx = true;
9616
9617 /**
9618  * @class Roo.Fx
9619  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9620  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9621  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9622  * Element effects to work.</p><br/>
9623  *
9624  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9625  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9626  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9627  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9628  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9629  * expected results and should be done with care.</p><br/>
9630  *
9631  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9632  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9633 <pre>
9634 Value  Description
9635 -----  -----------------------------
9636 tl     The top left corner
9637 t      The center of the top edge
9638 tr     The top right corner
9639 l      The center of the left edge
9640 r      The center of the right edge
9641 bl     The bottom left corner
9642 b      The center of the bottom edge
9643 br     The bottom right corner
9644 </pre>
9645  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9646  * below are common options that can be passed to any Fx method.</b>
9647  * @cfg {Function} callback A function called when the effect is finished
9648  * @cfg {Object} scope The scope of the effect function
9649  * @cfg {String} easing A valid Easing value for the effect
9650  * @cfg {String} afterCls A css class to apply after the effect
9651  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9652  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9653  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9654  * effects that end with the element being visually hidden, ignored otherwise)
9655  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9656  * a function which returns such a specification that will be applied to the Element after the effect finishes
9657  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9658  * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
9659  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9660  */
9661 Roo.Fx = {
9662         /**
9663          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9664          * origin for the slide effect.  This function automatically handles wrapping the element with
9665          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9666          * Usage:
9667          *<pre><code>
9668 // default: slide the element in from the top
9669 el.slideIn();
9670
9671 // custom: slide the element in from the right with a 2-second duration
9672 el.slideIn('r', { duration: 2 });
9673
9674 // common config options shown with default values
9675 el.slideIn('t', {
9676     easing: 'easeOut',
9677     duration: .5
9678 });
9679 </code></pre>
9680          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9681          * @param {Object} options (optional) Object literal with any of the Fx config options
9682          * @return {Roo.Element} The Element
9683          */
9684     slideIn : function(anchor, o){
9685         var el = this.getFxEl();
9686         o = o || {};
9687
9688         el.queueFx(o, function(){
9689
9690             anchor = anchor || "t";
9691
9692             // fix display to visibility
9693             this.fixDisplay();
9694
9695             // restore values after effect
9696             var r = this.getFxRestore();
9697             var b = this.getBox();
9698             // fixed size for slide
9699             this.setSize(b);
9700
9701             // wrap if needed
9702             var wrap = this.fxWrap(r.pos, o, "hidden");
9703
9704             var st = this.dom.style;
9705             st.visibility = "visible";
9706             st.position = "absolute";
9707
9708             // clear out temp styles after slide and unwrap
9709             var after = function(){
9710                 el.fxUnwrap(wrap, r.pos, o);
9711                 st.width = r.width;
9712                 st.height = r.height;
9713                 el.afterFx(o);
9714             };
9715             // time to calc the positions
9716             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9717
9718             switch(anchor.toLowerCase()){
9719                 case "t":
9720                     wrap.setSize(b.width, 0);
9721                     st.left = st.bottom = "0";
9722                     a = {height: bh};
9723                 break;
9724                 case "l":
9725                     wrap.setSize(0, b.height);
9726                     st.right = st.top = "0";
9727                     a = {width: bw};
9728                 break;
9729                 case "r":
9730                     wrap.setSize(0, b.height);
9731                     wrap.setX(b.right);
9732                     st.left = st.top = "0";
9733                     a = {width: bw, points: pt};
9734                 break;
9735                 case "b":
9736                     wrap.setSize(b.width, 0);
9737                     wrap.setY(b.bottom);
9738                     st.left = st.top = "0";
9739                     a = {height: bh, points: pt};
9740                 break;
9741                 case "tl":
9742                     wrap.setSize(0, 0);
9743                     st.right = st.bottom = "0";
9744                     a = {width: bw, height: bh};
9745                 break;
9746                 case "bl":
9747                     wrap.setSize(0, 0);
9748                     wrap.setY(b.y+b.height);
9749                     st.right = st.top = "0";
9750                     a = {width: bw, height: bh, points: pt};
9751                 break;
9752                 case "br":
9753                     wrap.setSize(0, 0);
9754                     wrap.setXY([b.right, b.bottom]);
9755                     st.left = st.top = "0";
9756                     a = {width: bw, height: bh, points: pt};
9757                 break;
9758                 case "tr":
9759                     wrap.setSize(0, 0);
9760                     wrap.setX(b.x+b.width);
9761                     st.left = st.bottom = "0";
9762                     a = {width: bw, height: bh, points: pt};
9763                 break;
9764             }
9765             this.dom.style.visibility = "visible";
9766             wrap.show();
9767
9768             arguments.callee.anim = wrap.fxanim(a,
9769                 o,
9770                 'motion',
9771                 .5,
9772                 'easeOut', after);
9773         });
9774         return this;
9775     },
9776     
9777         /**
9778          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
9779          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
9780          * 'hidden') but block elements will still take up space in the document.  The element must be removed
9781          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
9782          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9783          * Usage:
9784          *<pre><code>
9785 // default: slide the element out to the top
9786 el.slideOut();
9787
9788 // custom: slide the element out to the right with a 2-second duration
9789 el.slideOut('r', { duration: 2 });
9790
9791 // common config options shown with default values
9792 el.slideOut('t', {
9793     easing: 'easeOut',
9794     duration: .5,
9795     remove: false,
9796     useDisplay: false
9797 });
9798 </code></pre>
9799          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9800          * @param {Object} options (optional) Object literal with any of the Fx config options
9801          * @return {Roo.Element} The Element
9802          */
9803     slideOut : function(anchor, o){
9804         var el = this.getFxEl();
9805         o = o || {};
9806
9807         el.queueFx(o, function(){
9808
9809             anchor = anchor || "t";
9810
9811             // restore values after effect
9812             var r = this.getFxRestore();
9813             
9814             var b = this.getBox();
9815             // fixed size for slide
9816             this.setSize(b);
9817
9818             // wrap if needed
9819             var wrap = this.fxWrap(r.pos, o, "visible");
9820
9821             var st = this.dom.style;
9822             st.visibility = "visible";
9823             st.position = "absolute";
9824
9825             wrap.setSize(b);
9826
9827             var after = function(){
9828                 if(o.useDisplay){
9829                     el.setDisplayed(false);
9830                 }else{
9831                     el.hide();
9832                 }
9833
9834                 el.fxUnwrap(wrap, r.pos, o);
9835
9836                 st.width = r.width;
9837                 st.height = r.height;
9838
9839                 el.afterFx(o);
9840             };
9841
9842             var a, zero = {to: 0};
9843             switch(anchor.toLowerCase()){
9844                 case "t":
9845                     st.left = st.bottom = "0";
9846                     a = {height: zero};
9847                 break;
9848                 case "l":
9849                     st.right = st.top = "0";
9850                     a = {width: zero};
9851                 break;
9852                 case "r":
9853                     st.left = st.top = "0";
9854                     a = {width: zero, points: {to:[b.right, b.y]}};
9855                 break;
9856                 case "b":
9857                     st.left = st.top = "0";
9858                     a = {height: zero, points: {to:[b.x, b.bottom]}};
9859                 break;
9860                 case "tl":
9861                     st.right = st.bottom = "0";
9862                     a = {width: zero, height: zero};
9863                 break;
9864                 case "bl":
9865                     st.right = st.top = "0";
9866                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9867                 break;
9868                 case "br":
9869                     st.left = st.top = "0";
9870                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9871                 break;
9872                 case "tr":
9873                     st.left = st.bottom = "0";
9874                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9875                 break;
9876             }
9877
9878             arguments.callee.anim = wrap.fxanim(a,
9879                 o,
9880                 'motion',
9881                 .5,
9882                 "easeOut", after);
9883         });
9884         return this;
9885     },
9886
9887         /**
9888          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
9889          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
9890          * The element must be removed from the DOM using the 'remove' config option if desired.
9891          * Usage:
9892          *<pre><code>
9893 // default
9894 el.puff();
9895
9896 // common config options shown with default values
9897 el.puff({
9898     easing: 'easeOut',
9899     duration: .5,
9900     remove: false,
9901     useDisplay: false
9902 });
9903 </code></pre>
9904          * @param {Object} options (optional) Object literal with any of the Fx config options
9905          * @return {Roo.Element} The Element
9906          */
9907     puff : function(o){
9908         var el = this.getFxEl();
9909         o = o || {};
9910
9911         el.queueFx(o, function(){
9912             this.clearOpacity();
9913             this.show();
9914
9915             // restore values after effect
9916             var r = this.getFxRestore();
9917             var st = this.dom.style;
9918
9919             var after = function(){
9920                 if(o.useDisplay){
9921                     el.setDisplayed(false);
9922                 }else{
9923                     el.hide();
9924                 }
9925
9926                 el.clearOpacity();
9927
9928                 el.setPositioning(r.pos);
9929                 st.width = r.width;
9930                 st.height = r.height;
9931                 st.fontSize = '';
9932                 el.afterFx(o);
9933             };
9934
9935             var width = this.getWidth();
9936             var height = this.getHeight();
9937
9938             arguments.callee.anim = this.fxanim({
9939                     width : {to: this.adjustWidth(width * 2)},
9940                     height : {to: this.adjustHeight(height * 2)},
9941                     points : {by: [-(width * .5), -(height * .5)]},
9942                     opacity : {to: 0},
9943                     fontSize: {to:200, unit: "%"}
9944                 },
9945                 o,
9946                 'motion',
9947                 .5,
9948                 "easeOut", after);
9949         });
9950         return this;
9951     },
9952
9953         /**
9954          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9955          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
9956          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9957          * Usage:
9958          *<pre><code>
9959 // default
9960 el.switchOff();
9961
9962 // all config options shown with default values
9963 el.switchOff({
9964     easing: 'easeIn',
9965     duration: .3,
9966     remove: false,
9967     useDisplay: false
9968 });
9969 </code></pre>
9970          * @param {Object} options (optional) Object literal with any of the Fx config options
9971          * @return {Roo.Element} The Element
9972          */
9973     switchOff : function(o){
9974         var el = this.getFxEl();
9975         o = o || {};
9976
9977         el.queueFx(o, function(){
9978             this.clearOpacity();
9979             this.clip();
9980
9981             // restore values after effect
9982             var r = this.getFxRestore();
9983             var st = this.dom.style;
9984
9985             var after = function(){
9986                 if(o.useDisplay){
9987                     el.setDisplayed(false);
9988                 }else{
9989                     el.hide();
9990                 }
9991
9992                 el.clearOpacity();
9993                 el.setPositioning(r.pos);
9994                 st.width = r.width;
9995                 st.height = r.height;
9996
9997                 el.afterFx(o);
9998             };
9999
10000             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10001                 this.clearOpacity();
10002                 (function(){
10003                     this.fxanim({
10004                         height:{to:1},
10005                         points:{by:[0, this.getHeight() * .5]}
10006                     }, o, 'motion', 0.3, 'easeIn', after);
10007                 }).defer(100, this);
10008             });
10009         });
10010         return this;
10011     },
10012
10013     /**
10014      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10015      * changed using the "attr" config option) and then fading back to the original color. If no original
10016      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10017      * Usage:
10018 <pre><code>
10019 // default: highlight background to yellow
10020 el.highlight();
10021
10022 // custom: highlight foreground text to blue for 2 seconds
10023 el.highlight("0000ff", { attr: 'color', duration: 2 });
10024
10025 // common config options shown with default values
10026 el.highlight("ffff9c", {
10027     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10028     endColor: (current color) or "ffffff",
10029     easing: 'easeIn',
10030     duration: 1
10031 });
10032 </code></pre>
10033      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10034      * @param {Object} options (optional) Object literal with any of the Fx config options
10035      * @return {Roo.Element} The Element
10036      */ 
10037     highlight : function(color, o){
10038         var el = this.getFxEl();
10039         o = o || {};
10040
10041         el.queueFx(o, function(){
10042             color = color || "ffff9c";
10043             attr = o.attr || "backgroundColor";
10044
10045             this.clearOpacity();
10046             this.show();
10047
10048             var origColor = this.getColor(attr);
10049             var restoreColor = this.dom.style[attr];
10050             endColor = (o.endColor || origColor) || "ffffff";
10051
10052             var after = function(){
10053                 el.dom.style[attr] = restoreColor;
10054                 el.afterFx(o);
10055             };
10056
10057             var a = {};
10058             a[attr] = {from: color, to: endColor};
10059             arguments.callee.anim = this.fxanim(a,
10060                 o,
10061                 'color',
10062                 1,
10063                 'easeIn', after);
10064         });
10065         return this;
10066     },
10067
10068    /**
10069     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10070     * Usage:
10071 <pre><code>
10072 // default: a single light blue ripple
10073 el.frame();
10074
10075 // custom: 3 red ripples lasting 3 seconds total
10076 el.frame("ff0000", 3, { duration: 3 });
10077
10078 // common config options shown with default values
10079 el.frame("C3DAF9", 1, {
10080     duration: 1 //duration of entire animation (not each individual ripple)
10081     // Note: Easing is not configurable and will be ignored if included
10082 });
10083 </code></pre>
10084     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10085     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10086     * @param {Object} options (optional) Object literal with any of the Fx config options
10087     * @return {Roo.Element} The Element
10088     */
10089     frame : function(color, count, o){
10090         var el = this.getFxEl();
10091         o = o || {};
10092
10093         el.queueFx(o, function(){
10094             color = color || "#C3DAF9";
10095             if(color.length == 6){
10096                 color = "#" + color;
10097             }
10098             count = count || 1;
10099             duration = o.duration || 1;
10100             this.show();
10101
10102             var b = this.getBox();
10103             var animFn = function(){
10104                 var proxy = this.createProxy({
10105
10106                      style:{
10107                         visbility:"hidden",
10108                         position:"absolute",
10109                         "z-index":"35000", // yee haw
10110                         border:"0px solid " + color
10111                      }
10112                   });
10113                 var scale = Roo.isBorderBox ? 2 : 1;
10114                 proxy.animate({
10115                     top:{from:b.y, to:b.y - 20},
10116                     left:{from:b.x, to:b.x - 20},
10117                     borderWidth:{from:0, to:10},
10118                     opacity:{from:1, to:0},
10119                     height:{from:b.height, to:(b.height + (20*scale))},
10120                     width:{from:b.width, to:(b.width + (20*scale))}
10121                 }, duration, function(){
10122                     proxy.remove();
10123                 });
10124                 if(--count > 0){
10125                      animFn.defer((duration/2)*1000, this);
10126                 }else{
10127                     el.afterFx(o);
10128                 }
10129             };
10130             animFn.call(this);
10131         });
10132         return this;
10133     },
10134
10135    /**
10136     * Creates a pause before any subsequent queued effects begin.  If there are
10137     * no effects queued after the pause it will have no effect.
10138     * Usage:
10139 <pre><code>
10140 el.pause(1);
10141 </code></pre>
10142     * @param {Number} seconds The length of time to pause (in seconds)
10143     * @return {Roo.Element} The Element
10144     */
10145     pause : function(seconds){
10146         var el = this.getFxEl();
10147         var o = {};
10148
10149         el.queueFx(o, function(){
10150             setTimeout(function(){
10151                 el.afterFx(o);
10152             }, seconds * 1000);
10153         });
10154         return this;
10155     },
10156
10157    /**
10158     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10159     * using the "endOpacity" config option.
10160     * Usage:
10161 <pre><code>
10162 // default: fade in from opacity 0 to 100%
10163 el.fadeIn();
10164
10165 // custom: fade in from opacity 0 to 75% over 2 seconds
10166 el.fadeIn({ endOpacity: .75, duration: 2});
10167
10168 // common config options shown with default values
10169 el.fadeIn({
10170     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10171     easing: 'easeOut',
10172     duration: .5
10173 });
10174 </code></pre>
10175     * @param {Object} options (optional) Object literal with any of the Fx config options
10176     * @return {Roo.Element} The Element
10177     */
10178     fadeIn : function(o){
10179         var el = this.getFxEl();
10180         o = o || {};
10181         el.queueFx(o, function(){
10182             this.setOpacity(0);
10183             this.fixDisplay();
10184             this.dom.style.visibility = 'visible';
10185             var to = o.endOpacity || 1;
10186             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10187                 o, null, .5, "easeOut", function(){
10188                 if(to == 1){
10189                     this.clearOpacity();
10190                 }
10191                 el.afterFx(o);
10192             });
10193         });
10194         return this;
10195     },
10196
10197    /**
10198     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10199     * using the "endOpacity" config option.
10200     * Usage:
10201 <pre><code>
10202 // default: fade out from the element's current opacity to 0
10203 el.fadeOut();
10204
10205 // custom: fade out from the element's current opacity to 25% over 2 seconds
10206 el.fadeOut({ endOpacity: .25, duration: 2});
10207
10208 // common config options shown with default values
10209 el.fadeOut({
10210     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10211     easing: 'easeOut',
10212     duration: .5
10213     remove: false,
10214     useDisplay: false
10215 });
10216 </code></pre>
10217     * @param {Object} options (optional) Object literal with any of the Fx config options
10218     * @return {Roo.Element} The Element
10219     */
10220     fadeOut : function(o){
10221         var el = this.getFxEl();
10222         o = o || {};
10223         el.queueFx(o, function(){
10224             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10225                 o, null, .5, "easeOut", function(){
10226                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10227                      this.dom.style.display = "none";
10228                 }else{
10229                      this.dom.style.visibility = "hidden";
10230                 }
10231                 this.clearOpacity();
10232                 el.afterFx(o);
10233             });
10234         });
10235         return this;
10236     },
10237
10238    /**
10239     * Animates the transition of an element's dimensions from a starting height/width
10240     * to an ending height/width.
10241     * Usage:
10242 <pre><code>
10243 // change height and width to 100x100 pixels
10244 el.scale(100, 100);
10245
10246 // common config options shown with default values.  The height and width will default to
10247 // the element's existing values if passed as null.
10248 el.scale(
10249     [element's width],
10250     [element's height], {
10251     easing: 'easeOut',
10252     duration: .35
10253 });
10254 </code></pre>
10255     * @param {Number} width  The new width (pass undefined to keep the original width)
10256     * @param {Number} height  The new height (pass undefined to keep the original height)
10257     * @param {Object} options (optional) Object literal with any of the Fx config options
10258     * @return {Roo.Element} The Element
10259     */
10260     scale : function(w, h, o){
10261         this.shift(Roo.apply({}, o, {
10262             width: w,
10263             height: h
10264         }));
10265         return this;
10266     },
10267
10268    /**
10269     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10270     * Any of these properties not specified in the config object will not be changed.  This effect 
10271     * requires that at least one new dimension, position or opacity setting must be passed in on
10272     * the config object in order for the function to have any effect.
10273     * Usage:
10274 <pre><code>
10275 // slide the element horizontally to x position 200 while changing the height and opacity
10276 el.shift({ x: 200, height: 50, opacity: .8 });
10277
10278 // common config options shown with default values.
10279 el.shift({
10280     width: [element's width],
10281     height: [element's height],
10282     x: [element's x position],
10283     y: [element's y position],
10284     opacity: [element's opacity],
10285     easing: 'easeOut',
10286     duration: .35
10287 });
10288 </code></pre>
10289     * @param {Object} options  Object literal with any of the Fx config options
10290     * @return {Roo.Element} The Element
10291     */
10292     shift : function(o){
10293         var el = this.getFxEl();
10294         o = o || {};
10295         el.queueFx(o, function(){
10296             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10297             if(w !== undefined){
10298                 a.width = {to: this.adjustWidth(w)};
10299             }
10300             if(h !== undefined){
10301                 a.height = {to: this.adjustHeight(h)};
10302             }
10303             if(x !== undefined || y !== undefined){
10304                 a.points = {to: [
10305                     x !== undefined ? x : this.getX(),
10306                     y !== undefined ? y : this.getY()
10307                 ]};
10308             }
10309             if(op !== undefined){
10310                 a.opacity = {to: op};
10311             }
10312             if(o.xy !== undefined){
10313                 a.points = {to: o.xy};
10314             }
10315             arguments.callee.anim = this.fxanim(a,
10316                 o, 'motion', .35, "easeOut", function(){
10317                 el.afterFx(o);
10318             });
10319         });
10320         return this;
10321     },
10322
10323         /**
10324          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10325          * ending point of the effect.
10326          * Usage:
10327          *<pre><code>
10328 // default: slide the element downward while fading out
10329 el.ghost();
10330
10331 // custom: slide the element out to the right with a 2-second duration
10332 el.ghost('r', { duration: 2 });
10333
10334 // common config options shown with default values
10335 el.ghost('b', {
10336     easing: 'easeOut',
10337     duration: .5
10338     remove: false,
10339     useDisplay: false
10340 });
10341 </code></pre>
10342          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10343          * @param {Object} options (optional) Object literal with any of the Fx config options
10344          * @return {Roo.Element} The Element
10345          */
10346     ghost : function(anchor, o){
10347         var el = this.getFxEl();
10348         o = o || {};
10349
10350         el.queueFx(o, function(){
10351             anchor = anchor || "b";
10352
10353             // restore values after effect
10354             var r = this.getFxRestore();
10355             var w = this.getWidth(),
10356                 h = this.getHeight();
10357
10358             var st = this.dom.style;
10359
10360             var after = function(){
10361                 if(o.useDisplay){
10362                     el.setDisplayed(false);
10363                 }else{
10364                     el.hide();
10365                 }
10366
10367                 el.clearOpacity();
10368                 el.setPositioning(r.pos);
10369                 st.width = r.width;
10370                 st.height = r.height;
10371
10372                 el.afterFx(o);
10373             };
10374
10375             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10376             switch(anchor.toLowerCase()){
10377                 case "t":
10378                     pt.by = [0, -h];
10379                 break;
10380                 case "l":
10381                     pt.by = [-w, 0];
10382                 break;
10383                 case "r":
10384                     pt.by = [w, 0];
10385                 break;
10386                 case "b":
10387                     pt.by = [0, h];
10388                 break;
10389                 case "tl":
10390                     pt.by = [-w, -h];
10391                 break;
10392                 case "bl":
10393                     pt.by = [-w, h];
10394                 break;
10395                 case "br":
10396                     pt.by = [w, h];
10397                 break;
10398                 case "tr":
10399                     pt.by = [w, -h];
10400                 break;
10401             }
10402
10403             arguments.callee.anim = this.fxanim(a,
10404                 o,
10405                 'motion',
10406                 .5,
10407                 "easeOut", after);
10408         });
10409         return this;
10410     },
10411
10412         /**
10413          * Ensures that all effects queued after syncFx is called on the element are
10414          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10415          * @return {Roo.Element} The Element
10416          */
10417     syncFx : function(){
10418         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10419             block : false,
10420             concurrent : true,
10421             stopFx : false
10422         });
10423         return this;
10424     },
10425
10426         /**
10427          * Ensures that all effects queued after sequenceFx is called on the element are
10428          * run in sequence.  This is the opposite of {@link #syncFx}.
10429          * @return {Roo.Element} The Element
10430          */
10431     sequenceFx : function(){
10432         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10433             block : false,
10434             concurrent : false,
10435             stopFx : false
10436         });
10437         return this;
10438     },
10439
10440         /* @private */
10441     nextFx : function(){
10442         var ef = this.fxQueue[0];
10443         if(ef){
10444             ef.call(this);
10445         }
10446     },
10447
10448         /**
10449          * Returns true if the element has any effects actively running or queued, else returns false.
10450          * @return {Boolean} True if element has active effects, else false
10451          */
10452     hasActiveFx : function(){
10453         return this.fxQueue && this.fxQueue[0];
10454     },
10455
10456         /**
10457          * Stops any running effects and clears the element's internal effects queue if it contains
10458          * any additional effects that haven't started yet.
10459          * @return {Roo.Element} The Element
10460          */
10461     stopFx : function(){
10462         if(this.hasActiveFx()){
10463             var cur = this.fxQueue[0];
10464             if(cur && cur.anim && cur.anim.isAnimated()){
10465                 this.fxQueue = [cur]; // clear out others
10466                 cur.anim.stop(true);
10467             }
10468         }
10469         return this;
10470     },
10471
10472         /* @private */
10473     beforeFx : function(o){
10474         if(this.hasActiveFx() && !o.concurrent){
10475            if(o.stopFx){
10476                this.stopFx();
10477                return true;
10478            }
10479            return false;
10480         }
10481         return true;
10482     },
10483
10484         /**
10485          * Returns true if the element is currently blocking so that no other effect can be queued
10486          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10487          * used to ensure that an effect initiated by a user action runs to completion prior to the
10488          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10489          * @return {Boolean} True if blocking, else false
10490          */
10491     hasFxBlock : function(){
10492         var q = this.fxQueue;
10493         return q && q[0] && q[0].block;
10494     },
10495
10496         /* @private */
10497     queueFx : function(o, fn){
10498         if(!this.fxQueue){
10499             this.fxQueue = [];
10500         }
10501         if(!this.hasFxBlock()){
10502             Roo.applyIf(o, this.fxDefaults);
10503             if(!o.concurrent){
10504                 var run = this.beforeFx(o);
10505                 fn.block = o.block;
10506                 this.fxQueue.push(fn);
10507                 if(run){
10508                     this.nextFx();
10509                 }
10510             }else{
10511                 fn.call(this);
10512             }
10513         }
10514         return this;
10515     },
10516
10517         /* @private */
10518     fxWrap : function(pos, o, vis){
10519         var wrap;
10520         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10521             var wrapXY;
10522             if(o.fixPosition){
10523                 wrapXY = this.getXY();
10524             }
10525             var div = document.createElement("div");
10526             div.style.visibility = vis;
10527             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10528             wrap.setPositioning(pos);
10529             if(wrap.getStyle("position") == "static"){
10530                 wrap.position("relative");
10531             }
10532             this.clearPositioning('auto');
10533             wrap.clip();
10534             wrap.dom.appendChild(this.dom);
10535             if(wrapXY){
10536                 wrap.setXY(wrapXY);
10537             }
10538         }
10539         return wrap;
10540     },
10541
10542         /* @private */
10543     fxUnwrap : function(wrap, pos, o){
10544         this.clearPositioning();
10545         this.setPositioning(pos);
10546         if(!o.wrap){
10547             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10548             wrap.remove();
10549         }
10550     },
10551
10552         /* @private */
10553     getFxRestore : function(){
10554         var st = this.dom.style;
10555         return {pos: this.getPositioning(), width: st.width, height : st.height};
10556     },
10557
10558         /* @private */
10559     afterFx : function(o){
10560         if(o.afterStyle){
10561             this.applyStyles(o.afterStyle);
10562         }
10563         if(o.afterCls){
10564             this.addClass(o.afterCls);
10565         }
10566         if(o.remove === true){
10567             this.remove();
10568         }
10569         Roo.callback(o.callback, o.scope, [this]);
10570         if(!o.concurrent){
10571             this.fxQueue.shift();
10572             this.nextFx();
10573         }
10574     },
10575
10576         /* @private */
10577     getFxEl : function(){ // support for composite element fx
10578         return Roo.get(this.dom);
10579     },
10580
10581         /* @private */
10582     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10583         animType = animType || 'run';
10584         opt = opt || {};
10585         var anim = Roo.lib.Anim[animType](
10586             this.dom, args,
10587             (opt.duration || defaultDur) || .35,
10588             (opt.easing || defaultEase) || 'easeOut',
10589             function(){
10590                 Roo.callback(cb, this);
10591             },
10592             this
10593         );
10594         opt.anim = anim;
10595         return anim;
10596     }
10597 };
10598
10599 // backwords compat
10600 Roo.Fx.resize = Roo.Fx.scale;
10601
10602 //When included, Roo.Fx is automatically applied to Element so that all basic
10603 //effects are available directly via the Element API
10604 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10605  * Based on:
10606  * Ext JS Library 1.1.1
10607  * Copyright(c) 2006-2007, Ext JS, LLC.
10608  *
10609  * Originally Released Under LGPL - original licence link has changed is not relivant.
10610  *
10611  * Fork - LGPL
10612  * <script type="text/javascript">
10613  */
10614
10615
10616 /**
10617  * @class Roo.CompositeElement
10618  * Standard composite class. Creates a Roo.Element for every element in the collection.
10619  * <br><br>
10620  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10621  * actions will be performed on all the elements in this collection.</b>
10622  * <br><br>
10623  * All methods return <i>this</i> and can be chained.
10624  <pre><code>
10625  var els = Roo.select("#some-el div.some-class", true);
10626  // or select directly from an existing element
10627  var el = Roo.get('some-el');
10628  el.select('div.some-class', true);
10629
10630  els.setWidth(100); // all elements become 100 width
10631  els.hide(true); // all elements fade out and hide
10632  // or
10633  els.setWidth(100).hide(true);
10634  </code></pre>
10635  */
10636 Roo.CompositeElement = function(els){
10637     this.elements = [];
10638     this.addElements(els);
10639 };
10640 Roo.CompositeElement.prototype = {
10641     isComposite: true,
10642     addElements : function(els){
10643         if(!els) return this;
10644         if(typeof els == "string"){
10645             els = Roo.Element.selectorFunction(els);
10646         }
10647         var yels = this.elements;
10648         var index = yels.length-1;
10649         for(var i = 0, len = els.length; i < len; i++) {
10650                 yels[++index] = Roo.get(els[i]);
10651         }
10652         return this;
10653     },
10654
10655     /**
10656     * Clears this composite and adds the elements returned by the passed selector.
10657     * @param {String/Array} els A string CSS selector, an array of elements or an element
10658     * @return {CompositeElement} this
10659     */
10660     fill : function(els){
10661         this.elements = [];
10662         this.add(els);
10663         return this;
10664     },
10665
10666     /**
10667     * Filters this composite to only elements that match the passed selector.
10668     * @param {String} selector A string CSS selector
10669     * @return {CompositeElement} this
10670     */
10671     filter : function(selector){
10672         var els = [];
10673         this.each(function(el){
10674             if(el.is(selector)){
10675                 els[els.length] = el.dom;
10676             }
10677         });
10678         this.fill(els);
10679         return this;
10680     },
10681
10682     invoke : function(fn, args){
10683         var els = this.elements;
10684         for(var i = 0, len = els.length; i < len; i++) {
10685                 Roo.Element.prototype[fn].apply(els[i], args);
10686         }
10687         return this;
10688     },
10689     /**
10690     * Adds elements to this composite.
10691     * @param {String/Array} els A string CSS selector, an array of elements or an element
10692     * @return {CompositeElement} this
10693     */
10694     add : function(els){
10695         if(typeof els == "string"){
10696             this.addElements(Roo.Element.selectorFunction(els));
10697         }else if(els.length !== undefined){
10698             this.addElements(els);
10699         }else{
10700             this.addElements([els]);
10701         }
10702         return this;
10703     },
10704     /**
10705     * Calls the passed function passing (el, this, index) for each element in this composite.
10706     * @param {Function} fn The function to call
10707     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10708     * @return {CompositeElement} this
10709     */
10710     each : function(fn, scope){
10711         var els = this.elements;
10712         for(var i = 0, len = els.length; i < len; i++){
10713             if(fn.call(scope || els[i], els[i], this, i) === false) {
10714                 break;
10715             }
10716         }
10717         return this;
10718     },
10719
10720     /**
10721      * Returns the Element object at the specified index
10722      * @param {Number} index
10723      * @return {Roo.Element}
10724      */
10725     item : function(index){
10726         return this.elements[index] || null;
10727     },
10728
10729     /**
10730      * Returns the first Element
10731      * @return {Roo.Element}
10732      */
10733     first : function(){
10734         return this.item(0);
10735     },
10736
10737     /**
10738      * Returns the last Element
10739      * @return {Roo.Element}
10740      */
10741     last : function(){
10742         return this.item(this.elements.length-1);
10743     },
10744
10745     /**
10746      * Returns the number of elements in this composite
10747      * @return Number
10748      */
10749     getCount : function(){
10750         return this.elements.length;
10751     },
10752
10753     /**
10754      * Returns true if this composite contains the passed element
10755      * @return Boolean
10756      */
10757     contains : function(el){
10758         return this.indexOf(el) !== -1;
10759     },
10760
10761     /**
10762      * Returns true if this composite contains the passed element
10763      * @return Boolean
10764      */
10765     indexOf : function(el){
10766         return this.elements.indexOf(Roo.get(el));
10767     },
10768
10769
10770     /**
10771     * Removes the specified element(s).
10772     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10773     * or an array of any of those.
10774     * @param {Boolean} removeDom (optional) True to also remove the element from the document
10775     * @return {CompositeElement} this
10776     */
10777     removeElement : function(el, removeDom){
10778         if(el instanceof Array){
10779             for(var i = 0, len = el.length; i < len; i++){
10780                 this.removeElement(el[i]);
10781             }
10782             return this;
10783         }
10784         var index = typeof el == 'number' ? el : this.indexOf(el);
10785         if(index !== -1){
10786             if(removeDom){
10787                 var d = this.elements[index];
10788                 if(d.dom){
10789                     d.remove();
10790                 }else{
10791                     d.parentNode.removeChild(d);
10792                 }
10793             }
10794             this.elements.splice(index, 1);
10795         }
10796         return this;
10797     },
10798
10799     /**
10800     * Replaces the specified element with the passed element.
10801     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10802     * to replace.
10803     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10804     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10805     * @return {CompositeElement} this
10806     */
10807     replaceElement : function(el, replacement, domReplace){
10808         var index = typeof el == 'number' ? el : this.indexOf(el);
10809         if(index !== -1){
10810             if(domReplace){
10811                 this.elements[index].replaceWith(replacement);
10812             }else{
10813                 this.elements.splice(index, 1, Roo.get(replacement))
10814             }
10815         }
10816         return this;
10817     },
10818
10819     /**
10820      * Removes all elements.
10821      */
10822     clear : function(){
10823         this.elements = [];
10824     }
10825 };
10826 (function(){
10827     Roo.CompositeElement.createCall = function(proto, fnName){
10828         if(!proto[fnName]){
10829             proto[fnName] = function(){
10830                 return this.invoke(fnName, arguments);
10831             };
10832         }
10833     };
10834     for(var fnName in Roo.Element.prototype){
10835         if(typeof Roo.Element.prototype[fnName] == "function"){
10836             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10837         }
10838     };
10839 })();
10840 /*
10841  * Based on:
10842  * Ext JS Library 1.1.1
10843  * Copyright(c) 2006-2007, Ext JS, LLC.
10844  *
10845  * Originally Released Under LGPL - original licence link has changed is not relivant.
10846  *
10847  * Fork - LGPL
10848  * <script type="text/javascript">
10849  */
10850
10851 /**
10852  * @class Roo.CompositeElementLite
10853  * @extends Roo.CompositeElement
10854  * Flyweight composite class. Reuses the same Roo.Element for element operations.
10855  <pre><code>
10856  var els = Roo.select("#some-el div.some-class");
10857  // or select directly from an existing element
10858  var el = Roo.get('some-el');
10859  el.select('div.some-class');
10860
10861  els.setWidth(100); // all elements become 100 width
10862  els.hide(true); // all elements fade out and hide
10863  // or
10864  els.setWidth(100).hide(true);
10865  </code></pre><br><br>
10866  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10867  * actions will be performed on all the elements in this collection.</b>
10868  */
10869 Roo.CompositeElementLite = function(els){
10870     Roo.CompositeElementLite.superclass.constructor.call(this, els);
10871     this.el = new Roo.Element.Flyweight();
10872 };
10873 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10874     addElements : function(els){
10875         if(els){
10876             if(els instanceof Array){
10877                 this.elements = this.elements.concat(els);
10878             }else{
10879                 var yels = this.elements;
10880                 var index = yels.length-1;
10881                 for(var i = 0, len = els.length; i < len; i++) {
10882                     yels[++index] = els[i];
10883                 }
10884             }
10885         }
10886         return this;
10887     },
10888     invoke : function(fn, args){
10889         var els = this.elements;
10890         var el = this.el;
10891         for(var i = 0, len = els.length; i < len; i++) {
10892             el.dom = els[i];
10893                 Roo.Element.prototype[fn].apply(el, args);
10894         }
10895         return this;
10896     },
10897     /**
10898      * Returns a flyweight Element of the dom element object at the specified index
10899      * @param {Number} index
10900      * @return {Roo.Element}
10901      */
10902     item : function(index){
10903         if(!this.elements[index]){
10904             return null;
10905         }
10906         this.el.dom = this.elements[index];
10907         return this.el;
10908     },
10909
10910     // fixes scope with flyweight
10911     addListener : function(eventName, handler, scope, opt){
10912         var els = this.elements;
10913         for(var i = 0, len = els.length; i < len; i++) {
10914             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10915         }
10916         return this;
10917     },
10918
10919     /**
10920     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10921     * passed is the flyweight (shared) Roo.Element instance, so if you require a
10922     * a reference to the dom node, use el.dom.</b>
10923     * @param {Function} fn The function to call
10924     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10925     * @return {CompositeElement} this
10926     */
10927     each : function(fn, scope){
10928         var els = this.elements;
10929         var el = this.el;
10930         for(var i = 0, len = els.length; i < len; i++){
10931             el.dom = els[i];
10932                 if(fn.call(scope || el, el, this, i) === false){
10933                 break;
10934             }
10935         }
10936         return this;
10937     },
10938
10939     indexOf : function(el){
10940         return this.elements.indexOf(Roo.getDom(el));
10941     },
10942
10943     replaceElement : function(el, replacement, domReplace){
10944         var index = typeof el == 'number' ? el : this.indexOf(el);
10945         if(index !== -1){
10946             replacement = Roo.getDom(replacement);
10947             if(domReplace){
10948                 var d = this.elements[index];
10949                 d.parentNode.insertBefore(replacement, d);
10950                 d.parentNode.removeChild(d);
10951             }
10952             this.elements.splice(index, 1, replacement);
10953         }
10954         return this;
10955     }
10956 });
10957 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10958
10959 /*
10960  * Based on:
10961  * Ext JS Library 1.1.1
10962  * Copyright(c) 2006-2007, Ext JS, LLC.
10963  *
10964  * Originally Released Under LGPL - original licence link has changed is not relivant.
10965  *
10966  * Fork - LGPL
10967  * <script type="text/javascript">
10968  */
10969
10970  
10971
10972 /**
10973  * @class Roo.data.Connection
10974  * @extends Roo.util.Observable
10975  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
10976  * either to a configured URL, or to a URL specified at request time.<br><br>
10977  * <p>
10978  * Requests made by this class are asynchronous, and will return immediately. No data from
10979  * the server will be available to the statement immediately following the {@link #request} call.
10980  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
10981  * <p>
10982  * Note: If you are doing a file upload, you will not get a normal response object sent back to
10983  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
10984  * The response object is created using the innerHTML of the IFRAME's document as the responseText
10985  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
10986  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
10987  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
10988  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
10989  * standard DOM methods.
10990  * @constructor
10991  * @param {Object} config a configuration object.
10992  */
10993 Roo.data.Connection = function(config){
10994     Roo.apply(this, config);
10995     this.addEvents({
10996         /**
10997          * @event beforerequest
10998          * Fires before a network request is made to retrieve a data object.
10999          * @param {Connection} conn This Connection object.
11000          * @param {Object} options The options config object passed to the {@link #request} method.
11001          */
11002         "beforerequest" : true,
11003         /**
11004          * @event requestcomplete
11005          * Fires if the request was successfully completed.
11006          * @param {Connection} conn This Connection object.
11007          * @param {Object} response The XHR object containing the response data.
11008          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11009          * @param {Object} options The options config object passed to the {@link #request} method.
11010          */
11011         "requestcomplete" : true,
11012         /**
11013          * @event requestexception
11014          * Fires if an error HTTP status was returned from the server.
11015          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11016          * @param {Connection} conn This Connection object.
11017          * @param {Object} response The XHR object containing the response data.
11018          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11019          * @param {Object} options The options config object passed to the {@link #request} method.
11020          */
11021         "requestexception" : true
11022     });
11023     Roo.data.Connection.superclass.constructor.call(this);
11024 };
11025
11026 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11027     /**
11028      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11029      */
11030     /**
11031      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11032      * extra parameters to each request made by this object. (defaults to undefined)
11033      */
11034     /**
11035      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11036      *  to each request made by this object. (defaults to undefined)
11037      */
11038     /**
11039      * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11040      */
11041     /**
11042      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11043      */
11044     timeout : 30000,
11045     /**
11046      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11047      * @type Boolean
11048      */
11049     autoAbort:false,
11050
11051     /**
11052      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11053      * @type Boolean
11054      */
11055     disableCaching: true,
11056
11057     /**
11058      * Sends an HTTP request to a remote server.
11059      * @param {Object} options An object which may contain the following properties:<ul>
11060      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11061      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11062      * request, a url encoded string or a function to call to get either.</li>
11063      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11064      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11065      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11066      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11067      * <li>options {Object} The parameter to the request call.</li>
11068      * <li>success {Boolean} True if the request succeeded.</li>
11069      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11070      * </ul></li>
11071      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11072      * The callback is passed the following parameters:<ul>
11073      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11074      * <li>options {Object} The parameter to the request call.</li>
11075      * </ul></li>
11076      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11077      * The callback is passed the following parameters:<ul>
11078      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11079      * <li>options {Object} The parameter to the request call.</li>
11080      * </ul></li>
11081      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11082      * for the callback function. Defaults to the browser window.</li>
11083      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11084      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11085      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11086      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11087      * params for the post data. Any params will be appended to the URL.</li>
11088      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11089      * </ul>
11090      * @return {Number} transactionId
11091      */
11092     request : function(o){
11093         if(this.fireEvent("beforerequest", this, o) !== false){
11094             var p = o.params;
11095
11096             if(typeof p == "function"){
11097                 p = p.call(o.scope||window, o);
11098             }
11099             if(typeof p == "object"){
11100                 p = Roo.urlEncode(o.params);
11101             }
11102             if(this.extraParams){
11103                 var extras = Roo.urlEncode(this.extraParams);
11104                 p = p ? (p + '&' + extras) : extras;
11105             }
11106
11107             var url = o.url || this.url;
11108             if(typeof url == 'function'){
11109                 url = url.call(o.scope||window, o);
11110             }
11111
11112             if(o.form){
11113                 var form = Roo.getDom(o.form);
11114                 url = url || form.action;
11115
11116                 var enctype = form.getAttribute("enctype");
11117                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11118                     return this.doFormUpload(o, p, url);
11119                 }
11120                 var f = Roo.lib.Ajax.serializeForm(form);
11121                 p = p ? (p + '&' + f) : f;
11122             }
11123
11124             var hs = o.headers;
11125             if(this.defaultHeaders){
11126                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11127                 if(!o.headers){
11128                     o.headers = hs;
11129                 }
11130             }
11131
11132             var cb = {
11133                 success: this.handleResponse,
11134                 failure: this.handleFailure,
11135                 scope: this,
11136                 argument: {options: o},
11137                 timeout : this.timeout
11138             };
11139
11140             var method = o.method||this.method||(p ? "POST" : "GET");
11141
11142             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11143                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11144             }
11145
11146             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11147                 if(o.autoAbort){
11148                     this.abort();
11149                 }
11150             }else if(this.autoAbort !== false){
11151                 this.abort();
11152             }
11153
11154             if((method == 'GET' && p) || o.xmlData){
11155                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11156                 p = '';
11157             }
11158             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11159             return this.transId;
11160         }else{
11161             Roo.callback(o.callback, o.scope, [o, null, null]);
11162             return null;
11163         }
11164     },
11165
11166     /**
11167      * Determine whether this object has a request outstanding.
11168      * @param {Number} transactionId (Optional) defaults to the last transaction
11169      * @return {Boolean} True if there is an outstanding request.
11170      */
11171     isLoading : function(transId){
11172         if(transId){
11173             return Roo.lib.Ajax.isCallInProgress(transId);
11174         }else{
11175             return this.transId ? true : false;
11176         }
11177     },
11178
11179     /**
11180      * Aborts any outstanding request.
11181      * @param {Number} transactionId (Optional) defaults to the last transaction
11182      */
11183     abort : function(transId){
11184         if(transId || this.isLoading()){
11185             Roo.lib.Ajax.abort(transId || this.transId);
11186         }
11187     },
11188
11189     // private
11190     handleResponse : function(response){
11191         this.transId = false;
11192         var options = response.argument.options;
11193         response.argument = options ? options.argument : null;
11194         this.fireEvent("requestcomplete", this, response, options);
11195         Roo.callback(options.success, options.scope, [response, options]);
11196         Roo.callback(options.callback, options.scope, [options, true, response]);
11197     },
11198
11199     // private
11200     handleFailure : function(response, e){
11201         this.transId = false;
11202         var options = response.argument.options;
11203         response.argument = options ? options.argument : null;
11204         this.fireEvent("requestexception", this, response, options, e);
11205         Roo.callback(options.failure, options.scope, [response, options]);
11206         Roo.callback(options.callback, options.scope, [options, false, response]);
11207     },
11208
11209     // private
11210     doFormUpload : function(o, ps, url){
11211         var id = Roo.id();
11212         var frame = document.createElement('iframe');
11213         frame.id = id;
11214         frame.name = id;
11215         frame.className = 'x-hidden';
11216         if(Roo.isIE){
11217             frame.src = Roo.SSL_SECURE_URL;
11218         }
11219         document.body.appendChild(frame);
11220
11221         if(Roo.isIE){
11222            document.frames[id].name = id;
11223         }
11224
11225         var form = Roo.getDom(o.form);
11226         form.target = id;
11227         form.method = 'POST';
11228         form.enctype = form.encoding = 'multipart/form-data';
11229         if(url){
11230             form.action = url;
11231         }
11232
11233         var hiddens, hd;
11234         if(ps){ // add dynamic params
11235             hiddens = [];
11236             ps = Roo.urlDecode(ps, false);
11237             for(var k in ps){
11238                 if(ps.hasOwnProperty(k)){
11239                     hd = document.createElement('input');
11240                     hd.type = 'hidden';
11241                     hd.name = k;
11242                     hd.value = ps[k];
11243                     form.appendChild(hd);
11244                     hiddens.push(hd);
11245                 }
11246             }
11247         }
11248
11249         function cb(){
11250             var r = {  // bogus response object
11251                 responseText : '',
11252                 responseXML : null
11253             };
11254
11255             r.argument = o ? o.argument : null;
11256
11257             try { //
11258                 var doc;
11259                 if(Roo.isIE){
11260                     doc = frame.contentWindow.document;
11261                 }else {
11262                     doc = (frame.contentDocument || window.frames[id].document);
11263                 }
11264                 if(doc && doc.body){
11265                     r.responseText = doc.body.innerHTML;
11266                 }
11267                 if(doc && doc.XMLDocument){
11268                     r.responseXML = doc.XMLDocument;
11269                 }else {
11270                     r.responseXML = doc;
11271                 }
11272             }
11273             catch(e) {
11274                 // ignore
11275             }
11276
11277             Roo.EventManager.removeListener(frame, 'load', cb, this);
11278
11279             this.fireEvent("requestcomplete", this, r, o);
11280             Roo.callback(o.success, o.scope, [r, o]);
11281             Roo.callback(o.callback, o.scope, [o, true, r]);
11282
11283             setTimeout(function(){document.body.removeChild(frame);}, 100);
11284         }
11285
11286         Roo.EventManager.on(frame, 'load', cb, this);
11287         form.submit();
11288
11289         if(hiddens){ // remove dynamic params
11290             for(var i = 0, len = hiddens.length; i < len; i++){
11291                 form.removeChild(hiddens[i]);
11292             }
11293         }
11294     }
11295 });
11296
11297 /**
11298  * @class Roo.Ajax
11299  * @extends Roo.data.Connection
11300  * Global Ajax request class.
11301  *
11302  * @singleton
11303  */
11304 Roo.Ajax = new Roo.data.Connection({
11305     // fix up the docs
11306    /**
11307      * @cfg {String} url @hide
11308      */
11309     /**
11310      * @cfg {Object} extraParams @hide
11311      */
11312     /**
11313      * @cfg {Object} defaultHeaders @hide
11314      */
11315     /**
11316      * @cfg {String} method (Optional) @hide
11317      */
11318     /**
11319      * @cfg {Number} timeout (Optional) @hide
11320      */
11321     /**
11322      * @cfg {Boolean} autoAbort (Optional) @hide
11323      */
11324
11325     /**
11326      * @cfg {Boolean} disableCaching (Optional) @hide
11327      */
11328
11329     /**
11330      * @property  disableCaching
11331      * True to add a unique cache-buster param to GET requests. (defaults to true)
11332      * @type Boolean
11333      */
11334     /**
11335      * @property  url
11336      * The default URL to be used for requests to the server. (defaults to undefined)
11337      * @type String
11338      */
11339     /**
11340      * @property  extraParams
11341      * An object containing properties which are used as
11342      * extra parameters to each request made by this object. (defaults to undefined)
11343      * @type Object
11344      */
11345     /**
11346      * @property  defaultHeaders
11347      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11348      * @type Object
11349      */
11350     /**
11351      * @property  method
11352      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11353      * @type String
11354      */
11355     /**
11356      * @property  timeout
11357      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11358      * @type Number
11359      */
11360
11361     /**
11362      * @property  autoAbort
11363      * Whether a new request should abort any pending requests. (defaults to false)
11364      * @type Boolean
11365      */
11366     autoAbort : false,
11367
11368     /**
11369      * Serialize the passed form into a url encoded string
11370      * @param {String/HTMLElement} form
11371      * @return {String}
11372      */
11373     serializeForm : function(form){
11374         return Roo.lib.Ajax.serializeForm(form);
11375     }
11376 });/*
11377  * Based on:
11378  * Ext JS Library 1.1.1
11379  * Copyright(c) 2006-2007, Ext JS, LLC.
11380  *
11381  * Originally Released Under LGPL - original licence link has changed is not relivant.
11382  *
11383  * Fork - LGPL
11384  * <script type="text/javascript">
11385  */
11386  
11387 /**
11388  * @class Roo.Ajax
11389  * @extends Roo.data.Connection
11390  * Global Ajax request class.
11391  *
11392  * @instanceOf  Roo.data.Connection
11393  */
11394 Roo.Ajax = new Roo.data.Connection({
11395     // fix up the docs
11396     
11397     /**
11398      * fix up scoping
11399      * @scope Roo.Ajax
11400      */
11401     
11402    /**
11403      * @cfg {String} url @hide
11404      */
11405     /**
11406      * @cfg {Object} extraParams @hide
11407      */
11408     /**
11409      * @cfg {Object} defaultHeaders @hide
11410      */
11411     /**
11412      * @cfg {String} method (Optional) @hide
11413      */
11414     /**
11415      * @cfg {Number} timeout (Optional) @hide
11416      */
11417     /**
11418      * @cfg {Boolean} autoAbort (Optional) @hide
11419      */
11420
11421     /**
11422      * @cfg {Boolean} disableCaching (Optional) @hide
11423      */
11424
11425     /**
11426      * @property  disableCaching
11427      * True to add a unique cache-buster param to GET requests. (defaults to true)
11428      * @type Boolean
11429      */
11430     /**
11431      * @property  url
11432      * The default URL to be used for requests to the server. (defaults to undefined)
11433      * @type String
11434      */
11435     /**
11436      * @property  extraParams
11437      * An object containing properties which are used as
11438      * extra parameters to each request made by this object. (defaults to undefined)
11439      * @type Object
11440      */
11441     /**
11442      * @property  defaultHeaders
11443      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11444      * @type Object
11445      */
11446     /**
11447      * @property  method
11448      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11449      * @type String
11450      */
11451     /**
11452      * @property  timeout
11453      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11454      * @type Number
11455      */
11456
11457     /**
11458      * @property  autoAbort
11459      * Whether a new request should abort any pending requests. (defaults to false)
11460      * @type Boolean
11461      */
11462     autoAbort : false,
11463
11464     /**
11465      * Serialize the passed form into a url encoded string
11466      * @param {String/HTMLElement} form
11467      * @return {String}
11468      */
11469     serializeForm : function(form){
11470         return Roo.lib.Ajax.serializeForm(form);
11471     }
11472 });/*
11473  * Based on:
11474  * Ext JS Library 1.1.1
11475  * Copyright(c) 2006-2007, Ext JS, LLC.
11476  *
11477  * Originally Released Under LGPL - original licence link has changed is not relivant.
11478  *
11479  * Fork - LGPL
11480  * <script type="text/javascript">
11481  */
11482
11483  
11484 /**
11485  * @class Roo.UpdateManager
11486  * @extends Roo.util.Observable
11487  * Provides AJAX-style update for Element object.<br><br>
11488  * Usage:<br>
11489  * <pre><code>
11490  * // Get it from a Roo.Element object
11491  * var el = Roo.get("foo");
11492  * var mgr = el.getUpdateManager();
11493  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11494  * ...
11495  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11496  * <br>
11497  * // or directly (returns the same UpdateManager instance)
11498  * var mgr = new Roo.UpdateManager("myElementId");
11499  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11500  * mgr.on("update", myFcnNeedsToKnow);
11501  * <br>
11502    // short handed call directly from the element object
11503    Roo.get("foo").load({
11504         url: "bar.php",
11505         scripts:true,
11506         params: "for=bar",
11507         text: "Loading Foo..."
11508    });
11509  * </code></pre>
11510  * @constructor
11511  * Create new UpdateManager directly.
11512  * @param {String/HTMLElement/Roo.Element} el The element to update
11513  * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11514  */
11515 Roo.UpdateManager = function(el, forceNew){
11516     el = Roo.get(el);
11517     if(!forceNew && el.updateManager){
11518         return el.updateManager;
11519     }
11520     /**
11521      * The Element object
11522      * @type Roo.Element
11523      */
11524     this.el = el;
11525     /**
11526      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11527      * @type String
11528      */
11529     this.defaultUrl = null;
11530
11531     this.addEvents({
11532         /**
11533          * @event beforeupdate
11534          * Fired before an update is made, return false from your handler and the update is cancelled.
11535          * @param {Roo.Element} el
11536          * @param {String/Object/Function} url
11537          * @param {String/Object} params
11538          */
11539         "beforeupdate": true,
11540         /**
11541          * @event update
11542          * Fired after successful update is made.
11543          * @param {Roo.Element} el
11544          * @param {Object} oResponseObject The response Object
11545          */
11546         "update": true,
11547         /**
11548          * @event failure
11549          * Fired on update failure.
11550          * @param {Roo.Element} el
11551          * @param {Object} oResponseObject The response Object
11552          */
11553         "failure": true
11554     });
11555     var d = Roo.UpdateManager.defaults;
11556     /**
11557      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11558      * @type String
11559      */
11560     this.sslBlankUrl = d.sslBlankUrl;
11561     /**
11562      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11563      * @type Boolean
11564      */
11565     this.disableCaching = d.disableCaching;
11566     /**
11567      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11568      * @type String
11569      */
11570     this.indicatorText = d.indicatorText;
11571     /**
11572      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11573      * @type String
11574      */
11575     this.showLoadIndicator = d.showLoadIndicator;
11576     /**
11577      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11578      * @type Number
11579      */
11580     this.timeout = d.timeout;
11581
11582     /**
11583      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11584      * @type Boolean
11585      */
11586     this.loadScripts = d.loadScripts;
11587
11588     /**
11589      * Transaction object of current executing transaction
11590      */
11591     this.transaction = null;
11592
11593     /**
11594      * @private
11595      */
11596     this.autoRefreshProcId = null;
11597     /**
11598      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11599      * @type Function
11600      */
11601     this.refreshDelegate = this.refresh.createDelegate(this);
11602     /**
11603      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11604      * @type Function
11605      */
11606     this.updateDelegate = this.update.createDelegate(this);
11607     /**
11608      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11609      * @type Function
11610      */
11611     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11612     /**
11613      * @private
11614      */
11615     this.successDelegate = this.processSuccess.createDelegate(this);
11616     /**
11617      * @private
11618      */
11619     this.failureDelegate = this.processFailure.createDelegate(this);
11620
11621     if(!this.renderer){
11622      /**
11623       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11624       */
11625     this.renderer = new Roo.UpdateManager.BasicRenderer();
11626     }
11627     
11628     Roo.UpdateManager.superclass.constructor.call(this);
11629 };
11630
11631 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11632     /**
11633      * Get the Element this UpdateManager is bound to
11634      * @return {Roo.Element} The element
11635      */
11636     getEl : function(){
11637         return this.el;
11638     },
11639     /**
11640      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11641      * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11642 <pre><code>
11643 um.update({<br/>
11644     url: "your-url.php",<br/>
11645     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11646     callback: yourFunction,<br/>
11647     scope: yourObject, //(optional scope)  <br/>
11648     discardUrl: false, <br/>
11649     nocache: false,<br/>
11650     text: "Loading...",<br/>
11651     timeout: 30,<br/>
11652     scripts: false<br/>
11653 });
11654 </code></pre>
11655      * The only required property is url. The optional properties nocache, text and scripts
11656      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11657      * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
11658      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11659      * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11660      */
11661     update : function(url, params, callback, discardUrl){
11662         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11663             var method = this.method, cfg;
11664             if(typeof url == "object"){ // must be config object
11665                 cfg = url;
11666                 url = cfg.url;
11667                 params = params || cfg.params;
11668                 callback = callback || cfg.callback;
11669                 discardUrl = discardUrl || cfg.discardUrl;
11670                 if(callback && cfg.scope){
11671                     callback = callback.createDelegate(cfg.scope);
11672                 }
11673                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11674                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11675                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11676                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11677                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11678             }
11679             this.showLoading();
11680             if(!discardUrl){
11681                 this.defaultUrl = url;
11682             }
11683             if(typeof url == "function"){
11684                 url = url.call(this);
11685             }
11686
11687             method = method || (params ? "POST" : "GET");
11688             if(method == "GET"){
11689                 url = this.prepareUrl(url);
11690             }
11691
11692             var o = Roo.apply(cfg ||{}, {
11693                 url : url,
11694                 params: params,
11695                 success: this.successDelegate,
11696                 failure: this.failureDelegate,
11697                 callback: undefined,
11698                 timeout: (this.timeout*1000),
11699                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11700             });
11701
11702             this.transaction = Roo.Ajax.request(o);
11703         }
11704     },
11705
11706     /**
11707      * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11708      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11709      * @param {String/HTMLElement} form The form Id or form element
11710      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11711      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11712      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11713      */
11714     formUpdate : function(form, url, reset, callback){
11715         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11716             if(typeof url == "function"){
11717                 url = url.call(this);
11718             }
11719             form = Roo.getDom(form);
11720             this.transaction = Roo.Ajax.request({
11721                 form: form,
11722                 url:url,
11723                 success: this.successDelegate,
11724                 failure: this.failureDelegate,
11725                 timeout: (this.timeout*1000),
11726                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11727             });
11728             this.showLoading.defer(1, this);
11729         }
11730     },
11731
11732     /**
11733      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11734      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11735      */
11736     refresh : function(callback){
11737         if(this.defaultUrl == null){
11738             return;
11739         }
11740         this.update(this.defaultUrl, null, callback, true);
11741     },
11742
11743     /**
11744      * Set this element to auto refresh.
11745      * @param {Number} interval How often to update (in seconds).
11746      * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11747      * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "&param1=1&param2=2" or as an object {param1: 1, param2: 2}
11748      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11749      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11750      */
11751     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11752         if(refreshNow){
11753             this.update(url || this.defaultUrl, params, callback, true);
11754         }
11755         if(this.autoRefreshProcId){
11756             clearInterval(this.autoRefreshProcId);
11757         }
11758         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11759     },
11760
11761     /**
11762      * Stop auto refresh on this element.
11763      */
11764      stopAutoRefresh : function(){
11765         if(this.autoRefreshProcId){
11766             clearInterval(this.autoRefreshProcId);
11767             delete this.autoRefreshProcId;
11768         }
11769     },
11770
11771     isAutoRefreshing : function(){
11772        return this.autoRefreshProcId ? true : false;
11773     },
11774     /**
11775      * Called to update the element to "Loading" state. Override to perform custom action.
11776      */
11777     showLoading : function(){
11778         if(this.showLoadIndicator){
11779             this.el.update(this.indicatorText);
11780         }
11781     },
11782
11783     /**
11784      * Adds unique parameter to query string if disableCaching = true
11785      * @private
11786      */
11787     prepareUrl : function(url){
11788         if(this.disableCaching){
11789             var append = "_dc=" + (new Date().getTime());
11790             if(url.indexOf("?") !== -1){
11791                 url += "&" + append;
11792             }else{
11793                 url += "?" + append;
11794             }
11795         }
11796         return url;
11797     },
11798
11799     /**
11800      * @private
11801      */
11802     processSuccess : function(response){
11803         this.transaction = null;
11804         if(response.argument.form && response.argument.reset){
11805             try{ // put in try/catch since some older FF releases had problems with this
11806                 response.argument.form.reset();
11807             }catch(e){}
11808         }
11809         if(this.loadScripts){
11810             this.renderer.render(this.el, response, this,
11811                 this.updateComplete.createDelegate(this, [response]));
11812         }else{
11813             this.renderer.render(this.el, response, this);
11814             this.updateComplete(response);
11815         }
11816     },
11817
11818     updateComplete : function(response){
11819         this.fireEvent("update", this.el, response);
11820         if(typeof response.argument.callback == "function"){
11821             response.argument.callback(this.el, true, response);
11822         }
11823     },
11824
11825     /**
11826      * @private
11827      */
11828     processFailure : function(response){
11829         this.transaction = null;
11830         this.fireEvent("failure", this.el, response);
11831         if(typeof response.argument.callback == "function"){
11832             response.argument.callback(this.el, false, response);
11833         }
11834     },
11835
11836     /**
11837      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11838      * @param {Object} renderer The object implementing the render() method
11839      */
11840     setRenderer : function(renderer){
11841         this.renderer = renderer;
11842     },
11843
11844     getRenderer : function(){
11845        return this.renderer;
11846     },
11847
11848     /**
11849      * Set the defaultUrl used for updates
11850      * @param {String/Function} defaultUrl The url or a function to call to get the url
11851      */
11852     setDefaultUrl : function(defaultUrl){
11853         this.defaultUrl = defaultUrl;
11854     },
11855
11856     /**
11857      * Aborts the executing transaction
11858      */
11859     abort : function(){
11860         if(this.transaction){
11861             Roo.Ajax.abort(this.transaction);
11862         }
11863     },
11864
11865     /**
11866      * Returns true if an update is in progress
11867      * @return {Boolean}
11868      */
11869     isUpdating : function(){
11870         if(this.transaction){
11871             return Roo.Ajax.isLoading(this.transaction);
11872         }
11873         return false;
11874     }
11875 });
11876
11877 /**
11878  * @class Roo.UpdateManager.defaults
11879  * @static (not really - but it helps the doc tool)
11880  * The defaults collection enables customizing the default properties of UpdateManager
11881  */
11882    Roo.UpdateManager.defaults = {
11883        /**
11884          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11885          * @type Number
11886          */
11887          timeout : 30,
11888
11889          /**
11890          * True to process scripts by default (Defaults to false).
11891          * @type Boolean
11892          */
11893         loadScripts : false,
11894
11895         /**
11896         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11897         * @type String
11898         */
11899         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11900         /**
11901          * Whether to append unique parameter on get request to disable caching (Defaults to false).
11902          * @type Boolean
11903          */
11904         disableCaching : false,
11905         /**
11906          * Whether to show indicatorText when loading (Defaults to true).
11907          * @type Boolean
11908          */
11909         showLoadIndicator : true,
11910         /**
11911          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11912          * @type String
11913          */
11914         indicatorText : '<div class="loading-indicator">Loading...</div>'
11915    };
11916
11917 /**
11918  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11919  *Usage:
11920  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11921  * @param {String/HTMLElement/Roo.Element} el The element to update
11922  * @param {String} url The url
11923  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11924  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11925  * @static
11926  * @deprecated
11927  * @member Roo.UpdateManager
11928  */
11929 Roo.UpdateManager.updateElement = function(el, url, params, options){
11930     var um = Roo.get(el, true).getUpdateManager();
11931     Roo.apply(um, options);
11932     um.update(url, params, options ? options.callback : null);
11933 };
11934 // alias for backwards compat
11935 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11936 /**
11937  * @class Roo.UpdateManager.BasicRenderer
11938  * Default Content renderer. Updates the elements innerHTML with the responseText.
11939  */
11940 Roo.UpdateManager.BasicRenderer = function(){};
11941
11942 Roo.UpdateManager.BasicRenderer.prototype = {
11943     /**
11944      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11945      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11946      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11947      * @param {Roo.Element} el The element being rendered
11948      * @param {Object} response The YUI Connect response object
11949      * @param {UpdateManager} updateManager The calling update manager
11950      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11951      */
11952      render : function(el, response, updateManager, callback){
11953         el.update(response.responseText, updateManager.loadScripts, callback);
11954     }
11955 };
11956 /*
11957  * Based on:
11958  * Ext JS Library 1.1.1
11959  * Copyright(c) 2006-2007, Ext JS, LLC.
11960  *
11961  * Originally Released Under LGPL - original licence link has changed is not relivant.
11962  *
11963  * Fork - LGPL
11964  * <script type="text/javascript">
11965  */
11966
11967 /**
11968  * @class Roo.util.DelayedTask
11969  * Provides a convenient method of performing setTimeout where a new
11970  * timeout cancels the old timeout. An example would be performing validation on a keypress.
11971  * You can use this class to buffer
11972  * the keypress events for a certain number of milliseconds, and perform only if they stop
11973  * for that amount of time.
11974  * @constructor The parameters to this constructor serve as defaults and are not required.
11975  * @param {Function} fn (optional) The default function to timeout
11976  * @param {Object} scope (optional) The default scope of that timeout
11977  * @param {Array} args (optional) The default Array of arguments
11978  */
11979 Roo.util.DelayedTask = function(fn, scope, args){
11980     var id = null, d, t;
11981
11982     var call = function(){
11983         var now = new Date().getTime();
11984         if(now - t >= d){
11985             clearInterval(id);
11986             id = null;
11987             fn.apply(scope, args || []);
11988         }
11989     };
11990     /**
11991      * Cancels any pending timeout and queues a new one
11992      * @param {Number} delay The milliseconds to delay
11993      * @param {Function} newFn (optional) Overrides function passed to constructor
11994      * @param {Object} newScope (optional) Overrides scope passed to constructor
11995      * @param {Array} newArgs (optional) Overrides args passed to constructor
11996      */
11997     this.delay = function(delay, newFn, newScope, newArgs){
11998         if(id && delay != d){
11999             this.cancel();
12000         }
12001         d = delay;
12002         t = new Date().getTime();
12003         fn = newFn || fn;
12004         scope = newScope || scope;
12005         args = newArgs || args;
12006         if(!id){
12007             id = setInterval(call, d);
12008         }
12009     };
12010
12011     /**
12012      * Cancel the last queued timeout
12013      */
12014     this.cancel = function(){
12015         if(id){
12016             clearInterval(id);
12017             id = null;
12018         }
12019     };
12020 };/*
12021  * Based on:
12022  * Ext JS Library 1.1.1
12023  * Copyright(c) 2006-2007, Ext JS, LLC.
12024  *
12025  * Originally Released Under LGPL - original licence link has changed is not relivant.
12026  *
12027  * Fork - LGPL
12028  * <script type="text/javascript">
12029  */
12030  
12031  
12032 Roo.util.TaskRunner = function(interval){
12033     interval = interval || 10;
12034     var tasks = [], removeQueue = [];
12035     var id = 0;
12036     var running = false;
12037
12038     var stopThread = function(){
12039         running = false;
12040         clearInterval(id);
12041         id = 0;
12042     };
12043
12044     var startThread = function(){
12045         if(!running){
12046             running = true;
12047             id = setInterval(runTasks, interval);
12048         }
12049     };
12050
12051     var removeTask = function(task){
12052         removeQueue.push(task);
12053         if(task.onStop){
12054             task.onStop();
12055         }
12056     };
12057
12058     var runTasks = function(){
12059         if(removeQueue.length > 0){
12060             for(var i = 0, len = removeQueue.length; i < len; i++){
12061                 tasks.remove(removeQueue[i]);
12062             }
12063             removeQueue = [];
12064             if(tasks.length < 1){
12065                 stopThread();
12066                 return;
12067             }
12068         }
12069         var now = new Date().getTime();
12070         for(var i = 0, len = tasks.length; i < len; ++i){
12071             var t = tasks[i];
12072             var itime = now - t.taskRunTime;
12073             if(t.interval <= itime){
12074                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12075                 t.taskRunTime = now;
12076                 if(rt === false || t.taskRunCount === t.repeat){
12077                     removeTask(t);
12078                     return;
12079                 }
12080             }
12081             if(t.duration && t.duration <= (now - t.taskStartTime)){
12082                 removeTask(t);
12083             }
12084         }
12085     };
12086
12087     /**
12088      * Queues a new task.
12089      * @param {Object} task
12090      */
12091     this.start = function(task){
12092         tasks.push(task);
12093         task.taskStartTime = new Date().getTime();
12094         task.taskRunTime = 0;
12095         task.taskRunCount = 0;
12096         startThread();
12097         return task;
12098     };
12099
12100     this.stop = function(task){
12101         removeTask(task);
12102         return task;
12103     };
12104
12105     this.stopAll = function(){
12106         stopThread();
12107         for(var i = 0, len = tasks.length; i < len; i++){
12108             if(tasks[i].onStop){
12109                 tasks[i].onStop();
12110             }
12111         }
12112         tasks = [];
12113         removeQueue = [];
12114     };
12115 };
12116
12117 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12118  * Based on:
12119  * Ext JS Library 1.1.1
12120  * Copyright(c) 2006-2007, Ext JS, LLC.
12121  *
12122  * Originally Released Under LGPL - original licence link has changed is not relivant.
12123  *
12124  * Fork - LGPL
12125  * <script type="text/javascript">
12126  */
12127
12128  
12129 /**
12130  * @class Roo.util.MixedCollection
12131  * @extends Roo.util.Observable
12132  * A Collection class that maintains both numeric indexes and keys and exposes events.
12133  * @constructor
12134  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12135  * collection (defaults to false)
12136  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12137  * and return the key value for that item.  This is used when available to look up the key on items that
12138  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12139  * equivalent to providing an implementation for the {@link #getKey} method.
12140  */
12141 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12142     this.items = [];
12143     this.map = {};
12144     this.keys = [];
12145     this.length = 0;
12146     this.addEvents({
12147         /**
12148          * @event clear
12149          * Fires when the collection is cleared.
12150          */
12151         "clear" : true,
12152         /**
12153          * @event add
12154          * Fires when an item is added to the collection.
12155          * @param {Number} index The index at which the item was added.
12156          * @param {Object} o The item added.
12157          * @param {String} key The key associated with the added item.
12158          */
12159         "add" : true,
12160         /**
12161          * @event replace
12162          * Fires when an item is replaced in the collection.
12163          * @param {String} key he key associated with the new added.
12164          * @param {Object} old The item being replaced.
12165          * @param {Object} new The new item.
12166          */
12167         "replace" : true,
12168         /**
12169          * @event remove
12170          * Fires when an item is removed from the collection.
12171          * @param {Object} o The item being removed.
12172          * @param {String} key (optional) The key associated with the removed item.
12173          */
12174         "remove" : true,
12175         "sort" : true
12176     });
12177     this.allowFunctions = allowFunctions === true;
12178     if(keyFn){
12179         this.getKey = keyFn;
12180     }
12181     Roo.util.MixedCollection.superclass.constructor.call(this);
12182 };
12183
12184 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12185     allowFunctions : false,
12186     
12187 /**
12188  * Adds an item to the collection.
12189  * @param {String} key The key to associate with the item
12190  * @param {Object} o The item to add.
12191  * @return {Object} The item added.
12192  */
12193     add : function(key, o){
12194         if(arguments.length == 1){
12195             o = arguments[0];
12196             key = this.getKey(o);
12197         }
12198         if(typeof key == "undefined" || key === null){
12199             this.length++;
12200             this.items.push(o);
12201             this.keys.push(null);
12202         }else{
12203             var old = this.map[key];
12204             if(old){
12205                 return this.replace(key, o);
12206             }
12207             this.length++;
12208             this.items.push(o);
12209             this.map[key] = o;
12210             this.keys.push(key);
12211         }
12212         this.fireEvent("add", this.length-1, o, key);
12213         return o;
12214     },
12215    
12216 /**
12217   * MixedCollection has a generic way to fetch keys if you implement getKey.
12218 <pre><code>
12219 // normal way
12220 var mc = new Roo.util.MixedCollection();
12221 mc.add(someEl.dom.id, someEl);
12222 mc.add(otherEl.dom.id, otherEl);
12223 //and so on
12224
12225 // using getKey
12226 var mc = new Roo.util.MixedCollection();
12227 mc.getKey = function(el){
12228    return el.dom.id;
12229 };
12230 mc.add(someEl);
12231 mc.add(otherEl);
12232
12233 // or via the constructor
12234 var mc = new Roo.util.MixedCollection(false, function(el){
12235    return el.dom.id;
12236 });
12237 mc.add(someEl);
12238 mc.add(otherEl);
12239 </code></pre>
12240  * @param o {Object} The item for which to find the key.
12241  * @return {Object} The key for the passed item.
12242  */
12243     getKey : function(o){
12244          return o.id; 
12245     },
12246    
12247 /**
12248  * Replaces an item in the collection.
12249  * @param {String} key The key associated with the item to replace, or the item to replace.
12250  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12251  * @return {Object}  The new item.
12252  */
12253     replace : function(key, o){
12254         if(arguments.length == 1){
12255             o = arguments[0];
12256             key = this.getKey(o);
12257         }
12258         var old = this.item(key);
12259         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12260              return this.add(key, o);
12261         }
12262         var index = this.indexOfKey(key);
12263         this.items[index] = o;
12264         this.map[key] = o;
12265         this.fireEvent("replace", key, old, o);
12266         return o;
12267     },
12268    
12269 /**
12270  * Adds all elements of an Array or an Object to the collection.
12271  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12272  * an Array of values, each of which are added to the collection.
12273  */
12274     addAll : function(objs){
12275         if(arguments.length > 1 || objs instanceof Array){
12276             var args = arguments.length > 1 ? arguments : objs;
12277             for(var i = 0, len = args.length; i < len; i++){
12278                 this.add(args[i]);
12279             }
12280         }else{
12281             for(var key in objs){
12282                 if(this.allowFunctions || typeof objs[key] != "function"){
12283                     this.add(key, objs[key]);
12284                 }
12285             }
12286         }
12287     },
12288    
12289 /**
12290  * Executes the specified function once for every item in the collection, passing each
12291  * item as the first and only parameter. returning false from the function will stop the iteration.
12292  * @param {Function} fn The function to execute for each item.
12293  * @param {Object} scope (optional) The scope in which to execute the function.
12294  */
12295     each : function(fn, scope){
12296         var items = [].concat(this.items); // each safe for removal
12297         for(var i = 0, len = items.length; i < len; i++){
12298             if(fn.call(scope || items[i], items[i], i, len) === false){
12299                 break;
12300             }
12301         }
12302     },
12303    
12304 /**
12305  * Executes the specified function once for every key in the collection, passing each
12306  * key, and its associated item as the first two parameters.
12307  * @param {Function} fn The function to execute for each item.
12308  * @param {Object} scope (optional) The scope in which to execute the function.
12309  */
12310     eachKey : function(fn, scope){
12311         for(var i = 0, len = this.keys.length; i < len; i++){
12312             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12313         }
12314     },
12315    
12316 /**
12317  * Returns the first item in the collection which elicits a true return value from the
12318  * passed selection function.
12319  * @param {Function} fn The selection function to execute for each item.
12320  * @param {Object} scope (optional) The scope in which to execute the function.
12321  * @return {Object} The first item in the collection which returned true from the selection function.
12322  */
12323     find : function(fn, scope){
12324         for(var i = 0, len = this.items.length; i < len; i++){
12325             if(fn.call(scope || window, this.items[i], this.keys[i])){
12326                 return this.items[i];
12327             }
12328         }
12329         return null;
12330     },
12331    
12332 /**
12333  * Inserts an item at the specified index in the collection.
12334  * @param {Number} index The index to insert the item at.
12335  * @param {String} key The key to associate with the new item, or the item itself.
12336  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12337  * @return {Object} The item inserted.
12338  */
12339     insert : function(index, key, o){
12340         if(arguments.length == 2){
12341             o = arguments[1];
12342             key = this.getKey(o);
12343         }
12344         if(index >= this.length){
12345             return this.add(key, o);
12346         }
12347         this.length++;
12348         this.items.splice(index, 0, o);
12349         if(typeof key != "undefined" && key != null){
12350             this.map[key] = o;
12351         }
12352         this.keys.splice(index, 0, key);
12353         this.fireEvent("add", index, o, key);
12354         return o;
12355     },
12356    
12357 /**
12358  * Removed an item from the collection.
12359  * @param {Object} o The item to remove.
12360  * @return {Object} The item removed.
12361  */
12362     remove : function(o){
12363         return this.removeAt(this.indexOf(o));
12364     },
12365    
12366 /**
12367  * Remove an item from a specified index in the collection.
12368  * @param {Number} index The index within the collection of the item to remove.
12369  */
12370     removeAt : function(index){
12371         if(index < this.length && index >= 0){
12372             this.length--;
12373             var o = this.items[index];
12374             this.items.splice(index, 1);
12375             var key = this.keys[index];
12376             if(typeof key != "undefined"){
12377                 delete this.map[key];
12378             }
12379             this.keys.splice(index, 1);
12380             this.fireEvent("remove", o, key);
12381         }
12382     },
12383    
12384 /**
12385  * Removed an item associated with the passed key fom the collection.
12386  * @param {String} key The key of the item to remove.
12387  */
12388     removeKey : function(key){
12389         return this.removeAt(this.indexOfKey(key));
12390     },
12391    
12392 /**
12393  * Returns the number of items in the collection.
12394  * @return {Number} the number of items in the collection.
12395  */
12396     getCount : function(){
12397         return this.length; 
12398     },
12399    
12400 /**
12401  * Returns index within the collection of the passed Object.
12402  * @param {Object} o The item to find the index of.
12403  * @return {Number} index of the item.
12404  */
12405     indexOf : function(o){
12406         if(!this.items.indexOf){
12407             for(var i = 0, len = this.items.length; i < len; i++){
12408                 if(this.items[i] == o) return i;
12409             }
12410             return -1;
12411         }else{
12412             return this.items.indexOf(o);
12413         }
12414     },
12415    
12416 /**
12417  * Returns index within the collection of the passed key.
12418  * @param {String} key The key to find the index of.
12419  * @return {Number} index of the key.
12420  */
12421     indexOfKey : function(key){
12422         if(!this.keys.indexOf){
12423             for(var i = 0, len = this.keys.length; i < len; i++){
12424                 if(this.keys[i] == key) return i;
12425             }
12426             return -1;
12427         }else{
12428             return this.keys.indexOf(key);
12429         }
12430     },
12431    
12432 /**
12433  * Returns the item associated with the passed key OR index. Key has priority over index.
12434  * @param {String/Number} key The key or index of the item.
12435  * @return {Object} The item associated with the passed key.
12436  */
12437     item : function(key){
12438         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12439         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12440     },
12441     
12442 /**
12443  * Returns the item at the specified index.
12444  * @param {Number} index The index of the item.
12445  * @return {Object}
12446  */
12447     itemAt : function(index){
12448         return this.items[index];
12449     },
12450     
12451 /**
12452  * Returns the item associated with the passed key.
12453  * @param {String/Number} key The key of the item.
12454  * @return {Object} The item associated with the passed key.
12455  */
12456     key : function(key){
12457         return this.map[key];
12458     },
12459    
12460 /**
12461  * Returns true if the collection contains the passed Object as an item.
12462  * @param {Object} o  The Object to look for in the collection.
12463  * @return {Boolean} True if the collection contains the Object as an item.
12464  */
12465     contains : function(o){
12466         return this.indexOf(o) != -1;
12467     },
12468    
12469 /**
12470  * Returns true if the collection contains the passed Object as a key.
12471  * @param {String} key The key to look for in the collection.
12472  * @return {Boolean} True if the collection contains the Object as a key.
12473  */
12474     containsKey : function(key){
12475         return typeof this.map[key] != "undefined";
12476     },
12477    
12478 /**
12479  * Removes all items from the collection.
12480  */
12481     clear : function(){
12482         this.length = 0;
12483         this.items = [];
12484         this.keys = [];
12485         this.map = {};
12486         this.fireEvent("clear");
12487     },
12488    
12489 /**
12490  * Returns the first item in the collection.
12491  * @return {Object} the first item in the collection..
12492  */
12493     first : function(){
12494         return this.items[0]; 
12495     },
12496    
12497 /**
12498  * Returns the last item in the collection.
12499  * @return {Object} the last item in the collection..
12500  */
12501     last : function(){
12502         return this.items[this.length-1];   
12503     },
12504     
12505     _sort : function(property, dir, fn){
12506         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12507         fn = fn || function(a, b){
12508             return a-b;
12509         };
12510         var c = [], k = this.keys, items = this.items;
12511         for(var i = 0, len = items.length; i < len; i++){
12512             c[c.length] = {key: k[i], value: items[i], index: i};
12513         }
12514         c.sort(function(a, b){
12515             var v = fn(a[property], b[property]) * dsc;
12516             if(v == 0){
12517                 v = (a.index < b.index ? -1 : 1);
12518             }
12519             return v;
12520         });
12521         for(var i = 0, len = c.length; i < len; i++){
12522             items[i] = c[i].value;
12523             k[i] = c[i].key;
12524         }
12525         this.fireEvent("sort", this);
12526     },
12527     
12528     /**
12529      * Sorts this collection with the passed comparison function
12530      * @param {String} direction (optional) "ASC" or "DESC"
12531      * @param {Function} fn (optional) comparison function
12532      */
12533     sort : function(dir, fn){
12534         this._sort("value", dir, fn);
12535     },
12536     
12537     /**
12538      * Sorts this collection by keys
12539      * @param {String} direction (optional) "ASC" or "DESC"
12540      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12541      */
12542     keySort : function(dir, fn){
12543         this._sort("key", dir, fn || function(a, b){
12544             return String(a).toUpperCase()-String(b).toUpperCase();
12545         });
12546     },
12547     
12548     /**
12549      * Returns a range of items in this collection
12550      * @param {Number} startIndex (optional) defaults to 0
12551      * @param {Number} endIndex (optional) default to the last item
12552      * @return {Array} An array of items
12553      */
12554     getRange : function(start, end){
12555         var items = this.items;
12556         if(items.length < 1){
12557             return [];
12558         }
12559         start = start || 0;
12560         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12561         var r = [];
12562         if(start <= end){
12563             for(var i = start; i <= end; i++) {
12564                     r[r.length] = items[i];
12565             }
12566         }else{
12567             for(var i = start; i >= end; i--) {
12568                     r[r.length] = items[i];
12569             }
12570         }
12571         return r;
12572     },
12573         
12574     /**
12575      * Filter the <i>objects</i> in this collection by a specific property. 
12576      * Returns a new collection that has been filtered.
12577      * @param {String} property A property on your objects
12578      * @param {String/RegExp} value Either string that the property values 
12579      * should start with or a RegExp to test against the property
12580      * @return {MixedCollection} The new filtered collection
12581      */
12582     filter : function(property, value){
12583         if(!value.exec){ // not a regex
12584             value = String(value);
12585             if(value.length == 0){
12586                 return this.clone();
12587             }
12588             value = new RegExp("^" + Roo.escapeRe(value), "i");
12589         }
12590         return this.filterBy(function(o){
12591             return o && value.test(o[property]);
12592         });
12593         },
12594     
12595     /**
12596      * Filter by a function. * Returns a new collection that has been filtered.
12597      * The passed function will be called with each 
12598      * object in the collection. If the function returns true, the value is included 
12599      * otherwise it is filtered.
12600      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12601      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12602      * @return {MixedCollection} The new filtered collection
12603      */
12604     filterBy : function(fn, scope){
12605         var r = new Roo.util.MixedCollection();
12606         r.getKey = this.getKey;
12607         var k = this.keys, it = this.items;
12608         for(var i = 0, len = it.length; i < len; i++){
12609             if(fn.call(scope||this, it[i], k[i])){
12610                                 r.add(k[i], it[i]);
12611                         }
12612         }
12613         return r;
12614     },
12615     
12616     /**
12617      * Creates a duplicate of this collection
12618      * @return {MixedCollection}
12619      */
12620     clone : function(){
12621         var r = new Roo.util.MixedCollection();
12622         var k = this.keys, it = this.items;
12623         for(var i = 0, len = it.length; i < len; i++){
12624             r.add(k[i], it[i]);
12625         }
12626         r.getKey = this.getKey;
12627         return r;
12628     }
12629 });
12630 /**
12631  * Returns the item associated with the passed key or index.
12632  * @method
12633  * @param {String/Number} key The key or index of the item.
12634  * @return {Object} The item associated with the passed key.
12635  */
12636 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12637  * Based on:
12638  * Ext JS Library 1.1.1
12639  * Copyright(c) 2006-2007, Ext JS, LLC.
12640  *
12641  * Originally Released Under LGPL - original licence link has changed is not relivant.
12642  *
12643  * Fork - LGPL
12644  * <script type="text/javascript">
12645  */
12646 /**
12647  * @class Roo.util.JSON
12648  * Modified version of Douglas Crockford"s json.js that doesn"t
12649  * mess with the Object prototype 
12650  * http://www.json.org/js.html
12651  * @singleton
12652  */
12653 Roo.util.JSON = new (function(){
12654     var useHasOwn = {}.hasOwnProperty ? true : false;
12655     
12656     // crashes Safari in some instances
12657     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12658     
12659     var pad = function(n) {
12660         return n < 10 ? "0" + n : n;
12661     };
12662     
12663     var m = {
12664         "\b": '\\b',
12665         "\t": '\\t',
12666         "\n": '\\n',
12667         "\f": '\\f',
12668         "\r": '\\r',
12669         '"' : '\\"',
12670         "\\": '\\\\'
12671     };
12672
12673     var encodeString = function(s){
12674         if (/["\\\x00-\x1f]/.test(s)) {
12675             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12676                 var c = m[b];
12677                 if(c){
12678                     return c;
12679                 }
12680                 c = b.charCodeAt();
12681                 return "\\u00" +
12682                     Math.floor(c / 16).toString(16) +
12683                     (c % 16).toString(16);
12684             }) + '"';
12685         }
12686         return '"' + s + '"';
12687     };
12688     
12689     var encodeArray = function(o){
12690         var a = ["["], b, i, l = o.length, v;
12691             for (i = 0; i < l; i += 1) {
12692                 v = o[i];
12693                 switch (typeof v) {
12694                     case "undefined":
12695                     case "function":
12696                     case "unknown":
12697                         break;
12698                     default:
12699                         if (b) {
12700                             a.push(',');
12701                         }
12702                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12703                         b = true;
12704                 }
12705             }
12706             a.push("]");
12707             return a.join("");
12708     };
12709     
12710     var encodeDate = function(o){
12711         return '"' + o.getFullYear() + "-" +
12712                 pad(o.getMonth() + 1) + "-" +
12713                 pad(o.getDate()) + "T" +
12714                 pad(o.getHours()) + ":" +
12715                 pad(o.getMinutes()) + ":" +
12716                 pad(o.getSeconds()) + '"';
12717     };
12718     
12719     /**
12720      * Encodes an Object, Array or other value
12721      * @param {Mixed} o The variable to encode
12722      * @return {String} The JSON string
12723      */
12724     this.encode = function(o){
12725         if(typeof o == "undefined" || o === null){
12726             return "null";
12727         }else if(o instanceof Array){
12728             return encodeArray(o);
12729         }else if(o instanceof Date){
12730             return encodeDate(o);
12731         }else if(typeof o == "string"){
12732             return encodeString(o);
12733         }else if(typeof o == "number"){
12734             return isFinite(o) ? String(o) : "null";
12735         }else if(typeof o == "boolean"){
12736             return String(o);
12737         }else {
12738             var a = ["{"], b, i, v;
12739             for (i in o) {
12740                 if(!useHasOwn || o.hasOwnProperty(i)) {
12741                     v = o[i];
12742                     switch (typeof v) {
12743                     case "undefined":
12744                     case "function":
12745                     case "unknown":
12746                         break;
12747                     default:
12748                         if(b){
12749                             a.push(',');
12750                         }
12751                         a.push(this.encode(i), ":",
12752                                 v === null ? "null" : this.encode(v));
12753                         b = true;
12754                     }
12755                 }
12756             }
12757             a.push("}");
12758             return a.join("");
12759         }
12760     };
12761     
12762     /**
12763      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12764      * @param {String} json The JSON string
12765      * @return {Object} The resulting object
12766      */
12767     this.decode = function(json){
12768         /**
12769          * eval:var:json
12770          */
12771         return eval("(" + json + ')');
12772     };
12773 })();
12774 /** 
12775  * Shorthand for {@link Roo.util.JSON#encode}
12776  * @member Roo encode 
12777  * @method */
12778 Roo.encode = Roo.util.JSON.encode;
12779 /** 
12780  * Shorthand for {@link Roo.util.JSON#decode}
12781  * @member Roo decode 
12782  * @method */
12783 Roo.decode = Roo.util.JSON.decode;
12784 /*
12785  * Based on:
12786  * Ext JS Library 1.1.1
12787  * Copyright(c) 2006-2007, Ext JS, LLC.
12788  *
12789  * Originally Released Under LGPL - original licence link has changed is not relivant.
12790  *
12791  * Fork - LGPL
12792  * <script type="text/javascript">
12793  */
12794  
12795 /**
12796  * @class Roo.util.Format
12797  * Reusable data formatting functions
12798  * @singleton
12799  */
12800 Roo.util.Format = function(){
12801     var trimRe = /^\s+|\s+$/g;
12802     return {
12803         /**
12804          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12805          * @param {String} value The string to truncate
12806          * @param {Number} length The maximum length to allow before truncating
12807          * @return {String} The converted text
12808          */
12809         ellipsis : function(value, len){
12810             if(value && value.length > len){
12811                 return value.substr(0, len-3)+"...";
12812             }
12813             return value;
12814         },
12815
12816         /**
12817          * Checks a reference and converts it to empty string if it is undefined
12818          * @param {Mixed} value Reference to check
12819          * @return {Mixed} Empty string if converted, otherwise the original value
12820          */
12821         undef : function(value){
12822             return typeof value != "undefined" ? value : "";
12823         },
12824
12825         /**
12826          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12827          * @param {String} value The string to encode
12828          * @return {String} The encoded text
12829          */
12830         htmlEncode : function(value){
12831             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
12832         },
12833
12834         /**
12835          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12836          * @param {String} value The string to decode
12837          * @return {String} The decoded text
12838          */
12839         htmlDecode : function(value){
12840             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
12841         },
12842
12843         /**
12844          * Trims any whitespace from either side of a string
12845          * @param {String} value The text to trim
12846          * @return {String} The trimmed text
12847          */
12848         trim : function(value){
12849             return String(value).replace(trimRe, "");
12850         },
12851
12852         /**
12853          * Returns a substring from within an original string
12854          * @param {String} value The original text
12855          * @param {Number} start The start index of the substring
12856          * @param {Number} length The length of the substring
12857          * @return {String} The substring
12858          */
12859         substr : function(value, start, length){
12860             return String(value).substr(start, length);
12861         },
12862
12863         /**
12864          * Converts a string to all lower case letters
12865          * @param {String} value The text to convert
12866          * @return {String} The converted text
12867          */
12868         lowercase : function(value){
12869             return String(value).toLowerCase();
12870         },
12871
12872         /**
12873          * Converts a string to all upper case letters
12874          * @param {String} value The text to convert
12875          * @return {String} The converted text
12876          */
12877         uppercase : function(value){
12878             return String(value).toUpperCase();
12879         },
12880
12881         /**
12882          * Converts the first character only of a string to upper case
12883          * @param {String} value The text to convert
12884          * @return {String} The converted text
12885          */
12886         capitalize : function(value){
12887             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12888         },
12889
12890         // private
12891         call : function(value, fn){
12892             if(arguments.length > 2){
12893                 var args = Array.prototype.slice.call(arguments, 2);
12894                 args.unshift(value);
12895                  
12896                 return /** eval:var:value */  eval(fn).apply(window, args);
12897             }else{
12898                 /** eval:var:value */
12899                 return /** eval:var:value */ eval(fn).call(window, value);
12900             }
12901         },
12902
12903         /**
12904          * Format a number as US currency
12905          * @param {Number/String} value The numeric value to format
12906          * @return {String} The formatted currency string
12907          */
12908         usMoney : function(v){
12909             v = (Math.round((v-0)*100))/100;
12910             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12911             v = String(v);
12912             var ps = v.split('.');
12913             var whole = ps[0];
12914             var sub = ps[1] ? '.'+ ps[1] : '.00';
12915             var r = /(\d+)(\d{3})/;
12916             while (r.test(whole)) {
12917                 whole = whole.replace(r, '$1' + ',' + '$2');
12918             }
12919             return "$" + whole + sub ;
12920         },
12921
12922         /**
12923          * Parse a value into a formatted date using the specified format pattern.
12924          * @param {Mixed} value The value to format
12925          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12926          * @return {String} The formatted date string
12927          */
12928         date : function(v, format){
12929             if(!v){
12930                 return "";
12931             }
12932             if(!(v instanceof Date)){
12933                 v = new Date(Date.parse(v));
12934             }
12935             return v.dateFormat(format || "m/d/Y");
12936         },
12937
12938         /**
12939          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12940          * @param {String} format Any valid date format string
12941          * @return {Function} The date formatting function
12942          */
12943         dateRenderer : function(format){
12944             return function(v){
12945                 return Roo.util.Format.date(v, format);  
12946             };
12947         },
12948
12949         // private
12950         stripTagsRE : /<\/?[^>]+>/gi,
12951         
12952         /**
12953          * Strips all HTML tags
12954          * @param {Mixed} value The text from which to strip tags
12955          * @return {String} The stripped text
12956          */
12957         stripTags : function(v){
12958             return !v ? v : String(v).replace(this.stripTagsRE, "");
12959         }
12960     };
12961 }();/*
12962  * Based on:
12963  * Ext JS Library 1.1.1
12964  * Copyright(c) 2006-2007, Ext JS, LLC.
12965  *
12966  * Originally Released Under LGPL - original licence link has changed is not relivant.
12967  *
12968  * Fork - LGPL
12969  * <script type="text/javascript">
12970  */
12971
12972
12973  
12974
12975 /**
12976  * @class Roo.MasterTemplate
12977  * @extends Roo.Template
12978  * Provides a template that can have child templates. The syntax is:
12979 <pre><code>
12980 var t = new Roo.MasterTemplate(
12981         '&lt;select name="{name}"&gt;',
12982                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
12983         '&lt;/select&gt;'
12984 );
12985 t.add('options', {value: 'foo', text: 'bar'});
12986 // or you can add multiple child elements in one shot
12987 t.addAll('options', [
12988     {value: 'foo', text: 'bar'},
12989     {value: 'foo2', text: 'bar2'},
12990     {value: 'foo3', text: 'bar3'}
12991 ]);
12992 // then append, applying the master template values
12993 t.append('my-form', {name: 'my-select'});
12994 </code></pre>
12995 * A name attribute for the child template is not required if you have only one child
12996 * template or you want to refer to them by index.
12997  */
12998 Roo.MasterTemplate = function(){
12999     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13000     this.originalHtml = this.html;
13001     var st = {};
13002     var m, re = this.subTemplateRe;
13003     re.lastIndex = 0;
13004     var subIndex = 0;
13005     while(m = re.exec(this.html)){
13006         var name = m[1], content = m[2];
13007         st[subIndex] = {
13008             name: name,
13009             index: subIndex,
13010             buffer: [],
13011             tpl : new Roo.Template(content)
13012         };
13013         if(name){
13014             st[name] = st[subIndex];
13015         }
13016         st[subIndex].tpl.compile();
13017         st[subIndex].tpl.call = this.call.createDelegate(this);
13018         subIndex++;
13019     }
13020     this.subCount = subIndex;
13021     this.subs = st;
13022 };
13023 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13024     /**
13025     * The regular expression used to match sub templates
13026     * @type RegExp
13027     * @property
13028     */
13029     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13030
13031     /**
13032      * Applies the passed values to a child template.
13033      * @param {String/Number} name (optional) The name or index of the child template
13034      * @param {Array/Object} values The values to be applied to the template
13035      * @return {MasterTemplate} this
13036      */
13037      add : function(name, values){
13038         if(arguments.length == 1){
13039             values = arguments[0];
13040             name = 0;
13041         }
13042         var s = this.subs[name];
13043         s.buffer[s.buffer.length] = s.tpl.apply(values);
13044         return this;
13045     },
13046
13047     /**
13048      * Applies all the passed values to a child template.
13049      * @param {String/Number} name (optional) The name or index of the child template
13050      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13051      * @param {Boolean} reset (optional) True to reset the template first
13052      * @return {MasterTemplate} this
13053      */
13054     fill : function(name, values, reset){
13055         var a = arguments;
13056         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13057             values = a[0];
13058             name = 0;
13059             reset = a[1];
13060         }
13061         if(reset){
13062             this.reset();
13063         }
13064         for(var i = 0, len = values.length; i < len; i++){
13065             this.add(name, values[i]);
13066         }
13067         return this;
13068     },
13069
13070     /**
13071      * Resets the template for reuse
13072      * @return {MasterTemplate} this
13073      */
13074      reset : function(){
13075         var s = this.subs;
13076         for(var i = 0; i < this.subCount; i++){
13077             s[i].buffer = [];
13078         }
13079         return this;
13080     },
13081
13082     applyTemplate : function(values){
13083         var s = this.subs;
13084         var replaceIndex = -1;
13085         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13086             return s[++replaceIndex].buffer.join("");
13087         });
13088         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13089     },
13090
13091     apply : function(){
13092         return this.applyTemplate.apply(this, arguments);
13093     },
13094
13095     compile : function(){return this;}
13096 });
13097
13098 /**
13099  * Alias for fill().
13100  * @method
13101  */
13102 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13103  /**
13104  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13105  * var tpl = Roo.MasterTemplate.from('element-id');
13106  * @param {String/HTMLElement} el
13107  * @param {Object} config
13108  * @static
13109  */
13110 Roo.MasterTemplate.from = function(el, config){
13111     el = Roo.getDom(el);
13112     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13113 };/*
13114  * Based on:
13115  * Ext JS Library 1.1.1
13116  * Copyright(c) 2006-2007, Ext JS, LLC.
13117  *
13118  * Originally Released Under LGPL - original licence link has changed is not relivant.
13119  *
13120  * Fork - LGPL
13121  * <script type="text/javascript">
13122  */
13123
13124  
13125 /**
13126  * @class Roo.util.CSS
13127  * Utility class for manipulating CSS rules
13128  * @singleton
13129  */
13130 Roo.util.CSS = function(){
13131         var rules = null;
13132         var doc = document;
13133
13134     var camelRe = /(-[a-z])/gi;
13135     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13136
13137    return {
13138    /**
13139     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13140     * tag and appended to the HEAD of the document.
13141     * @param {String} cssText The text containing the css rules
13142     * @param {String} id An id to add to the stylesheet for later removal
13143     * @return {StyleSheet}
13144     */
13145    createStyleSheet : function(cssText, id){
13146        var ss;
13147        var head = doc.getElementsByTagName("head")[0];
13148        var rules = doc.createElement("style");
13149        rules.setAttribute("type", "text/css");
13150        if(id){
13151            rules.setAttribute("id", id);
13152        }
13153        if(Roo.isIE){
13154            head.appendChild(rules);
13155            ss = rules.styleSheet;
13156            ss.cssText = cssText;
13157        }else{
13158            try{
13159                 rules.appendChild(doc.createTextNode(cssText));
13160            }catch(e){
13161                rules.cssText = cssText; 
13162            }
13163            head.appendChild(rules);
13164            ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13165        }
13166        this.cacheStyleSheet(ss);
13167        return ss;
13168    },
13169
13170    /**
13171     * Removes a style or link tag by id
13172     * @param {String} id The id of the tag
13173     */
13174    removeStyleSheet : function(id){
13175        var existing = doc.getElementById(id);
13176        if(existing){
13177            existing.parentNode.removeChild(existing);
13178        }
13179    },
13180
13181    /**
13182     * Dynamically swaps an existing stylesheet reference for a new one
13183     * @param {String} id The id of an existing link tag to remove
13184     * @param {String} url The href of the new stylesheet to include
13185     */
13186    swapStyleSheet : function(id, url){
13187        this.removeStyleSheet(id);
13188        var ss = doc.createElement("link");
13189        ss.setAttribute("rel", "stylesheet");
13190        ss.setAttribute("type", "text/css");
13191        ss.setAttribute("id", id);
13192        ss.setAttribute("href", url);
13193        doc.getElementsByTagName("head")[0].appendChild(ss);
13194    },
13195    
13196    /**
13197     * Refresh the rule cache if you have dynamically added stylesheets
13198     * @return {Object} An object (hash) of rules indexed by selector
13199     */
13200    refreshCache : function(){
13201        return this.getRules(true);
13202    },
13203
13204    // private
13205    cacheStyleSheet : function(ss){
13206        if(!rules){
13207            rules = {};
13208        }
13209        try{// try catch for cross domain access issue
13210            var ssRules = ss.cssRules || ss.rules;
13211            for(var j = ssRules.length-1; j >= 0; --j){
13212                rules[ssRules[j].selectorText] = ssRules[j];
13213            }
13214        }catch(e){}
13215    },
13216    
13217    /**
13218     * Gets all css rules for the document
13219     * @param {Boolean} refreshCache true to refresh the internal cache
13220     * @return {Object} An object (hash) of rules indexed by selector
13221     */
13222    getRules : function(refreshCache){
13223                 if(rules == null || refreshCache){
13224                         rules = {};
13225                         var ds = doc.styleSheets;
13226                         for(var i =0, len = ds.length; i < len; i++){
13227                             try{
13228                         this.cacheStyleSheet(ds[i]);
13229                     }catch(e){} 
13230                 }
13231                 }
13232                 return rules;
13233         },
13234         
13235         /**
13236     * Gets an an individual CSS rule by selector(s)
13237     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13238     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13239     * @return {CSSRule} The CSS rule or null if one is not found
13240     */
13241    getRule : function(selector, refreshCache){
13242                 var rs = this.getRules(refreshCache);
13243                 if(!(selector instanceof Array)){
13244                     return rs[selector];
13245                 }
13246                 for(var i = 0; i < selector.length; i++){
13247                         if(rs[selector[i]]){
13248                                 return rs[selector[i]];
13249                         }
13250                 }
13251                 return null;
13252         },
13253         
13254         
13255         /**
13256     * Updates a rule property
13257     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13258     * @param {String} property The css property
13259     * @param {String} value The new value for the property
13260     * @return {Boolean} true If a rule was found and updated
13261     */
13262    updateRule : function(selector, property, value){
13263                 if(!(selector instanceof Array)){
13264                         var rule = this.getRule(selector);
13265                         if(rule){
13266                                 rule.style[property.replace(camelRe, camelFn)] = value;
13267                                 return true;
13268                         }
13269                 }else{
13270                         for(var i = 0; i < selector.length; i++){
13271                                 if(this.updateRule(selector[i], property, value)){
13272                                         return true;
13273                                 }
13274                         }
13275                 }
13276                 return false;
13277         }
13278    };   
13279 }();/*
13280  * Based on:
13281  * Ext JS Library 1.1.1
13282  * Copyright(c) 2006-2007, Ext JS, LLC.
13283  *
13284  * Originally Released Under LGPL - original licence link has changed is not relivant.
13285  *
13286  * Fork - LGPL
13287  * <script type="text/javascript">
13288  */
13289
13290  
13291
13292 /**
13293  * @class Roo.util.ClickRepeater
13294  * @extends Roo.util.Observable
13295  * 
13296  * A wrapper class which can be applied to any element. Fires a "click" event while the
13297  * mouse is pressed. The interval between firings may be specified in the config but
13298  * defaults to 10 milliseconds.
13299  * 
13300  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13301  * 
13302  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13303  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13304  * Similar to an autorepeat key delay.
13305  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13306  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13307  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13308  *           "interval" and "delay" are ignored. "immediate" is honored.
13309  * @cfg {Boolean} preventDefault True to prevent the default click event
13310  * @cfg {Boolean} stopDefault True to stop the default click event
13311  * 
13312  * @history
13313  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13314  *     2007-02-02 jvs Renamed to ClickRepeater
13315  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13316  *
13317  *  @constructor
13318  * @param {String/HTMLElement/Element} el The element to listen on
13319  * @param {Object} config
13320  **/
13321 Roo.util.ClickRepeater = function(el, config)
13322 {
13323     this.el = Roo.get(el);
13324     this.el.unselectable();
13325
13326     Roo.apply(this, config);
13327
13328     this.addEvents({
13329     /**
13330      * @event mousedown
13331      * Fires when the mouse button is depressed.
13332      * @param {Roo.util.ClickRepeater} this
13333      */
13334         "mousedown" : true,
13335     /**
13336      * @event click
13337      * Fires on a specified interval during the time the element is pressed.
13338      * @param {Roo.util.ClickRepeater} this
13339      */
13340         "click" : true,
13341     /**
13342      * @event mouseup
13343      * Fires when the mouse key is released.
13344      * @param {Roo.util.ClickRepeater} this
13345      */
13346         "mouseup" : true
13347     });
13348
13349     this.el.on("mousedown", this.handleMouseDown, this);
13350     if(this.preventDefault || this.stopDefault){
13351         this.el.on("click", function(e){
13352             if(this.preventDefault){
13353                 e.preventDefault();
13354             }
13355             if(this.stopDefault){
13356                 e.stopEvent();
13357             }
13358         }, this);
13359     }
13360
13361     // allow inline handler
13362     if(this.handler){
13363         this.on("click", this.handler,  this.scope || this);
13364     }
13365
13366     Roo.util.ClickRepeater.superclass.constructor.call(this);
13367 };
13368
13369 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13370     interval : 20,
13371     delay: 250,
13372     preventDefault : true,
13373     stopDefault : false,
13374     timer : 0,
13375
13376     // private
13377     handleMouseDown : function(){
13378         clearTimeout(this.timer);
13379         this.el.blur();
13380         if(this.pressClass){
13381             this.el.addClass(this.pressClass);
13382         }
13383         this.mousedownTime = new Date();
13384
13385         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13386         this.el.on("mouseout", this.handleMouseOut, this);
13387
13388         this.fireEvent("mousedown", this);
13389         this.fireEvent("click", this);
13390         
13391         this.timer = this.click.defer(this.delay || this.interval, this);
13392     },
13393
13394     // private
13395     click : function(){
13396         this.fireEvent("click", this);
13397         this.timer = this.click.defer(this.getInterval(), this);
13398     },
13399
13400     // private
13401     getInterval: function(){
13402         if(!this.accelerate){
13403             return this.interval;
13404         }
13405         var pressTime = this.mousedownTime.getElapsed();
13406         if(pressTime < 500){
13407             return 400;
13408         }else if(pressTime < 1700){
13409             return 320;
13410         }else if(pressTime < 2600){
13411             return 250;
13412         }else if(pressTime < 3500){
13413             return 180;
13414         }else if(pressTime < 4400){
13415             return 140;
13416         }else if(pressTime < 5300){
13417             return 80;
13418         }else if(pressTime < 6200){
13419             return 50;
13420         }else{
13421             return 10;
13422         }
13423     },
13424
13425     // private
13426     handleMouseOut : function(){
13427         clearTimeout(this.timer);
13428         if(this.pressClass){
13429             this.el.removeClass(this.pressClass);
13430         }
13431         this.el.on("mouseover", this.handleMouseReturn, this);
13432     },
13433
13434     // private
13435     handleMouseReturn : function(){
13436         this.el.un("mouseover", this.handleMouseReturn);
13437         if(this.pressClass){
13438             this.el.addClass(this.pressClass);
13439         }
13440         this.click();
13441     },
13442
13443     // private
13444     handleMouseUp : function(){
13445         clearTimeout(this.timer);
13446         this.el.un("mouseover", this.handleMouseReturn);
13447         this.el.un("mouseout", this.handleMouseOut);
13448         Roo.get(document).un("mouseup", this.handleMouseUp);
13449         this.el.removeClass(this.pressClass);
13450         this.fireEvent("mouseup", this);
13451     }
13452 });/*
13453  * Based on:
13454  * Ext JS Library 1.1.1
13455  * Copyright(c) 2006-2007, Ext JS, LLC.
13456  *
13457  * Originally Released Under LGPL - original licence link has changed is not relivant.
13458  *
13459  * Fork - LGPL
13460  * <script type="text/javascript">
13461  */
13462
13463  
13464 /**
13465  * @class Roo.KeyNav
13466  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13467  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13468  * way to implement custom navigation schemes for any UI component.</p>
13469  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13470  * pageUp, pageDown, del, home, end.  Usage:</p>
13471  <pre><code>
13472 var nav = new Roo.KeyNav("my-element", {
13473     "left" : function(e){
13474         this.moveLeft(e.ctrlKey);
13475     },
13476     "right" : function(e){
13477         this.moveRight(e.ctrlKey);
13478     },
13479     "enter" : function(e){
13480         this.save();
13481     },
13482     scope : this
13483 });
13484 </code></pre>
13485  * @constructor
13486  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13487  * @param {Object} config The config
13488  */
13489 Roo.KeyNav = function(el, config){
13490     this.el = Roo.get(el);
13491     Roo.apply(this, config);
13492     if(!this.disabled){
13493         this.disabled = true;
13494         this.enable();
13495     }
13496 };
13497
13498 Roo.KeyNav.prototype = {
13499     /**
13500      * @cfg {Boolean} disabled
13501      * True to disable this KeyNav instance (defaults to false)
13502      */
13503     disabled : false,
13504     /**
13505      * @cfg {String} defaultEventAction
13506      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13507      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13508      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13509      */
13510     defaultEventAction: "stopEvent",
13511     /**
13512      * @cfg {Boolean} forceKeyDown
13513      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13514      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13515      * handle keydown instead of keypress.
13516      */
13517     forceKeyDown : false,
13518
13519     // private
13520     prepareEvent : function(e){
13521         var k = e.getKey();
13522         var h = this.keyToHandler[k];
13523         //if(h && this[h]){
13524         //    e.stopPropagation();
13525         //}
13526         if(Roo.isSafari && h && k >= 37 && k <= 40){
13527             e.stopEvent();
13528         }
13529     },
13530
13531     // private
13532     relay : function(e){
13533         var k = e.getKey();
13534         var h = this.keyToHandler[k];
13535         if(h && this[h]){
13536             if(this.doRelay(e, this[h], h) !== true){
13537                 e[this.defaultEventAction]();
13538             }
13539         }
13540     },
13541
13542     // private
13543     doRelay : function(e, h, hname){
13544         return h.call(this.scope || this, e);
13545     },
13546
13547     // possible handlers
13548     enter : false,
13549     left : false,
13550     right : false,
13551     up : false,
13552     down : false,
13553     tab : false,
13554     esc : false,
13555     pageUp : false,
13556     pageDown : false,
13557     del : false,
13558     home : false,
13559     end : false,
13560
13561     // quick lookup hash
13562     keyToHandler : {
13563         37 : "left",
13564         39 : "right",
13565         38 : "up",
13566         40 : "down",
13567         33 : "pageUp",
13568         34 : "pageDown",
13569         46 : "del",
13570         36 : "home",
13571         35 : "end",
13572         13 : "enter",
13573         27 : "esc",
13574         9  : "tab"
13575     },
13576
13577         /**
13578          * Enable this KeyNav
13579          */
13580         enable: function(){
13581                 if(this.disabled){
13582             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13583             // the EventObject will normalize Safari automatically
13584             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13585                 this.el.on("keydown", this.relay,  this);
13586             }else{
13587                 this.el.on("keydown", this.prepareEvent,  this);
13588                 this.el.on("keypress", this.relay,  this);
13589             }
13590                     this.disabled = false;
13591                 }
13592         },
13593
13594         /**
13595          * Disable this KeyNav
13596          */
13597         disable: function(){
13598                 if(!this.disabled){
13599                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13600                 this.el.un("keydown", this.relay);
13601             }else{
13602                 this.el.un("keydown", this.prepareEvent);
13603                 this.el.un("keypress", this.relay);
13604             }
13605                     this.disabled = true;
13606                 }
13607         }
13608 };/*
13609  * Based on:
13610  * Ext JS Library 1.1.1
13611  * Copyright(c) 2006-2007, Ext JS, LLC.
13612  *
13613  * Originally Released Under LGPL - original licence link has changed is not relivant.
13614  *
13615  * Fork - LGPL
13616  * <script type="text/javascript">
13617  */
13618
13619  
13620 /**
13621  * @class Roo.KeyMap
13622  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13623  * The constructor accepts the same config object as defined by {@link #addBinding}.
13624  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13625  * combination it will call the function with this signature (if the match is a multi-key
13626  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13627  * A KeyMap can also handle a string representation of keys.<br />
13628  * Usage:
13629  <pre><code>
13630 // map one key by key code
13631 var map = new Roo.KeyMap("my-element", {
13632     key: 13, // or Roo.EventObject.ENTER
13633     fn: myHandler,
13634     scope: myObject
13635 });
13636
13637 // map multiple keys to one action by string
13638 var map = new Roo.KeyMap("my-element", {
13639     key: "a\r\n\t",
13640     fn: myHandler,
13641     scope: myObject
13642 });
13643
13644 // map multiple keys to multiple actions by strings and array of codes
13645 var map = new Roo.KeyMap("my-element", [
13646     {
13647         key: [10,13],
13648         fn: function(){ alert("Return was pressed"); }
13649     }, {
13650         key: "abc",
13651         fn: function(){ alert('a, b or c was pressed'); }
13652     }, {
13653         key: "\t",
13654         ctrl:true,
13655         shift:true,
13656         fn: function(){ alert('Control + shift + tab was pressed.'); }
13657     }
13658 ]);
13659 </code></pre>
13660  * <b>Note: A KeyMap starts enabled</b>
13661  * @constructor
13662  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13663  * @param {Object} config The config (see {@link #addBinding})
13664  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13665  */
13666 Roo.KeyMap = function(el, config, eventName){
13667     this.el  = Roo.get(el);
13668     this.eventName = eventName || "keydown";
13669     this.bindings = [];
13670     if(config){
13671         this.addBinding(config);
13672     }
13673     this.enable();
13674 };
13675
13676 Roo.KeyMap.prototype = {
13677     /**
13678      * True to stop the event from bubbling and prevent the default browser action if the
13679      * key was handled by the KeyMap (defaults to false)
13680      * @type Boolean
13681      */
13682     stopEvent : false,
13683
13684     /**
13685      * Add a new binding to this KeyMap. The following config object properties are supported:
13686      * <pre>
13687 Property    Type             Description
13688 ----------  ---------------  ----------------------------------------------------------------------
13689 key         String/Array     A single keycode or an array of keycodes to handle
13690 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13691 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13692 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13693 fn          Function         The function to call when KeyMap finds the expected key combination
13694 scope       Object           The scope of the callback function
13695 </pre>
13696      *
13697      * Usage:
13698      * <pre><code>
13699 // Create a KeyMap
13700 var map = new Roo.KeyMap(document, {
13701     key: Roo.EventObject.ENTER,
13702     fn: handleKey,
13703     scope: this
13704 });
13705
13706 //Add a new binding to the existing KeyMap later
13707 map.addBinding({
13708     key: 'abc',
13709     shift: true,
13710     fn: handleKey,
13711     scope: this
13712 });
13713 </code></pre>
13714      * @param {Object/Array} config A single KeyMap config or an array of configs
13715      */
13716         addBinding : function(config){
13717         if(config instanceof Array){
13718             for(var i = 0, len = config.length; i < len; i++){
13719                 this.addBinding(config[i]);
13720             }
13721             return;
13722         }
13723         var keyCode = config.key,
13724             shift = config.shift, 
13725             ctrl = config.ctrl, 
13726             alt = config.alt,
13727             fn = config.fn,
13728             scope = config.scope;
13729         if(typeof keyCode == "string"){
13730             var ks = [];
13731             var keyString = keyCode.toUpperCase();
13732             for(var j = 0, len = keyString.length; j < len; j++){
13733                 ks.push(keyString.charCodeAt(j));
13734             }
13735             keyCode = ks;
13736         }
13737         var keyArray = keyCode instanceof Array;
13738         var handler = function(e){
13739             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
13740                 var k = e.getKey();
13741                 if(keyArray){
13742                     for(var i = 0, len = keyCode.length; i < len; i++){
13743                         if(keyCode[i] == k){
13744                           if(this.stopEvent){
13745                               e.stopEvent();
13746                           }
13747                           fn.call(scope || window, k, e);
13748                           return;
13749                         }
13750                     }
13751                 }else{
13752                     if(k == keyCode){
13753                         if(this.stopEvent){
13754                            e.stopEvent();
13755                         }
13756                         fn.call(scope || window, k, e);
13757                     }
13758                 }
13759             }
13760         };
13761         this.bindings.push(handler);  
13762         },
13763
13764     /**
13765      * Shorthand for adding a single key listener
13766      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13767      * following options:
13768      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13769      * @param {Function} fn The function to call
13770      * @param {Object} scope (optional) The scope of the function
13771      */
13772     on : function(key, fn, scope){
13773         var keyCode, shift, ctrl, alt;
13774         if(typeof key == "object" && !(key instanceof Array)){
13775             keyCode = key.key;
13776             shift = key.shift;
13777             ctrl = key.ctrl;
13778             alt = key.alt;
13779         }else{
13780             keyCode = key;
13781         }
13782         this.addBinding({
13783             key: keyCode,
13784             shift: shift,
13785             ctrl: ctrl,
13786             alt: alt,
13787             fn: fn,
13788             scope: scope
13789         })
13790     },
13791
13792     // private
13793     handleKeyDown : function(e){
13794             if(this.enabled){ //just in case
13795             var b = this.bindings;
13796             for(var i = 0, len = b.length; i < len; i++){
13797                 b[i].call(this, e);
13798             }
13799             }
13800         },
13801         
13802         /**
13803          * Returns true if this KeyMap is enabled
13804          * @return {Boolean} 
13805          */
13806         isEnabled : function(){
13807             return this.enabled;  
13808         },
13809         
13810         /**
13811          * Enables this KeyMap
13812          */
13813         enable: function(){
13814                 if(!this.enabled){
13815                     this.el.on(this.eventName, this.handleKeyDown, this);
13816                     this.enabled = true;
13817                 }
13818         },
13819
13820         /**
13821          * Disable this KeyMap
13822          */
13823         disable: function(){
13824                 if(this.enabled){
13825                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
13826                     this.enabled = false;
13827                 }
13828         }
13829 };/*
13830  * Based on:
13831  * Ext JS Library 1.1.1
13832  * Copyright(c) 2006-2007, Ext JS, LLC.
13833  *
13834  * Originally Released Under LGPL - original licence link has changed is not relivant.
13835  *
13836  * Fork - LGPL
13837  * <script type="text/javascript">
13838  */
13839
13840  
13841 /**
13842  * @class Roo.util.TextMetrics
13843  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13844  * wide, in pixels, a given block of text will be.
13845  * @singleton
13846  */
13847 Roo.util.TextMetrics = function(){
13848     var shared;
13849     return {
13850         /**
13851          * Measures the size of the specified text
13852          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13853          * that can affect the size of the rendered text
13854          * @param {String} text The text to measure
13855          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13856          * in order to accurately measure the text height
13857          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13858          */
13859         measure : function(el, text, fixedWidth){
13860             if(!shared){
13861                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13862             }
13863             shared.bind(el);
13864             shared.setFixedWidth(fixedWidth || 'auto');
13865             return shared.getSize(text);
13866         },
13867
13868         /**
13869          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
13870          * the overhead of multiple calls to initialize the style properties on each measurement.
13871          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13872          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13873          * in order to accurately measure the text height
13874          * @return {Roo.util.TextMetrics.Instance} instance The new instance
13875          */
13876         createInstance : function(el, fixedWidth){
13877             return Roo.util.TextMetrics.Instance(el, fixedWidth);
13878         }
13879     };
13880 }();
13881
13882  
13883
13884 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13885     var ml = new Roo.Element(document.createElement('div'));
13886     document.body.appendChild(ml.dom);
13887     ml.position('absolute');
13888     ml.setLeftTop(-1000, -1000);
13889     ml.hide();
13890
13891     if(fixedWidth){
13892         ml.setWidth(fixedWidth);
13893     }
13894      
13895     var instance = {
13896         /**
13897          * Returns the size of the specified text based on the internal element's style and width properties
13898          * @memberOf Roo.util.TextMetrics.Instance#
13899          * @param {String} text The text to measure
13900          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13901          */
13902         getSize : function(text){
13903             ml.update(text);
13904             var s = ml.getSize();
13905             ml.update('');
13906             return s;
13907         },
13908
13909         /**
13910          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13911          * that can affect the size of the rendered text
13912          * @memberOf Roo.util.TextMetrics.Instance#
13913          * @param {String/HTMLElement} el The element, dom node or id
13914          */
13915         bind : function(el){
13916             ml.setStyle(
13917                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13918             );
13919         },
13920
13921         /**
13922          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
13923          * to set a fixed width in order to accurately measure the text height.
13924          * @memberOf Roo.util.TextMetrics.Instance#
13925          * @param {Number} width The width to set on the element
13926          */
13927         setFixedWidth : function(width){
13928             ml.setWidth(width);
13929         },
13930
13931         /**
13932          * Returns the measured width of the specified text
13933          * @memberOf Roo.util.TextMetrics.Instance#
13934          * @param {String} text The text to measure
13935          * @return {Number} width The width in pixels
13936          */
13937         getWidth : function(text){
13938             ml.dom.style.width = 'auto';
13939             return this.getSize(text).width;
13940         },
13941
13942         /**
13943          * Returns the measured height of the specified text.  For multiline text, be sure to call
13944          * {@link #setFixedWidth} if necessary.
13945          * @memberOf Roo.util.TextMetrics.Instance#
13946          * @param {String} text The text to measure
13947          * @return {Number} height The height in pixels
13948          */
13949         getHeight : function(text){
13950             return this.getSize(text).height;
13951         }
13952     };
13953
13954     instance.bind(bindTo);
13955
13956     return instance;
13957 };
13958
13959 // backwards compat
13960 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13961  * Based on:
13962  * Ext JS Library 1.1.1
13963  * Copyright(c) 2006-2007, Ext JS, LLC.
13964  *
13965  * Originally Released Under LGPL - original licence link has changed is not relivant.
13966  *
13967  * Fork - LGPL
13968  * <script type="text/javascript">
13969  */
13970
13971 /**
13972  * @class Roo.state.Provider
13973  * Abstract base class for state provider implementations. This class provides methods
13974  * for encoding and decoding <b>typed</b> variables including dates and defines the 
13975  * Provider interface.
13976  */
13977 Roo.state.Provider = function(){
13978     /**
13979      * @event statechange
13980      * Fires when a state change occurs.
13981      * @param {Provider} this This state provider
13982      * @param {String} key The state key which was changed
13983      * @param {String} value The encoded value for the state
13984      */
13985     this.addEvents({
13986         "statechange": true
13987     });
13988     this.state = {};
13989     Roo.state.Provider.superclass.constructor.call(this);
13990 };
13991 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
13992     /**
13993      * Returns the current value for a key
13994      * @param {String} name The key name
13995      * @param {Mixed} defaultValue A default value to return if the key's value is not found
13996      * @return {Mixed} The state data
13997      */
13998     get : function(name, defaultValue){
13999         return typeof this.state[name] == "undefined" ?
14000             defaultValue : this.state[name];
14001     },
14002     
14003     /**
14004      * Clears a value from the state
14005      * @param {String} name The key name
14006      */
14007     clear : function(name){
14008         delete this.state[name];
14009         this.fireEvent("statechange", this, name, null);
14010     },
14011     
14012     /**
14013      * Sets the value for a key
14014      * @param {String} name The key name
14015      * @param {Mixed} value The value to set
14016      */
14017     set : function(name, value){
14018         this.state[name] = value;
14019         this.fireEvent("statechange", this, name, value);
14020     },
14021     
14022     /**
14023      * Decodes a string previously encoded with {@link #encodeValue}.
14024      * @param {String} value The value to decode
14025      * @return {Mixed} The decoded value
14026      */
14027     decodeValue : function(cookie){
14028         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14029         var matches = re.exec(unescape(cookie));
14030         if(!matches || !matches[1]) return; // non state cookie
14031         var type = matches[1];
14032         var v = matches[2];
14033         switch(type){
14034             case "n":
14035                 return parseFloat(v);
14036             case "d":
14037                 return new Date(Date.parse(v));
14038             case "b":
14039                 return (v == "1");
14040             case "a":
14041                 var all = [];
14042                 var values = v.split("^");
14043                 for(var i = 0, len = values.length; i < len; i++){
14044                     all.push(this.decodeValue(values[i]));
14045                 }
14046                 return all;
14047            case "o":
14048                 var all = {};
14049                 var values = v.split("^");
14050                 for(var i = 0, len = values.length; i < len; i++){
14051                     var kv = values[i].split("=");
14052                     all[kv[0]] = this.decodeValue(kv[1]);
14053                 }
14054                 return all;
14055            default:
14056                 return v;
14057         }
14058     },
14059     
14060     /**
14061      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14062      * @param {Mixed} value The value to encode
14063      * @return {String} The encoded value
14064      */
14065     encodeValue : function(v){
14066         var enc;
14067         if(typeof v == "number"){
14068             enc = "n:" + v;
14069         }else if(typeof v == "boolean"){
14070             enc = "b:" + (v ? "1" : "0");
14071         }else if(v instanceof Date){
14072             enc = "d:" + v.toGMTString();
14073         }else if(v instanceof Array){
14074             var flat = "";
14075             for(var i = 0, len = v.length; i < len; i++){
14076                 flat += this.encodeValue(v[i]);
14077                 if(i != len-1) flat += "^";
14078             }
14079             enc = "a:" + flat;
14080         }else if(typeof v == "object"){
14081             var flat = "";
14082             for(var key in v){
14083                 if(typeof v[key] != "function"){
14084                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14085                 }
14086             }
14087             enc = "o:" + flat.substring(0, flat.length-1);
14088         }else{
14089             enc = "s:" + v;
14090         }
14091         return escape(enc);        
14092     }
14093 });
14094
14095 /*
14096  * Based on:
14097  * Ext JS Library 1.1.1
14098  * Copyright(c) 2006-2007, Ext JS, LLC.
14099  *
14100  * Originally Released Under LGPL - original licence link has changed is not relivant.
14101  *
14102  * Fork - LGPL
14103  * <script type="text/javascript">
14104  */
14105 /**
14106  * @class Roo.state.Manager
14107  * This is the global state manager. By default all components that are "state aware" check this class
14108  * for state information if you don't pass them a custom state provider. In order for this class
14109  * to be useful, it must be initialized with a provider when your application initializes.
14110  <pre><code>
14111 // in your initialization function
14112 init : function(){
14113    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14114    ...
14115    // supposed you have a {@link Roo.BorderLayout}
14116    var layout = new Roo.BorderLayout(...);
14117    layout.restoreState();
14118    // or a {Roo.BasicDialog}
14119    var dialog = new Roo.BasicDialog(...);
14120    dialog.restoreState();
14121  </code></pre>
14122  * @singleton
14123  */
14124 Roo.state.Manager = function(){
14125     var provider = new Roo.state.Provider();
14126     
14127     return {
14128         /**
14129          * Configures the default state provider for your application
14130          * @param {Provider} stateProvider The state provider to set
14131          */
14132         setProvider : function(stateProvider){
14133             provider = stateProvider;
14134         },
14135         
14136         /**
14137          * Returns the current value for a key
14138          * @param {String} name The key name
14139          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14140          * @return {Mixed} The state data
14141          */
14142         get : function(key, defaultValue){
14143             return provider.get(key, defaultValue);
14144         },
14145         
14146         /**
14147          * Sets the value for a key
14148          * @param {String} name The key name
14149          * @param {Mixed} value The state data
14150          */
14151          set : function(key, value){
14152             provider.set(key, value);
14153         },
14154         
14155         /**
14156          * Clears a value from the state
14157          * @param {String} name The key name
14158          */
14159         clear : function(key){
14160             provider.clear(key);
14161         },
14162         
14163         /**
14164          * Gets the currently configured state provider
14165          * @return {Provider} The state provider
14166          */
14167         getProvider : function(){
14168             return provider;
14169         }
14170     };
14171 }();
14172 /*
14173  * Based on:
14174  * Ext JS Library 1.1.1
14175  * Copyright(c) 2006-2007, Ext JS, LLC.
14176  *
14177  * Originally Released Under LGPL - original licence link has changed is not relivant.
14178  *
14179  * Fork - LGPL
14180  * <script type="text/javascript">
14181  */
14182 /**
14183  * @class Roo.state.CookieProvider
14184  * @extends Roo.state.Provider
14185  * The default Provider implementation which saves state via cookies.
14186  * <br />Usage:
14187  <pre><code>
14188    var cp = new Roo.state.CookieProvider({
14189        path: "/cgi-bin/",
14190        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14191        domain: "roojs.com"
14192    })
14193    Roo.state.Manager.setProvider(cp);
14194  </code></pre>
14195  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14196  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14197  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14198  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14199  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14200  * domain the page is running on including the 'www' like 'www.roojs.com')
14201  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14202  * @constructor
14203  * Create a new CookieProvider
14204  * @param {Object} config The configuration object
14205  */
14206 Roo.state.CookieProvider = function(config){
14207     Roo.state.CookieProvider.superclass.constructor.call(this);
14208     this.path = "/";
14209     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14210     this.domain = null;
14211     this.secure = false;
14212     Roo.apply(this, config);
14213     this.state = this.readCookies();
14214 };
14215
14216 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14217     // private
14218     set : function(name, value){
14219         if(typeof value == "undefined" || value === null){
14220             this.clear(name);
14221             return;
14222         }
14223         this.setCookie(name, value);
14224         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14225     },
14226
14227     // private
14228     clear : function(name){
14229         this.clearCookie(name);
14230         Roo.state.CookieProvider.superclass.clear.call(this, name);
14231     },
14232
14233     // private
14234     readCookies : function(){
14235         var cookies = {};
14236         var c = document.cookie + ";";
14237         var re = /\s?(.*?)=(.*?);/g;
14238         var matches;
14239         while((matches = re.exec(c)) != null){
14240             var name = matches[1];
14241             var value = matches[2];
14242             if(name && name.substring(0,3) == "ys-"){
14243                 cookies[name.substr(3)] = this.decodeValue(value);
14244             }
14245         }
14246         return cookies;
14247     },
14248
14249     // private
14250     setCookie : function(name, value){
14251         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14252            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14253            ((this.path == null) ? "" : ("; path=" + this.path)) +
14254            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14255            ((this.secure == true) ? "; secure" : "");
14256     },
14257
14258     // private
14259     clearCookie : function(name){
14260         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14261            ((this.path == null) ? "" : ("; path=" + this.path)) +
14262            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14263            ((this.secure == true) ? "; secure" : "");
14264     }
14265 });