roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isGecko = !isSafari && ua.indexOf("gecko") > -1,
61         isBorderBox = isIE && !isStrict,
62         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64         isLinux = (ua.indexOf("linux") != -1),
65         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66         isIOS = /iphone|ipad/.test(ua),
67         isTouch =  (function() {
68             try {  
69                 document.createEvent("TouchEvent");  
70                 return true;  
71             } catch (e) {  
72                 return false;  
73             } 
74             
75         })();
76     // remove css image flicker
77         if(isIE && !isIE7){
78         try{
79             document.execCommand("BackgroundImageCache", false, true);
80         }catch(e){}
81     }
82     
83     Roo.apply(Roo, {
84         /**
85          * True if the browser is in strict mode
86          * @type Boolean
87          */
88         isStrict : isStrict,
89         /**
90          * True if the page is running over SSL
91          * @type Boolean
92          */
93         isSecure : isSecure,
94         /**
95          * True when the document is fully initialized and ready for action
96          * @type Boolean
97          */
98         isReady : false,
99         /**
100          * Turn on debugging output (currently only the factory uses this)
101          * @type Boolean
102          */
103         
104         debug: false,
105
106         /**
107          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
108          * @type Boolean
109          */
110         enableGarbageCollector : true,
111
112         /**
113          * True to automatically purge event listeners after uncaching an element (defaults to false).
114          * Note: this only happens if enableGarbageCollector is true.
115          * @type Boolean
116          */
117         enableListenerCollection:false,
118
119         /**
120          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
121          * the IE insecure content warning (defaults to javascript:false).
122          * @type String
123          */
124         SSL_SECURE_URL : "javascript:false",
125
126         /**
127          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
128          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
129          * @type String
130          */
131         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
132
133         emptyFn : function(){},
134         
135         /**
136          * Copies all the properties of config to obj if they don't already exist.
137          * @param {Object} obj The receiver of the properties
138          * @param {Object} config The source of the properties
139          * @return {Object} returns obj
140          */
141         applyIf : function(o, c){
142             if(o && c){
143                 for(var p in c){
144                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
145                 }
146             }
147             return o;
148         },
149
150         /**
151          * Applies event listeners to elements by selectors when the document is ready.
152          * The event name is specified with an @ suffix.
153 <pre><code>
154 Roo.addBehaviors({
155    // add a listener for click on all anchors in element with id foo
156    '#foo a@click' : function(e, t){
157        // do something
158    },
159
160    // add the same listener to multiple selectors (separated by comma BEFORE the @)
161    '#foo a, #bar span.some-class@mouseover' : function(){
162        // do something
163    }
164 });
165 </code></pre>
166          * @param {Object} obj The list of behaviors to apply
167          */
168         addBehaviors : function(o){
169             if(!Roo.isReady){
170                 Roo.onReady(function(){
171                     Roo.addBehaviors(o);
172                 });
173                 return;
174             }
175             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
176             for(var b in o){
177                 var parts = b.split('@');
178                 if(parts[1]){ // for Object prototype breakers
179                     var s = parts[0];
180                     if(!cache[s]){
181                         cache[s] = Roo.select(s);
182                     }
183                     cache[s].on(parts[1], o[b]);
184                 }
185             }
186             cache = null;
187         },
188
189         /**
190          * Generates unique ids. If the element already has an id, it is unchanged
191          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
192          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
193          * @return {String} The generated Id.
194          */
195         id : function(el, prefix){
196             prefix = prefix || "roo-gen";
197             el = Roo.getDom(el);
198             var id = prefix + (++idSeed);
199             return el ? (el.id ? el.id : (el.id = id)) : id;
200         },
201          
202        
203         /**
204          * Extends one class with another class and optionally overrides members with the passed literal. This class
205          * also adds the function "override()" to the class that can be used to override
206          * members on an instance.
207          * @param {Object} subclass The class inheriting the functionality
208          * @param {Object} superclass The class being extended
209          * @param {Object} overrides (optional) A literal with members
210          * @method extend
211          */
212         extend : function(){
213             // inline overrides
214             var io = function(o){
215                 for(var m in o){
216                     this[m] = o[m];
217                 }
218             };
219             return function(sb, sp, overrides){
220                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
221                     overrides = sp;
222                     sp = sb;
223                     sb = function(){sp.apply(this, arguments);};
224                 }
225                 var F = function(){}, sbp, spp = sp.prototype;
226                 F.prototype = spp;
227                 sbp = sb.prototype = new F();
228                 sbp.constructor=sb;
229                 sb.superclass=spp;
230                 
231                 if(spp.constructor == Object.prototype.constructor){
232                     spp.constructor=sp;
233                    
234                 }
235                 
236                 sb.override = function(o){
237                     Roo.override(sb, o);
238                 };
239                 sbp.override = io;
240                 Roo.override(sb, overrides);
241                 return sb;
242             };
243         }(),
244
245         /**
246          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
247          * Usage:<pre><code>
248 Roo.override(MyClass, {
249     newMethod1: function(){
250         // etc.
251     },
252     newMethod2: function(foo){
253         // etc.
254     }
255 });
256  </code></pre>
257          * @param {Object} origclass The class to override
258          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
259          * containing one or more methods.
260          * @method override
261          */
262         override : function(origclass, overrides){
263             if(overrides){
264                 var p = origclass.prototype;
265                 for(var method in overrides){
266                     p[method] = overrides[method];
267                 }
268             }
269         },
270         /**
271          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
272          * <pre><code>
273 Roo.namespace('Company', 'Company.data');
274 Company.Widget = function() { ... }
275 Company.data.CustomStore = function(config) { ... }
276 </code></pre>
277          * @param {String} namespace1
278          * @param {String} namespace2
279          * @param {String} etc
280          * @method namespace
281          */
282         namespace : function(){
283             var a=arguments, o=null, i, j, d, rt;
284             for (i=0; i<a.length; ++i) {
285                 d=a[i].split(".");
286                 rt = d[0];
287                 /** eval:var:o */
288                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
289                 for (j=1; j<d.length; ++j) {
290                     o[d[j]]=o[d[j]] || {};
291                     o=o[d[j]];
292                 }
293             }
294         },
295         /**
296          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
297          * <pre><code>
298 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
299 Roo.factory(conf, Roo.data);
300 </code></pre>
301          * @param {String} classname
302          * @param {String} namespace (optional)
303          * @method factory
304          */
305          
306         factory : function(c, ns)
307         {
308             // no xtype, no ns or c.xns - or forced off by c.xns
309             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
310                 return c;
311             }
312             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
313             if (c.constructor == ns[c.xtype]) {// already created...
314                 return c;
315             }
316             if (ns[c.xtype]) {
317                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
318                 var ret = new ns[c.xtype](c);
319                 ret.xns = false;
320                 return ret;
321             }
322             c.xns = false; // prevent recursion..
323             return c;
324         },
325          /**
326          * Logs to console if it can.
327          *
328          * @param {String|Object} string
329          * @method log
330          */
331         log : function(s)
332         {
333             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
334                 return; // alerT?
335             }
336             console.log(s);
337             
338         },
339         /**
340          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
341          * @param {Object} o
342          * @return {String}
343          */
344         urlEncode : function(o){
345             if(!o){
346                 return "";
347             }
348             var buf = [];
349             for(var key in o){
350                 var ov = o[key], k = Roo.encodeURIComponent(key);
351                 var type = typeof ov;
352                 if(type == 'undefined'){
353                     buf.push(k, "=&");
354                 }else if(type != "function" && type != "object"){
355                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
356                 }else if(ov instanceof Array){
357                     if (ov.length) {
358                             for(var i = 0, len = ov.length; i < len; i++) {
359                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
360                             }
361                         } else {
362                             buf.push(k, "=&");
363                         }
364                 }
365             }
366             buf.pop();
367             return buf.join("");
368         },
369          /**
370          * Safe version of encodeURIComponent
371          * @param {String} data 
372          * @return {String} 
373          */
374         
375         encodeURIComponent : function (data)
376         {
377             try {
378                 return encodeURIComponent(data);
379             } catch(e) {} // should be an uri encode error.
380             
381             if (data == '' || data == null){
382                return '';
383             }
384             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
385             function nibble_to_hex(nibble){
386                 var chars = '0123456789ABCDEF';
387                 return chars.charAt(nibble);
388             }
389             data = data.toString();
390             var buffer = '';
391             for(var i=0; i<data.length; i++){
392                 var c = data.charCodeAt(i);
393                 var bs = new Array();
394                 if (c > 0x10000){
395                         // 4 bytes
396                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
397                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
398                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
399                     bs[3] = 0x80 | (c & 0x3F);
400                 }else if (c > 0x800){
401                          // 3 bytes
402                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
403                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
404                     bs[2] = 0x80 | (c & 0x3F);
405                 }else if (c > 0x80){
406                        // 2 bytes
407                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
408                     bs[1] = 0x80 | (c & 0x3F);
409                 }else{
410                         // 1 byte
411                     bs[0] = c;
412                 }
413                 for(var j=0; j<bs.length; j++){
414                     var b = bs[j];
415                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
416                             + nibble_to_hex(b &0x0F);
417                     buffer += '%'+hex;
418                }
419             }
420             return buffer;    
421              
422         },
423
424         /**
425          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
426          * @param {String} string
427          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
428          * @return {Object} A literal with members
429          */
430         urlDecode : function(string, overwrite){
431             if(!string || !string.length){
432                 return {};
433             }
434             var obj = {};
435             var pairs = string.split('&');
436             var pair, name, value;
437             for(var i = 0, len = pairs.length; i < len; i++){
438                 pair = pairs[i].split('=');
439                 name = decodeURIComponent(pair[0]);
440                 value = decodeURIComponent(pair[1]);
441                 if(overwrite !== true){
442                     if(typeof obj[name] == "undefined"){
443                         obj[name] = value;
444                     }else if(typeof obj[name] == "string"){
445                         obj[name] = [obj[name]];
446                         obj[name].push(value);
447                     }else{
448                         obj[name].push(value);
449                     }
450                 }else{
451                     obj[name] = value;
452                 }
453             }
454             return obj;
455         },
456
457         /**
458          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
459          * passed array is not really an array, your function is called once with it.
460          * The supplied function is called with (Object item, Number index, Array allItems).
461          * @param {Array/NodeList/Mixed} array
462          * @param {Function} fn
463          * @param {Object} scope
464          */
465         each : function(array, fn, scope){
466             if(typeof array.length == "undefined" || typeof array == "string"){
467                 array = [array];
468             }
469             for(var i = 0, len = array.length; i < len; i++){
470                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
471             }
472         },
473
474         // deprecated
475         combine : function(){
476             var as = arguments, l = as.length, r = [];
477             for(var i = 0; i < l; i++){
478                 var a = as[i];
479                 if(a instanceof Array){
480                     r = r.concat(a);
481                 }else if(a.length !== undefined && !a.substr){
482                     r = r.concat(Array.prototype.slice.call(a, 0));
483                 }else{
484                     r.push(a);
485                 }
486             }
487             return r;
488         },
489
490         /**
491          * Escapes the passed string for use in a regular expression
492          * @param {String} str
493          * @return {String}
494          */
495         escapeRe : function(s) {
496             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
497         },
498
499         // internal
500         callback : function(cb, scope, args, delay){
501             if(typeof cb == "function"){
502                 if(delay){
503                     cb.defer(delay, scope, args || []);
504                 }else{
505                     cb.apply(scope, args || []);
506                 }
507             }
508         },
509
510         /**
511          * Return the dom node for the passed string (id), dom node, or Roo.Element
512          * @param {String/HTMLElement/Roo.Element} el
513          * @return HTMLElement
514          */
515         getDom : function(el){
516             if(!el){
517                 return null;
518             }
519             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
520         },
521
522         /**
523         * Shorthand for {@link Roo.ComponentMgr#get}
524         * @param {String} id
525         * @return Roo.Component
526         */
527         getCmp : function(id){
528             return Roo.ComponentMgr.get(id);
529         },
530          
531         num : function(v, defaultValue){
532             if(typeof v != 'number'){
533                 return defaultValue;
534             }
535             return v;
536         },
537
538         destroy : function(){
539             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
540                 var as = a[i];
541                 if(as){
542                     if(as.dom){
543                         as.removeAllListeners();
544                         as.remove();
545                         continue;
546                     }
547                     if(typeof as.purgeListeners == 'function'){
548                         as.purgeListeners();
549                     }
550                     if(typeof as.destroy == 'function'){
551                         as.destroy();
552                     }
553                 }
554             }
555         },
556
557         // inpired by a similar function in mootools library
558         /**
559          * Returns the type of object that is passed in. If the object passed in is null or undefined it
560          * return false otherwise it returns one of the following values:<ul>
561          * <li><b>string</b>: If the object passed is a string</li>
562          * <li><b>number</b>: If the object passed is a number</li>
563          * <li><b>boolean</b>: If the object passed is a boolean value</li>
564          * <li><b>function</b>: If the object passed is a function reference</li>
565          * <li><b>object</b>: If the object passed is an object</li>
566          * <li><b>array</b>: If the object passed is an array</li>
567          * <li><b>regexp</b>: If the object passed is a regular expression</li>
568          * <li><b>element</b>: If the object passed is a DOM Element</li>
569          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
570          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
571          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
572          * @param {Mixed} object
573          * @return {String}
574          */
575         type : function(o){
576             if(o === undefined || o === null){
577                 return false;
578             }
579             if(o.htmlElement){
580                 return 'element';
581             }
582             var t = typeof o;
583             if(t == 'object' && o.nodeName) {
584                 switch(o.nodeType) {
585                     case 1: return 'element';
586                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
587                 }
588             }
589             if(t == 'object' || t == 'function') {
590                 switch(o.constructor) {
591                     case Array: return 'array';
592                     case RegExp: return 'regexp';
593                 }
594                 if(typeof o.length == 'number' && typeof o.item == 'function') {
595                     return 'nodelist';
596                 }
597             }
598             return t;
599         },
600
601         /**
602          * Returns true if the passed value is null, undefined or an empty string (optional).
603          * @param {Mixed} value The value to test
604          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
605          * @return {Boolean}
606          */
607         isEmpty : function(v, allowBlank){
608             return v === null || v === undefined || (!allowBlank ? v === '' : false);
609         },
610         
611         /** @type Boolean */
612         isOpera : isOpera,
613         /** @type Boolean */
614         isSafari : isSafari,
615         /** @type Boolean */
616         isFirefox : isFirefox,
617         /** @type Boolean */
618         isIE : isIE,
619         /** @type Boolean */
620         isIE7 : isIE7,
621         /** @type Boolean */
622         isIE11 : isIE11,
623         /** @type Boolean */
624         isGecko : isGecko,
625         /** @type Boolean */
626         isBorderBox : isBorderBox,
627         /** @type Boolean */
628         isWindows : isWindows,
629         /** @type Boolean */
630         isLinux : isLinux,
631         /** @type Boolean */
632         isMac : isMac,
633         /** @type Boolean */
634         isIOS : isIOS,
635         /** @type Boolean */
636         isTouch : isTouch,
637
638         /**
639          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
640          * you may want to set this to true.
641          * @type Boolean
642          */
643         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
644         
645         
646                 
647         /**
648          * Selects a single element as a Roo Element
649          * This is about as close as you can get to jQuery's $('do crazy stuff')
650          * @param {String} selector The selector/xpath query
651          * @param {Node} root (optional) The start of the query (defaults to document).
652          * @return {Roo.Element}
653          */
654         selectNode : function(selector, root) 
655         {
656             var node = Roo.DomQuery.selectNode(selector,root);
657             return node ? Roo.get(node) : new Roo.Element(false);
658         }
659         
660     });
661
662
663 })();
664
665 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
666                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
667                 "Roo.app", "Roo.ux",
668                 "Roo.bootstrap",
669                 "Roo.bootstrap.dash");
670 /*
671  * Based on:
672  * Ext JS Library 1.1.1
673  * Copyright(c) 2006-2007, Ext JS, LLC.
674  *
675  * Originally Released Under LGPL - original licence link has changed is not relivant.
676  *
677  * Fork - LGPL
678  * <script type="text/javascript">
679  */
680
681 (function() {    
682     // wrappedn so fnCleanup is not in global scope...
683     if(Roo.isIE) {
684         function fnCleanUp() {
685             var p = Function.prototype;
686             delete p.createSequence;
687             delete p.defer;
688             delete p.createDelegate;
689             delete p.createCallback;
690             delete p.createInterceptor;
691
692             window.detachEvent("onunload", fnCleanUp);
693         }
694         window.attachEvent("onunload", fnCleanUp);
695     }
696 })();
697
698
699 /**
700  * @class Function
701  * These functions are available on every Function object (any JavaScript function).
702  */
703 Roo.apply(Function.prototype, {
704      /**
705      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
706      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
707      * Will create a function that is bound to those 2 args.
708      * @return {Function} The new function
709     */
710     createCallback : function(/*args...*/){
711         // make args available, in function below
712         var args = arguments;
713         var method = this;
714         return function() {
715             return method.apply(window, args);
716         };
717     },
718
719     /**
720      * Creates a delegate (callback) that sets the scope to obj.
721      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
722      * Will create a function that is automatically scoped to this.
723      * @param {Object} obj (optional) The object for which the scope is set
724      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
725      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
726      *                                             if a number the args are inserted at the specified position
727      * @return {Function} The new function
728      */
729     createDelegate : function(obj, args, appendArgs){
730         var method = this;
731         return function() {
732             var callArgs = args || arguments;
733             if(appendArgs === true){
734                 callArgs = Array.prototype.slice.call(arguments, 0);
735                 callArgs = callArgs.concat(args);
736             }else if(typeof appendArgs == "number"){
737                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
738                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
739                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
740             }
741             return method.apply(obj || window, callArgs);
742         };
743     },
744
745     /**
746      * Calls this function after the number of millseconds specified.
747      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
748      * @param {Object} obj (optional) The object for which the scope is set
749      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
750      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
751      *                                             if a number the args are inserted at the specified position
752      * @return {Number} The timeout id that can be used with clearTimeout
753      */
754     defer : function(millis, obj, args, appendArgs){
755         var fn = this.createDelegate(obj, args, appendArgs);
756         if(millis){
757             return setTimeout(fn, millis);
758         }
759         fn();
760         return 0;
761     },
762     /**
763      * Create a combined function call sequence of the original function + the passed function.
764      * The resulting function returns the results of the original function.
765      * The passed fcn is called with the parameters of the original function
766      * @param {Function} fcn The function to sequence
767      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
768      * @return {Function} The new function
769      */
770     createSequence : function(fcn, scope){
771         if(typeof fcn != "function"){
772             return this;
773         }
774         var method = this;
775         return function() {
776             var retval = method.apply(this || window, arguments);
777             fcn.apply(scope || this || window, arguments);
778             return retval;
779         };
780     },
781
782     /**
783      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
784      * The resulting function returns the results of the original function.
785      * The passed fcn is called with the parameters of the original function.
786      * @addon
787      * @param {Function} fcn The function to call before the original
788      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
789      * @return {Function} The new function
790      */
791     createInterceptor : function(fcn, scope){
792         if(typeof fcn != "function"){
793             return this;
794         }
795         var method = this;
796         return function() {
797             fcn.target = this;
798             fcn.method = method;
799             if(fcn.apply(scope || this || window, arguments) === false){
800                 return;
801             }
802             return method.apply(this || window, arguments);
803         };
804     }
805 });
806 /*
807  * Based on:
808  * Ext JS Library 1.1.1
809  * Copyright(c) 2006-2007, Ext JS, LLC.
810  *
811  * Originally Released Under LGPL - original licence link has changed is not relivant.
812  *
813  * Fork - LGPL
814  * <script type="text/javascript">
815  */
816
817 Roo.applyIf(String, {
818     
819     /** @scope String */
820     
821     /**
822      * Escapes the passed string for ' and \
823      * @param {String} string The string to escape
824      * @return {String} The escaped string
825      * @static
826      */
827     escape : function(string) {
828         return string.replace(/('|\\)/g, "\\$1");
829     },
830
831     /**
832      * Pads the left side of a string with a specified character.  This is especially useful
833      * for normalizing number and date strings.  Example usage:
834      * <pre><code>
835 var s = String.leftPad('123', 5, '0');
836 // s now contains the string: '00123'
837 </code></pre>
838      * @param {String} string The original string
839      * @param {Number} size The total length of the output string
840      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
841      * @return {String} The padded string
842      * @static
843      */
844     leftPad : function (val, size, ch) {
845         var result = new String(val);
846         if(ch === null || ch === undefined || ch === '') {
847             ch = " ";
848         }
849         while (result.length < size) {
850             result = ch + result;
851         }
852         return result;
853     },
854
855     /**
856      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
857      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
858      * <pre><code>
859 var cls = 'my-class', text = 'Some text';
860 var s = String.format('<div class="{0}">{1}</div>', cls, text);
861 // s now contains the string: '<div class="my-class">Some text</div>'
862 </code></pre>
863      * @param {String} string The tokenized string to be formatted
864      * @param {String} value1 The value to replace token {0}
865      * @param {String} value2 Etc...
866      * @return {String} The formatted string
867      * @static
868      */
869     format : function(format){
870         var args = Array.prototype.slice.call(arguments, 1);
871         return format.replace(/\{(\d+)\}/g, function(m, i){
872             return Roo.util.Format.htmlEncode(args[i]);
873         });
874     }
875 });
876
877 /**
878  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
879  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
880  * they are already different, the first value passed in is returned.  Note that this method returns the new value
881  * but does not change the current string.
882  * <pre><code>
883 // alternate sort directions
884 sort = sort.toggle('ASC', 'DESC');
885
886 // instead of conditional logic:
887 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
888 </code></pre>
889  * @param {String} value The value to compare to the current string
890  * @param {String} other The new value to use if the string already equals the first value passed in
891  * @return {String} The new value
892  */
893  
894 String.prototype.toggle = function(value, other){
895     return this == value ? other : value;
896 };/*
897  * Based on:
898  * Ext JS Library 1.1.1
899  * Copyright(c) 2006-2007, Ext JS, LLC.
900  *
901  * Originally Released Under LGPL - original licence link has changed is not relivant.
902  *
903  * Fork - LGPL
904  * <script type="text/javascript">
905  */
906
907  /**
908  * @class Number
909  */
910 Roo.applyIf(Number.prototype, {
911     /**
912      * Checks whether or not the current number is within a desired range.  If the number is already within the
913      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
914      * exceeded.  Note that this method returns the constrained value but does not change the current number.
915      * @param {Number} min The minimum number in the range
916      * @param {Number} max The maximum number in the range
917      * @return {Number} The constrained value if outside the range, otherwise the current value
918      */
919     constrain : function(min, max){
920         return Math.min(Math.max(this, min), max);
921     }
922 });/*
923  * Based on:
924  * Ext JS Library 1.1.1
925  * Copyright(c) 2006-2007, Ext JS, LLC.
926  *
927  * Originally Released Under LGPL - original licence link has changed is not relivant.
928  *
929  * Fork - LGPL
930  * <script type="text/javascript">
931  */
932  /**
933  * @class Array
934  */
935 Roo.applyIf(Array.prototype, {
936     /**
937      * 
938      * Checks whether or not the specified object exists in the array.
939      * @param {Object} o The object to check for
940      * @return {Number} The index of o in the array (or -1 if it is not found)
941      */
942     indexOf : function(o){
943        for (var i = 0, len = this.length; i < len; i++){
944               if(this[i] == o) { return i; }
945        }
946            return -1;
947     },
948
949     /**
950      * Removes the specified object from the array.  If the object is not found nothing happens.
951      * @param {Object} o The object to remove
952      */
953     remove : function(o){
954        var index = this.indexOf(o);
955        if(index != -1){
956            this.splice(index, 1);
957        }
958     },
959     /**
960      * Map (JS 1.6 compatibility)
961      * @param {Function} function  to call
962      */
963     map : function(fun )
964     {
965         var len = this.length >>> 0;
966         if (typeof fun != "function") {
967             throw new TypeError();
968         }
969         var res = new Array(len);
970         var thisp = arguments[1];
971         for (var i = 0; i < len; i++)
972         {
973             if (i in this) {
974                 res[i] = fun.call(thisp, this[i], i, this);
975             }
976         }
977
978         return res;
979     }
980     
981 });
982
983
984  
985 /*
986  * Based on:
987  * Ext JS Library 1.1.1
988  * Copyright(c) 2006-2007, Ext JS, LLC.
989  *
990  * Originally Released Under LGPL - original licence link has changed is not relivant.
991  *
992  * Fork - LGPL
993  * <script type="text/javascript">
994  */
995
996 /**
997  * @class Date
998  *
999  * The date parsing and format syntax is a subset of
1000  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1001  * supported will provide results equivalent to their PHP versions.
1002  *
1003  * Following is the list of all currently supported formats:
1004  *<pre>
1005 Sample date:
1006 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1007
1008 Format  Output      Description
1009 ------  ----------  --------------------------------------------------------------
1010   d      10         Day of the month, 2 digits with leading zeros
1011   D      Wed        A textual representation of a day, three letters
1012   j      10         Day of the month without leading zeros
1013   l      Wednesday  A full textual representation of the day of the week
1014   S      th         English ordinal day of month suffix, 2 chars (use with j)
1015   w      3          Numeric representation of the day of the week
1016   z      9          The julian date, or day of the year (0-365)
1017   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1018   F      January    A full textual representation of the month
1019   m      01         Numeric representation of a month, with leading zeros
1020   M      Jan        Month name abbreviation, three letters
1021   n      1          Numeric representation of a month, without leading zeros
1022   t      31         Number of days in the given month
1023   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1024   Y      2007       A full numeric representation of a year, 4 digits
1025   y      07         A two digit representation of a year
1026   a      pm         Lowercase Ante meridiem and Post meridiem
1027   A      PM         Uppercase Ante meridiem and Post meridiem
1028   g      3          12-hour format of an hour without leading zeros
1029   G      15         24-hour format of an hour without leading zeros
1030   h      03         12-hour format of an hour with leading zeros
1031   H      15         24-hour format of an hour with leading zeros
1032   i      05         Minutes with leading zeros
1033   s      01         Seconds, with leading zeros
1034   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1035   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1036   T      CST        Timezone setting of the machine running the code
1037   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1038 </pre>
1039  *
1040  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1041  * <pre><code>
1042 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1043 document.write(dt.format('Y-m-d'));                         //2007-01-10
1044 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1045 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
1046  </code></pre>
1047  *
1048  * Here are some standard date/time patterns that you might find helpful.  They
1049  * are not part of the source of Date.js, but to use them you can simply copy this
1050  * block of code into any script that is included after Date.js and they will also become
1051  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1052  * <pre><code>
1053 Date.patterns = {
1054     ISO8601Long:"Y-m-d H:i:s",
1055     ISO8601Short:"Y-m-d",
1056     ShortDate: "n/j/Y",
1057     LongDate: "l, F d, Y",
1058     FullDateTime: "l, F d, Y g:i:s A",
1059     MonthDay: "F d",
1060     ShortTime: "g:i A",
1061     LongTime: "g:i:s A",
1062     SortableDateTime: "Y-m-d\\TH:i:s",
1063     UniversalSortableDateTime: "Y-m-d H:i:sO",
1064     YearMonth: "F, Y"
1065 };
1066 </code></pre>
1067  *
1068  * Example usage:
1069  * <pre><code>
1070 var dt = new Date();
1071 document.write(dt.format(Date.patterns.ShortDate));
1072  </code></pre>
1073  */
1074
1075 /*
1076  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1077  * They generate precompiled functions from date formats instead of parsing and
1078  * processing the pattern every time you format a date.  These functions are available
1079  * on every Date object (any javascript function).
1080  *
1081  * The original article and download are here:
1082  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1083  *
1084  */
1085  
1086  
1087  // was in core
1088 /**
1089  Returns the number of milliseconds between this date and date
1090  @param {Date} date (optional) Defaults to now
1091  @return {Number} The diff in milliseconds
1092  @member Date getElapsed
1093  */
1094 Date.prototype.getElapsed = function(date) {
1095         return Math.abs((date || new Date()).getTime()-this.getTime());
1096 };
1097 // was in date file..
1098
1099
1100 // private
1101 Date.parseFunctions = {count:0};
1102 // private
1103 Date.parseRegexes = [];
1104 // private
1105 Date.formatFunctions = {count:0};
1106
1107 // private
1108 Date.prototype.dateFormat = function(format) {
1109     if (Date.formatFunctions[format] == null) {
1110         Date.createNewFormat(format);
1111     }
1112     var func = Date.formatFunctions[format];
1113     return this[func]();
1114 };
1115
1116
1117 /**
1118  * Formats a date given the supplied format string
1119  * @param {String} format The format string
1120  * @return {String} The formatted date
1121  * @method
1122  */
1123 Date.prototype.format = Date.prototype.dateFormat;
1124
1125 // private
1126 Date.createNewFormat = function(format) {
1127     var funcName = "format" + Date.formatFunctions.count++;
1128     Date.formatFunctions[format] = funcName;
1129     var code = "Date.prototype." + funcName + " = function(){return ";
1130     var special = false;
1131     var ch = '';
1132     for (var i = 0; i < format.length; ++i) {
1133         ch = format.charAt(i);
1134         if (!special && ch == "\\") {
1135             special = true;
1136         }
1137         else if (special) {
1138             special = false;
1139             code += "'" + String.escape(ch) + "' + ";
1140         }
1141         else {
1142             code += Date.getFormatCode(ch);
1143         }
1144     }
1145     /** eval:var:zzzzzzzzzzzzz */
1146     eval(code.substring(0, code.length - 3) + ";}");
1147 };
1148
1149 // private
1150 Date.getFormatCode = function(character) {
1151     switch (character) {
1152     case "d":
1153         return "String.leftPad(this.getDate(), 2, '0') + ";
1154     case "D":
1155         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1156     case "j":
1157         return "this.getDate() + ";
1158     case "l":
1159         return "Date.dayNames[this.getDay()] + ";
1160     case "S":
1161         return "this.getSuffix() + ";
1162     case "w":
1163         return "this.getDay() + ";
1164     case "z":
1165         return "this.getDayOfYear() + ";
1166     case "W":
1167         return "this.getWeekOfYear() + ";
1168     case "F":
1169         return "Date.monthNames[this.getMonth()] + ";
1170     case "m":
1171         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1172     case "M":
1173         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1174     case "n":
1175         return "(this.getMonth() + 1) + ";
1176     case "t":
1177         return "this.getDaysInMonth() + ";
1178     case "L":
1179         return "(this.isLeapYear() ? 1 : 0) + ";
1180     case "Y":
1181         return "this.getFullYear() + ";
1182     case "y":
1183         return "('' + this.getFullYear()).substring(2, 4) + ";
1184     case "a":
1185         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1186     case "A":
1187         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1188     case "g":
1189         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1190     case "G":
1191         return "this.getHours() + ";
1192     case "h":
1193         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1194     case "H":
1195         return "String.leftPad(this.getHours(), 2, '0') + ";
1196     case "i":
1197         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1198     case "s":
1199         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1200     case "O":
1201         return "this.getGMTOffset() + ";
1202     case "P":
1203         return "this.getGMTColonOffset() + ";
1204     case "T":
1205         return "this.getTimezone() + ";
1206     case "Z":
1207         return "(this.getTimezoneOffset() * -60) + ";
1208     default:
1209         return "'" + String.escape(character) + "' + ";
1210     }
1211 };
1212
1213 /**
1214  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1215  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1216  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1217  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1218  * string or the parse operation will fail.
1219  * Example Usage:
1220 <pre><code>
1221 //dt = Fri May 25 2007 (current date)
1222 var dt = new Date();
1223
1224 //dt = Thu May 25 2006 (today's month/day in 2006)
1225 dt = Date.parseDate("2006", "Y");
1226
1227 //dt = Sun Jan 15 2006 (all date parts specified)
1228 dt = Date.parseDate("2006-1-15", "Y-m-d");
1229
1230 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1231 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1232 </code></pre>
1233  * @param {String} input The unparsed date as a string
1234  * @param {String} format The format the date is in
1235  * @return {Date} The parsed date
1236  * @static
1237  */
1238 Date.parseDate = function(input, format) {
1239     if (Date.parseFunctions[format] == null) {
1240         Date.createParser(format);
1241     }
1242     var func = Date.parseFunctions[format];
1243     return Date[func](input);
1244 };
1245 /**
1246  * @private
1247  */
1248
1249 Date.createParser = function(format) {
1250     var funcName = "parse" + Date.parseFunctions.count++;
1251     var regexNum = Date.parseRegexes.length;
1252     var currentGroup = 1;
1253     Date.parseFunctions[format] = funcName;
1254
1255     var code = "Date." + funcName + " = function(input){\n"
1256         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1257         + "var d = new Date();\n"
1258         + "y = d.getFullYear();\n"
1259         + "m = d.getMonth();\n"
1260         + "d = d.getDate();\n"
1261         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1262         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1263         + "if (results && results.length > 0) {";
1264     var regex = "";
1265
1266     var special = false;
1267     var ch = '';
1268     for (var i = 0; i < format.length; ++i) {
1269         ch = format.charAt(i);
1270         if (!special && ch == "\\") {
1271             special = true;
1272         }
1273         else if (special) {
1274             special = false;
1275             regex += String.escape(ch);
1276         }
1277         else {
1278             var obj = Date.formatCodeToRegex(ch, currentGroup);
1279             currentGroup += obj.g;
1280             regex += obj.s;
1281             if (obj.g && obj.c) {
1282                 code += obj.c;
1283             }
1284         }
1285     }
1286
1287     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1288         + "{v = new Date(y, m, d, h, i, s);}\n"
1289         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1290         + "{v = new Date(y, m, d, h, i);}\n"
1291         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1292         + "{v = new Date(y, m, d, h);}\n"
1293         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1294         + "{v = new Date(y, m, d);}\n"
1295         + "else if (y >= 0 && m >= 0)\n"
1296         + "{v = new Date(y, m);}\n"
1297         + "else if (y >= 0)\n"
1298         + "{v = new Date(y);}\n"
1299         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1300         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1301         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1302         + ";}";
1303
1304     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1305     /** eval:var:zzzzzzzzzzzzz */
1306     eval(code);
1307 };
1308
1309 // private
1310 Date.formatCodeToRegex = function(character, currentGroup) {
1311     switch (character) {
1312     case "D":
1313         return {g:0,
1314         c:null,
1315         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1316     case "j":
1317         return {g:1,
1318             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1319             s:"(\\d{1,2})"}; // day of month without leading zeroes
1320     case "d":
1321         return {g:1,
1322             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1323             s:"(\\d{2})"}; // day of month with leading zeroes
1324     case "l":
1325         return {g:0,
1326             c:null,
1327             s:"(?:" + Date.dayNames.join("|") + ")"};
1328     case "S":
1329         return {g:0,
1330             c:null,
1331             s:"(?:st|nd|rd|th)"};
1332     case "w":
1333         return {g:0,
1334             c:null,
1335             s:"\\d"};
1336     case "z":
1337         return {g:0,
1338             c:null,
1339             s:"(?:\\d{1,3})"};
1340     case "W":
1341         return {g:0,
1342             c:null,
1343             s:"(?:\\d{2})"};
1344     case "F":
1345         return {g:1,
1346             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1347             s:"(" + Date.monthNames.join("|") + ")"};
1348     case "M":
1349         return {g:1,
1350             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1351             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1352     case "n":
1353         return {g:1,
1354             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1355             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1356     case "m":
1357         return {g:1,
1358             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1359             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1360     case "t":
1361         return {g:0,
1362             c:null,
1363             s:"\\d{1,2}"};
1364     case "L":
1365         return {g:0,
1366             c:null,
1367             s:"(?:1|0)"};
1368     case "Y":
1369         return {g:1,
1370             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1371             s:"(\\d{4})"};
1372     case "y":
1373         return {g:1,
1374             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1375                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1376             s:"(\\d{1,2})"};
1377     case "a":
1378         return {g:1,
1379             c:"if (results[" + currentGroup + "] == 'am') {\n"
1380                 + "if (h == 12) { h = 0; }\n"
1381                 + "} else { if (h < 12) { h += 12; }}",
1382             s:"(am|pm)"};
1383     case "A":
1384         return {g:1,
1385             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1386                 + "if (h == 12) { h = 0; }\n"
1387                 + "} else { if (h < 12) { h += 12; }}",
1388             s:"(AM|PM)"};
1389     case "g":
1390     case "G":
1391         return {g:1,
1392             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1393             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1394     case "h":
1395     case "H":
1396         return {g:1,
1397             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1398             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1399     case "i":
1400         return {g:1,
1401             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1402             s:"(\\d{2})"};
1403     case "s":
1404         return {g:1,
1405             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1406             s:"(\\d{2})"};
1407     case "O":
1408         return {g:1,
1409             c:[
1410                 "o = results[", currentGroup, "];\n",
1411                 "var sn = o.substring(0,1);\n", // get + / - sign
1412                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1413                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1414                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1415                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1416             ].join(""),
1417             s:"([+\-]\\d{2,4})"};
1418     
1419     
1420     case "P":
1421         return {g:1,
1422                 c:[
1423                    "o = results[", currentGroup, "];\n",
1424                    "var sn = o.substring(0,1);\n",
1425                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1426                    "var mn = o.substring(4,6) % 60;\n",
1427                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1428                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1429             ].join(""),
1430             s:"([+\-]\\d{4})"};
1431     case "T":
1432         return {g:0,
1433             c:null,
1434             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1435     case "Z":
1436         return {g:1,
1437             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1438                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1439             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1440     default:
1441         return {g:0,
1442             c:null,
1443             s:String.escape(character)};
1444     }
1445 };
1446
1447 /**
1448  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1449  * @return {String} The abbreviated timezone name (e.g. 'CST')
1450  */
1451 Date.prototype.getTimezone = function() {
1452     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1453 };
1454
1455 /**
1456  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1457  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1458  */
1459 Date.prototype.getGMTOffset = function() {
1460     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1461         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1462         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1463 };
1464
1465 /**
1466  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1467  * @return {String} 2-characters representing hours and 2-characters representing minutes
1468  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1469  */
1470 Date.prototype.getGMTColonOffset = function() {
1471         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1472                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1473                 + ":"
1474                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1475 }
1476
1477 /**
1478  * Get the numeric day number of the year, adjusted for leap year.
1479  * @return {Number} 0 through 364 (365 in leap years)
1480  */
1481 Date.prototype.getDayOfYear = function() {
1482     var num = 0;
1483     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1484     for (var i = 0; i < this.getMonth(); ++i) {
1485         num += Date.daysInMonth[i];
1486     }
1487     return num + this.getDate() - 1;
1488 };
1489
1490 /**
1491  * Get the string representation of the numeric week number of the year
1492  * (equivalent to the format specifier 'W').
1493  * @return {String} '00' through '52'
1494  */
1495 Date.prototype.getWeekOfYear = function() {
1496     // Skip to Thursday of this week
1497     var now = this.getDayOfYear() + (4 - this.getDay());
1498     // Find the first Thursday of the year
1499     var jan1 = new Date(this.getFullYear(), 0, 1);
1500     var then = (7 - jan1.getDay() + 4);
1501     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1502 };
1503
1504 /**
1505  * Whether or not the current date is in a leap year.
1506  * @return {Boolean} True if the current date is in a leap year, else false
1507  */
1508 Date.prototype.isLeapYear = function() {
1509     var year = this.getFullYear();
1510     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1511 };
1512
1513 /**
1514  * Get the first day of the current month, adjusted for leap year.  The returned value
1515  * is the numeric day index within the week (0-6) which can be used in conjunction with
1516  * the {@link #monthNames} array to retrieve the textual day name.
1517  * Example:
1518  *<pre><code>
1519 var dt = new Date('1/10/2007');
1520 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1521 </code></pre>
1522  * @return {Number} The day number (0-6)
1523  */
1524 Date.prototype.getFirstDayOfMonth = function() {
1525     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1526     return (day < 0) ? (day + 7) : day;
1527 };
1528
1529 /**
1530  * Get the last day of the current month, adjusted for leap year.  The returned value
1531  * is the numeric day index within the week (0-6) which can be used in conjunction with
1532  * the {@link #monthNames} array to retrieve the textual day name.
1533  * Example:
1534  *<pre><code>
1535 var dt = new Date('1/10/2007');
1536 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1537 </code></pre>
1538  * @return {Number} The day number (0-6)
1539  */
1540 Date.prototype.getLastDayOfMonth = function() {
1541     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1542     return (day < 0) ? (day + 7) : day;
1543 };
1544
1545
1546 /**
1547  * Get the first date of this date's month
1548  * @return {Date}
1549  */
1550 Date.prototype.getFirstDateOfMonth = function() {
1551     return new Date(this.getFullYear(), this.getMonth(), 1);
1552 };
1553
1554 /**
1555  * Get the last date of this date's month
1556  * @return {Date}
1557  */
1558 Date.prototype.getLastDateOfMonth = function() {
1559     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1560 };
1561 /**
1562  * Get the number of days in the current month, adjusted for leap year.
1563  * @return {Number} The number of days in the month
1564  */
1565 Date.prototype.getDaysInMonth = function() {
1566     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1567     return Date.daysInMonth[this.getMonth()];
1568 };
1569
1570 /**
1571  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1572  * @return {String} 'st, 'nd', 'rd' or 'th'
1573  */
1574 Date.prototype.getSuffix = function() {
1575     switch (this.getDate()) {
1576         case 1:
1577         case 21:
1578         case 31:
1579             return "st";
1580         case 2:
1581         case 22:
1582             return "nd";
1583         case 3:
1584         case 23:
1585             return "rd";
1586         default:
1587             return "th";
1588     }
1589 };
1590
1591 // private
1592 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1593
1594 /**
1595  * An array of textual month names.
1596  * Override these values for international dates, for example...
1597  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1598  * @type Array
1599  * @static
1600  */
1601 Date.monthNames =
1602    ["January",
1603     "February",
1604     "March",
1605     "April",
1606     "May",
1607     "June",
1608     "July",
1609     "August",
1610     "September",
1611     "October",
1612     "November",
1613     "December"];
1614
1615 /**
1616  * An array of textual day names.
1617  * Override these values for international dates, for example...
1618  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1619  * @type Array
1620  * @static
1621  */
1622 Date.dayNames =
1623    ["Sunday",
1624     "Monday",
1625     "Tuesday",
1626     "Wednesday",
1627     "Thursday",
1628     "Friday",
1629     "Saturday"];
1630
1631 // private
1632 Date.y2kYear = 50;
1633 // private
1634 Date.monthNumbers = {
1635     Jan:0,
1636     Feb:1,
1637     Mar:2,
1638     Apr:3,
1639     May:4,
1640     Jun:5,
1641     Jul:6,
1642     Aug:7,
1643     Sep:8,
1644     Oct:9,
1645     Nov:10,
1646     Dec:11};
1647
1648 /**
1649  * Creates and returns a new Date instance with the exact same date value as the called instance.
1650  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1651  * variable will also be changed.  When the intention is to create a new variable that will not
1652  * modify the original instance, you should create a clone.
1653  *
1654  * Example of correctly cloning a date:
1655  * <pre><code>
1656 //wrong way:
1657 var orig = new Date('10/1/2006');
1658 var copy = orig;
1659 copy.setDate(5);
1660 document.write(orig);  //returns 'Thu Oct 05 2006'!
1661
1662 //correct way:
1663 var orig = new Date('10/1/2006');
1664 var copy = orig.clone();
1665 copy.setDate(5);
1666 document.write(orig);  //returns 'Thu Oct 01 2006'
1667 </code></pre>
1668  * @return {Date} The new Date instance
1669  */
1670 Date.prototype.clone = function() {
1671         return new Date(this.getTime());
1672 };
1673
1674 /**
1675  * Clears any time information from this date
1676  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1677  @return {Date} this or the clone
1678  */
1679 Date.prototype.clearTime = function(clone){
1680     if(clone){
1681         return this.clone().clearTime();
1682     }
1683     this.setHours(0);
1684     this.setMinutes(0);
1685     this.setSeconds(0);
1686     this.setMilliseconds(0);
1687     return this;
1688 };
1689
1690 // private
1691 // safari setMonth is broken -- check that this is only donw once...
1692 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1693     Date.brokenSetMonth = Date.prototype.setMonth;
1694         Date.prototype.setMonth = function(num){
1695                 if(num <= -1){
1696                         var n = Math.ceil(-num);
1697                         var back_year = Math.ceil(n/12);
1698                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1699                         this.setFullYear(this.getFullYear() - back_year);
1700                         return Date.brokenSetMonth.call(this, month);
1701                 } else {
1702                         return Date.brokenSetMonth.apply(this, arguments);
1703                 }
1704         };
1705 }
1706
1707 /** Date interval constant 
1708 * @static 
1709 * @type String */
1710 Date.MILLI = "ms";
1711 /** Date interval constant 
1712 * @static 
1713 * @type String */
1714 Date.SECOND = "s";
1715 /** Date interval constant 
1716 * @static 
1717 * @type String */
1718 Date.MINUTE = "mi";
1719 /** Date interval constant 
1720 * @static 
1721 * @type String */
1722 Date.HOUR = "h";
1723 /** Date interval constant 
1724 * @static 
1725 * @type String */
1726 Date.DAY = "d";
1727 /** Date interval constant 
1728 * @static 
1729 * @type String */
1730 Date.MONTH = "mo";
1731 /** Date interval constant 
1732 * @static 
1733 * @type String */
1734 Date.YEAR = "y";
1735
1736 /**
1737  * Provides a convenient method of performing basic date arithmetic.  This method
1738  * does not modify the Date instance being called - it creates and returns
1739  * a new Date instance containing the resulting date value.
1740  *
1741  * Examples:
1742  * <pre><code>
1743 //Basic usage:
1744 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1745 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1746
1747 //Negative values will subtract correctly:
1748 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1749 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1750
1751 //You can even chain several calls together in one line!
1752 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1753 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1754  </code></pre>
1755  *
1756  * @param {String} interval   A valid date interval enum value
1757  * @param {Number} value      The amount to add to the current date
1758  * @return {Date} The new Date instance
1759  */
1760 Date.prototype.add = function(interval, value){
1761   var d = this.clone();
1762   if (!interval || value === 0) { return d; }
1763   switch(interval.toLowerCase()){
1764     case Date.MILLI:
1765       d.setMilliseconds(this.getMilliseconds() + value);
1766       break;
1767     case Date.SECOND:
1768       d.setSeconds(this.getSeconds() + value);
1769       break;
1770     case Date.MINUTE:
1771       d.setMinutes(this.getMinutes() + value);
1772       break;
1773     case Date.HOUR:
1774       d.setHours(this.getHours() + value);
1775       break;
1776     case Date.DAY:
1777       d.setDate(this.getDate() + value);
1778       break;
1779     case Date.MONTH:
1780       var day = this.getDate();
1781       if(day > 28){
1782           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1783       }
1784       d.setDate(day);
1785       d.setMonth(this.getMonth() + value);
1786       break;
1787     case Date.YEAR:
1788       d.setFullYear(this.getFullYear() + value);
1789       break;
1790   }
1791   return d;
1792 };
1793 /*
1794  * Based on:
1795  * Ext JS Library 1.1.1
1796  * Copyright(c) 2006-2007, Ext JS, LLC.
1797  *
1798  * Originally Released Under LGPL - original licence link has changed is not relivant.
1799  *
1800  * Fork - LGPL
1801  * <script type="text/javascript">
1802  */
1803
1804 /**
1805  * @class Roo.lib.Dom
1806  * @static
1807  * 
1808  * Dom utils (from YIU afaik)
1809  * 
1810  **/
1811 Roo.lib.Dom = {
1812     /**
1813      * Get the view width
1814      * @param {Boolean} full True will get the full document, otherwise it's the view width
1815      * @return {Number} The width
1816      */
1817      
1818     getViewWidth : function(full) {
1819         return full ? this.getDocumentWidth() : this.getViewportWidth();
1820     },
1821     /**
1822      * Get the view height
1823      * @param {Boolean} full True will get the full document, otherwise it's the view height
1824      * @return {Number} The height
1825      */
1826     getViewHeight : function(full) {
1827         return full ? this.getDocumentHeight() : this.getViewportHeight();
1828     },
1829
1830     getDocumentHeight: function() {
1831         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1832         return Math.max(scrollHeight, this.getViewportHeight());
1833     },
1834
1835     getDocumentWidth: function() {
1836         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1837         return Math.max(scrollWidth, this.getViewportWidth());
1838     },
1839
1840     getViewportHeight: function() {
1841         var height = self.innerHeight;
1842         var mode = document.compatMode;
1843
1844         if ((mode || Roo.isIE) && !Roo.isOpera) {
1845             height = (mode == "CSS1Compat") ?
1846                      document.documentElement.clientHeight :
1847                      document.body.clientHeight;
1848         }
1849
1850         return height;
1851     },
1852
1853     getViewportWidth: function() {
1854         var width = self.innerWidth;
1855         var mode = document.compatMode;
1856
1857         if (mode || Roo.isIE) {
1858             width = (mode == "CSS1Compat") ?
1859                     document.documentElement.clientWidth :
1860                     document.body.clientWidth;
1861         }
1862         return width;
1863     },
1864
1865     isAncestor : function(p, c) {
1866         p = Roo.getDom(p);
1867         c = Roo.getDom(c);
1868         if (!p || !c) {
1869             return false;
1870         }
1871
1872         if (p.contains && !Roo.isSafari) {
1873             return p.contains(c);
1874         } else if (p.compareDocumentPosition) {
1875             return !!(p.compareDocumentPosition(c) & 16);
1876         } else {
1877             var parent = c.parentNode;
1878             while (parent) {
1879                 if (parent == p) {
1880                     return true;
1881                 }
1882                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1883                     return false;
1884                 }
1885                 parent = parent.parentNode;
1886             }
1887             return false;
1888         }
1889     },
1890
1891     getRegion : function(el) {
1892         return Roo.lib.Region.getRegion(el);
1893     },
1894
1895     getY : function(el) {
1896         return this.getXY(el)[1];
1897     },
1898
1899     getX : function(el) {
1900         return this.getXY(el)[0];
1901     },
1902
1903     getXY : function(el) {
1904         var p, pe, b, scroll, bd = document.body;
1905         el = Roo.getDom(el);
1906         var fly = Roo.lib.AnimBase.fly;
1907         if (el.getBoundingClientRect) {
1908             b = el.getBoundingClientRect();
1909             scroll = fly(document).getScroll();
1910             return [b.left + scroll.left, b.top + scroll.top];
1911         }
1912         var x = 0, y = 0;
1913
1914         p = el;
1915
1916         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1917
1918         while (p) {
1919
1920             x += p.offsetLeft;
1921             y += p.offsetTop;
1922
1923             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1924                 hasAbsolute = true;
1925             }
1926
1927             if (Roo.isGecko) {
1928                 pe = fly(p);
1929
1930                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1931                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1932
1933
1934                 x += bl;
1935                 y += bt;
1936
1937
1938                 if (p != el && pe.getStyle('overflow') != 'visible') {
1939                     x += bl;
1940                     y += bt;
1941                 }
1942             }
1943             p = p.offsetParent;
1944         }
1945
1946         if (Roo.isSafari && hasAbsolute) {
1947             x -= bd.offsetLeft;
1948             y -= bd.offsetTop;
1949         }
1950
1951         if (Roo.isGecko && !hasAbsolute) {
1952             var dbd = fly(bd);
1953             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1954             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1955         }
1956
1957         p = el.parentNode;
1958         while (p && p != bd) {
1959             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1960                 x -= p.scrollLeft;
1961                 y -= p.scrollTop;
1962             }
1963             p = p.parentNode;
1964         }
1965         return [x, y];
1966     },
1967  
1968   
1969
1970
1971     setXY : function(el, xy) {
1972         el = Roo.fly(el, '_setXY');
1973         el.position();
1974         var pts = el.translatePoints(xy);
1975         if (xy[0] !== false) {
1976             el.dom.style.left = pts.left + "px";
1977         }
1978         if (xy[1] !== false) {
1979             el.dom.style.top = pts.top + "px";
1980         }
1981     },
1982
1983     setX : function(el, x) {
1984         this.setXY(el, [x, false]);
1985     },
1986
1987     setY : function(el, y) {
1988         this.setXY(el, [false, y]);
1989     }
1990 };
1991 /*
1992  * Portions of this file are based on pieces of Yahoo User Interface Library
1993  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1994  * YUI licensed under the BSD License:
1995  * http://developer.yahoo.net/yui/license.txt
1996  * <script type="text/javascript">
1997  *
1998  */
1999
2000 Roo.lib.Event = function() {
2001     var loadComplete = false;
2002     var listeners = [];
2003     var unloadListeners = [];
2004     var retryCount = 0;
2005     var onAvailStack = [];
2006     var counter = 0;
2007     var lastError = null;
2008
2009     return {
2010         POLL_RETRYS: 200,
2011         POLL_INTERVAL: 20,
2012         EL: 0,
2013         TYPE: 1,
2014         FN: 2,
2015         WFN: 3,
2016         OBJ: 3,
2017         ADJ_SCOPE: 4,
2018         _interval: null,
2019
2020         startInterval: function() {
2021             if (!this._interval) {
2022                 var self = this;
2023                 var callback = function() {
2024                     self._tryPreloadAttach();
2025                 };
2026                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2027
2028             }
2029         },
2030
2031         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2032             onAvailStack.push({ id:         p_id,
2033                 fn:         p_fn,
2034                 obj:        p_obj,
2035                 override:   p_override,
2036                 checkReady: false    });
2037
2038             retryCount = this.POLL_RETRYS;
2039             this.startInterval();
2040         },
2041
2042
2043         addListener: function(el, eventName, fn) {
2044             el = Roo.getDom(el);
2045             if (!el || !fn) {
2046                 return false;
2047             }
2048
2049             if ("unload" == eventName) {
2050                 unloadListeners[unloadListeners.length] =
2051                 [el, eventName, fn];
2052                 return true;
2053             }
2054
2055             var wrappedFn = function(e) {
2056                 return fn(Roo.lib.Event.getEvent(e));
2057             };
2058
2059             var li = [el, eventName, fn, wrappedFn];
2060
2061             var index = listeners.length;
2062             listeners[index] = li;
2063
2064             this.doAdd(el, eventName, wrappedFn, false);
2065             return true;
2066
2067         },
2068
2069
2070         removeListener: function(el, eventName, fn) {
2071             var i, len;
2072
2073             el = Roo.getDom(el);
2074
2075             if(!fn) {
2076                 return this.purgeElement(el, false, eventName);
2077             }
2078
2079
2080             if ("unload" == eventName) {
2081
2082                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2083                     var li = unloadListeners[i];
2084                     if (li &&
2085                         li[0] == el &&
2086                         li[1] == eventName &&
2087                         li[2] == fn) {
2088                         unloadListeners.splice(i, 1);
2089                         return true;
2090                     }
2091                 }
2092
2093                 return false;
2094             }
2095
2096             var cacheItem = null;
2097
2098
2099             var index = arguments[3];
2100
2101             if ("undefined" == typeof index) {
2102                 index = this._getCacheIndex(el, eventName, fn);
2103             }
2104
2105             if (index >= 0) {
2106                 cacheItem = listeners[index];
2107             }
2108
2109             if (!el || !cacheItem) {
2110                 return false;
2111             }
2112
2113             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2114
2115             delete listeners[index][this.WFN];
2116             delete listeners[index][this.FN];
2117             listeners.splice(index, 1);
2118
2119             return true;
2120
2121         },
2122
2123
2124         getTarget: function(ev, resolveTextNode) {
2125             ev = ev.browserEvent || ev;
2126             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2127             var t = ev.target || ev.srcElement;
2128             return this.resolveTextNode(t);
2129         },
2130
2131
2132         resolveTextNode: function(node) {
2133             if (Roo.isSafari && node && 3 == node.nodeType) {
2134                 return node.parentNode;
2135             } else {
2136                 return node;
2137             }
2138         },
2139
2140
2141         getPageX: function(ev) {
2142             ev = ev.browserEvent || ev;
2143             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2144             var x = ev.pageX;
2145             if (!x && 0 !== x) {
2146                 x = ev.clientX || 0;
2147
2148                 if (Roo.isIE) {
2149                     x += this.getScroll()[1];
2150                 }
2151             }
2152
2153             return x;
2154         },
2155
2156
2157         getPageY: function(ev) {
2158             ev = ev.browserEvent || ev;
2159             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2160             var y = ev.pageY;
2161             if (!y && 0 !== y) {
2162                 y = ev.clientY || 0;
2163
2164                 if (Roo.isIE) {
2165                     y += this.getScroll()[0];
2166                 }
2167             }
2168
2169
2170             return y;
2171         },
2172
2173
2174         getXY: function(ev) {
2175             ev = ev.browserEvent || ev;
2176             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2177             return [this.getPageX(ev), this.getPageY(ev)];
2178         },
2179
2180
2181         getRelatedTarget: function(ev) {
2182             ev = ev.browserEvent || ev;
2183             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2184             var t = ev.relatedTarget;
2185             if (!t) {
2186                 if (ev.type == "mouseout") {
2187                     t = ev.toElement;
2188                 } else if (ev.type == "mouseover") {
2189                     t = ev.fromElement;
2190                 }
2191             }
2192
2193             return this.resolveTextNode(t);
2194         },
2195
2196
2197         getTime: function(ev) {
2198             ev = ev.browserEvent || ev;
2199             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2200             if (!ev.time) {
2201                 var t = new Date().getTime();
2202                 try {
2203                     ev.time = t;
2204                 } catch(ex) {
2205                     this.lastError = ex;
2206                     return t;
2207                 }
2208             }
2209
2210             return ev.time;
2211         },
2212
2213
2214         stopEvent: function(ev) {
2215             this.stopPropagation(ev);
2216             this.preventDefault(ev);
2217         },
2218
2219
2220         stopPropagation: function(ev) {
2221             ev = ev.browserEvent || ev;
2222             if (ev.stopPropagation) {
2223                 ev.stopPropagation();
2224             } else {
2225                 ev.cancelBubble = true;
2226             }
2227         },
2228
2229
2230         preventDefault: function(ev) {
2231             ev = ev.browserEvent || ev;
2232             if(ev.preventDefault) {
2233                 ev.preventDefault();
2234             } else {
2235                 ev.returnValue = false;
2236             }
2237         },
2238
2239
2240         getEvent: function(e) {
2241             var ev = e || window.event;
2242             if (!ev) {
2243                 var c = this.getEvent.caller;
2244                 while (c) {
2245                     ev = c.arguments[0];
2246                     if (ev && Event == ev.constructor) {
2247                         break;
2248                     }
2249                     c = c.caller;
2250                 }
2251             }
2252             return ev;
2253         },
2254
2255
2256         getCharCode: function(ev) {
2257             ev = ev.browserEvent || ev;
2258             return ev.charCode || ev.keyCode || 0;
2259         },
2260
2261
2262         _getCacheIndex: function(el, eventName, fn) {
2263             for (var i = 0,len = listeners.length; i < len; ++i) {
2264                 var li = listeners[i];
2265                 if (li &&
2266                     li[this.FN] == fn &&
2267                     li[this.EL] == el &&
2268                     li[this.TYPE] == eventName) {
2269                     return i;
2270                 }
2271             }
2272
2273             return -1;
2274         },
2275
2276
2277         elCache: {},
2278
2279
2280         getEl: function(id) {
2281             return document.getElementById(id);
2282         },
2283
2284
2285         clearCache: function() {
2286         },
2287
2288
2289         _load: function(e) {
2290             loadComplete = true;
2291             var EU = Roo.lib.Event;
2292
2293
2294             if (Roo.isIE) {
2295                 EU.doRemove(window, "load", EU._load);
2296             }
2297         },
2298
2299
2300         _tryPreloadAttach: function() {
2301
2302             if (this.locked) {
2303                 return false;
2304             }
2305
2306             this.locked = true;
2307
2308
2309             var tryAgain = !loadComplete;
2310             if (!tryAgain) {
2311                 tryAgain = (retryCount > 0);
2312             }
2313
2314
2315             var notAvail = [];
2316             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2317                 var item = onAvailStack[i];
2318                 if (item) {
2319                     var el = this.getEl(item.id);
2320
2321                     if (el) {
2322                         if (!item.checkReady ||
2323                             loadComplete ||
2324                             el.nextSibling ||
2325                             (document && document.body)) {
2326
2327                             var scope = el;
2328                             if (item.override) {
2329                                 if (item.override === true) {
2330                                     scope = item.obj;
2331                                 } else {
2332                                     scope = item.override;
2333                                 }
2334                             }
2335                             item.fn.call(scope, item.obj);
2336                             onAvailStack[i] = null;
2337                         }
2338                     } else {
2339                         notAvail.push(item);
2340                     }
2341                 }
2342             }
2343
2344             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2345
2346             if (tryAgain) {
2347
2348                 this.startInterval();
2349             } else {
2350                 clearInterval(this._interval);
2351                 this._interval = null;
2352             }
2353
2354             this.locked = false;
2355
2356             return true;
2357
2358         },
2359
2360
2361         purgeElement: function(el, recurse, eventName) {
2362             var elListeners = this.getListeners(el, eventName);
2363             if (elListeners) {
2364                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2365                     var l = elListeners[i];
2366                     this.removeListener(el, l.type, l.fn);
2367                 }
2368             }
2369
2370             if (recurse && el && el.childNodes) {
2371                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2372                     this.purgeElement(el.childNodes[i], recurse, eventName);
2373                 }
2374             }
2375         },
2376
2377
2378         getListeners: function(el, eventName) {
2379             var results = [], searchLists;
2380             if (!eventName) {
2381                 searchLists = [listeners, unloadListeners];
2382             } else if (eventName == "unload") {
2383                 searchLists = [unloadListeners];
2384             } else {
2385                 searchLists = [listeners];
2386             }
2387
2388             for (var j = 0; j < searchLists.length; ++j) {
2389                 var searchList = searchLists[j];
2390                 if (searchList && searchList.length > 0) {
2391                     for (var i = 0,len = searchList.length; i < len; ++i) {
2392                         var l = searchList[i];
2393                         if (l && l[this.EL] === el &&
2394                             (!eventName || eventName === l[this.TYPE])) {
2395                             results.push({
2396                                 type:   l[this.TYPE],
2397                                 fn:     l[this.FN],
2398                                 obj:    l[this.OBJ],
2399                                 adjust: l[this.ADJ_SCOPE],
2400                                 index:  i
2401                             });
2402                         }
2403                     }
2404                 }
2405             }
2406
2407             return (results.length) ? results : null;
2408         },
2409
2410
2411         _unload: function(e) {
2412
2413             var EU = Roo.lib.Event, i, j, l, len, index;
2414
2415             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2416                 l = unloadListeners[i];
2417                 if (l) {
2418                     var scope = window;
2419                     if (l[EU.ADJ_SCOPE]) {
2420                         if (l[EU.ADJ_SCOPE] === true) {
2421                             scope = l[EU.OBJ];
2422                         } else {
2423                             scope = l[EU.ADJ_SCOPE];
2424                         }
2425                     }
2426                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2427                     unloadListeners[i] = null;
2428                     l = null;
2429                     scope = null;
2430                 }
2431             }
2432
2433             unloadListeners = null;
2434
2435             if (listeners && listeners.length > 0) {
2436                 j = listeners.length;
2437                 while (j) {
2438                     index = j - 1;
2439                     l = listeners[index];
2440                     if (l) {
2441                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2442                                 l[EU.FN], index);
2443                     }
2444                     j = j - 1;
2445                 }
2446                 l = null;
2447
2448                 EU.clearCache();
2449             }
2450
2451             EU.doRemove(window, "unload", EU._unload);
2452
2453         },
2454
2455
2456         getScroll: function() {
2457             var dd = document.documentElement, db = document.body;
2458             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2459                 return [dd.scrollTop, dd.scrollLeft];
2460             } else if (db) {
2461                 return [db.scrollTop, db.scrollLeft];
2462             } else {
2463                 return [0, 0];
2464             }
2465         },
2466
2467
2468         doAdd: function () {
2469             if (window.addEventListener) {
2470                 return function(el, eventName, fn, capture) {
2471                     el.addEventListener(eventName, fn, (capture));
2472                 };
2473             } else if (window.attachEvent) {
2474                 return function(el, eventName, fn, capture) {
2475                     el.attachEvent("on" + eventName, fn);
2476                 };
2477             } else {
2478                 return function() {
2479                 };
2480             }
2481         }(),
2482
2483
2484         doRemove: function() {
2485             if (window.removeEventListener) {
2486                 return function (el, eventName, fn, capture) {
2487                     el.removeEventListener(eventName, fn, (capture));
2488                 };
2489             } else if (window.detachEvent) {
2490                 return function (el, eventName, fn) {
2491                     el.detachEvent("on" + eventName, fn);
2492                 };
2493             } else {
2494                 return function() {
2495                 };
2496             }
2497         }()
2498     };
2499     
2500 }();
2501 (function() {     
2502    
2503     var E = Roo.lib.Event;
2504     E.on = E.addListener;
2505     E.un = E.removeListener;
2506
2507     if (document && document.body) {
2508         E._load();
2509     } else {
2510         E.doAdd(window, "load", E._load);
2511     }
2512     E.doAdd(window, "unload", E._unload);
2513     E._tryPreloadAttach();
2514 })();
2515
2516 /*
2517  * Portions of this file are based on pieces of Yahoo User Interface Library
2518  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2519  * YUI licensed under the BSD License:
2520  * http://developer.yahoo.net/yui/license.txt
2521  * <script type="text/javascript">
2522  *
2523  */
2524
2525 (function() {
2526     /**
2527      * @class Roo.lib.Ajax
2528      *
2529      */
2530     Roo.lib.Ajax = {
2531         /**
2532          * @static 
2533          */
2534         request : function(method, uri, cb, data, options) {
2535             if(options){
2536                 var hs = options.headers;
2537                 if(hs){
2538                     for(var h in hs){
2539                         if(hs.hasOwnProperty(h)){
2540                             this.initHeader(h, hs[h], false);
2541                         }
2542                     }
2543                 }
2544                 if(options.xmlData){
2545                     this.initHeader('Content-Type', 'text/xml', false);
2546                     method = 'POST';
2547                     data = options.xmlData;
2548                 }
2549             }
2550
2551             return this.asyncRequest(method, uri, cb, data);
2552         },
2553
2554         serializeForm : function(form) {
2555             if(typeof form == 'string') {
2556                 form = (document.getElementById(form) || document.forms[form]);
2557             }
2558
2559             var el, name, val, disabled, data = '', hasSubmit = false;
2560             for (var i = 0; i < form.elements.length; i++) {
2561                 el = form.elements[i];
2562                 disabled = form.elements[i].disabled;
2563                 name = form.elements[i].name;
2564                 val = form.elements[i].value;
2565
2566                 if (!disabled && name){
2567                     switch (el.type)
2568                             {
2569                         case 'select-one':
2570                         case 'select-multiple':
2571                             for (var j = 0; j < el.options.length; j++) {
2572                                 if (el.options[j].selected) {
2573                                     if (Roo.isIE) {
2574                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2575                                     }
2576                                     else {
2577                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2578                                     }
2579                                 }
2580                             }
2581                             break;
2582                         case 'radio':
2583                         case 'checkbox':
2584                             if (el.checked) {
2585                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2586                             }
2587                             break;
2588                         case 'file':
2589
2590                         case undefined:
2591
2592                         case 'reset':
2593
2594                         case 'button':
2595
2596                             break;
2597                         case 'submit':
2598                             if(hasSubmit == false) {
2599                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2600                                 hasSubmit = true;
2601                             }
2602                             break;
2603                         default:
2604                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2605                             break;
2606                     }
2607                 }
2608             }
2609             data = data.substr(0, data.length - 1);
2610             return data;
2611         },
2612
2613         headers:{},
2614
2615         hasHeaders:false,
2616
2617         useDefaultHeader:true,
2618
2619         defaultPostHeader:'application/x-www-form-urlencoded',
2620
2621         useDefaultXhrHeader:true,
2622
2623         defaultXhrHeader:'XMLHttpRequest',
2624
2625         hasDefaultHeaders:true,
2626
2627         defaultHeaders:{},
2628
2629         poll:{},
2630
2631         timeout:{},
2632
2633         pollInterval:50,
2634
2635         transactionId:0,
2636
2637         setProgId:function(id)
2638         {
2639             this.activeX.unshift(id);
2640         },
2641
2642         setDefaultPostHeader:function(b)
2643         {
2644             this.useDefaultHeader = b;
2645         },
2646
2647         setDefaultXhrHeader:function(b)
2648         {
2649             this.useDefaultXhrHeader = b;
2650         },
2651
2652         setPollingInterval:function(i)
2653         {
2654             if (typeof i == 'number' && isFinite(i)) {
2655                 this.pollInterval = i;
2656             }
2657         },
2658
2659         createXhrObject:function(transactionId)
2660         {
2661             var obj,http;
2662             try
2663             {
2664
2665                 http = new XMLHttpRequest();
2666
2667                 obj = { conn:http, tId:transactionId };
2668             }
2669             catch(e)
2670             {
2671                 for (var i = 0; i < this.activeX.length; ++i) {
2672                     try
2673                     {
2674
2675                         http = new ActiveXObject(this.activeX[i]);
2676
2677                         obj = { conn:http, tId:transactionId };
2678                         break;
2679                     }
2680                     catch(e) {
2681                     }
2682                 }
2683             }
2684             finally
2685             {
2686                 return obj;
2687             }
2688         },
2689
2690         getConnectionObject:function()
2691         {
2692             var o;
2693             var tId = this.transactionId;
2694
2695             try
2696             {
2697                 o = this.createXhrObject(tId);
2698                 if (o) {
2699                     this.transactionId++;
2700                 }
2701             }
2702             catch(e) {
2703             }
2704             finally
2705             {
2706                 return o;
2707             }
2708         },
2709
2710         asyncRequest:function(method, uri, callback, postData)
2711         {
2712             var o = this.getConnectionObject();
2713
2714             if (!o) {
2715                 return null;
2716             }
2717             else {
2718                 o.conn.open(method, uri, true);
2719
2720                 if (this.useDefaultXhrHeader) {
2721                     if (!this.defaultHeaders['X-Requested-With']) {
2722                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2723                     }
2724                 }
2725
2726                 if(postData && this.useDefaultHeader){
2727                     this.initHeader('Content-Type', this.defaultPostHeader);
2728                 }
2729
2730                  if (this.hasDefaultHeaders || this.hasHeaders) {
2731                     this.setHeader(o);
2732                 }
2733
2734                 this.handleReadyState(o, callback);
2735                 o.conn.send(postData || null);
2736
2737                 return o;
2738             }
2739         },
2740
2741         handleReadyState:function(o, callback)
2742         {
2743             var oConn = this;
2744
2745             if (callback && callback.timeout) {
2746                 
2747                 this.timeout[o.tId] = window.setTimeout(function() {
2748                     oConn.abort(o, callback, true);
2749                 }, callback.timeout);
2750             }
2751
2752             this.poll[o.tId] = window.setInterval(
2753                     function() {
2754                         if (o.conn && o.conn.readyState == 4) {
2755                             window.clearInterval(oConn.poll[o.tId]);
2756                             delete oConn.poll[o.tId];
2757
2758                             if(callback && callback.timeout) {
2759                                 window.clearTimeout(oConn.timeout[o.tId]);
2760                                 delete oConn.timeout[o.tId];
2761                             }
2762
2763                             oConn.handleTransactionResponse(o, callback);
2764                         }
2765                     }
2766                     , this.pollInterval);
2767         },
2768
2769         handleTransactionResponse:function(o, callback, isAbort)
2770         {
2771
2772             if (!callback) {
2773                 this.releaseObject(o);
2774                 return;
2775             }
2776
2777             var httpStatus, responseObject;
2778
2779             try
2780             {
2781                 if (o.conn.status !== undefined && o.conn.status != 0) {
2782                     httpStatus = o.conn.status;
2783                 }
2784                 else {
2785                     httpStatus = 13030;
2786                 }
2787             }
2788             catch(e) {
2789
2790
2791                 httpStatus = 13030;
2792             }
2793
2794             if (httpStatus >= 200 && httpStatus < 300) {
2795                 responseObject = this.createResponseObject(o, callback.argument);
2796                 if (callback.success) {
2797                     if (!callback.scope) {
2798                         callback.success(responseObject);
2799                     }
2800                     else {
2801
2802
2803                         callback.success.apply(callback.scope, [responseObject]);
2804                     }
2805                 }
2806             }
2807             else {
2808                 switch (httpStatus) {
2809
2810                     case 12002:
2811                     case 12029:
2812                     case 12030:
2813                     case 12031:
2814                     case 12152:
2815                     case 13030:
2816                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2817                         if (callback.failure) {
2818                             if (!callback.scope) {
2819                                 callback.failure(responseObject);
2820                             }
2821                             else {
2822                                 callback.failure.apply(callback.scope, [responseObject]);
2823                             }
2824                         }
2825                         break;
2826                     default:
2827                         responseObject = this.createResponseObject(o, callback.argument);
2828                         if (callback.failure) {
2829                             if (!callback.scope) {
2830                                 callback.failure(responseObject);
2831                             }
2832                             else {
2833                                 callback.failure.apply(callback.scope, [responseObject]);
2834                             }
2835                         }
2836                 }
2837             }
2838
2839             this.releaseObject(o);
2840             responseObject = null;
2841         },
2842
2843         createResponseObject:function(o, callbackArg)
2844         {
2845             var obj = {};
2846             var headerObj = {};
2847
2848             try
2849             {
2850                 var headerStr = o.conn.getAllResponseHeaders();
2851                 var header = headerStr.split('\n');
2852                 for (var i = 0; i < header.length; i++) {
2853                     var delimitPos = header[i].indexOf(':');
2854                     if (delimitPos != -1) {
2855                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2856                     }
2857                 }
2858             }
2859             catch(e) {
2860             }
2861
2862             obj.tId = o.tId;
2863             obj.status = o.conn.status;
2864             obj.statusText = o.conn.statusText;
2865             obj.getResponseHeader = headerObj;
2866             obj.getAllResponseHeaders = headerStr;
2867             obj.responseText = o.conn.responseText;
2868             obj.responseXML = o.conn.responseXML;
2869
2870             if (typeof callbackArg !== undefined) {
2871                 obj.argument = callbackArg;
2872             }
2873
2874             return obj;
2875         },
2876
2877         createExceptionObject:function(tId, callbackArg, isAbort)
2878         {
2879             var COMM_CODE = 0;
2880             var COMM_ERROR = 'communication failure';
2881             var ABORT_CODE = -1;
2882             var ABORT_ERROR = 'transaction aborted';
2883
2884             var obj = {};
2885
2886             obj.tId = tId;
2887             if (isAbort) {
2888                 obj.status = ABORT_CODE;
2889                 obj.statusText = ABORT_ERROR;
2890             }
2891             else {
2892                 obj.status = COMM_CODE;
2893                 obj.statusText = COMM_ERROR;
2894             }
2895
2896             if (callbackArg) {
2897                 obj.argument = callbackArg;
2898             }
2899
2900             return obj;
2901         },
2902
2903         initHeader:function(label, value, isDefault)
2904         {
2905             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2906
2907             if (headerObj[label] === undefined) {
2908                 headerObj[label] = value;
2909             }
2910             else {
2911
2912
2913                 headerObj[label] = value + "," + headerObj[label];
2914             }
2915
2916             if (isDefault) {
2917                 this.hasDefaultHeaders = true;
2918             }
2919             else {
2920                 this.hasHeaders = true;
2921             }
2922         },
2923
2924
2925         setHeader:function(o)
2926         {
2927             if (this.hasDefaultHeaders) {
2928                 for (var prop in this.defaultHeaders) {
2929                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2930                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2931                     }
2932                 }
2933             }
2934
2935             if (this.hasHeaders) {
2936                 for (var prop in this.headers) {
2937                     if (this.headers.hasOwnProperty(prop)) {
2938                         o.conn.setRequestHeader(prop, this.headers[prop]);
2939                     }
2940                 }
2941                 this.headers = {};
2942                 this.hasHeaders = false;
2943             }
2944         },
2945
2946         resetDefaultHeaders:function() {
2947             delete this.defaultHeaders;
2948             this.defaultHeaders = {};
2949             this.hasDefaultHeaders = false;
2950         },
2951
2952         abort:function(o, callback, isTimeout)
2953         {
2954             if(this.isCallInProgress(o)) {
2955                 o.conn.abort();
2956                 window.clearInterval(this.poll[o.tId]);
2957                 delete this.poll[o.tId];
2958                 if (isTimeout) {
2959                     delete this.timeout[o.tId];
2960                 }
2961
2962                 this.handleTransactionResponse(o, callback, true);
2963
2964                 return true;
2965             }
2966             else {
2967                 return false;
2968             }
2969         },
2970
2971
2972         isCallInProgress:function(o)
2973         {
2974             if (o && o.conn) {
2975                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2976             }
2977             else {
2978
2979                 return false;
2980             }
2981         },
2982
2983
2984         releaseObject:function(o)
2985         {
2986
2987             o.conn = null;
2988
2989             o = null;
2990         },
2991
2992         activeX:[
2993         'MSXML2.XMLHTTP.3.0',
2994         'MSXML2.XMLHTTP',
2995         'Microsoft.XMLHTTP'
2996         ]
2997
2998
2999     };
3000 })();/*
3001  * Portions of this file are based on pieces of Yahoo User Interface Library
3002  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3003  * YUI licensed under the BSD License:
3004  * http://developer.yahoo.net/yui/license.txt
3005  * <script type="text/javascript">
3006  *
3007  */
3008
3009 Roo.lib.Region = function(t, r, b, l) {
3010     this.top = t;
3011     this[1] = t;
3012     this.right = r;
3013     this.bottom = b;
3014     this.left = l;
3015     this[0] = l;
3016 };
3017
3018
3019 Roo.lib.Region.prototype = {
3020     contains : function(region) {
3021         return ( region.left >= this.left &&
3022                  region.right <= this.right &&
3023                  region.top >= this.top &&
3024                  region.bottom <= this.bottom    );
3025
3026     },
3027
3028     getArea : function() {
3029         return ( (this.bottom - this.top) * (this.right - this.left) );
3030     },
3031
3032     intersect : function(region) {
3033         var t = Math.max(this.top, region.top);
3034         var r = Math.min(this.right, region.right);
3035         var b = Math.min(this.bottom, region.bottom);
3036         var l = Math.max(this.left, region.left);
3037
3038         if (b >= t && r >= l) {
3039             return new Roo.lib.Region(t, r, b, l);
3040         } else {
3041             return null;
3042         }
3043     },
3044     union : function(region) {
3045         var t = Math.min(this.top, region.top);
3046         var r = Math.max(this.right, region.right);
3047         var b = Math.max(this.bottom, region.bottom);
3048         var l = Math.min(this.left, region.left);
3049
3050         return new Roo.lib.Region(t, r, b, l);
3051     },
3052
3053     adjust : function(t, l, b, r) {
3054         this.top += t;
3055         this.left += l;
3056         this.right += r;
3057         this.bottom += b;
3058         return this;
3059     }
3060 };
3061
3062 Roo.lib.Region.getRegion = function(el) {
3063     var p = Roo.lib.Dom.getXY(el);
3064
3065     var t = p[1];
3066     var r = p[0] + el.offsetWidth;
3067     var b = p[1] + el.offsetHeight;
3068     var l = p[0];
3069
3070     return new Roo.lib.Region(t, r, b, l);
3071 };
3072 /*
3073  * Portions of this file are based on pieces of Yahoo User Interface Library
3074  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3075  * YUI licensed under the BSD License:
3076  * http://developer.yahoo.net/yui/license.txt
3077  * <script type="text/javascript">
3078  *
3079  */
3080 //@@dep Roo.lib.Region
3081
3082
3083 Roo.lib.Point = function(x, y) {
3084     if (x instanceof Array) {
3085         y = x[1];
3086         x = x[0];
3087     }
3088     this.x = this.right = this.left = this[0] = x;
3089     this.y = this.top = this.bottom = this[1] = y;
3090 };
3091
3092 Roo.lib.Point.prototype = new Roo.lib.Region();
3093 /*
3094  * Portions of this file are based on pieces of Yahoo User Interface Library
3095  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3096  * YUI licensed under the BSD License:
3097  * http://developer.yahoo.net/yui/license.txt
3098  * <script type="text/javascript">
3099  *
3100  */
3101  
3102 (function() {   
3103
3104     Roo.lib.Anim = {
3105         scroll : function(el, args, duration, easing, cb, scope) {
3106             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3107         },
3108
3109         motion : function(el, args, duration, easing, cb, scope) {
3110             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3111         },
3112
3113         color : function(el, args, duration, easing, cb, scope) {
3114             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3115         },
3116
3117         run : function(el, args, duration, easing, cb, scope, type) {
3118             type = type || Roo.lib.AnimBase;
3119             if (typeof easing == "string") {
3120                 easing = Roo.lib.Easing[easing];
3121             }
3122             var anim = new type(el, args, duration, easing);
3123             anim.animateX(function() {
3124                 Roo.callback(cb, scope);
3125             });
3126             return anim;
3127         }
3128     };
3129 })();/*
3130  * Portions of this file are based on pieces of Yahoo User Interface Library
3131  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3132  * YUI licensed under the BSD License:
3133  * http://developer.yahoo.net/yui/license.txt
3134  * <script type="text/javascript">
3135  *
3136  */
3137
3138 (function() {    
3139     var libFlyweight;
3140     
3141     function fly(el) {
3142         if (!libFlyweight) {
3143             libFlyweight = new Roo.Element.Flyweight();
3144         }
3145         libFlyweight.dom = el;
3146         return libFlyweight;
3147     }
3148
3149     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3150     
3151    
3152     
3153     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3154         if (el) {
3155             this.init(el, attributes, duration, method);
3156         }
3157     };
3158
3159     Roo.lib.AnimBase.fly = fly;
3160     
3161     
3162     
3163     Roo.lib.AnimBase.prototype = {
3164
3165         toString: function() {
3166             var el = this.getEl();
3167             var id = el.id || el.tagName;
3168             return ("Anim " + id);
3169         },
3170
3171         patterns: {
3172             noNegatives:        /width|height|opacity|padding/i,
3173             offsetAttribute:  /^((width|height)|(top|left))$/,
3174             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3175             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3176         },
3177
3178
3179         doMethod: function(attr, start, end) {
3180             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3181         },
3182
3183
3184         setAttribute: function(attr, val, unit) {
3185             if (this.patterns.noNegatives.test(attr)) {
3186                 val = (val > 0) ? val : 0;
3187             }
3188
3189             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3190         },
3191
3192
3193         getAttribute: function(attr) {
3194             var el = this.getEl();
3195             var val = fly(el).getStyle(attr);
3196
3197             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3198                 return parseFloat(val);
3199             }
3200
3201             var a = this.patterns.offsetAttribute.exec(attr) || [];
3202             var pos = !!( a[3] );
3203             var box = !!( a[2] );
3204
3205
3206             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3207                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3208             } else {
3209                 val = 0;
3210             }
3211
3212             return val;
3213         },
3214
3215
3216         getDefaultUnit: function(attr) {
3217             if (this.patterns.defaultUnit.test(attr)) {
3218                 return 'px';
3219             }
3220
3221             return '';
3222         },
3223
3224         animateX : function(callback, scope) {
3225             var f = function() {
3226                 this.onComplete.removeListener(f);
3227                 if (typeof callback == "function") {
3228                     callback.call(scope || this, this);
3229                 }
3230             };
3231             this.onComplete.addListener(f, this);
3232             this.animate();
3233         },
3234
3235
3236         setRuntimeAttribute: function(attr) {
3237             var start;
3238             var end;
3239             var attributes = this.attributes;
3240
3241             this.runtimeAttributes[attr] = {};
3242
3243             var isset = function(prop) {
3244                 return (typeof prop !== 'undefined');
3245             };
3246
3247             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3248                 return false;
3249             }
3250
3251             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3252
3253
3254             if (isset(attributes[attr]['to'])) {
3255                 end = attributes[attr]['to'];
3256             } else if (isset(attributes[attr]['by'])) {
3257                 if (start.constructor == Array) {
3258                     end = [];
3259                     for (var i = 0, len = start.length; i < len; ++i) {
3260                         end[i] = start[i] + attributes[attr]['by'][i];
3261                     }
3262                 } else {
3263                     end = start + attributes[attr]['by'];
3264                 }
3265             }
3266
3267             this.runtimeAttributes[attr].start = start;
3268             this.runtimeAttributes[attr].end = end;
3269
3270
3271             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3272         },
3273
3274
3275         init: function(el, attributes, duration, method) {
3276
3277             var isAnimated = false;
3278
3279
3280             var startTime = null;
3281
3282
3283             var actualFrames = 0;
3284
3285
3286             el = Roo.getDom(el);
3287
3288
3289             this.attributes = attributes || {};
3290
3291
3292             this.duration = duration || 1;
3293
3294
3295             this.method = method || Roo.lib.Easing.easeNone;
3296
3297
3298             this.useSeconds = true;
3299
3300
3301             this.currentFrame = 0;
3302
3303
3304             this.totalFrames = Roo.lib.AnimMgr.fps;
3305
3306
3307             this.getEl = function() {
3308                 return el;
3309             };
3310
3311
3312             this.isAnimated = function() {
3313                 return isAnimated;
3314             };
3315
3316
3317             this.getStartTime = function() {
3318                 return startTime;
3319             };
3320
3321             this.runtimeAttributes = {};
3322
3323
3324             this.animate = function() {
3325                 if (this.isAnimated()) {
3326                     return false;
3327                 }
3328
3329                 this.currentFrame = 0;
3330
3331                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3332
3333                 Roo.lib.AnimMgr.registerElement(this);
3334             };
3335
3336
3337             this.stop = function(finish) {
3338                 if (finish) {
3339                     this.currentFrame = this.totalFrames;
3340                     this._onTween.fire();
3341                 }
3342                 Roo.lib.AnimMgr.stop(this);
3343             };
3344
3345             var onStart = function() {
3346                 this.onStart.fire();
3347
3348                 this.runtimeAttributes = {};
3349                 for (var attr in this.attributes) {
3350                     this.setRuntimeAttribute(attr);
3351                 }
3352
3353                 isAnimated = true;
3354                 actualFrames = 0;
3355                 startTime = new Date();
3356             };
3357
3358
3359             var onTween = function() {
3360                 var data = {
3361                     duration: new Date() - this.getStartTime(),
3362                     currentFrame: this.currentFrame
3363                 };
3364
3365                 data.toString = function() {
3366                     return (
3367                             'duration: ' + data.duration +
3368                             ', currentFrame: ' + data.currentFrame
3369                             );
3370                 };
3371
3372                 this.onTween.fire(data);
3373
3374                 var runtimeAttributes = this.runtimeAttributes;
3375
3376                 for (var attr in runtimeAttributes) {
3377                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3378                 }
3379
3380                 actualFrames += 1;
3381             };
3382
3383             var onComplete = function() {
3384                 var actual_duration = (new Date() - startTime) / 1000 ;
3385
3386                 var data = {
3387                     duration: actual_duration,
3388                     frames: actualFrames,
3389                     fps: actualFrames / actual_duration
3390                 };
3391
3392                 data.toString = function() {
3393                     return (
3394                             'duration: ' + data.duration +
3395                             ', frames: ' + data.frames +
3396                             ', fps: ' + data.fps
3397                             );
3398                 };
3399
3400                 isAnimated = false;
3401                 actualFrames = 0;
3402                 this.onComplete.fire(data);
3403             };
3404
3405
3406             this._onStart = new Roo.util.Event(this);
3407             this.onStart = new Roo.util.Event(this);
3408             this.onTween = new Roo.util.Event(this);
3409             this._onTween = new Roo.util.Event(this);
3410             this.onComplete = new Roo.util.Event(this);
3411             this._onComplete = new Roo.util.Event(this);
3412             this._onStart.addListener(onStart);
3413             this._onTween.addListener(onTween);
3414             this._onComplete.addListener(onComplete);
3415         }
3416     };
3417 })();
3418 /*
3419  * Portions of this file are based on pieces of Yahoo User Interface Library
3420  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3421  * YUI licensed under the BSD License:
3422  * http://developer.yahoo.net/yui/license.txt
3423  * <script type="text/javascript">
3424  *
3425  */
3426
3427 Roo.lib.AnimMgr = new function() {
3428
3429     var thread = null;
3430
3431
3432     var queue = [];
3433
3434
3435     var tweenCount = 0;
3436
3437
3438     this.fps = 1000;
3439
3440
3441     this.delay = 1;
3442
3443
3444     this.registerElement = function(tween) {
3445         queue[queue.length] = tween;
3446         tweenCount += 1;
3447         tween._onStart.fire();
3448         this.start();
3449     };
3450
3451
3452     this.unRegister = function(tween, index) {
3453         tween._onComplete.fire();
3454         index = index || getIndex(tween);
3455         if (index != -1) {
3456             queue.splice(index, 1);
3457         }
3458
3459         tweenCount -= 1;
3460         if (tweenCount <= 0) {
3461             this.stop();
3462         }
3463     };
3464
3465
3466     this.start = function() {
3467         if (thread === null) {
3468             thread = setInterval(this.run, this.delay);
3469         }
3470     };
3471
3472
3473     this.stop = function(tween) {
3474         if (!tween) {
3475             clearInterval(thread);
3476
3477             for (var i = 0, len = queue.length; i < len; ++i) {
3478                 if (queue[0].isAnimated()) {
3479                     this.unRegister(queue[0], 0);
3480                 }
3481             }
3482
3483             queue = [];
3484             thread = null;
3485             tweenCount = 0;
3486         }
3487         else {
3488             this.unRegister(tween);
3489         }
3490     };
3491
3492
3493     this.run = function() {
3494         for (var i = 0, len = queue.length; i < len; ++i) {
3495             var tween = queue[i];
3496             if (!tween || !tween.isAnimated()) {
3497                 continue;
3498             }
3499
3500             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3501             {
3502                 tween.currentFrame += 1;
3503
3504                 if (tween.useSeconds) {
3505                     correctFrame(tween);
3506                 }
3507                 tween._onTween.fire();
3508             }
3509             else {
3510                 Roo.lib.AnimMgr.stop(tween, i);
3511             }
3512         }
3513     };
3514
3515     var getIndex = function(anim) {
3516         for (var i = 0, len = queue.length; i < len; ++i) {
3517             if (queue[i] == anim) {
3518                 return i;
3519             }
3520         }
3521         return -1;
3522     };
3523
3524
3525     var correctFrame = function(tween) {
3526         var frames = tween.totalFrames;
3527         var frame = tween.currentFrame;
3528         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3529         var elapsed = (new Date() - tween.getStartTime());
3530         var tweak = 0;
3531
3532         if (elapsed < tween.duration * 1000) {
3533             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3534         } else {
3535             tweak = frames - (frame + 1);
3536         }
3537         if (tweak > 0 && isFinite(tweak)) {
3538             if (tween.currentFrame + tweak >= frames) {
3539                 tweak = frames - (frame + 1);
3540             }
3541
3542             tween.currentFrame += tweak;
3543         }
3544     };
3545 };
3546
3547     /*
3548  * Portions of this file are based on pieces of Yahoo User Interface Library
3549  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3550  * YUI licensed under the BSD License:
3551  * http://developer.yahoo.net/yui/license.txt
3552  * <script type="text/javascript">
3553  *
3554  */
3555 Roo.lib.Bezier = new function() {
3556
3557         this.getPosition = function(points, t) {
3558             var n = points.length;
3559             var tmp = [];
3560
3561             for (var i = 0; i < n; ++i) {
3562                 tmp[i] = [points[i][0], points[i][1]];
3563             }
3564
3565             for (var j = 1; j < n; ++j) {
3566                 for (i = 0; i < n - j; ++i) {
3567                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3568                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3569                 }
3570             }
3571
3572             return [ tmp[0][0], tmp[0][1] ];
3573
3574         };
3575     };/*
3576  * Portions of this file are based on pieces of Yahoo User Interface Library
3577  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3578  * YUI licensed under the BSD License:
3579  * http://developer.yahoo.net/yui/license.txt
3580  * <script type="text/javascript">
3581  *
3582  */
3583 (function() {
3584
3585     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3586         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3587     };
3588
3589     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3590
3591     var fly = Roo.lib.AnimBase.fly;
3592     var Y = Roo.lib;
3593     var superclass = Y.ColorAnim.superclass;
3594     var proto = Y.ColorAnim.prototype;
3595
3596     proto.toString = function() {
3597         var el = this.getEl();
3598         var id = el.id || el.tagName;
3599         return ("ColorAnim " + id);
3600     };
3601
3602     proto.patterns.color = /color$/i;
3603     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3604     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3605     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3606     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3607
3608
3609     proto.parseColor = function(s) {
3610         if (s.length == 3) {
3611             return s;
3612         }
3613
3614         var c = this.patterns.hex.exec(s);
3615         if (c && c.length == 4) {
3616             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3617         }
3618
3619         c = this.patterns.rgb.exec(s);
3620         if (c && c.length == 4) {
3621             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3622         }
3623
3624         c = this.patterns.hex3.exec(s);
3625         if (c && c.length == 4) {
3626             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3627         }
3628
3629         return null;
3630     };
3631     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3632     proto.getAttribute = function(attr) {
3633         var el = this.getEl();
3634         if (this.patterns.color.test(attr)) {
3635             var val = fly(el).getStyle(attr);
3636
3637             if (this.patterns.transparent.test(val)) {
3638                 var parent = el.parentNode;
3639                 val = fly(parent).getStyle(attr);
3640
3641                 while (parent && this.patterns.transparent.test(val)) {
3642                     parent = parent.parentNode;
3643                     val = fly(parent).getStyle(attr);
3644                     if (parent.tagName.toUpperCase() == 'HTML') {
3645                         val = '#fff';
3646                     }
3647                 }
3648             }
3649         } else {
3650             val = superclass.getAttribute.call(this, attr);
3651         }
3652
3653         return val;
3654     };
3655     proto.getAttribute = function(attr) {
3656         var el = this.getEl();
3657         if (this.patterns.color.test(attr)) {
3658             var val = fly(el).getStyle(attr);
3659
3660             if (this.patterns.transparent.test(val)) {
3661                 var parent = el.parentNode;
3662                 val = fly(parent).getStyle(attr);
3663
3664                 while (parent && this.patterns.transparent.test(val)) {
3665                     parent = parent.parentNode;
3666                     val = fly(parent).getStyle(attr);
3667                     if (parent.tagName.toUpperCase() == 'HTML') {
3668                         val = '#fff';
3669                     }
3670                 }
3671             }
3672         } else {
3673             val = superclass.getAttribute.call(this, attr);
3674         }
3675
3676         return val;
3677     };
3678
3679     proto.doMethod = function(attr, start, end) {
3680         var val;
3681
3682         if (this.patterns.color.test(attr)) {
3683             val = [];
3684             for (var i = 0, len = start.length; i < len; ++i) {
3685                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3686             }
3687
3688             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3689         }
3690         else {
3691             val = superclass.doMethod.call(this, attr, start, end);
3692         }
3693
3694         return val;
3695     };
3696
3697     proto.setRuntimeAttribute = function(attr) {
3698         superclass.setRuntimeAttribute.call(this, attr);
3699
3700         if (this.patterns.color.test(attr)) {
3701             var attributes = this.attributes;
3702             var start = this.parseColor(this.runtimeAttributes[attr].start);
3703             var end = this.parseColor(this.runtimeAttributes[attr].end);
3704
3705             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3706                 end = this.parseColor(attributes[attr].by);
3707
3708                 for (var i = 0, len = start.length; i < len; ++i) {
3709                     end[i] = start[i] + end[i];
3710                 }
3711             }
3712
3713             this.runtimeAttributes[attr].start = start;
3714             this.runtimeAttributes[attr].end = end;
3715         }
3716     };
3717 })();
3718
3719 /*
3720  * Portions of this file are based on pieces of Yahoo User Interface Library
3721  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3722  * YUI licensed under the BSD License:
3723  * http://developer.yahoo.net/yui/license.txt
3724  * <script type="text/javascript">
3725  *
3726  */
3727 Roo.lib.Easing = {
3728
3729
3730     easeNone: function (t, b, c, d) {
3731         return c * t / d + b;
3732     },
3733
3734
3735     easeIn: function (t, b, c, d) {
3736         return c * (t /= d) * t + b;
3737     },
3738
3739
3740     easeOut: function (t, b, c, d) {
3741         return -c * (t /= d) * (t - 2) + b;
3742     },
3743
3744
3745     easeBoth: function (t, b, c, d) {
3746         if ((t /= d / 2) < 1) {
3747             return c / 2 * t * t + b;
3748         }
3749
3750         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3751     },
3752
3753
3754     easeInStrong: function (t, b, c, d) {
3755         return c * (t /= d) * t * t * t + b;
3756     },
3757
3758
3759     easeOutStrong: function (t, b, c, d) {
3760         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3761     },
3762
3763
3764     easeBothStrong: function (t, b, c, d) {
3765         if ((t /= d / 2) < 1) {
3766             return c / 2 * t * t * t * t + b;
3767         }
3768
3769         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3770     },
3771
3772
3773
3774     elasticIn: function (t, b, c, d, a, p) {
3775         if (t == 0) {
3776             return b;
3777         }
3778         if ((t /= d) == 1) {
3779             return b + c;
3780         }
3781         if (!p) {
3782             p = d * .3;
3783         }
3784
3785         if (!a || a < Math.abs(c)) {
3786             a = c;
3787             var s = p / 4;
3788         }
3789         else {
3790             var s = p / (2 * Math.PI) * Math.asin(c / a);
3791         }
3792
3793         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3794     },
3795
3796
3797     elasticOut: function (t, b, c, d, a, p) {
3798         if (t == 0) {
3799             return b;
3800         }
3801         if ((t /= d) == 1) {
3802             return b + c;
3803         }
3804         if (!p) {
3805             p = d * .3;
3806         }
3807
3808         if (!a || a < Math.abs(c)) {
3809             a = c;
3810             var s = p / 4;
3811         }
3812         else {
3813             var s = p / (2 * Math.PI) * Math.asin(c / a);
3814         }
3815
3816         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3817     },
3818
3819
3820     elasticBoth: function (t, b, c, d, a, p) {
3821         if (t == 0) {
3822             return b;
3823         }
3824
3825         if ((t /= d / 2) == 2) {
3826             return b + c;
3827         }
3828
3829         if (!p) {
3830             p = d * (.3 * 1.5);
3831         }
3832
3833         if (!a || a < Math.abs(c)) {
3834             a = c;
3835             var s = p / 4;
3836         }
3837         else {
3838             var s = p / (2 * Math.PI) * Math.asin(c / a);
3839         }
3840
3841         if (t < 1) {
3842             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3843                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3844         }
3845         return a * Math.pow(2, -10 * (t -= 1)) *
3846                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3847     },
3848
3849
3850
3851     backIn: function (t, b, c, d, s) {
3852         if (typeof s == 'undefined') {
3853             s = 1.70158;
3854         }
3855         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3856     },
3857
3858
3859     backOut: function (t, b, c, d, s) {
3860         if (typeof s == 'undefined') {
3861             s = 1.70158;
3862         }
3863         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3864     },
3865
3866
3867     backBoth: function (t, b, c, d, s) {
3868         if (typeof s == 'undefined') {
3869             s = 1.70158;
3870         }
3871
3872         if ((t /= d / 2 ) < 1) {
3873             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3874         }
3875         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3876     },
3877
3878
3879     bounceIn: function (t, b, c, d) {
3880         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3881     },
3882
3883
3884     bounceOut: function (t, b, c, d) {
3885         if ((t /= d) < (1 / 2.75)) {
3886             return c * (7.5625 * t * t) + b;
3887         } else if (t < (2 / 2.75)) {
3888             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3889         } else if (t < (2.5 / 2.75)) {
3890             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3891         }
3892         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3893     },
3894
3895
3896     bounceBoth: function (t, b, c, d) {
3897         if (t < d / 2) {
3898             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3899         }
3900         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3901     }
3902 };/*
3903  * Portions of this file are based on pieces of Yahoo User Interface Library
3904  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3905  * YUI licensed under the BSD License:
3906  * http://developer.yahoo.net/yui/license.txt
3907  * <script type="text/javascript">
3908  *
3909  */
3910     (function() {
3911         Roo.lib.Motion = function(el, attributes, duration, method) {
3912             if (el) {
3913                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3914             }
3915         };
3916
3917         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3918
3919
3920         var Y = Roo.lib;
3921         var superclass = Y.Motion.superclass;
3922         var proto = Y.Motion.prototype;
3923
3924         proto.toString = function() {
3925             var el = this.getEl();
3926             var id = el.id || el.tagName;
3927             return ("Motion " + id);
3928         };
3929
3930         proto.patterns.points = /^points$/i;
3931
3932         proto.setAttribute = function(attr, val, unit) {
3933             if (this.patterns.points.test(attr)) {
3934                 unit = unit || 'px';
3935                 superclass.setAttribute.call(this, 'left', val[0], unit);
3936                 superclass.setAttribute.call(this, 'top', val[1], unit);
3937             } else {
3938                 superclass.setAttribute.call(this, attr, val, unit);
3939             }
3940         };
3941
3942         proto.getAttribute = function(attr) {
3943             if (this.patterns.points.test(attr)) {
3944                 var val = [
3945                         superclass.getAttribute.call(this, 'left'),
3946                         superclass.getAttribute.call(this, 'top')
3947                         ];
3948             } else {
3949                 val = superclass.getAttribute.call(this, attr);
3950             }
3951
3952             return val;
3953         };
3954
3955         proto.doMethod = function(attr, start, end) {
3956             var val = null;
3957
3958             if (this.patterns.points.test(attr)) {
3959                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3960                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3961             } else {
3962                 val = superclass.doMethod.call(this, attr, start, end);
3963             }
3964             return val;
3965         };
3966
3967         proto.setRuntimeAttribute = function(attr) {
3968             if (this.patterns.points.test(attr)) {
3969                 var el = this.getEl();
3970                 var attributes = this.attributes;
3971                 var start;
3972                 var control = attributes['points']['control'] || [];
3973                 var end;
3974                 var i, len;
3975
3976                 if (control.length > 0 && !(control[0] instanceof Array)) {
3977                     control = [control];
3978                 } else {
3979                     var tmp = [];
3980                     for (i = 0,len = control.length; i < len; ++i) {
3981                         tmp[i] = control[i];
3982                     }
3983                     control = tmp;
3984                 }
3985
3986                 Roo.fly(el).position();
3987
3988                 if (isset(attributes['points']['from'])) {
3989                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3990                 }
3991                 else {
3992                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3993                 }
3994
3995                 start = this.getAttribute('points');
3996
3997
3998                 if (isset(attributes['points']['to'])) {
3999                     end = translateValues.call(this, attributes['points']['to'], start);
4000
4001                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4002                     for (i = 0,len = control.length; i < len; ++i) {
4003                         control[i] = translateValues.call(this, control[i], start);
4004                     }
4005
4006
4007                 } else if (isset(attributes['points']['by'])) {
4008                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4009
4010                     for (i = 0,len = control.length; i < len; ++i) {
4011                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4012                     }
4013                 }
4014
4015                 this.runtimeAttributes[attr] = [start];
4016
4017                 if (control.length > 0) {
4018                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4019                 }
4020
4021                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4022             }
4023             else {
4024                 superclass.setRuntimeAttribute.call(this, attr);
4025             }
4026         };
4027
4028         var translateValues = function(val, start) {
4029             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4030             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4031
4032             return val;
4033         };
4034
4035         var isset = function(prop) {
4036             return (typeof prop !== 'undefined');
4037         };
4038     })();
4039 /*
4040  * Portions of this file are based on pieces of Yahoo User Interface Library
4041  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4042  * YUI licensed under the BSD License:
4043  * http://developer.yahoo.net/yui/license.txt
4044  * <script type="text/javascript">
4045  *
4046  */
4047     (function() {
4048         Roo.lib.Scroll = function(el, attributes, duration, method) {
4049             if (el) {
4050                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4051             }
4052         };
4053
4054         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4055
4056
4057         var Y = Roo.lib;
4058         var superclass = Y.Scroll.superclass;
4059         var proto = Y.Scroll.prototype;
4060
4061         proto.toString = function() {
4062             var el = this.getEl();
4063             var id = el.id || el.tagName;
4064             return ("Scroll " + id);
4065         };
4066
4067         proto.doMethod = function(attr, start, end) {
4068             var val = null;
4069
4070             if (attr == 'scroll') {
4071                 val = [
4072                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4073                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4074                         ];
4075
4076             } else {
4077                 val = superclass.doMethod.call(this, attr, start, end);
4078             }
4079             return val;
4080         };
4081
4082         proto.getAttribute = function(attr) {
4083             var val = null;
4084             var el = this.getEl();
4085
4086             if (attr == 'scroll') {
4087                 val = [ el.scrollLeft, el.scrollTop ];
4088             } else {
4089                 val = superclass.getAttribute.call(this, attr);
4090             }
4091
4092             return val;
4093         };
4094
4095         proto.setAttribute = function(attr, val, unit) {
4096             var el = this.getEl();
4097
4098             if (attr == 'scroll') {
4099                 el.scrollLeft = val[0];
4100                 el.scrollTop = val[1];
4101             } else {
4102                 superclass.setAttribute.call(this, attr, val, unit);
4103             }
4104         };
4105     })();
4106 /*
4107  * Based on:
4108  * Ext JS Library 1.1.1
4109  * Copyright(c) 2006-2007, Ext JS, LLC.
4110  *
4111  * Originally Released Under LGPL - original licence link has changed is not relivant.
4112  *
4113  * Fork - LGPL
4114  * <script type="text/javascript">
4115  */
4116
4117
4118 // nasty IE9 hack - what a pile of crap that is..
4119
4120  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4121     Range.prototype.createContextualFragment = function (html) {
4122         var doc = window.document;
4123         var container = doc.createElement("div");
4124         container.innerHTML = html;
4125         var frag = doc.createDocumentFragment(), n;
4126         while ((n = container.firstChild)) {
4127             frag.appendChild(n);
4128         }
4129         return frag;
4130     };
4131 }
4132
4133 /**
4134  * @class Roo.DomHelper
4135  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4136  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4137  * @singleton
4138  */
4139 Roo.DomHelper = function(){
4140     var tempTableEl = null;
4141     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4142     var tableRe = /^table|tbody|tr|td$/i;
4143     var xmlns = {};
4144     // build as innerHTML where available
4145     /** @ignore */
4146     var createHtml = function(o){
4147         if(typeof o == 'string'){
4148             return o;
4149         }
4150         var b = "";
4151         if(!o.tag){
4152             o.tag = "div";
4153         }
4154         b += "<" + o.tag;
4155         for(var attr in o){
4156             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4157             if(attr == "style"){
4158                 var s = o["style"];
4159                 if(typeof s == "function"){
4160                     s = s.call();
4161                 }
4162                 if(typeof s == "string"){
4163                     b += ' style="' + s + '"';
4164                 }else if(typeof s == "object"){
4165                     b += ' style="';
4166                     for(var key in s){
4167                         if(typeof s[key] != "function"){
4168                             b += key + ":" + s[key] + ";";
4169                         }
4170                     }
4171                     b += '"';
4172                 }
4173             }else{
4174                 if(attr == "cls"){
4175                     b += ' class="' + o["cls"] + '"';
4176                 }else if(attr == "htmlFor"){
4177                     b += ' for="' + o["htmlFor"] + '"';
4178                 }else{
4179                     b += " " + attr + '="' + o[attr] + '"';
4180                 }
4181             }
4182         }
4183         if(emptyTags.test(o.tag)){
4184             b += "/>";
4185         }else{
4186             b += ">";
4187             var cn = o.children || o.cn;
4188             if(cn){
4189                 //http://bugs.kde.org/show_bug.cgi?id=71506
4190                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4191                     for(var i = 0, len = cn.length; i < len; i++) {
4192                         b += createHtml(cn[i], b);
4193                     }
4194                 }else{
4195                     b += createHtml(cn, b);
4196                 }
4197             }
4198             if(o.html){
4199                 b += o.html;
4200             }
4201             b += "</" + o.tag + ">";
4202         }
4203         return b;
4204     };
4205
4206     // build as dom
4207     /** @ignore */
4208     var createDom = function(o, parentNode){
4209          
4210         // defininition craeted..
4211         var ns = false;
4212         if (o.ns && o.ns != 'html') {
4213                
4214             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4215                 xmlns[o.ns] = o.xmlns;
4216                 ns = o.xmlns;
4217             }
4218             if (typeof(xmlns[o.ns]) == 'undefined') {
4219                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4220             }
4221             ns = xmlns[o.ns];
4222         }
4223         
4224         
4225         if (typeof(o) == 'string') {
4226             return parentNode.appendChild(document.createTextNode(o));
4227         }
4228         o.tag = o.tag || div;
4229         if (o.ns && Roo.isIE) {
4230             ns = false;
4231             o.tag = o.ns + ':' + o.tag;
4232             
4233         }
4234         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4235         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4236         for(var attr in o){
4237             
4238             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4239                     attr == "style" || typeof o[attr] == "function") { continue; }
4240                     
4241             if(attr=="cls" && Roo.isIE){
4242                 el.className = o["cls"];
4243             }else{
4244                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4245                 else { 
4246                     el[attr] = o[attr];
4247                 }
4248             }
4249         }
4250         Roo.DomHelper.applyStyles(el, o.style);
4251         var cn = o.children || o.cn;
4252         if(cn){
4253             //http://bugs.kde.org/show_bug.cgi?id=71506
4254              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4255                 for(var i = 0, len = cn.length; i < len; i++) {
4256                     createDom(cn[i], el);
4257                 }
4258             }else{
4259                 createDom(cn, el);
4260             }
4261         }
4262         if(o.html){
4263             el.innerHTML = o.html;
4264         }
4265         if(parentNode){
4266            parentNode.appendChild(el);
4267         }
4268         return el;
4269     };
4270
4271     var ieTable = function(depth, s, h, e){
4272         tempTableEl.innerHTML = [s, h, e].join('');
4273         var i = -1, el = tempTableEl;
4274         while(++i < depth){
4275             el = el.firstChild;
4276         }
4277         return el;
4278     };
4279
4280     // kill repeat to save bytes
4281     var ts = '<table>',
4282         te = '</table>',
4283         tbs = ts+'<tbody>',
4284         tbe = '</tbody>'+te,
4285         trs = tbs + '<tr>',
4286         tre = '</tr>'+tbe;
4287
4288     /**
4289      * @ignore
4290      * Nasty code for IE's broken table implementation
4291      */
4292     var insertIntoTable = function(tag, where, el, html){
4293         if(!tempTableEl){
4294             tempTableEl = document.createElement('div');
4295         }
4296         var node;
4297         var before = null;
4298         if(tag == 'td'){
4299             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4300                 return;
4301             }
4302             if(where == 'beforebegin'){
4303                 before = el;
4304                 el = el.parentNode;
4305             } else{
4306                 before = el.nextSibling;
4307                 el = el.parentNode;
4308             }
4309             node = ieTable(4, trs, html, tre);
4310         }
4311         else if(tag == 'tr'){
4312             if(where == 'beforebegin'){
4313                 before = el;
4314                 el = el.parentNode;
4315                 node = ieTable(3, tbs, html, tbe);
4316             } else if(where == 'afterend'){
4317                 before = el.nextSibling;
4318                 el = el.parentNode;
4319                 node = ieTable(3, tbs, html, tbe);
4320             } else{ // INTO a TR
4321                 if(where == 'afterbegin'){
4322                     before = el.firstChild;
4323                 }
4324                 node = ieTable(4, trs, html, tre);
4325             }
4326         } else if(tag == 'tbody'){
4327             if(where == 'beforebegin'){
4328                 before = el;
4329                 el = el.parentNode;
4330                 node = ieTable(2, ts, html, te);
4331             } else if(where == 'afterend'){
4332                 before = el.nextSibling;
4333                 el = el.parentNode;
4334                 node = ieTable(2, ts, html, te);
4335             } else{
4336                 if(where == 'afterbegin'){
4337                     before = el.firstChild;
4338                 }
4339                 node = ieTable(3, tbs, html, tbe);
4340             }
4341         } else{ // TABLE
4342             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4343                 return;
4344             }
4345             if(where == 'afterbegin'){
4346                 before = el.firstChild;
4347             }
4348             node = ieTable(2, ts, html, te);
4349         }
4350         el.insertBefore(node, before);
4351         return node;
4352     };
4353
4354     return {
4355     /** True to force the use of DOM instead of html fragments @type Boolean */
4356     useDom : false,
4357
4358     /**
4359      * Returns the markup for the passed Element(s) config
4360      * @param {Object} o The Dom object spec (and children)
4361      * @return {String}
4362      */
4363     markup : function(o){
4364         return createHtml(o);
4365     },
4366
4367     /**
4368      * Applies a style specification to an element
4369      * @param {String/HTMLElement} el The element to apply styles to
4370      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4371      * a function which returns such a specification.
4372      */
4373     applyStyles : function(el, styles){
4374         if(styles){
4375            el = Roo.fly(el);
4376            if(typeof styles == "string"){
4377                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4378                var matches;
4379                while ((matches = re.exec(styles)) != null){
4380                    el.setStyle(matches[1], matches[2]);
4381                }
4382            }else if (typeof styles == "object"){
4383                for (var style in styles){
4384                   el.setStyle(style, styles[style]);
4385                }
4386            }else if (typeof styles == "function"){
4387                 Roo.DomHelper.applyStyles(el, styles.call());
4388            }
4389         }
4390     },
4391
4392     /**
4393      * Inserts an HTML fragment into the Dom
4394      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4395      * @param {HTMLElement} el The context element
4396      * @param {String} html The HTML fragmenet
4397      * @return {HTMLElement} The new node
4398      */
4399     insertHtml : function(where, el, html){
4400         where = where.toLowerCase();
4401         if(el.insertAdjacentHTML){
4402             if(tableRe.test(el.tagName)){
4403                 var rs;
4404                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4405                     return rs;
4406                 }
4407             }
4408             switch(where){
4409                 case "beforebegin":
4410                     el.insertAdjacentHTML('BeforeBegin', html);
4411                     return el.previousSibling;
4412                 case "afterbegin":
4413                     el.insertAdjacentHTML('AfterBegin', html);
4414                     return el.firstChild;
4415                 case "beforeend":
4416                     el.insertAdjacentHTML('BeforeEnd', html);
4417                     return el.lastChild;
4418                 case "afterend":
4419                     el.insertAdjacentHTML('AfterEnd', html);
4420                     return el.nextSibling;
4421             }
4422             throw 'Illegal insertion point -> "' + where + '"';
4423         }
4424         var range = el.ownerDocument.createRange();
4425         var frag;
4426         switch(where){
4427              case "beforebegin":
4428                 range.setStartBefore(el);
4429                 frag = range.createContextualFragment(html);
4430                 el.parentNode.insertBefore(frag, el);
4431                 return el.previousSibling;
4432              case "afterbegin":
4433                 if(el.firstChild){
4434                     range.setStartBefore(el.firstChild);
4435                     frag = range.createContextualFragment(html);
4436                     el.insertBefore(frag, el.firstChild);
4437                     return el.firstChild;
4438                 }else{
4439                     el.innerHTML = html;
4440                     return el.firstChild;
4441                 }
4442             case "beforeend":
4443                 if(el.lastChild){
4444                     range.setStartAfter(el.lastChild);
4445                     frag = range.createContextualFragment(html);
4446                     el.appendChild(frag);
4447                     return el.lastChild;
4448                 }else{
4449                     el.innerHTML = html;
4450                     return el.lastChild;
4451                 }
4452             case "afterend":
4453                 range.setStartAfter(el);
4454                 frag = range.createContextualFragment(html);
4455                 el.parentNode.insertBefore(frag, el.nextSibling);
4456                 return el.nextSibling;
4457             }
4458             throw 'Illegal insertion point -> "' + where + '"';
4459     },
4460
4461     /**
4462      * Creates new Dom element(s) and inserts them before el
4463      * @param {String/HTMLElement/Element} el The context element
4464      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4465      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4466      * @return {HTMLElement/Roo.Element} The new node
4467      */
4468     insertBefore : function(el, o, returnElement){
4469         return this.doInsert(el, o, returnElement, "beforeBegin");
4470     },
4471
4472     /**
4473      * Creates new Dom element(s) and inserts them after el
4474      * @param {String/HTMLElement/Element} el The context element
4475      * @param {Object} o The Dom object spec (and children)
4476      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4477      * @return {HTMLElement/Roo.Element} The new node
4478      */
4479     insertAfter : function(el, o, returnElement){
4480         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4481     },
4482
4483     /**
4484      * Creates new Dom element(s) and inserts them as the first child of el
4485      * @param {String/HTMLElement/Element} el The context element
4486      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4487      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4488      * @return {HTMLElement/Roo.Element} The new node
4489      */
4490     insertFirst : function(el, o, returnElement){
4491         return this.doInsert(el, o, returnElement, "afterBegin");
4492     },
4493
4494     // private
4495     doInsert : function(el, o, returnElement, pos, sibling){
4496         el = Roo.getDom(el);
4497         var newNode;
4498         if(this.useDom || o.ns){
4499             newNode = createDom(o, null);
4500             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4501         }else{
4502             var html = createHtml(o);
4503             newNode = this.insertHtml(pos, el, html);
4504         }
4505         return returnElement ? Roo.get(newNode, true) : newNode;
4506     },
4507
4508     /**
4509      * Creates new Dom element(s) and appends them to el
4510      * @param {String/HTMLElement/Element} el The context element
4511      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4512      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4513      * @return {HTMLElement/Roo.Element} The new node
4514      */
4515     append : function(el, o, returnElement){
4516         el = Roo.getDom(el);
4517         var newNode;
4518         if(this.useDom || o.ns){
4519             newNode = createDom(o, null);
4520             el.appendChild(newNode);
4521         }else{
4522             var html = createHtml(o);
4523             newNode = this.insertHtml("beforeEnd", el, html);
4524         }
4525         return returnElement ? Roo.get(newNode, true) : newNode;
4526     },
4527
4528     /**
4529      * Creates new Dom element(s) and overwrites the contents of el with them
4530      * @param {String/HTMLElement/Element} el The context element
4531      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4532      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4533      * @return {HTMLElement/Roo.Element} The new node
4534      */
4535     overwrite : function(el, o, returnElement){
4536         el = Roo.getDom(el);
4537         if (o.ns) {
4538           
4539             while (el.childNodes.length) {
4540                 el.removeChild(el.firstChild);
4541             }
4542             createDom(o, el);
4543         } else {
4544             el.innerHTML = createHtml(o);   
4545         }
4546         
4547         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4548     },
4549
4550     /**
4551      * Creates a new Roo.DomHelper.Template from the Dom object spec
4552      * @param {Object} o The Dom object spec (and children)
4553      * @return {Roo.DomHelper.Template} The new template
4554      */
4555     createTemplate : function(o){
4556         var html = createHtml(o);
4557         return new Roo.Template(html);
4558     }
4559     };
4560 }();
4561 /*
4562  * Based on:
4563  * Ext JS Library 1.1.1
4564  * Copyright(c) 2006-2007, Ext JS, LLC.
4565  *
4566  * Originally Released Under LGPL - original licence link has changed is not relivant.
4567  *
4568  * Fork - LGPL
4569  * <script type="text/javascript">
4570  */
4571  
4572 /**
4573 * @class Roo.Template
4574 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4575 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4576 * Usage:
4577 <pre><code>
4578 var t = new Roo.Template({
4579     html :  '&lt;div name="{id}"&gt;' + 
4580         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4581         '&lt;/div&gt;',
4582     myformat: function (value, allValues) {
4583         return 'XX' + value;
4584     }
4585 });
4586 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4587 </code></pre>
4588 * For more information see this blog post with examples:
4589 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4590      - Create Elements using DOM, HTML fragments and Templates</a>. 
4591 * @constructor
4592 * @param {Object} cfg - Configuration object.
4593 */
4594 Roo.Template = function(cfg){
4595     // BC!
4596     if(cfg instanceof Array){
4597         cfg = cfg.join("");
4598     }else if(arguments.length > 1){
4599         cfg = Array.prototype.join.call(arguments, "");
4600     }
4601     
4602     
4603     if (typeof(cfg) == 'object') {
4604         Roo.apply(this,cfg)
4605     } else {
4606         // bc
4607         this.html = cfg;
4608     }
4609     if (this.url) {
4610         this.load();
4611     }
4612     
4613 };
4614 Roo.Template.prototype = {
4615     
4616     /**
4617      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4618      *                    it should be fixed so that template is observable...
4619      */
4620     url : false,
4621     /**
4622      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4623      */
4624     html : '',
4625     /**
4626      * Returns an HTML fragment of this template with the specified values applied.
4627      * @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'})
4628      * @return {String} The HTML fragment
4629      */
4630     applyTemplate : function(values){
4631         try {
4632            
4633             if(this.compiled){
4634                 return this.compiled(values);
4635             }
4636             var useF = this.disableFormats !== true;
4637             var fm = Roo.util.Format, tpl = this;
4638             var fn = function(m, name, format, args){
4639                 if(format && useF){
4640                     if(format.substr(0, 5) == "this."){
4641                         return tpl.call(format.substr(5), values[name], values);
4642                     }else{
4643                         if(args){
4644                             // quoted values are required for strings in compiled templates, 
4645                             // but for non compiled we need to strip them
4646                             // quoted reversed for jsmin
4647                             var re = /^\s*['"](.*)["']\s*$/;
4648                             args = args.split(',');
4649                             for(var i = 0, len = args.length; i < len; i++){
4650                                 args[i] = args[i].replace(re, "$1");
4651                             }
4652                             args = [values[name]].concat(args);
4653                         }else{
4654                             args = [values[name]];
4655                         }
4656                         return fm[format].apply(fm, args);
4657                     }
4658                 }else{
4659                     return values[name] !== undefined ? values[name] : "";
4660                 }
4661             };
4662             return this.html.replace(this.re, fn);
4663         } catch (e) {
4664             Roo.log(e);
4665             throw e;
4666         }
4667          
4668     },
4669     
4670     loading : false,
4671       
4672     load : function ()
4673     {
4674          
4675         if (this.loading) {
4676             return;
4677         }
4678         var _t = this;
4679         
4680         this.loading = true;
4681         this.compiled = false;
4682         
4683         var cx = new Roo.data.Connection();
4684         cx.request({
4685             url : this.url,
4686             method : 'GET',
4687             success : function (response) {
4688                 _t.loading = false;
4689                 _t.html = response.responseText;
4690                 _t.url = false;
4691                 _t.compile();
4692              },
4693             failure : function(response) {
4694                 Roo.log("Template failed to load from " + _t.url);
4695                 _t.loading = false;
4696             }
4697         });
4698     },
4699
4700     /**
4701      * Sets the HTML used as the template and optionally compiles it.
4702      * @param {String} html
4703      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4704      * @return {Roo.Template} this
4705      */
4706     set : function(html, compile){
4707         this.html = html;
4708         this.compiled = null;
4709         if(compile){
4710             this.compile();
4711         }
4712         return this;
4713     },
4714     
4715     /**
4716      * True to disable format functions (defaults to false)
4717      * @type Boolean
4718      */
4719     disableFormats : false,
4720     
4721     /**
4722     * The regular expression used to match template variables 
4723     * @type RegExp
4724     * @property 
4725     */
4726     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4727     
4728     /**
4729      * Compiles the template into an internal function, eliminating the RegEx overhead.
4730      * @return {Roo.Template} this
4731      */
4732     compile : function(){
4733         var fm = Roo.util.Format;
4734         var useF = this.disableFormats !== true;
4735         var sep = Roo.isGecko ? "+" : ",";
4736         var fn = function(m, name, format, args){
4737             if(format && useF){
4738                 args = args ? ',' + args : "";
4739                 if(format.substr(0, 5) != "this."){
4740                     format = "fm." + format + '(';
4741                 }else{
4742                     format = 'this.call("'+ format.substr(5) + '", ';
4743                     args = ", values";
4744                 }
4745             }else{
4746                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4747             }
4748             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4749         };
4750         var body;
4751         // branched to use + in gecko and [].join() in others
4752         if(Roo.isGecko){
4753             body = "this.compiled = function(values){ return '" +
4754                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4755                     "';};";
4756         }else{
4757             body = ["this.compiled = function(values){ return ['"];
4758             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4759             body.push("'].join('');};");
4760             body = body.join('');
4761         }
4762         /**
4763          * eval:var:values
4764          * eval:var:fm
4765          */
4766         eval(body);
4767         return this;
4768     },
4769     
4770     // private function used to call members
4771     call : function(fnName, value, allValues){
4772         return this[fnName](value, allValues);
4773     },
4774     
4775     /**
4776      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4777      * @param {String/HTMLElement/Roo.Element} el The context element
4778      * @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'})
4779      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4780      * @return {HTMLElement/Roo.Element} The new node or Element
4781      */
4782     insertFirst: function(el, values, returnElement){
4783         return this.doInsert('afterBegin', el, values, returnElement);
4784     },
4785
4786     /**
4787      * Applies the supplied values to the template and inserts the new node(s) before el.
4788      * @param {String/HTMLElement/Roo.Element} el The context element
4789      * @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'})
4790      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4791      * @return {HTMLElement/Roo.Element} The new node or Element
4792      */
4793     insertBefore: function(el, values, returnElement){
4794         return this.doInsert('beforeBegin', el, values, returnElement);
4795     },
4796
4797     /**
4798      * Applies the supplied values to the template and inserts the new node(s) after el.
4799      * @param {String/HTMLElement/Roo.Element} el The context element
4800      * @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'})
4801      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4802      * @return {HTMLElement/Roo.Element} The new node or Element
4803      */
4804     insertAfter : function(el, values, returnElement){
4805         return this.doInsert('afterEnd', el, values, returnElement);
4806     },
4807     
4808     /**
4809      * Applies the supplied values to the template and appends the new node(s) to el.
4810      * @param {String/HTMLElement/Roo.Element} el The context element
4811      * @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'})
4812      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4813      * @return {HTMLElement/Roo.Element} The new node or Element
4814      */
4815     append : function(el, values, returnElement){
4816         return this.doInsert('beforeEnd', el, values, returnElement);
4817     },
4818
4819     doInsert : function(where, el, values, returnEl){
4820         el = Roo.getDom(el);
4821         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4822         return returnEl ? Roo.get(newNode, true) : newNode;
4823     },
4824
4825     /**
4826      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4827      * @param {String/HTMLElement/Roo.Element} el The context element
4828      * @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'})
4829      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4830      * @return {HTMLElement/Roo.Element} The new node or Element
4831      */
4832     overwrite : function(el, values, returnElement){
4833         el = Roo.getDom(el);
4834         el.innerHTML = this.applyTemplate(values);
4835         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4836     }
4837 };
4838 /**
4839  * Alias for {@link #applyTemplate}
4840  * @method
4841  */
4842 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4843
4844 // backwards compat
4845 Roo.DomHelper.Template = Roo.Template;
4846
4847 /**
4848  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4849  * @param {String/HTMLElement} el A DOM element or its id
4850  * @returns {Roo.Template} The created template
4851  * @static
4852  */
4853 Roo.Template.from = function(el){
4854     el = Roo.getDom(el);
4855     return new Roo.Template(el.value || el.innerHTML);
4856 };/*
4857  * Based on:
4858  * Ext JS Library 1.1.1
4859  * Copyright(c) 2006-2007, Ext JS, LLC.
4860  *
4861  * Originally Released Under LGPL - original licence link has changed is not relivant.
4862  *
4863  * Fork - LGPL
4864  * <script type="text/javascript">
4865  */
4866  
4867
4868 /*
4869  * This is code is also distributed under MIT license for use
4870  * with jQuery and prototype JavaScript libraries.
4871  */
4872 /**
4873  * @class Roo.DomQuery
4874 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).
4875 <p>
4876 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>
4877
4878 <p>
4879 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.
4880 </p>
4881 <h4>Element Selectors:</h4>
4882 <ul class="list">
4883     <li> <b>*</b> any element</li>
4884     <li> <b>E</b> an element with the tag E</li>
4885     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4886     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4887     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4888     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4889 </ul>
4890 <h4>Attribute Selectors:</h4>
4891 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4892 <ul class="list">
4893     <li> <b>E[foo]</b> has an attribute "foo"</li>
4894     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4895     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4896     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4897     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4898     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4899     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4900 </ul>
4901 <h4>Pseudo Classes:</h4>
4902 <ul class="list">
4903     <li> <b>E:first-child</b> E is the first child of its parent</li>
4904     <li> <b>E:last-child</b> E is the last child of its parent</li>
4905     <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>
4906     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4907     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4908     <li> <b>E:only-child</b> E is the only child of its parent</li>
4909     <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>
4910     <li> <b>E:first</b> the first E in the resultset</li>
4911     <li> <b>E:last</b> the last E in the resultset</li>
4912     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4913     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4914     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4915     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4916     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4917     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4918     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4919     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4920     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4921 </ul>
4922 <h4>CSS Value Selectors:</h4>
4923 <ul class="list">
4924     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4925     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4926     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4927     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4928     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4929     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4930 </ul>
4931  * @singleton
4932  */
4933 Roo.DomQuery = function(){
4934     var cache = {}, simpleCache = {}, valueCache = {};
4935     var nonSpace = /\S/;
4936     var trimRe = /^\s+|\s+$/g;
4937     var tplRe = /\{(\d+)\}/g;
4938     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4939     var tagTokenRe = /^(#)?([\w-\*]+)/;
4940     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4941
4942     function child(p, index){
4943         var i = 0;
4944         var n = p.firstChild;
4945         while(n){
4946             if(n.nodeType == 1){
4947                if(++i == index){
4948                    return n;
4949                }
4950             }
4951             n = n.nextSibling;
4952         }
4953         return null;
4954     };
4955
4956     function next(n){
4957         while((n = n.nextSibling) && n.nodeType != 1);
4958         return n;
4959     };
4960
4961     function prev(n){
4962         while((n = n.previousSibling) && n.nodeType != 1);
4963         return n;
4964     };
4965
4966     function children(d){
4967         var n = d.firstChild, ni = -1;
4968             while(n){
4969                 var nx = n.nextSibling;
4970                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4971                     d.removeChild(n);
4972                 }else{
4973                     n.nodeIndex = ++ni;
4974                 }
4975                 n = nx;
4976             }
4977             return this;
4978         };
4979
4980     function byClassName(c, a, v){
4981         if(!v){
4982             return c;
4983         }
4984         var r = [], ri = -1, cn;
4985         for(var i = 0, ci; ci = c[i]; i++){
4986             if((' '+ci.className+' ').indexOf(v) != -1){
4987                 r[++ri] = ci;
4988             }
4989         }
4990         return r;
4991     };
4992
4993     function attrValue(n, attr){
4994         if(!n.tagName && typeof n.length != "undefined"){
4995             n = n[0];
4996         }
4997         if(!n){
4998             return null;
4999         }
5000         if(attr == "for"){
5001             return n.htmlFor;
5002         }
5003         if(attr == "class" || attr == "className"){
5004             return n.className;
5005         }
5006         return n.getAttribute(attr) || n[attr];
5007
5008     };
5009
5010     function getNodes(ns, mode, tagName){
5011         var result = [], ri = -1, cs;
5012         if(!ns){
5013             return result;
5014         }
5015         tagName = tagName || "*";
5016         if(typeof ns.getElementsByTagName != "undefined"){
5017             ns = [ns];
5018         }
5019         if(!mode){
5020             for(var i = 0, ni; ni = ns[i]; i++){
5021                 cs = ni.getElementsByTagName(tagName);
5022                 for(var j = 0, ci; ci = cs[j]; j++){
5023                     result[++ri] = ci;
5024                 }
5025             }
5026         }else if(mode == "/" || mode == ">"){
5027             var utag = tagName.toUpperCase();
5028             for(var i = 0, ni, cn; ni = ns[i]; i++){
5029                 cn = ni.children || ni.childNodes;
5030                 for(var j = 0, cj; cj = cn[j]; j++){
5031                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5032                         result[++ri] = cj;
5033                     }
5034                 }
5035             }
5036         }else if(mode == "+"){
5037             var utag = tagName.toUpperCase();
5038             for(var i = 0, n; n = ns[i]; i++){
5039                 while((n = n.nextSibling) && n.nodeType != 1);
5040                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5041                     result[++ri] = n;
5042                 }
5043             }
5044         }else if(mode == "~"){
5045             for(var i = 0, n; n = ns[i]; i++){
5046                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5047                 if(n){
5048                     result[++ri] = n;
5049                 }
5050             }
5051         }
5052         return result;
5053     };
5054
5055     function concat(a, b){
5056         if(b.slice){
5057             return a.concat(b);
5058         }
5059         for(var i = 0, l = b.length; i < l; i++){
5060             a[a.length] = b[i];
5061         }
5062         return a;
5063     }
5064
5065     function byTag(cs, tagName){
5066         if(cs.tagName || cs == document){
5067             cs = [cs];
5068         }
5069         if(!tagName){
5070             return cs;
5071         }
5072         var r = [], ri = -1;
5073         tagName = tagName.toLowerCase();
5074         for(var i = 0, ci; ci = cs[i]; i++){
5075             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5076                 r[++ri] = ci;
5077             }
5078         }
5079         return r;
5080     };
5081
5082     function byId(cs, attr, id){
5083         if(cs.tagName || cs == document){
5084             cs = [cs];
5085         }
5086         if(!id){
5087             return cs;
5088         }
5089         var r = [], ri = -1;
5090         for(var i = 0,ci; ci = cs[i]; i++){
5091             if(ci && ci.id == id){
5092                 r[++ri] = ci;
5093                 return r;
5094             }
5095         }
5096         return r;
5097     };
5098
5099     function byAttribute(cs, attr, value, op, custom){
5100         var r = [], ri = -1, st = custom=="{";
5101         var f = Roo.DomQuery.operators[op];
5102         for(var i = 0, ci; ci = cs[i]; i++){
5103             var a;
5104             if(st){
5105                 a = Roo.DomQuery.getStyle(ci, attr);
5106             }
5107             else if(attr == "class" || attr == "className"){
5108                 a = ci.className;
5109             }else if(attr == "for"){
5110                 a = ci.htmlFor;
5111             }else if(attr == "href"){
5112                 a = ci.getAttribute("href", 2);
5113             }else{
5114                 a = ci.getAttribute(attr);
5115             }
5116             if((f && f(a, value)) || (!f && a)){
5117                 r[++ri] = ci;
5118             }
5119         }
5120         return r;
5121     };
5122
5123     function byPseudo(cs, name, value){
5124         return Roo.DomQuery.pseudos[name](cs, value);
5125     };
5126
5127     // This is for IE MSXML which does not support expandos.
5128     // IE runs the same speed using setAttribute, however FF slows way down
5129     // and Safari completely fails so they need to continue to use expandos.
5130     var isIE = window.ActiveXObject ? true : false;
5131
5132     // this eval is stop the compressor from
5133     // renaming the variable to something shorter
5134     
5135     /** eval:var:batch */
5136     var batch = 30803; 
5137
5138     var key = 30803;
5139
5140     function nodupIEXml(cs){
5141         var d = ++key;
5142         cs[0].setAttribute("_nodup", d);
5143         var r = [cs[0]];
5144         for(var i = 1, len = cs.length; i < len; i++){
5145             var c = cs[i];
5146             if(!c.getAttribute("_nodup") != d){
5147                 c.setAttribute("_nodup", d);
5148                 r[r.length] = c;
5149             }
5150         }
5151         for(var i = 0, len = cs.length; i < len; i++){
5152             cs[i].removeAttribute("_nodup");
5153         }
5154         return r;
5155     }
5156
5157     function nodup(cs){
5158         if(!cs){
5159             return [];
5160         }
5161         var len = cs.length, c, i, r = cs, cj, ri = -1;
5162         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5163             return cs;
5164         }
5165         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5166             return nodupIEXml(cs);
5167         }
5168         var d = ++key;
5169         cs[0]._nodup = d;
5170         for(i = 1; c = cs[i]; i++){
5171             if(c._nodup != d){
5172                 c._nodup = d;
5173             }else{
5174                 r = [];
5175                 for(var j = 0; j < i; j++){
5176                     r[++ri] = cs[j];
5177                 }
5178                 for(j = i+1; cj = cs[j]; j++){
5179                     if(cj._nodup != d){
5180                         cj._nodup = d;
5181                         r[++ri] = cj;
5182                     }
5183                 }
5184                 return r;
5185             }
5186         }
5187         return r;
5188     }
5189
5190     function quickDiffIEXml(c1, c2){
5191         var d = ++key;
5192         for(var i = 0, len = c1.length; i < len; i++){
5193             c1[i].setAttribute("_qdiff", d);
5194         }
5195         var r = [];
5196         for(var i = 0, len = c2.length; i < len; i++){
5197             if(c2[i].getAttribute("_qdiff") != d){
5198                 r[r.length] = c2[i];
5199             }
5200         }
5201         for(var i = 0, len = c1.length; i < len; i++){
5202            c1[i].removeAttribute("_qdiff");
5203         }
5204         return r;
5205     }
5206
5207     function quickDiff(c1, c2){
5208         var len1 = c1.length;
5209         if(!len1){
5210             return c2;
5211         }
5212         if(isIE && c1[0].selectSingleNode){
5213             return quickDiffIEXml(c1, c2);
5214         }
5215         var d = ++key;
5216         for(var i = 0; i < len1; i++){
5217             c1[i]._qdiff = d;
5218         }
5219         var r = [];
5220         for(var i = 0, len = c2.length; i < len; i++){
5221             if(c2[i]._qdiff != d){
5222                 r[r.length] = c2[i];
5223             }
5224         }
5225         return r;
5226     }
5227
5228     function quickId(ns, mode, root, id){
5229         if(ns == root){
5230            var d = root.ownerDocument || root;
5231            return d.getElementById(id);
5232         }
5233         ns = getNodes(ns, mode, "*");
5234         return byId(ns, null, id);
5235     }
5236
5237     return {
5238         getStyle : function(el, name){
5239             return Roo.fly(el).getStyle(name);
5240         },
5241         /**
5242          * Compiles a selector/xpath query into a reusable function. The returned function
5243          * takes one parameter "root" (optional), which is the context node from where the query should start.
5244          * @param {String} selector The selector/xpath query
5245          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5246          * @return {Function}
5247          */
5248         compile : function(path, type){
5249             type = type || "select";
5250             
5251             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5252             var q = path, mode, lq;
5253             var tk = Roo.DomQuery.matchers;
5254             var tklen = tk.length;
5255             var mm;
5256
5257             // accept leading mode switch
5258             var lmode = q.match(modeRe);
5259             if(lmode && lmode[1]){
5260                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5261                 q = q.replace(lmode[1], "");
5262             }
5263             // strip leading slashes
5264             while(path.substr(0, 1)=="/"){
5265                 path = path.substr(1);
5266             }
5267
5268             while(q && lq != q){
5269                 lq = q;
5270                 var tm = q.match(tagTokenRe);
5271                 if(type == "select"){
5272                     if(tm){
5273                         if(tm[1] == "#"){
5274                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5275                         }else{
5276                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5277                         }
5278                         q = q.replace(tm[0], "");
5279                     }else if(q.substr(0, 1) != '@'){
5280                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5281                     }
5282                 }else{
5283                     if(tm){
5284                         if(tm[1] == "#"){
5285                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5286                         }else{
5287                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5288                         }
5289                         q = q.replace(tm[0], "");
5290                     }
5291                 }
5292                 while(!(mm = q.match(modeRe))){
5293                     var matched = false;
5294                     for(var j = 0; j < tklen; j++){
5295                         var t = tk[j];
5296                         var m = q.match(t.re);
5297                         if(m){
5298                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5299                                                     return m[i];
5300                                                 });
5301                             q = q.replace(m[0], "");
5302                             matched = true;
5303                             break;
5304                         }
5305                     }
5306                     // prevent infinite loop on bad selector
5307                     if(!matched){
5308                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5309                     }
5310                 }
5311                 if(mm[1]){
5312                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5313                     q = q.replace(mm[1], "");
5314                 }
5315             }
5316             fn[fn.length] = "return nodup(n);\n}";
5317             
5318              /** 
5319               * list of variables that need from compression as they are used by eval.
5320              *  eval:var:batch 
5321              *  eval:var:nodup
5322              *  eval:var:byTag
5323              *  eval:var:ById
5324              *  eval:var:getNodes
5325              *  eval:var:quickId
5326              *  eval:var:mode
5327              *  eval:var:root
5328              *  eval:var:n
5329              *  eval:var:byClassName
5330              *  eval:var:byPseudo
5331              *  eval:var:byAttribute
5332              *  eval:var:attrValue
5333              * 
5334              **/ 
5335             eval(fn.join(""));
5336             return f;
5337         },
5338
5339         /**
5340          * Selects a group of elements.
5341          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5342          * @param {Node} root (optional) The start of the query (defaults to document).
5343          * @return {Array}
5344          */
5345         select : function(path, root, type){
5346             if(!root || root == document){
5347                 root = document;
5348             }
5349             if(typeof root == "string"){
5350                 root = document.getElementById(root);
5351             }
5352             var paths = path.split(",");
5353             var results = [];
5354             for(var i = 0, len = paths.length; i < len; i++){
5355                 var p = paths[i].replace(trimRe, "");
5356                 if(!cache[p]){
5357                     cache[p] = Roo.DomQuery.compile(p);
5358                     if(!cache[p]){
5359                         throw p + " is not a valid selector";
5360                     }
5361                 }
5362                 var result = cache[p](root);
5363                 if(result && result != document){
5364                     results = results.concat(result);
5365                 }
5366             }
5367             if(paths.length > 1){
5368                 return nodup(results);
5369             }
5370             return results;
5371         },
5372
5373         /**
5374          * Selects a single element.
5375          * @param {String} selector The selector/xpath query
5376          * @param {Node} root (optional) The start of the query (defaults to document).
5377          * @return {Element}
5378          */
5379         selectNode : function(path, root){
5380             return Roo.DomQuery.select(path, root)[0];
5381         },
5382
5383         /**
5384          * Selects the value of a node, optionally replacing null with the defaultValue.
5385          * @param {String} selector The selector/xpath query
5386          * @param {Node} root (optional) The start of the query (defaults to document).
5387          * @param {String} defaultValue
5388          */
5389         selectValue : function(path, root, defaultValue){
5390             path = path.replace(trimRe, "");
5391             if(!valueCache[path]){
5392                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5393             }
5394             var n = valueCache[path](root);
5395             n = n[0] ? n[0] : n;
5396             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5397             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5398         },
5399
5400         /**
5401          * Selects the value of a node, parsing integers and floats.
5402          * @param {String} selector The selector/xpath query
5403          * @param {Node} root (optional) The start of the query (defaults to document).
5404          * @param {Number} defaultValue
5405          * @return {Number}
5406          */
5407         selectNumber : function(path, root, defaultValue){
5408             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5409             return parseFloat(v);
5410         },
5411
5412         /**
5413          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5414          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5415          * @param {String} selector The simple selector to test
5416          * @return {Boolean}
5417          */
5418         is : function(el, ss){
5419             if(typeof el == "string"){
5420                 el = document.getElementById(el);
5421             }
5422             var isArray = (el instanceof Array);
5423             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5424             return isArray ? (result.length == el.length) : (result.length > 0);
5425         },
5426
5427         /**
5428          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5429          * @param {Array} el An array of elements to filter
5430          * @param {String} selector The simple selector to test
5431          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5432          * the selector instead of the ones that match
5433          * @return {Array}
5434          */
5435         filter : function(els, ss, nonMatches){
5436             ss = ss.replace(trimRe, "");
5437             if(!simpleCache[ss]){
5438                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5439             }
5440             var result = simpleCache[ss](els);
5441             return nonMatches ? quickDiff(result, els) : result;
5442         },
5443
5444         /**
5445          * Collection of matching regular expressions and code snippets.
5446          */
5447         matchers : [{
5448                 re: /^\.([\w-]+)/,
5449                 select: 'n = byClassName(n, null, " {1} ");'
5450             }, {
5451                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5452                 select: 'n = byPseudo(n, "{1}", "{2}");'
5453             },{
5454                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5455                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5456             }, {
5457                 re: /^#([\w-]+)/,
5458                 select: 'n = byId(n, null, "{1}");'
5459             },{
5460                 re: /^@([\w-]+)/,
5461                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5462             }
5463         ],
5464
5465         /**
5466          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5467          * 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;.
5468          */
5469         operators : {
5470             "=" : function(a, v){
5471                 return a == v;
5472             },
5473             "!=" : function(a, v){
5474                 return a != v;
5475             },
5476             "^=" : function(a, v){
5477                 return a && a.substr(0, v.length) == v;
5478             },
5479             "$=" : function(a, v){
5480                 return a && a.substr(a.length-v.length) == v;
5481             },
5482             "*=" : function(a, v){
5483                 return a && a.indexOf(v) !== -1;
5484             },
5485             "%=" : function(a, v){
5486                 return (a % v) == 0;
5487             },
5488             "|=" : function(a, v){
5489                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5490             },
5491             "~=" : function(a, v){
5492                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5493             }
5494         },
5495
5496         /**
5497          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5498          * and the argument (if any) supplied in the selector.
5499          */
5500         pseudos : {
5501             "first-child" : function(c){
5502                 var r = [], ri = -1, n;
5503                 for(var i = 0, ci; ci = n = c[i]; i++){
5504                     while((n = n.previousSibling) && n.nodeType != 1);
5505                     if(!n){
5506                         r[++ri] = ci;
5507                     }
5508                 }
5509                 return r;
5510             },
5511
5512             "last-child" : function(c){
5513                 var r = [], ri = -1, n;
5514                 for(var i = 0, ci; ci = n = c[i]; i++){
5515                     while((n = n.nextSibling) && n.nodeType != 1);
5516                     if(!n){
5517                         r[++ri] = ci;
5518                     }
5519                 }
5520                 return r;
5521             },
5522
5523             "nth-child" : function(c, a) {
5524                 var r = [], ri = -1;
5525                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5526                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5527                 for(var i = 0, n; n = c[i]; i++){
5528                     var pn = n.parentNode;
5529                     if (batch != pn._batch) {
5530                         var j = 0;
5531                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5532                             if(cn.nodeType == 1){
5533                                cn.nodeIndex = ++j;
5534                             }
5535                         }
5536                         pn._batch = batch;
5537                     }
5538                     if (f == 1) {
5539                         if (l == 0 || n.nodeIndex == l){
5540                             r[++ri] = n;
5541                         }
5542                     } else if ((n.nodeIndex + l) % f == 0){
5543                         r[++ri] = n;
5544                     }
5545                 }
5546
5547                 return r;
5548             },
5549
5550             "only-child" : function(c){
5551                 var r = [], ri = -1;;
5552                 for(var i = 0, ci; ci = c[i]; i++){
5553                     if(!prev(ci) && !next(ci)){
5554                         r[++ri] = ci;
5555                     }
5556                 }
5557                 return r;
5558             },
5559
5560             "empty" : function(c){
5561                 var r = [], ri = -1;
5562                 for(var i = 0, ci; ci = c[i]; i++){
5563                     var cns = ci.childNodes, j = 0, cn, empty = true;
5564                     while(cn = cns[j]){
5565                         ++j;
5566                         if(cn.nodeType == 1 || cn.nodeType == 3){
5567                             empty = false;
5568                             break;
5569                         }
5570                     }
5571                     if(empty){
5572                         r[++ri] = ci;
5573                     }
5574                 }
5575                 return r;
5576             },
5577
5578             "contains" : function(c, v){
5579                 var r = [], ri = -1;
5580                 for(var i = 0, ci; ci = c[i]; i++){
5581                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5582                         r[++ri] = ci;
5583                     }
5584                 }
5585                 return r;
5586             },
5587
5588             "nodeValue" : function(c, v){
5589                 var r = [], ri = -1;
5590                 for(var i = 0, ci; ci = c[i]; i++){
5591                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5592                         r[++ri] = ci;
5593                     }
5594                 }
5595                 return r;
5596             },
5597
5598             "checked" : function(c){
5599                 var r = [], ri = -1;
5600                 for(var i = 0, ci; ci = c[i]; i++){
5601                     if(ci.checked == true){
5602                         r[++ri] = ci;
5603                     }
5604                 }
5605                 return r;
5606             },
5607
5608             "not" : function(c, ss){
5609                 return Roo.DomQuery.filter(c, ss, true);
5610             },
5611
5612             "odd" : function(c){
5613                 return this["nth-child"](c, "odd");
5614             },
5615
5616             "even" : function(c){
5617                 return this["nth-child"](c, "even");
5618             },
5619
5620             "nth" : function(c, a){
5621                 return c[a-1] || [];
5622             },
5623
5624             "first" : function(c){
5625                 return c[0] || [];
5626             },
5627
5628             "last" : function(c){
5629                 return c[c.length-1] || [];
5630             },
5631
5632             "has" : function(c, ss){
5633                 var s = Roo.DomQuery.select;
5634                 var r = [], ri = -1;
5635                 for(var i = 0, ci; ci = c[i]; i++){
5636                     if(s(ss, ci).length > 0){
5637                         r[++ri] = ci;
5638                     }
5639                 }
5640                 return r;
5641             },
5642
5643             "next" : function(c, ss){
5644                 var is = Roo.DomQuery.is;
5645                 var r = [], ri = -1;
5646                 for(var i = 0, ci; ci = c[i]; i++){
5647                     var n = next(ci);
5648                     if(n && is(n, ss)){
5649                         r[++ri] = ci;
5650                     }
5651                 }
5652                 return r;
5653             },
5654
5655             "prev" : function(c, ss){
5656                 var is = Roo.DomQuery.is;
5657                 var r = [], ri = -1;
5658                 for(var i = 0, ci; ci = c[i]; i++){
5659                     var n = prev(ci);
5660                     if(n && is(n, ss)){
5661                         r[++ri] = ci;
5662                     }
5663                 }
5664                 return r;
5665             }
5666         }
5667     };
5668 }();
5669
5670 /**
5671  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5672  * @param {String} path The selector/xpath query
5673  * @param {Node} root (optional) The start of the query (defaults to document).
5674  * @return {Array}
5675  * @member Roo
5676  * @method query
5677  */
5678 Roo.query = Roo.DomQuery.select;
5679 /*
5680  * Based on:
5681  * Ext JS Library 1.1.1
5682  * Copyright(c) 2006-2007, Ext JS, LLC.
5683  *
5684  * Originally Released Under LGPL - original licence link has changed is not relivant.
5685  *
5686  * Fork - LGPL
5687  * <script type="text/javascript">
5688  */
5689
5690 /**
5691  * @class Roo.util.Observable
5692  * Base class that provides a common interface for publishing events. Subclasses are expected to
5693  * to have a property "events" with all the events defined.<br>
5694  * For example:
5695  * <pre><code>
5696  Employee = function(name){
5697     this.name = name;
5698     this.addEvents({
5699         "fired" : true,
5700         "quit" : true
5701     });
5702  }
5703  Roo.extend(Employee, Roo.util.Observable);
5704 </code></pre>
5705  * @param {Object} config properties to use (incuding events / listeners)
5706  */
5707
5708 Roo.util.Observable = function(cfg){
5709     
5710     cfg = cfg|| {};
5711     this.addEvents(cfg.events || {});
5712     if (cfg.events) {
5713         delete cfg.events; // make sure
5714     }
5715      
5716     Roo.apply(this, cfg);
5717     
5718     if(this.listeners){
5719         this.on(this.listeners);
5720         delete this.listeners;
5721     }
5722 };
5723 Roo.util.Observable.prototype = {
5724     /** 
5725  * @cfg {Object} listeners  list of events and functions to call for this object, 
5726  * For example :
5727  * <pre><code>
5728     listeners :  { 
5729        'click' : function(e) {
5730            ..... 
5731         } ,
5732         .... 
5733     } 
5734   </code></pre>
5735  */
5736     
5737     
5738     /**
5739      * Fires the specified event with the passed parameters (minus the event name).
5740      * @param {String} eventName
5741      * @param {Object...} args Variable number of parameters are passed to handlers
5742      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5743      */
5744     fireEvent : function(){
5745         var ce = this.events[arguments[0].toLowerCase()];
5746         if(typeof ce == "object"){
5747             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5748         }else{
5749             return true;
5750         }
5751     },
5752
5753     // private
5754     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5755
5756     /**
5757      * Appends an event handler to this component
5758      * @param {String}   eventName The type of event to listen for
5759      * @param {Function} handler The method the event invokes
5760      * @param {Object}   scope (optional) The scope in which to execute the handler
5761      * function. The handler function's "this" context.
5762      * @param {Object}   options (optional) An object containing handler configuration
5763      * properties. This may contain any of the following properties:<ul>
5764      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5765      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5766      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5767      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5768      * by the specified number of milliseconds. If the event fires again within that time, the original
5769      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5770      * </ul><br>
5771      * <p>
5772      * <b>Combining Options</b><br>
5773      * Using the options argument, it is possible to combine different types of listeners:<br>
5774      * <br>
5775      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5776                 <pre><code>
5777                 el.on('click', this.onClick, this, {
5778                         single: true,
5779                 delay: 100,
5780                 forumId: 4
5781                 });
5782                 </code></pre>
5783      * <p>
5784      * <b>Attaching multiple handlers in 1 call</b><br>
5785      * The method also allows for a single argument to be passed which is a config object containing properties
5786      * which specify multiple handlers.
5787      * <pre><code>
5788                 el.on({
5789                         'click': {
5790                         fn: this.onClick,
5791                         scope: this,
5792                         delay: 100
5793                 }, 
5794                 'mouseover': {
5795                         fn: this.onMouseOver,
5796                         scope: this
5797                 },
5798                 'mouseout': {
5799                         fn: this.onMouseOut,
5800                         scope: this
5801                 }
5802                 });
5803                 </code></pre>
5804      * <p>
5805      * Or a shorthand syntax which passes the same scope object to all handlers:
5806         <pre><code>
5807                 el.on({
5808                         'click': this.onClick,
5809                 'mouseover': this.onMouseOver,
5810                 'mouseout': this.onMouseOut,
5811                 scope: this
5812                 });
5813                 </code></pre>
5814      */
5815     addListener : function(eventName, fn, scope, o){
5816         if(typeof eventName == "object"){
5817             o = eventName;
5818             for(var e in o){
5819                 if(this.filterOptRe.test(e)){
5820                     continue;
5821                 }
5822                 if(typeof o[e] == "function"){
5823                     // shared options
5824                     this.addListener(e, o[e], o.scope,  o);
5825                 }else{
5826                     // individual options
5827                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5828                 }
5829             }
5830             return;
5831         }
5832         o = (!o || typeof o == "boolean") ? {} : o;
5833         eventName = eventName.toLowerCase();
5834         var ce = this.events[eventName] || true;
5835         if(typeof ce == "boolean"){
5836             ce = new Roo.util.Event(this, eventName);
5837             this.events[eventName] = ce;
5838         }
5839         ce.addListener(fn, scope, o);
5840     },
5841
5842     /**
5843      * Removes a listener
5844      * @param {String}   eventName     The type of event to listen for
5845      * @param {Function} handler        The handler to remove
5846      * @param {Object}   scope  (optional) The scope (this object) for the handler
5847      */
5848     removeListener : function(eventName, fn, scope){
5849         var ce = this.events[eventName.toLowerCase()];
5850         if(typeof ce == "object"){
5851             ce.removeListener(fn, scope);
5852         }
5853     },
5854
5855     /**
5856      * Removes all listeners for this object
5857      */
5858     purgeListeners : function(){
5859         for(var evt in this.events){
5860             if(typeof this.events[evt] == "object"){
5861                  this.events[evt].clearListeners();
5862             }
5863         }
5864     },
5865
5866     relayEvents : function(o, events){
5867         var createHandler = function(ename){
5868             return function(){
5869                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5870             };
5871         };
5872         for(var i = 0, len = events.length; i < len; i++){
5873             var ename = events[i];
5874             if(!this.events[ename]){ this.events[ename] = true; };
5875             o.on(ename, createHandler(ename), this);
5876         }
5877     },
5878
5879     /**
5880      * Used to define events on this Observable
5881      * @param {Object} object The object with the events defined
5882      */
5883     addEvents : function(o){
5884         if(!this.events){
5885             this.events = {};
5886         }
5887         Roo.applyIf(this.events, o);
5888     },
5889
5890     /**
5891      * Checks to see if this object has any listeners for a specified event
5892      * @param {String} eventName The name of the event to check for
5893      * @return {Boolean} True if the event is being listened for, else false
5894      */
5895     hasListener : function(eventName){
5896         var e = this.events[eventName];
5897         return typeof e == "object" && e.listeners.length > 0;
5898     }
5899 };
5900 /**
5901  * Appends an event handler to this element (shorthand for addListener)
5902  * @param {String}   eventName     The type of event to listen for
5903  * @param {Function} handler        The method the event invokes
5904  * @param {Object}   scope (optional) The scope in which to execute the handler
5905  * function. The handler function's "this" context.
5906  * @param {Object}   options  (optional)
5907  * @method
5908  */
5909 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5910 /**
5911  * Removes a listener (shorthand for removeListener)
5912  * @param {String}   eventName     The type of event to listen for
5913  * @param {Function} handler        The handler to remove
5914  * @param {Object}   scope  (optional) The scope (this object) for the handler
5915  * @method
5916  */
5917 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5918
5919 /**
5920  * Starts capture on the specified Observable. All events will be passed
5921  * to the supplied function with the event name + standard signature of the event
5922  * <b>before</b> the event is fired. If the supplied function returns false,
5923  * the event will not fire.
5924  * @param {Observable} o The Observable to capture
5925  * @param {Function} fn The function to call
5926  * @param {Object} scope (optional) The scope (this object) for the fn
5927  * @static
5928  */
5929 Roo.util.Observable.capture = function(o, fn, scope){
5930     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5931 };
5932
5933 /**
5934  * Removes <b>all</b> added captures from the Observable.
5935  * @param {Observable} o The Observable to release
5936  * @static
5937  */
5938 Roo.util.Observable.releaseCapture = function(o){
5939     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5940 };
5941
5942 (function(){
5943
5944     var createBuffered = function(h, o, scope){
5945         var task = new Roo.util.DelayedTask();
5946         return function(){
5947             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5948         };
5949     };
5950
5951     var createSingle = function(h, e, fn, scope){
5952         return function(){
5953             e.removeListener(fn, scope);
5954             return h.apply(scope, arguments);
5955         };
5956     };
5957
5958     var createDelayed = function(h, o, scope){
5959         return function(){
5960             var args = Array.prototype.slice.call(arguments, 0);
5961             setTimeout(function(){
5962                 h.apply(scope, args);
5963             }, o.delay || 10);
5964         };
5965     };
5966
5967     Roo.util.Event = function(obj, name){
5968         this.name = name;
5969         this.obj = obj;
5970         this.listeners = [];
5971     };
5972
5973     Roo.util.Event.prototype = {
5974         addListener : function(fn, scope, options){
5975             var o = options || {};
5976             scope = scope || this.obj;
5977             if(!this.isListening(fn, scope)){
5978                 var l = {fn: fn, scope: scope, options: o};
5979                 var h = fn;
5980                 if(o.delay){
5981                     h = createDelayed(h, o, scope);
5982                 }
5983                 if(o.single){
5984                     h = createSingle(h, this, fn, scope);
5985                 }
5986                 if(o.buffer){
5987                     h = createBuffered(h, o, scope);
5988                 }
5989                 l.fireFn = h;
5990                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5991                     this.listeners.push(l);
5992                 }else{
5993                     this.listeners = this.listeners.slice(0);
5994                     this.listeners.push(l);
5995                 }
5996             }
5997         },
5998
5999         findListener : function(fn, scope){
6000             scope = scope || this.obj;
6001             var ls = this.listeners;
6002             for(var i = 0, len = ls.length; i < len; i++){
6003                 var l = ls[i];
6004                 if(l.fn == fn && l.scope == scope){
6005                     return i;
6006                 }
6007             }
6008             return -1;
6009         },
6010
6011         isListening : function(fn, scope){
6012             return this.findListener(fn, scope) != -1;
6013         },
6014
6015         removeListener : function(fn, scope){
6016             var index;
6017             if((index = this.findListener(fn, scope)) != -1){
6018                 if(!this.firing){
6019                     this.listeners.splice(index, 1);
6020                 }else{
6021                     this.listeners = this.listeners.slice(0);
6022                     this.listeners.splice(index, 1);
6023                 }
6024                 return true;
6025             }
6026             return false;
6027         },
6028
6029         clearListeners : function(){
6030             this.listeners = [];
6031         },
6032
6033         fire : function(){
6034             var ls = this.listeners, scope, len = ls.length;
6035             if(len > 0){
6036                 this.firing = true;
6037                 var args = Array.prototype.slice.call(arguments, 0);
6038                 for(var i = 0; i < len; i++){
6039                     var l = ls[i];
6040                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6041                         this.firing = false;
6042                         return false;
6043                     }
6044                 }
6045                 this.firing = false;
6046             }
6047             return true;
6048         }
6049     };
6050 })();/*
6051  * Based on:
6052  * Ext JS Library 1.1.1
6053  * Copyright(c) 2006-2007, Ext JS, LLC.
6054  *
6055  * Originally Released Under LGPL - original licence link has changed is not relivant.
6056  *
6057  * Fork - LGPL
6058  * <script type="text/javascript">
6059  */
6060
6061 /**
6062  * @class Roo.EventManager
6063  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6064  * several useful events directly.
6065  * See {@link Roo.EventObject} for more details on normalized event objects.
6066  * @singleton
6067  */
6068 Roo.EventManager = function(){
6069     var docReadyEvent, docReadyProcId, docReadyState = false;
6070     var resizeEvent, resizeTask, textEvent, textSize;
6071     var E = Roo.lib.Event;
6072     var D = Roo.lib.Dom;
6073
6074     
6075     
6076
6077     var fireDocReady = function(){
6078         if(!docReadyState){
6079             docReadyState = true;
6080             Roo.isReady = true;
6081             if(docReadyProcId){
6082                 clearInterval(docReadyProcId);
6083             }
6084             if(Roo.isGecko || Roo.isOpera) {
6085                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6086             }
6087             if(Roo.isIE){
6088                 var defer = document.getElementById("ie-deferred-loader");
6089                 if(defer){
6090                     defer.onreadystatechange = null;
6091                     defer.parentNode.removeChild(defer);
6092                 }
6093             }
6094             if(docReadyEvent){
6095                 docReadyEvent.fire();
6096                 docReadyEvent.clearListeners();
6097             }
6098         }
6099     };
6100     
6101     var initDocReady = function(){
6102         docReadyEvent = new Roo.util.Event();
6103         if(Roo.isGecko || Roo.isOpera) {
6104             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6105         }else if(Roo.isIE){
6106             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6107             var defer = document.getElementById("ie-deferred-loader");
6108             defer.onreadystatechange = function(){
6109                 if(this.readyState == "complete"){
6110                     fireDocReady();
6111                 }
6112             };
6113         }else if(Roo.isSafari){ 
6114             docReadyProcId = setInterval(function(){
6115                 var rs = document.readyState;
6116                 if(rs == "complete") {
6117                     fireDocReady();     
6118                  }
6119             }, 10);
6120         }
6121         // no matter what, make sure it fires on load
6122         E.on(window, "load", fireDocReady);
6123     };
6124
6125     var createBuffered = function(h, o){
6126         var task = new Roo.util.DelayedTask(h);
6127         return function(e){
6128             // create new event object impl so new events don't wipe out properties
6129             e = new Roo.EventObjectImpl(e);
6130             task.delay(o.buffer, h, null, [e]);
6131         };
6132     };
6133
6134     var createSingle = function(h, el, ename, fn){
6135         return function(e){
6136             Roo.EventManager.removeListener(el, ename, fn);
6137             h(e);
6138         };
6139     };
6140
6141     var createDelayed = function(h, o){
6142         return function(e){
6143             // create new event object impl so new events don't wipe out properties
6144             e = new Roo.EventObjectImpl(e);
6145             setTimeout(function(){
6146                 h(e);
6147             }, o.delay || 10);
6148         };
6149     };
6150     var transitionEndVal = false;
6151     
6152     var transitionEnd = function()
6153     {
6154         if (transitionEndVal) {
6155             return transitionEndVal;
6156         }
6157         var el = document.createElement('div');
6158
6159         var transEndEventNames = {
6160             WebkitTransition : 'webkitTransitionEnd',
6161             MozTransition    : 'transitionend',
6162             OTransition      : 'oTransitionEnd otransitionend',
6163             transition       : 'transitionend'
6164         };
6165     
6166         for (var name in transEndEventNames) {
6167             if (el.style[name] !== undefined) {
6168                 transitionEndVal = transEndEventNames[name];
6169                 return  transitionEndVal ;
6170             }
6171         }
6172     }
6173     
6174
6175     var listen = function(element, ename, opt, fn, scope){
6176         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6177         fn = fn || o.fn; scope = scope || o.scope;
6178         var el = Roo.getDom(element);
6179         
6180         
6181         if(!el){
6182             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6183         }
6184         
6185         if (ename == 'transitionend') {
6186             ename = transitionEnd();
6187         }
6188         var h = function(e){
6189             e = Roo.EventObject.setEvent(e);
6190             var t;
6191             if(o.delegate){
6192                 t = e.getTarget(o.delegate, el);
6193                 if(!t){
6194                     return;
6195                 }
6196             }else{
6197                 t = e.target;
6198             }
6199             if(o.stopEvent === true){
6200                 e.stopEvent();
6201             }
6202             if(o.preventDefault === true){
6203                e.preventDefault();
6204             }
6205             if(o.stopPropagation === true){
6206                 e.stopPropagation();
6207             }
6208
6209             if(o.normalized === false){
6210                 e = e.browserEvent;
6211             }
6212
6213             fn.call(scope || el, e, t, o);
6214         };
6215         if(o.delay){
6216             h = createDelayed(h, o);
6217         }
6218         if(o.single){
6219             h = createSingle(h, el, ename, fn);
6220         }
6221         if(o.buffer){
6222             h = createBuffered(h, o);
6223         }
6224         fn._handlers = fn._handlers || [];
6225         
6226         
6227         fn._handlers.push([Roo.id(el), ename, h]);
6228         
6229         
6230          
6231         E.on(el, ename, h);
6232         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6233             el.addEventListener("DOMMouseScroll", h, false);
6234             E.on(window, 'unload', function(){
6235                 el.removeEventListener("DOMMouseScroll", h, false);
6236             });
6237         }
6238         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6239             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6240         }
6241         return h;
6242     };
6243
6244     var stopListening = function(el, ename, fn){
6245         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6246         if(hds){
6247             for(var i = 0, len = hds.length; i < len; i++){
6248                 var h = hds[i];
6249                 if(h[0] == id && h[1] == ename){
6250                     hd = h[2];
6251                     hds.splice(i, 1);
6252                     break;
6253                 }
6254             }
6255         }
6256         E.un(el, ename, hd);
6257         el = Roo.getDom(el);
6258         if(ename == "mousewheel" && el.addEventListener){
6259             el.removeEventListener("DOMMouseScroll", hd, false);
6260         }
6261         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6262             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6263         }
6264     };
6265
6266     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6267     
6268     var pub = {
6269         
6270         
6271         /** 
6272          * Fix for doc tools
6273          * @scope Roo.EventManager
6274          */
6275         
6276         
6277         /** 
6278          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6279          * object with a Roo.EventObject
6280          * @param {Function} fn        The method the event invokes
6281          * @param {Object}   scope    An object that becomes the scope of the handler
6282          * @param {boolean}  override If true, the obj passed in becomes
6283          *                             the execution scope of the listener
6284          * @return {Function} The wrapped function
6285          * @deprecated
6286          */
6287         wrap : function(fn, scope, override){
6288             return function(e){
6289                 Roo.EventObject.setEvent(e);
6290                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6291             };
6292         },
6293         
6294         /**
6295      * Appends an event handler to an element (shorthand for addListener)
6296      * @param {String/HTMLElement}   element        The html element or id to assign the
6297      * @param {String}   eventName The type of event to listen for
6298      * @param {Function} handler The method the event invokes
6299      * @param {Object}   scope (optional) The scope in which to execute the handler
6300      * function. The handler function's "this" context.
6301      * @param {Object}   options (optional) An object containing handler configuration
6302      * properties. This may contain any of the following properties:<ul>
6303      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6304      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6305      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6306      * <li>preventDefault {Boolean} True to prevent the default action</li>
6307      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6308      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6309      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6310      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6311      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6312      * by the specified number of milliseconds. If the event fires again within that time, the original
6313      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6314      * </ul><br>
6315      * <p>
6316      * <b>Combining Options</b><br>
6317      * Using the options argument, it is possible to combine different types of listeners:<br>
6318      * <br>
6319      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6320      * Code:<pre><code>
6321 el.on('click', this.onClick, this, {
6322     single: true,
6323     delay: 100,
6324     stopEvent : true,
6325     forumId: 4
6326 });</code></pre>
6327      * <p>
6328      * <b>Attaching multiple handlers in 1 call</b><br>
6329       * The method also allows for a single argument to be passed which is a config object containing properties
6330      * which specify multiple handlers.
6331      * <p>
6332      * Code:<pre><code>
6333 el.on({
6334     'click' : {
6335         fn: this.onClick
6336         scope: this,
6337         delay: 100
6338     },
6339     'mouseover' : {
6340         fn: this.onMouseOver
6341         scope: this
6342     },
6343     'mouseout' : {
6344         fn: this.onMouseOut
6345         scope: this
6346     }
6347 });</code></pre>
6348      * <p>
6349      * Or a shorthand syntax:<br>
6350      * Code:<pre><code>
6351 el.on({
6352     'click' : this.onClick,
6353     'mouseover' : this.onMouseOver,
6354     'mouseout' : this.onMouseOut
6355     scope: this
6356 });</code></pre>
6357      */
6358         addListener : function(element, eventName, fn, scope, options){
6359             if(typeof eventName == "object"){
6360                 var o = eventName;
6361                 for(var e in o){
6362                     if(propRe.test(e)){
6363                         continue;
6364                     }
6365                     if(typeof o[e] == "function"){
6366                         // shared options
6367                         listen(element, e, o, o[e], o.scope);
6368                     }else{
6369                         // individual options
6370                         listen(element, e, o[e]);
6371                     }
6372                 }
6373                 return;
6374             }
6375             return listen(element, eventName, options, fn, scope);
6376         },
6377         
6378         /**
6379          * Removes an event handler
6380          *
6381          * @param {String/HTMLElement}   element        The id or html element to remove the 
6382          *                             event from
6383          * @param {String}   eventName     The type of event
6384          * @param {Function} fn
6385          * @return {Boolean} True if a listener was actually removed
6386          */
6387         removeListener : function(element, eventName, fn){
6388             return stopListening(element, eventName, fn);
6389         },
6390         
6391         /**
6392          * Fires when the document is ready (before onload and before images are loaded). Can be 
6393          * accessed shorthanded Roo.onReady().
6394          * @param {Function} fn        The method the event invokes
6395          * @param {Object}   scope    An  object that becomes the scope of the handler
6396          * @param {boolean}  options
6397          */
6398         onDocumentReady : function(fn, scope, options){
6399             if(docReadyState){ // if it already fired
6400                 docReadyEvent.addListener(fn, scope, options);
6401                 docReadyEvent.fire();
6402                 docReadyEvent.clearListeners();
6403                 return;
6404             }
6405             if(!docReadyEvent){
6406                 initDocReady();
6407             }
6408             docReadyEvent.addListener(fn, scope, options);
6409         },
6410         
6411         /**
6412          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6413          * @param {Function} fn        The method the event invokes
6414          * @param {Object}   scope    An object that becomes the scope of the handler
6415          * @param {boolean}  options
6416          */
6417         onWindowResize : function(fn, scope, options){
6418             if(!resizeEvent){
6419                 resizeEvent = new Roo.util.Event();
6420                 resizeTask = new Roo.util.DelayedTask(function(){
6421                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6422                 });
6423                 E.on(window, "resize", function(){
6424                     if(Roo.isIE){
6425                         resizeTask.delay(50);
6426                     }else{
6427                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6428                     }
6429                 });
6430             }
6431             resizeEvent.addListener(fn, scope, options);
6432         },
6433
6434         /**
6435          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6436          * @param {Function} fn        The method the event invokes
6437          * @param {Object}   scope    An object that becomes the scope of the handler
6438          * @param {boolean}  options
6439          */
6440         onTextResize : function(fn, scope, options){
6441             if(!textEvent){
6442                 textEvent = new Roo.util.Event();
6443                 var textEl = new Roo.Element(document.createElement('div'));
6444                 textEl.dom.className = 'x-text-resize';
6445                 textEl.dom.innerHTML = 'X';
6446                 textEl.appendTo(document.body);
6447                 textSize = textEl.dom.offsetHeight;
6448                 setInterval(function(){
6449                     if(textEl.dom.offsetHeight != textSize){
6450                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6451                     }
6452                 }, this.textResizeInterval);
6453             }
6454             textEvent.addListener(fn, scope, options);
6455         },
6456
6457         /**
6458          * Removes the passed window resize listener.
6459          * @param {Function} fn        The method the event invokes
6460          * @param {Object}   scope    The scope of handler
6461          */
6462         removeResizeListener : function(fn, scope){
6463             if(resizeEvent){
6464                 resizeEvent.removeListener(fn, scope);
6465             }
6466         },
6467
6468         // private
6469         fireResize : function(){
6470             if(resizeEvent){
6471                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6472             }   
6473         },
6474         /**
6475          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6476          */
6477         ieDeferSrc : false,
6478         /**
6479          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6480          */
6481         textResizeInterval : 50
6482     };
6483     
6484     /**
6485      * Fix for doc tools
6486      * @scopeAlias pub=Roo.EventManager
6487      */
6488     
6489      /**
6490      * Appends an event handler to an element (shorthand for addListener)
6491      * @param {String/HTMLElement}   element        The html element or id to assign the
6492      * @param {String}   eventName The type of event to listen for
6493      * @param {Function} handler The method the event invokes
6494      * @param {Object}   scope (optional) The scope in which to execute the handler
6495      * function. The handler function's "this" context.
6496      * @param {Object}   options (optional) An object containing handler configuration
6497      * properties. This may contain any of the following properties:<ul>
6498      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6499      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6500      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6501      * <li>preventDefault {Boolean} True to prevent the default action</li>
6502      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6503      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6504      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6505      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6506      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6507      * by the specified number of milliseconds. If the event fires again within that time, the original
6508      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6509      * </ul><br>
6510      * <p>
6511      * <b>Combining Options</b><br>
6512      * Using the options argument, it is possible to combine different types of listeners:<br>
6513      * <br>
6514      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6515      * Code:<pre><code>
6516 el.on('click', this.onClick, this, {
6517     single: true,
6518     delay: 100,
6519     stopEvent : true,
6520     forumId: 4
6521 });</code></pre>
6522      * <p>
6523      * <b>Attaching multiple handlers in 1 call</b><br>
6524       * The method also allows for a single argument to be passed which is a config object containing properties
6525      * which specify multiple handlers.
6526      * <p>
6527      * Code:<pre><code>
6528 el.on({
6529     'click' : {
6530         fn: this.onClick
6531         scope: this,
6532         delay: 100
6533     },
6534     'mouseover' : {
6535         fn: this.onMouseOver
6536         scope: this
6537     },
6538     'mouseout' : {
6539         fn: this.onMouseOut
6540         scope: this
6541     }
6542 });</code></pre>
6543      * <p>
6544      * Or a shorthand syntax:<br>
6545      * Code:<pre><code>
6546 el.on({
6547     'click' : this.onClick,
6548     'mouseover' : this.onMouseOver,
6549     'mouseout' : this.onMouseOut
6550     scope: this
6551 });</code></pre>
6552      */
6553     pub.on = pub.addListener;
6554     pub.un = pub.removeListener;
6555
6556     pub.stoppedMouseDownEvent = new Roo.util.Event();
6557     return pub;
6558 }();
6559 /**
6560   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6561   * @param {Function} fn        The method the event invokes
6562   * @param {Object}   scope    An  object that becomes the scope of the handler
6563   * @param {boolean}  override If true, the obj passed in becomes
6564   *                             the execution scope of the listener
6565   * @member Roo
6566   * @method onReady
6567  */
6568 Roo.onReady = Roo.EventManager.onDocumentReady;
6569
6570 Roo.onReady(function(){
6571     var bd = Roo.get(document.body);
6572     if(!bd){ return; }
6573
6574     var cls = [
6575             Roo.isIE ? "roo-ie"
6576             : Roo.isGecko ? "roo-gecko"
6577             : Roo.isOpera ? "roo-opera"
6578             : Roo.isSafari ? "roo-safari" : ""];
6579
6580     if(Roo.isMac){
6581         cls.push("roo-mac");
6582     }
6583     if(Roo.isLinux){
6584         cls.push("roo-linux");
6585     }
6586     if(Roo.isIOS){
6587         cls.push("roo-ios");
6588     }
6589     if(Roo.isTouch){
6590         cls.push("roo-touch");
6591     }
6592     if(Roo.isBorderBox){
6593         cls.push('roo-border-box');
6594     }
6595     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6596         var p = bd.dom.parentNode;
6597         if(p){
6598             p.className += ' roo-strict';
6599         }
6600     }
6601     bd.addClass(cls.join(' '));
6602 });
6603
6604 /**
6605  * @class Roo.EventObject
6606  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6607  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6608  * Example:
6609  * <pre><code>
6610  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6611     e.preventDefault();
6612     var target = e.getTarget();
6613     ...
6614  }
6615  var myDiv = Roo.get("myDiv");
6616  myDiv.on("click", handleClick);
6617  //or
6618  Roo.EventManager.on("myDiv", 'click', handleClick);
6619  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6620  </code></pre>
6621  * @singleton
6622  */
6623 Roo.EventObject = function(){
6624     
6625     var E = Roo.lib.Event;
6626     
6627     // safari keypress events for special keys return bad keycodes
6628     var safariKeys = {
6629         63234 : 37, // left
6630         63235 : 39, // right
6631         63232 : 38, // up
6632         63233 : 40, // down
6633         63276 : 33, // page up
6634         63277 : 34, // page down
6635         63272 : 46, // delete
6636         63273 : 36, // home
6637         63275 : 35  // end
6638     };
6639
6640     // normalize button clicks
6641     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6642                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6643
6644     Roo.EventObjectImpl = function(e){
6645         if(e){
6646             this.setEvent(e.browserEvent || e);
6647         }
6648     };
6649     Roo.EventObjectImpl.prototype = {
6650         /**
6651          * Used to fix doc tools.
6652          * @scope Roo.EventObject.prototype
6653          */
6654             
6655
6656         
6657         
6658         /** The normal browser event */
6659         browserEvent : null,
6660         /** The button pressed in a mouse event */
6661         button : -1,
6662         /** True if the shift key was down during the event */
6663         shiftKey : false,
6664         /** True if the control key was down during the event */
6665         ctrlKey : false,
6666         /** True if the alt key was down during the event */
6667         altKey : false,
6668
6669         /** Key constant 
6670         * @type Number */
6671         BACKSPACE : 8,
6672         /** Key constant 
6673         * @type Number */
6674         TAB : 9,
6675         /** Key constant 
6676         * @type Number */
6677         RETURN : 13,
6678         /** Key constant 
6679         * @type Number */
6680         ENTER : 13,
6681         /** Key constant 
6682         * @type Number */
6683         SHIFT : 16,
6684         /** Key constant 
6685         * @type Number */
6686         CONTROL : 17,
6687         /** Key constant 
6688         * @type Number */
6689         ESC : 27,
6690         /** Key constant 
6691         * @type Number */
6692         SPACE : 32,
6693         /** Key constant 
6694         * @type Number */
6695         PAGEUP : 33,
6696         /** Key constant 
6697         * @type Number */
6698         PAGEDOWN : 34,
6699         /** Key constant 
6700         * @type Number */
6701         END : 35,
6702         /** Key constant 
6703         * @type Number */
6704         HOME : 36,
6705         /** Key constant 
6706         * @type Number */
6707         LEFT : 37,
6708         /** Key constant 
6709         * @type Number */
6710         UP : 38,
6711         /** Key constant 
6712         * @type Number */
6713         RIGHT : 39,
6714         /** Key constant 
6715         * @type Number */
6716         DOWN : 40,
6717         /** Key constant 
6718         * @type Number */
6719         DELETE : 46,
6720         /** Key constant 
6721         * @type Number */
6722         F5 : 116,
6723
6724            /** @private */
6725         setEvent : function(e){
6726             if(e == this || (e && e.browserEvent)){ // already wrapped
6727                 return e;
6728             }
6729             this.browserEvent = e;
6730             if(e){
6731                 // normalize buttons
6732                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6733                 if(e.type == 'click' && this.button == -1){
6734                     this.button = 0;
6735                 }
6736                 this.type = e.type;
6737                 this.shiftKey = e.shiftKey;
6738                 // mac metaKey behaves like ctrlKey
6739                 this.ctrlKey = e.ctrlKey || e.metaKey;
6740                 this.altKey = e.altKey;
6741                 // in getKey these will be normalized for the mac
6742                 this.keyCode = e.keyCode;
6743                 // keyup warnings on firefox.
6744                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6745                 // cache the target for the delayed and or buffered events
6746                 this.target = E.getTarget(e);
6747                 // same for XY
6748                 this.xy = E.getXY(e);
6749             }else{
6750                 this.button = -1;
6751                 this.shiftKey = false;
6752                 this.ctrlKey = false;
6753                 this.altKey = false;
6754                 this.keyCode = 0;
6755                 this.charCode =0;
6756                 this.target = null;
6757                 this.xy = [0, 0];
6758             }
6759             return this;
6760         },
6761
6762         /**
6763          * Stop the event (preventDefault and stopPropagation)
6764          */
6765         stopEvent : function(){
6766             if(this.browserEvent){
6767                 if(this.browserEvent.type == 'mousedown'){
6768                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6769                 }
6770                 E.stopEvent(this.browserEvent);
6771             }
6772         },
6773
6774         /**
6775          * Prevents the browsers default handling of the event.
6776          */
6777         preventDefault : function(){
6778             if(this.browserEvent){
6779                 E.preventDefault(this.browserEvent);
6780             }
6781         },
6782
6783         /** @private */
6784         isNavKeyPress : function(){
6785             var k = this.keyCode;
6786             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6787             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6788         },
6789
6790         isSpecialKey : function(){
6791             var k = this.keyCode;
6792             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6793             (k == 16) || (k == 17) ||
6794             (k >= 18 && k <= 20) ||
6795             (k >= 33 && k <= 35) ||
6796             (k >= 36 && k <= 39) ||
6797             (k >= 44 && k <= 45);
6798         },
6799         /**
6800          * Cancels bubbling of the event.
6801          */
6802         stopPropagation : function(){
6803             if(this.browserEvent){
6804                 if(this.type == 'mousedown'){
6805                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6806                 }
6807                 E.stopPropagation(this.browserEvent);
6808             }
6809         },
6810
6811         /**
6812          * Gets the key code for the event.
6813          * @return {Number}
6814          */
6815         getCharCode : function(){
6816             return this.charCode || this.keyCode;
6817         },
6818
6819         /**
6820          * Returns a normalized keyCode for the event.
6821          * @return {Number} The key code
6822          */
6823         getKey : function(){
6824             var k = this.keyCode || this.charCode;
6825             return Roo.isSafari ? (safariKeys[k] || k) : k;
6826         },
6827
6828         /**
6829          * Gets the x coordinate of the event.
6830          * @return {Number}
6831          */
6832         getPageX : function(){
6833             return this.xy[0];
6834         },
6835
6836         /**
6837          * Gets the y coordinate of the event.
6838          * @return {Number}
6839          */
6840         getPageY : function(){
6841             return this.xy[1];
6842         },
6843
6844         /**
6845          * Gets the time of the event.
6846          * @return {Number}
6847          */
6848         getTime : function(){
6849             if(this.browserEvent){
6850                 return E.getTime(this.browserEvent);
6851             }
6852             return null;
6853         },
6854
6855         /**
6856          * Gets the page coordinates of the event.
6857          * @return {Array} The xy values like [x, y]
6858          */
6859         getXY : function(){
6860             return this.xy;
6861         },
6862
6863         /**
6864          * Gets the target for the event.
6865          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6866          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6867                 search as a number or element (defaults to 10 || document.body)
6868          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6869          * @return {HTMLelement}
6870          */
6871         getTarget : function(selector, maxDepth, returnEl){
6872             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6873         },
6874         /**
6875          * Gets the related target.
6876          * @return {HTMLElement}
6877          */
6878         getRelatedTarget : function(){
6879             if(this.browserEvent){
6880                 return E.getRelatedTarget(this.browserEvent);
6881             }
6882             return null;
6883         },
6884
6885         /**
6886          * Normalizes mouse wheel delta across browsers
6887          * @return {Number} The delta
6888          */
6889         getWheelDelta : function(){
6890             var e = this.browserEvent;
6891             var delta = 0;
6892             if(e.wheelDelta){ /* IE/Opera. */
6893                 delta = e.wheelDelta/120;
6894             }else if(e.detail){ /* Mozilla case. */
6895                 delta = -e.detail/3;
6896             }
6897             return delta;
6898         },
6899
6900         /**
6901          * Returns true if the control, meta, shift or alt key was pressed during this event.
6902          * @return {Boolean}
6903          */
6904         hasModifier : function(){
6905             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6906         },
6907
6908         /**
6909          * Returns true if the target of this event equals el or is a child of el
6910          * @param {String/HTMLElement/Element} el
6911          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6912          * @return {Boolean}
6913          */
6914         within : function(el, related){
6915             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6916             return t && Roo.fly(el).contains(t);
6917         },
6918
6919         getPoint : function(){
6920             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6921         }
6922     };
6923
6924     return new Roo.EventObjectImpl();
6925 }();
6926             
6927     /*
6928  * Based on:
6929  * Ext JS Library 1.1.1
6930  * Copyright(c) 2006-2007, Ext JS, LLC.
6931  *
6932  * Originally Released Under LGPL - original licence link has changed is not relivant.
6933  *
6934  * Fork - LGPL
6935  * <script type="text/javascript">
6936  */
6937
6938  
6939 // was in Composite Element!??!?!
6940  
6941 (function(){
6942     var D = Roo.lib.Dom;
6943     var E = Roo.lib.Event;
6944     var A = Roo.lib.Anim;
6945
6946     // local style camelizing for speed
6947     var propCache = {};
6948     var camelRe = /(-[a-z])/gi;
6949     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6950     var view = document.defaultView;
6951
6952 /**
6953  * @class Roo.Element
6954  * Represents an Element in the DOM.<br><br>
6955  * Usage:<br>
6956 <pre><code>
6957 var el = Roo.get("my-div");
6958
6959 // or with getEl
6960 var el = getEl("my-div");
6961
6962 // or with a DOM element
6963 var el = Roo.get(myDivElement);
6964 </code></pre>
6965  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6966  * each call instead of constructing a new one.<br><br>
6967  * <b>Animations</b><br />
6968  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6969  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6970 <pre>
6971 Option    Default   Description
6972 --------- --------  ---------------------------------------------
6973 duration  .35       The duration of the animation in seconds
6974 easing    easeOut   The YUI easing method
6975 callback  none      A function to execute when the anim completes
6976 scope     this      The scope (this) of the callback function
6977 </pre>
6978 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6979 * manipulate the animation. Here's an example:
6980 <pre><code>
6981 var el = Roo.get("my-div");
6982
6983 // no animation
6984 el.setWidth(100);
6985
6986 // default animation
6987 el.setWidth(100, true);
6988
6989 // animation with some options set
6990 el.setWidth(100, {
6991     duration: 1,
6992     callback: this.foo,
6993     scope: this
6994 });
6995
6996 // using the "anim" property to get the Anim object
6997 var opt = {
6998     duration: 1,
6999     callback: this.foo,
7000     scope: this
7001 };
7002 el.setWidth(100, opt);
7003 ...
7004 if(opt.anim.isAnimated()){
7005     opt.anim.stop();
7006 }
7007 </code></pre>
7008 * <b> Composite (Collections of) Elements</b><br />
7009  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7010  * @constructor Create a new Element directly.
7011  * @param {String/HTMLElement} element
7012  * @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).
7013  */
7014     Roo.Element = function(element, forceNew){
7015         var dom = typeof element == "string" ?
7016                 document.getElementById(element) : element;
7017         if(!dom){ // invalid id/element
7018             return null;
7019         }
7020         var id = dom.id;
7021         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7022             return Roo.Element.cache[id];
7023         }
7024
7025         /**
7026          * The DOM element
7027          * @type HTMLElement
7028          */
7029         this.dom = dom;
7030
7031         /**
7032          * The DOM element ID
7033          * @type String
7034          */
7035         this.id = id || Roo.id(dom);
7036     };
7037
7038     var El = Roo.Element;
7039
7040     El.prototype = {
7041         /**
7042          * The element's default display mode  (defaults to "")
7043          * @type String
7044          */
7045         originalDisplay : "",
7046
7047         visibilityMode : 1,
7048         /**
7049          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7050          * @type String
7051          */
7052         defaultUnit : "px",
7053         
7054         /**
7055          * Sets the element's visibility mode. When setVisible() is called it
7056          * will use this to determine whether to set the visibility or the display property.
7057          * @param visMode Element.VISIBILITY or Element.DISPLAY
7058          * @return {Roo.Element} this
7059          */
7060         setVisibilityMode : function(visMode){
7061             this.visibilityMode = visMode;
7062             return this;
7063         },
7064         /**
7065          * Convenience method for setVisibilityMode(Element.DISPLAY)
7066          * @param {String} display (optional) What to set display to when visible
7067          * @return {Roo.Element} this
7068          */
7069         enableDisplayMode : function(display){
7070             this.setVisibilityMode(El.DISPLAY);
7071             if(typeof display != "undefined") { this.originalDisplay = display; }
7072             return this;
7073         },
7074
7075         /**
7076          * 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)
7077          * @param {String} selector The simple selector to test
7078          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7079                 search as a number or element (defaults to 10 || document.body)
7080          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7081          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7082          */
7083         findParent : function(simpleSelector, maxDepth, returnEl){
7084             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7085             maxDepth = maxDepth || 50;
7086             if(typeof maxDepth != "number"){
7087                 stopEl = Roo.getDom(maxDepth);
7088                 maxDepth = 10;
7089             }
7090             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7091                 if(dq.is(p, simpleSelector)){
7092                     return returnEl ? Roo.get(p) : p;
7093                 }
7094                 depth++;
7095                 p = p.parentNode;
7096             }
7097             return null;
7098         },
7099
7100
7101         /**
7102          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7103          * @param {String} selector The simple selector to test
7104          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7105                 search as a number or element (defaults to 10 || document.body)
7106          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7107          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7108          */
7109         findParentNode : function(simpleSelector, maxDepth, returnEl){
7110             var p = Roo.fly(this.dom.parentNode, '_internal');
7111             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7112         },
7113
7114         /**
7115          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7116          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7117          * @param {String} selector The simple selector to test
7118          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7119                 search as a number or element (defaults to 10 || document.body)
7120          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7121          */
7122         up : function(simpleSelector, maxDepth){
7123             return this.findParentNode(simpleSelector, maxDepth, true);
7124         },
7125
7126
7127
7128         /**
7129          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7130          * @param {String} selector The simple selector to test
7131          * @return {Boolean} True if this element matches the selector, else false
7132          */
7133         is : function(simpleSelector){
7134             return Roo.DomQuery.is(this.dom, simpleSelector);
7135         },
7136
7137         /**
7138          * Perform animation on this element.
7139          * @param {Object} args The YUI animation control args
7140          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7141          * @param {Function} onComplete (optional) Function to call when animation completes
7142          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7143          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7144          * @return {Roo.Element} this
7145          */
7146         animate : function(args, duration, onComplete, easing, animType){
7147             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7148             return this;
7149         },
7150
7151         /*
7152          * @private Internal animation call
7153          */
7154         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7155             animType = animType || 'run';
7156             opt = opt || {};
7157             var anim = Roo.lib.Anim[animType](
7158                 this.dom, args,
7159                 (opt.duration || defaultDur) || .35,
7160                 (opt.easing || defaultEase) || 'easeOut',
7161                 function(){
7162                     Roo.callback(cb, this);
7163                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7164                 },
7165                 this
7166             );
7167             opt.anim = anim;
7168             return anim;
7169         },
7170
7171         // private legacy anim prep
7172         preanim : function(a, i){
7173             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7174         },
7175
7176         /**
7177          * Removes worthless text nodes
7178          * @param {Boolean} forceReclean (optional) By default the element
7179          * keeps track if it has been cleaned already so
7180          * you can call this over and over. However, if you update the element and
7181          * need to force a reclean, you can pass true.
7182          */
7183         clean : function(forceReclean){
7184             if(this.isCleaned && forceReclean !== true){
7185                 return this;
7186             }
7187             var ns = /\S/;
7188             var d = this.dom, n = d.firstChild, ni = -1;
7189             while(n){
7190                 var nx = n.nextSibling;
7191                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7192                     d.removeChild(n);
7193                 }else{
7194                     n.nodeIndex = ++ni;
7195                 }
7196                 n = nx;
7197             }
7198             this.isCleaned = true;
7199             return this;
7200         },
7201
7202         // private
7203         calcOffsetsTo : function(el){
7204             el = Roo.get(el);
7205             var d = el.dom;
7206             var restorePos = false;
7207             if(el.getStyle('position') == 'static'){
7208                 el.position('relative');
7209                 restorePos = true;
7210             }
7211             var x = 0, y =0;
7212             var op = this.dom;
7213             while(op && op != d && op.tagName != 'HTML'){
7214                 x+= op.offsetLeft;
7215                 y+= op.offsetTop;
7216                 op = op.offsetParent;
7217             }
7218             if(restorePos){
7219                 el.position('static');
7220             }
7221             return [x, y];
7222         },
7223
7224         /**
7225          * Scrolls this element into view within the passed container.
7226          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7227          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7228          * @return {Roo.Element} this
7229          */
7230         scrollIntoView : function(container, hscroll){
7231             var c = Roo.getDom(container) || document.body;
7232             var el = this.dom;
7233
7234             var o = this.calcOffsetsTo(c),
7235                 l = o[0],
7236                 t = o[1],
7237                 b = t+el.offsetHeight,
7238                 r = l+el.offsetWidth;
7239
7240             var ch = c.clientHeight;
7241             var ct = parseInt(c.scrollTop, 10);
7242             var cl = parseInt(c.scrollLeft, 10);
7243             var cb = ct + ch;
7244             var cr = cl + c.clientWidth;
7245
7246             if(t < ct){
7247                 c.scrollTop = t;
7248             }else if(b > cb){
7249                 c.scrollTop = b-ch;
7250             }
7251
7252             if(hscroll !== false){
7253                 if(l < cl){
7254                     c.scrollLeft = l;
7255                 }else if(r > cr){
7256                     c.scrollLeft = r-c.clientWidth;
7257                 }
7258             }
7259             return this;
7260         },
7261
7262         // private
7263         scrollChildIntoView : function(child, hscroll){
7264             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7265         },
7266
7267         /**
7268          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7269          * the new height may not be available immediately.
7270          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7271          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7272          * @param {Function} onComplete (optional) Function to call when animation completes
7273          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7274          * @return {Roo.Element} this
7275          */
7276         autoHeight : function(animate, duration, onComplete, easing){
7277             var oldHeight = this.getHeight();
7278             this.clip();
7279             this.setHeight(1); // force clipping
7280             setTimeout(function(){
7281                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7282                 if(!animate){
7283                     this.setHeight(height);
7284                     this.unclip();
7285                     if(typeof onComplete == "function"){
7286                         onComplete();
7287                     }
7288                 }else{
7289                     this.setHeight(oldHeight); // restore original height
7290                     this.setHeight(height, animate, duration, function(){
7291                         this.unclip();
7292                         if(typeof onComplete == "function") { onComplete(); }
7293                     }.createDelegate(this), easing);
7294                 }
7295             }.createDelegate(this), 0);
7296             return this;
7297         },
7298
7299         /**
7300          * Returns true if this element is an ancestor of the passed element
7301          * @param {HTMLElement/String} el The element to check
7302          * @return {Boolean} True if this element is an ancestor of el, else false
7303          */
7304         contains : function(el){
7305             if(!el){return false;}
7306             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7307         },
7308
7309         /**
7310          * Checks whether the element is currently visible using both visibility and display properties.
7311          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7312          * @return {Boolean} True if the element is currently visible, else false
7313          */
7314         isVisible : function(deep) {
7315             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7316             if(deep !== true || !vis){
7317                 return vis;
7318             }
7319             var p = this.dom.parentNode;
7320             while(p && p.tagName.toLowerCase() != "body"){
7321                 if(!Roo.fly(p, '_isVisible').isVisible()){
7322                     return false;
7323                 }
7324                 p = p.parentNode;
7325             }
7326             return true;
7327         },
7328
7329         /**
7330          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7331          * @param {String} selector The CSS selector
7332          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7333          * @return {CompositeElement/CompositeElementLite} The composite element
7334          */
7335         select : function(selector, unique){
7336             return El.select(selector, unique, this.dom);
7337         },
7338
7339         /**
7340          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7341          * @param {String} selector The CSS selector
7342          * @return {Array} An array of the matched nodes
7343          */
7344         query : function(selector, unique){
7345             return Roo.DomQuery.select(selector, this.dom);
7346         },
7347
7348         /**
7349          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7350          * @param {String} selector The CSS selector
7351          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7352          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7353          */
7354         child : function(selector, returnDom){
7355             var n = Roo.DomQuery.selectNode(selector, this.dom);
7356             return returnDom ? n : Roo.get(n);
7357         },
7358
7359         /**
7360          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7361          * @param {String} selector The CSS selector
7362          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7363          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7364          */
7365         down : function(selector, returnDom){
7366             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7367             return returnDom ? n : Roo.get(n);
7368         },
7369
7370         /**
7371          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7372          * @param {String} group The group the DD object is member of
7373          * @param {Object} config The DD config object
7374          * @param {Object} overrides An object containing methods to override/implement on the DD object
7375          * @return {Roo.dd.DD} The DD object
7376          */
7377         initDD : function(group, config, overrides){
7378             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7379             return Roo.apply(dd, overrides);
7380         },
7381
7382         /**
7383          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7384          * @param {String} group The group the DDProxy object is member of
7385          * @param {Object} config The DDProxy config object
7386          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7387          * @return {Roo.dd.DDProxy} The DDProxy object
7388          */
7389         initDDProxy : function(group, config, overrides){
7390             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7391             return Roo.apply(dd, overrides);
7392         },
7393
7394         /**
7395          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7396          * @param {String} group The group the DDTarget object is member of
7397          * @param {Object} config The DDTarget config object
7398          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7399          * @return {Roo.dd.DDTarget} The DDTarget object
7400          */
7401         initDDTarget : function(group, config, overrides){
7402             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7403             return Roo.apply(dd, overrides);
7404         },
7405
7406         /**
7407          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7408          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7409          * @param {Boolean} visible Whether the element is visible
7410          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7411          * @return {Roo.Element} this
7412          */
7413          setVisible : function(visible, animate){
7414             if(!animate || !A){
7415                 if(this.visibilityMode == El.DISPLAY){
7416                     this.setDisplayed(visible);
7417                 }else{
7418                     this.fixDisplay();
7419                     this.dom.style.visibility = visible ? "visible" : "hidden";
7420                 }
7421             }else{
7422                 // closure for composites
7423                 var dom = this.dom;
7424                 var visMode = this.visibilityMode;
7425                 if(visible){
7426                     this.setOpacity(.01);
7427                     this.setVisible(true);
7428                 }
7429                 this.anim({opacity: { to: (visible?1:0) }},
7430                       this.preanim(arguments, 1),
7431                       null, .35, 'easeIn', function(){
7432                          if(!visible){
7433                              if(visMode == El.DISPLAY){
7434                                  dom.style.display = "none";
7435                              }else{
7436                                  dom.style.visibility = "hidden";
7437                              }
7438                              Roo.get(dom).setOpacity(1);
7439                          }
7440                      });
7441             }
7442             return this;
7443         },
7444
7445         /**
7446          * Returns true if display is not "none"
7447          * @return {Boolean}
7448          */
7449         isDisplayed : function() {
7450             return this.getStyle("display") != "none";
7451         },
7452
7453         /**
7454          * Toggles the element's visibility or display, depending on visibility mode.
7455          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7456          * @return {Roo.Element} this
7457          */
7458         toggle : function(animate){
7459             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7460             return this;
7461         },
7462
7463         /**
7464          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7465          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7466          * @return {Roo.Element} this
7467          */
7468         setDisplayed : function(value) {
7469             if(typeof value == "boolean"){
7470                value = value ? this.originalDisplay : "none";
7471             }
7472             this.setStyle("display", value);
7473             return this;
7474         },
7475
7476         /**
7477          * Tries to focus the element. Any exceptions are caught and ignored.
7478          * @return {Roo.Element} this
7479          */
7480         focus : function() {
7481             try{
7482                 this.dom.focus();
7483             }catch(e){}
7484             return this;
7485         },
7486
7487         /**
7488          * Tries to blur the element. Any exceptions are caught and ignored.
7489          * @return {Roo.Element} this
7490          */
7491         blur : function() {
7492             try{
7493                 this.dom.blur();
7494             }catch(e){}
7495             return this;
7496         },
7497
7498         /**
7499          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7500          * @param {String/Array} className The CSS class to add, or an array of classes
7501          * @return {Roo.Element} this
7502          */
7503         addClass : function(className){
7504             if(className instanceof Array){
7505                 for(var i = 0, len = className.length; i < len; i++) {
7506                     this.addClass(className[i]);
7507                 }
7508             }else{
7509                 if(className && !this.hasClass(className)){
7510                     this.dom.className = this.dom.className + " " + className;
7511                 }
7512             }
7513             return this;
7514         },
7515
7516         /**
7517          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7518          * @param {String/Array} className The CSS class to add, or an array of classes
7519          * @return {Roo.Element} this
7520          */
7521         radioClass : function(className){
7522             var siblings = this.dom.parentNode.childNodes;
7523             for(var i = 0; i < siblings.length; i++) {
7524                 var s = siblings[i];
7525                 if(s.nodeType == 1){
7526                     Roo.get(s).removeClass(className);
7527                 }
7528             }
7529             this.addClass(className);
7530             return this;
7531         },
7532
7533         /**
7534          * Removes one or more CSS classes from the element.
7535          * @param {String/Array} className The CSS class to remove, or an array of classes
7536          * @return {Roo.Element} this
7537          */
7538         removeClass : function(className){
7539             if(!className || !this.dom.className){
7540                 return this;
7541             }
7542             if(className instanceof Array){
7543                 for(var i = 0, len = className.length; i < len; i++) {
7544                     this.removeClass(className[i]);
7545                 }
7546             }else{
7547                 if(this.hasClass(className)){
7548                     var re = this.classReCache[className];
7549                     if (!re) {
7550                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7551                        this.classReCache[className] = re;
7552                     }
7553                     this.dom.className =
7554                         this.dom.className.replace(re, " ");
7555                 }
7556             }
7557             return this;
7558         },
7559
7560         // private
7561         classReCache: {},
7562
7563         /**
7564          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7565          * @param {String} className The CSS class to toggle
7566          * @return {Roo.Element} this
7567          */
7568         toggleClass : function(className){
7569             if(this.hasClass(className)){
7570                 this.removeClass(className);
7571             }else{
7572                 this.addClass(className);
7573             }
7574             return this;
7575         },
7576
7577         /**
7578          * Checks if the specified CSS class exists on this element's DOM node.
7579          * @param {String} className The CSS class to check for
7580          * @return {Boolean} True if the class exists, else false
7581          */
7582         hasClass : function(className){
7583             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7584         },
7585
7586         /**
7587          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7588          * @param {String} oldClassName The CSS class to replace
7589          * @param {String} newClassName The replacement CSS class
7590          * @return {Roo.Element} this
7591          */
7592         replaceClass : function(oldClassName, newClassName){
7593             this.removeClass(oldClassName);
7594             this.addClass(newClassName);
7595             return this;
7596         },
7597
7598         /**
7599          * Returns an object with properties matching the styles requested.
7600          * For example, el.getStyles('color', 'font-size', 'width') might return
7601          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7602          * @param {String} style1 A style name
7603          * @param {String} style2 A style name
7604          * @param {String} etc.
7605          * @return {Object} The style object
7606          */
7607         getStyles : function(){
7608             var a = arguments, len = a.length, r = {};
7609             for(var i = 0; i < len; i++){
7610                 r[a[i]] = this.getStyle(a[i]);
7611             }
7612             return r;
7613         },
7614
7615         /**
7616          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7617          * @param {String} property The style property whose value is returned.
7618          * @return {String} The current value of the style property for this element.
7619          */
7620         getStyle : function(){
7621             return view && view.getComputedStyle ?
7622                 function(prop){
7623                     var el = this.dom, v, cs, camel;
7624                     if(prop == 'float'){
7625                         prop = "cssFloat";
7626                     }
7627                     if(el.style && (v = el.style[prop])){
7628                         return v;
7629                     }
7630                     if(cs = view.getComputedStyle(el, "")){
7631                         if(!(camel = propCache[prop])){
7632                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7633                         }
7634                         return cs[camel];
7635                     }
7636                     return null;
7637                 } :
7638                 function(prop){
7639                     var el = this.dom, v, cs, camel;
7640                     if(prop == 'opacity'){
7641                         if(typeof el.style.filter == 'string'){
7642                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7643                             if(m){
7644                                 var fv = parseFloat(m[1]);
7645                                 if(!isNaN(fv)){
7646                                     return fv ? fv / 100 : 0;
7647                                 }
7648                             }
7649                         }
7650                         return 1;
7651                     }else if(prop == 'float'){
7652                         prop = "styleFloat";
7653                     }
7654                     if(!(camel = propCache[prop])){
7655                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7656                     }
7657                     if(v = el.style[camel]){
7658                         return v;
7659                     }
7660                     if(cs = el.currentStyle){
7661                         return cs[camel];
7662                     }
7663                     return null;
7664                 };
7665         }(),
7666
7667         /**
7668          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7669          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7670          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7671          * @return {Roo.Element} this
7672          */
7673         setStyle : function(prop, value){
7674             if(typeof prop == "string"){
7675                 
7676                 if (prop == 'float') {
7677                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7678                     return this;
7679                 }
7680                 
7681                 var camel;
7682                 if(!(camel = propCache[prop])){
7683                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7684                 }
7685                 
7686                 if(camel == 'opacity') {
7687                     this.setOpacity(value);
7688                 }else{
7689                     this.dom.style[camel] = value;
7690                 }
7691             }else{
7692                 for(var style in prop){
7693                     if(typeof prop[style] != "function"){
7694                        this.setStyle(style, prop[style]);
7695                     }
7696                 }
7697             }
7698             return this;
7699         },
7700
7701         /**
7702          * More flexible version of {@link #setStyle} for setting style properties.
7703          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7704          * a function which returns such a specification.
7705          * @return {Roo.Element} this
7706          */
7707         applyStyles : function(style){
7708             Roo.DomHelper.applyStyles(this.dom, style);
7709             return this;
7710         },
7711
7712         /**
7713           * 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).
7714           * @return {Number} The X position of the element
7715           */
7716         getX : function(){
7717             return D.getX(this.dom);
7718         },
7719
7720         /**
7721           * 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).
7722           * @return {Number} The Y position of the element
7723           */
7724         getY : function(){
7725             return D.getY(this.dom);
7726         },
7727
7728         /**
7729           * 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).
7730           * @return {Array} The XY position of the element
7731           */
7732         getXY : function(){
7733             return D.getXY(this.dom);
7734         },
7735
7736         /**
7737          * 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).
7738          * @param {Number} The X position of the element
7739          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7740          * @return {Roo.Element} this
7741          */
7742         setX : function(x, animate){
7743             if(!animate || !A){
7744                 D.setX(this.dom, x);
7745             }else{
7746                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7747             }
7748             return this;
7749         },
7750
7751         /**
7752          * 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).
7753          * @param {Number} The Y position of the element
7754          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7755          * @return {Roo.Element} this
7756          */
7757         setY : function(y, animate){
7758             if(!animate || !A){
7759                 D.setY(this.dom, y);
7760             }else{
7761                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7762             }
7763             return this;
7764         },
7765
7766         /**
7767          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7768          * @param {String} left The left CSS property value
7769          * @return {Roo.Element} this
7770          */
7771         setLeft : function(left){
7772             this.setStyle("left", this.addUnits(left));
7773             return this;
7774         },
7775
7776         /**
7777          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7778          * @param {String} top The top CSS property value
7779          * @return {Roo.Element} this
7780          */
7781         setTop : function(top){
7782             this.setStyle("top", this.addUnits(top));
7783             return this;
7784         },
7785
7786         /**
7787          * Sets the element's CSS right style.
7788          * @param {String} right The right CSS property value
7789          * @return {Roo.Element} this
7790          */
7791         setRight : function(right){
7792             this.setStyle("right", this.addUnits(right));
7793             return this;
7794         },
7795
7796         /**
7797          * Sets the element's CSS bottom style.
7798          * @param {String} bottom The bottom CSS property value
7799          * @return {Roo.Element} this
7800          */
7801         setBottom : function(bottom){
7802             this.setStyle("bottom", this.addUnits(bottom));
7803             return this;
7804         },
7805
7806         /**
7807          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7808          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7809          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7810          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7811          * @return {Roo.Element} this
7812          */
7813         setXY : function(pos, animate){
7814             if(!animate || !A){
7815                 D.setXY(this.dom, pos);
7816             }else{
7817                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7818             }
7819             return this;
7820         },
7821
7822         /**
7823          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7824          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7825          * @param {Number} x X value for new position (coordinates are page-based)
7826          * @param {Number} y Y value for new position (coordinates are page-based)
7827          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7828          * @return {Roo.Element} this
7829          */
7830         setLocation : function(x, y, animate){
7831             this.setXY([x, y], this.preanim(arguments, 2));
7832             return this;
7833         },
7834
7835         /**
7836          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7837          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7838          * @param {Number} x X value for new position (coordinates are page-based)
7839          * @param {Number} y Y value for new position (coordinates are page-based)
7840          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7841          * @return {Roo.Element} this
7842          */
7843         moveTo : function(x, y, animate){
7844             this.setXY([x, y], this.preanim(arguments, 2));
7845             return this;
7846         },
7847
7848         /**
7849          * Returns the region of the given element.
7850          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7851          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7852          */
7853         getRegion : function(){
7854             return D.getRegion(this.dom);
7855         },
7856
7857         /**
7858          * Returns the offset height of the element
7859          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7860          * @return {Number} The element's height
7861          */
7862         getHeight : function(contentHeight){
7863             var h = this.dom.offsetHeight || 0;
7864             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7865         },
7866
7867         /**
7868          * Returns the offset width of the element
7869          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7870          * @return {Number} The element's width
7871          */
7872         getWidth : function(contentWidth){
7873             var w = this.dom.offsetWidth || 0;
7874             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7875         },
7876
7877         /**
7878          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7879          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7880          * if a height has not been set using CSS.
7881          * @return {Number}
7882          */
7883         getComputedHeight : function(){
7884             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7885             if(!h){
7886                 h = parseInt(this.getStyle('height'), 10) || 0;
7887                 if(!this.isBorderBox()){
7888                     h += this.getFrameWidth('tb');
7889                 }
7890             }
7891             return h;
7892         },
7893
7894         /**
7895          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7896          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7897          * if a width has not been set using CSS.
7898          * @return {Number}
7899          */
7900         getComputedWidth : function(){
7901             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7902             if(!w){
7903                 w = parseInt(this.getStyle('width'), 10) || 0;
7904                 if(!this.isBorderBox()){
7905                     w += this.getFrameWidth('lr');
7906                 }
7907             }
7908             return w;
7909         },
7910
7911         /**
7912          * Returns the size of the element.
7913          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7914          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7915          */
7916         getSize : function(contentSize){
7917             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7918         },
7919
7920         /**
7921          * Returns the width and height of the viewport.
7922          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7923          */
7924         getViewSize : function(){
7925             var d = this.dom, doc = document, aw = 0, ah = 0;
7926             if(d == doc || d == doc.body){
7927                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7928             }else{
7929                 return {
7930                     width : d.clientWidth,
7931                     height: d.clientHeight
7932                 };
7933             }
7934         },
7935
7936         /**
7937          * Returns the value of the "value" attribute
7938          * @param {Boolean} asNumber true to parse the value as a number
7939          * @return {String/Number}
7940          */
7941         getValue : function(asNumber){
7942             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7943         },
7944
7945         // private
7946         adjustWidth : function(width){
7947             if(typeof width == "number"){
7948                 if(this.autoBoxAdjust && !this.isBorderBox()){
7949                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7950                 }
7951                 if(width < 0){
7952                     width = 0;
7953                 }
7954             }
7955             return width;
7956         },
7957
7958         // private
7959         adjustHeight : function(height){
7960             if(typeof height == "number"){
7961                if(this.autoBoxAdjust && !this.isBorderBox()){
7962                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7963                }
7964                if(height < 0){
7965                    height = 0;
7966                }
7967             }
7968             return height;
7969         },
7970
7971         /**
7972          * Set the width of the element
7973          * @param {Number} width The new width
7974          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7975          * @return {Roo.Element} this
7976          */
7977         setWidth : function(width, animate){
7978             width = this.adjustWidth(width);
7979             if(!animate || !A){
7980                 this.dom.style.width = this.addUnits(width);
7981             }else{
7982                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7983             }
7984             return this;
7985         },
7986
7987         /**
7988          * Set the height of the element
7989          * @param {Number} height The new height
7990          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7991          * @return {Roo.Element} this
7992          */
7993          setHeight : function(height, animate){
7994             height = this.adjustHeight(height);
7995             if(!animate || !A){
7996                 this.dom.style.height = this.addUnits(height);
7997             }else{
7998                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7999             }
8000             return this;
8001         },
8002
8003         /**
8004          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8005          * @param {Number} width The new width
8006          * @param {Number} height The new height
8007          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8008          * @return {Roo.Element} this
8009          */
8010          setSize : function(width, height, animate){
8011             if(typeof width == "object"){ // in case of object from getSize()
8012                 height = width.height; width = width.width;
8013             }
8014             width = this.adjustWidth(width); height = this.adjustHeight(height);
8015             if(!animate || !A){
8016                 this.dom.style.width = this.addUnits(width);
8017                 this.dom.style.height = this.addUnits(height);
8018             }else{
8019                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8020             }
8021             return this;
8022         },
8023
8024         /**
8025          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8026          * @param {Number} x X value for new position (coordinates are page-based)
8027          * @param {Number} y Y value for new position (coordinates are page-based)
8028          * @param {Number} width The new width
8029          * @param {Number} height The new height
8030          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8031          * @return {Roo.Element} this
8032          */
8033         setBounds : function(x, y, width, height, animate){
8034             if(!animate || !A){
8035                 this.setSize(width, height);
8036                 this.setLocation(x, y);
8037             }else{
8038                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8039                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8040                               this.preanim(arguments, 4), 'motion');
8041             }
8042             return this;
8043         },
8044
8045         /**
8046          * 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.
8047          * @param {Roo.lib.Region} region The region to fill
8048          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8049          * @return {Roo.Element} this
8050          */
8051         setRegion : function(region, animate){
8052             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8053             return this;
8054         },
8055
8056         /**
8057          * Appends an event handler
8058          *
8059          * @param {String}   eventName     The type of event to append
8060          * @param {Function} fn        The method the event invokes
8061          * @param {Object} scope       (optional) The scope (this object) of the fn
8062          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8063          */
8064         addListener : function(eventName, fn, scope, options){
8065             if (this.dom) {
8066                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8067             }
8068         },
8069
8070         /**
8071          * Removes an event handler from this element
8072          * @param {String} eventName the type of event to remove
8073          * @param {Function} fn the method the event invokes
8074          * @return {Roo.Element} this
8075          */
8076         removeListener : function(eventName, fn){
8077             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8078             return this;
8079         },
8080
8081         /**
8082          * Removes all previous added listeners from this element
8083          * @return {Roo.Element} this
8084          */
8085         removeAllListeners : function(){
8086             E.purgeElement(this.dom);
8087             return this;
8088         },
8089
8090         relayEvent : function(eventName, observable){
8091             this.on(eventName, function(e){
8092                 observable.fireEvent(eventName, e);
8093             });
8094         },
8095
8096         /**
8097          * Set the opacity of the element
8098          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8099          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8100          * @return {Roo.Element} this
8101          */
8102          setOpacity : function(opacity, animate){
8103             if(!animate || !A){
8104                 var s = this.dom.style;
8105                 if(Roo.isIE){
8106                     s.zoom = 1;
8107                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8108                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8109                 }else{
8110                     s.opacity = opacity;
8111                 }
8112             }else{
8113                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8114             }
8115             return this;
8116         },
8117
8118         /**
8119          * Gets the left X coordinate
8120          * @param {Boolean} local True to get the local css position instead of page coordinate
8121          * @return {Number}
8122          */
8123         getLeft : function(local){
8124             if(!local){
8125                 return this.getX();
8126             }else{
8127                 return parseInt(this.getStyle("left"), 10) || 0;
8128             }
8129         },
8130
8131         /**
8132          * Gets the right X coordinate of the element (element X position + element width)
8133          * @param {Boolean} local True to get the local css position instead of page coordinate
8134          * @return {Number}
8135          */
8136         getRight : function(local){
8137             if(!local){
8138                 return this.getX() + this.getWidth();
8139             }else{
8140                 return (this.getLeft(true) + this.getWidth()) || 0;
8141             }
8142         },
8143
8144         /**
8145          * Gets the top Y coordinate
8146          * @param {Boolean} local True to get the local css position instead of page coordinate
8147          * @return {Number}
8148          */
8149         getTop : function(local) {
8150             if(!local){
8151                 return this.getY();
8152             }else{
8153                 return parseInt(this.getStyle("top"), 10) || 0;
8154             }
8155         },
8156
8157         /**
8158          * Gets the bottom Y coordinate of the element (element Y position + element height)
8159          * @param {Boolean} local True to get the local css position instead of page coordinate
8160          * @return {Number}
8161          */
8162         getBottom : function(local){
8163             if(!local){
8164                 return this.getY() + this.getHeight();
8165             }else{
8166                 return (this.getTop(true) + this.getHeight()) || 0;
8167             }
8168         },
8169
8170         /**
8171         * Initializes positioning on this element. If a desired position is not passed, it will make the
8172         * the element positioned relative IF it is not already positioned.
8173         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8174         * @param {Number} zIndex (optional) The zIndex to apply
8175         * @param {Number} x (optional) Set the page X position
8176         * @param {Number} y (optional) Set the page Y position
8177         */
8178         position : function(pos, zIndex, x, y){
8179             if(!pos){
8180                if(this.getStyle('position') == 'static'){
8181                    this.setStyle('position', 'relative');
8182                }
8183             }else{
8184                 this.setStyle("position", pos);
8185             }
8186             if(zIndex){
8187                 this.setStyle("z-index", zIndex);
8188             }
8189             if(x !== undefined && y !== undefined){
8190                 this.setXY([x, y]);
8191             }else if(x !== undefined){
8192                 this.setX(x);
8193             }else if(y !== undefined){
8194                 this.setY(y);
8195             }
8196         },
8197
8198         /**
8199         * Clear positioning back to the default when the document was loaded
8200         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8201         * @return {Roo.Element} this
8202          */
8203         clearPositioning : function(value){
8204             value = value ||'';
8205             this.setStyle({
8206                 "left": value,
8207                 "right": value,
8208                 "top": value,
8209                 "bottom": value,
8210                 "z-index": "",
8211                 "position" : "static"
8212             });
8213             return this;
8214         },
8215
8216         /**
8217         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8218         * snapshot before performing an update and then restoring the element.
8219         * @return {Object}
8220         */
8221         getPositioning : function(){
8222             var l = this.getStyle("left");
8223             var t = this.getStyle("top");
8224             return {
8225                 "position" : this.getStyle("position"),
8226                 "left" : l,
8227                 "right" : l ? "" : this.getStyle("right"),
8228                 "top" : t,
8229                 "bottom" : t ? "" : this.getStyle("bottom"),
8230                 "z-index" : this.getStyle("z-index")
8231             };
8232         },
8233
8234         /**
8235          * Gets the width of the border(s) for the specified side(s)
8236          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8237          * passing lr would get the border (l)eft width + the border (r)ight width.
8238          * @return {Number} The width of the sides passed added together
8239          */
8240         getBorderWidth : function(side){
8241             return this.addStyles(side, El.borders);
8242         },
8243
8244         /**
8245          * Gets the width of the padding(s) for the specified side(s)
8246          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8247          * passing lr would get the padding (l)eft + the padding (r)ight.
8248          * @return {Number} The padding of the sides passed added together
8249          */
8250         getPadding : function(side){
8251             return this.addStyles(side, El.paddings);
8252         },
8253
8254         /**
8255         * Set positioning with an object returned by getPositioning().
8256         * @param {Object} posCfg
8257         * @return {Roo.Element} this
8258          */
8259         setPositioning : function(pc){
8260             this.applyStyles(pc);
8261             if(pc.right == "auto"){
8262                 this.dom.style.right = "";
8263             }
8264             if(pc.bottom == "auto"){
8265                 this.dom.style.bottom = "";
8266             }
8267             return this;
8268         },
8269
8270         // private
8271         fixDisplay : function(){
8272             if(this.getStyle("display") == "none"){
8273                 this.setStyle("visibility", "hidden");
8274                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8275                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8276                     this.setStyle("display", "block");
8277                 }
8278             }
8279         },
8280
8281         /**
8282          * Quick set left and top adding default units
8283          * @param {String} left The left CSS property value
8284          * @param {String} top The top CSS property value
8285          * @return {Roo.Element} this
8286          */
8287          setLeftTop : function(left, top){
8288             this.dom.style.left = this.addUnits(left);
8289             this.dom.style.top = this.addUnits(top);
8290             return this;
8291         },
8292
8293         /**
8294          * Move this element relative to its current position.
8295          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8296          * @param {Number} distance How far to move the element in pixels
8297          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8298          * @return {Roo.Element} this
8299          */
8300          move : function(direction, distance, animate){
8301             var xy = this.getXY();
8302             direction = direction.toLowerCase();
8303             switch(direction){
8304                 case "l":
8305                 case "left":
8306                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8307                     break;
8308                case "r":
8309                case "right":
8310                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8311                     break;
8312                case "t":
8313                case "top":
8314                case "up":
8315                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8316                     break;
8317                case "b":
8318                case "bottom":
8319                case "down":
8320                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8321                     break;
8322             }
8323             return this;
8324         },
8325
8326         /**
8327          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8328          * @return {Roo.Element} this
8329          */
8330         clip : function(){
8331             if(!this.isClipped){
8332                this.isClipped = true;
8333                this.originalClip = {
8334                    "o": this.getStyle("overflow"),
8335                    "x": this.getStyle("overflow-x"),
8336                    "y": this.getStyle("overflow-y")
8337                };
8338                this.setStyle("overflow", "hidden");
8339                this.setStyle("overflow-x", "hidden");
8340                this.setStyle("overflow-y", "hidden");
8341             }
8342             return this;
8343         },
8344
8345         /**
8346          *  Return clipping (overflow) to original clipping before clip() was called
8347          * @return {Roo.Element} this
8348          */
8349         unclip : function(){
8350             if(this.isClipped){
8351                 this.isClipped = false;
8352                 var o = this.originalClip;
8353                 if(o.o){this.setStyle("overflow", o.o);}
8354                 if(o.x){this.setStyle("overflow-x", o.x);}
8355                 if(o.y){this.setStyle("overflow-y", o.y);}
8356             }
8357             return this;
8358         },
8359
8360
8361         /**
8362          * Gets the x,y coordinates specified by the anchor position on the element.
8363          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8364          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8365          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8366          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8367          * @return {Array} [x, y] An array containing the element's x and y coordinates
8368          */
8369         getAnchorXY : function(anchor, local, s){
8370             //Passing a different size is useful for pre-calculating anchors,
8371             //especially for anchored animations that change the el size.
8372
8373             var w, h, vp = false;
8374             if(!s){
8375                 var d = this.dom;
8376                 if(d == document.body || d == document){
8377                     vp = true;
8378                     w = D.getViewWidth(); h = D.getViewHeight();
8379                 }else{
8380                     w = this.getWidth(); h = this.getHeight();
8381                 }
8382             }else{
8383                 w = s.width;  h = s.height;
8384             }
8385             var x = 0, y = 0, r = Math.round;
8386             switch((anchor || "tl").toLowerCase()){
8387                 case "c":
8388                     x = r(w*.5);
8389                     y = r(h*.5);
8390                 break;
8391                 case "t":
8392                     x = r(w*.5);
8393                     y = 0;
8394                 break;
8395                 case "l":
8396                     x = 0;
8397                     y = r(h*.5);
8398                 break;
8399                 case "r":
8400                     x = w;
8401                     y = r(h*.5);
8402                 break;
8403                 case "b":
8404                     x = r(w*.5);
8405                     y = h;
8406                 break;
8407                 case "tl":
8408                     x = 0;
8409                     y = 0;
8410                 break;
8411                 case "bl":
8412                     x = 0;
8413                     y = h;
8414                 break;
8415                 case "br":
8416                     x = w;
8417                     y = h;
8418                 break;
8419                 case "tr":
8420                     x = w;
8421                     y = 0;
8422                 break;
8423             }
8424             if(local === true){
8425                 return [x, y];
8426             }
8427             if(vp){
8428                 var sc = this.getScroll();
8429                 return [x + sc.left, y + sc.top];
8430             }
8431             //Add the element's offset xy
8432             var o = this.getXY();
8433             return [x+o[0], y+o[1]];
8434         },
8435
8436         /**
8437          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8438          * supported position values.
8439          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8440          * @param {String} position The position to align to.
8441          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8442          * @return {Array} [x, y]
8443          */
8444         getAlignToXY : function(el, p, o){
8445             el = Roo.get(el);
8446             var d = this.dom;
8447             if(!el.dom){
8448                 throw "Element.alignTo with an element that doesn't exist";
8449             }
8450             var c = false; //constrain to viewport
8451             var p1 = "", p2 = "";
8452             o = o || [0,0];
8453
8454             if(!p){
8455                 p = "tl-bl";
8456             }else if(p == "?"){
8457                 p = "tl-bl?";
8458             }else if(p.indexOf("-") == -1){
8459                 p = "tl-" + p;
8460             }
8461             p = p.toLowerCase();
8462             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8463             if(!m){
8464                throw "Element.alignTo with an invalid alignment " + p;
8465             }
8466             p1 = m[1]; p2 = m[2]; c = !!m[3];
8467
8468             //Subtract the aligned el's internal xy from the target's offset xy
8469             //plus custom offset to get the aligned el's new offset xy
8470             var a1 = this.getAnchorXY(p1, true);
8471             var a2 = el.getAnchorXY(p2, false);
8472             var x = a2[0] - a1[0] + o[0];
8473             var y = a2[1] - a1[1] + o[1];
8474             if(c){
8475                 //constrain the aligned el to viewport if necessary
8476                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8477                 // 5px of margin for ie
8478                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8479
8480                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8481                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8482                 //otherwise swap the aligned el to the opposite border of the target.
8483                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8484                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8485                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8486                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8487
8488                var doc = document;
8489                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8490                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8491
8492                if((x+w) > dw + scrollX){
8493                     x = swapX ? r.left-w : dw+scrollX-w;
8494                 }
8495                if(x < scrollX){
8496                    x = swapX ? r.right : scrollX;
8497                }
8498                if((y+h) > dh + scrollY){
8499                     y = swapY ? r.top-h : dh+scrollY-h;
8500                 }
8501                if (y < scrollY){
8502                    y = swapY ? r.bottom : scrollY;
8503                }
8504             }
8505             return [x,y];
8506         },
8507
8508         // private
8509         getConstrainToXY : function(){
8510             var os = {top:0, left:0, bottom:0, right: 0};
8511
8512             return function(el, local, offsets, proposedXY){
8513                 el = Roo.get(el);
8514                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8515
8516                 var vw, vh, vx = 0, vy = 0;
8517                 if(el.dom == document.body || el.dom == document){
8518                     vw = Roo.lib.Dom.getViewWidth();
8519                     vh = Roo.lib.Dom.getViewHeight();
8520                 }else{
8521                     vw = el.dom.clientWidth;
8522                     vh = el.dom.clientHeight;
8523                     if(!local){
8524                         var vxy = el.getXY();
8525                         vx = vxy[0];
8526                         vy = vxy[1];
8527                     }
8528                 }
8529
8530                 var s = el.getScroll();
8531
8532                 vx += offsets.left + s.left;
8533                 vy += offsets.top + s.top;
8534
8535                 vw -= offsets.right;
8536                 vh -= offsets.bottom;
8537
8538                 var vr = vx+vw;
8539                 var vb = vy+vh;
8540
8541                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8542                 var x = xy[0], y = xy[1];
8543                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8544
8545                 // only move it if it needs it
8546                 var moved = false;
8547
8548                 // first validate right/bottom
8549                 if((x + w) > vr){
8550                     x = vr - w;
8551                     moved = true;
8552                 }
8553                 if((y + h) > vb){
8554                     y = vb - h;
8555                     moved = true;
8556                 }
8557                 // then make sure top/left isn't negative
8558                 if(x < vx){
8559                     x = vx;
8560                     moved = true;
8561                 }
8562                 if(y < vy){
8563                     y = vy;
8564                     moved = true;
8565                 }
8566                 return moved ? [x, y] : false;
8567             };
8568         }(),
8569
8570         // private
8571         adjustForConstraints : function(xy, parent, offsets){
8572             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8573         },
8574
8575         /**
8576          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8577          * document it aligns it to the viewport.
8578          * The position parameter is optional, and can be specified in any one of the following formats:
8579          * <ul>
8580          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8581          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8582          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8583          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8584          *   <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
8585          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8586          * </ul>
8587          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8588          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8589          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8590          * that specified in order to enforce the viewport constraints.
8591          * Following are all of the supported anchor positions:
8592     <pre>
8593     Value  Description
8594     -----  -----------------------------
8595     tl     The top left corner (default)
8596     t      The center of the top edge
8597     tr     The top right corner
8598     l      The center of the left edge
8599     c      In the center of the element
8600     r      The center of the right edge
8601     bl     The bottom left corner
8602     b      The center of the bottom edge
8603     br     The bottom right corner
8604     </pre>
8605     Example Usage:
8606     <pre><code>
8607     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8608     el.alignTo("other-el");
8609
8610     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8611     el.alignTo("other-el", "tr?");
8612
8613     // align the bottom right corner of el with the center left edge of other-el
8614     el.alignTo("other-el", "br-l?");
8615
8616     // align the center of el with the bottom left corner of other-el and
8617     // adjust the x position by -6 pixels (and the y position by 0)
8618     el.alignTo("other-el", "c-bl", [-6, 0]);
8619     </code></pre>
8620          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8621          * @param {String} position The position to align to.
8622          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8623          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8624          * @return {Roo.Element} this
8625          */
8626         alignTo : function(element, position, offsets, animate){
8627             var xy = this.getAlignToXY(element, position, offsets);
8628             this.setXY(xy, this.preanim(arguments, 3));
8629             return this;
8630         },
8631
8632         /**
8633          * Anchors an element to another element and realigns it when the window is resized.
8634          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8635          * @param {String} position The position to align to.
8636          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8637          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8638          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8639          * is a number, it is used as the buffer delay (defaults to 50ms).
8640          * @param {Function} callback The function to call after the animation finishes
8641          * @return {Roo.Element} this
8642          */
8643         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8644             var action = function(){
8645                 this.alignTo(el, alignment, offsets, animate);
8646                 Roo.callback(callback, this);
8647             };
8648             Roo.EventManager.onWindowResize(action, this);
8649             var tm = typeof monitorScroll;
8650             if(tm != 'undefined'){
8651                 Roo.EventManager.on(window, 'scroll', action, this,
8652                     {buffer: tm == 'number' ? monitorScroll : 50});
8653             }
8654             action.call(this); // align immediately
8655             return this;
8656         },
8657         /**
8658          * Clears any opacity settings from this element. Required in some cases for IE.
8659          * @return {Roo.Element} this
8660          */
8661         clearOpacity : function(){
8662             if (window.ActiveXObject) {
8663                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8664                     this.dom.style.filter = "";
8665                 }
8666             } else {
8667                 this.dom.style.opacity = "";
8668                 this.dom.style["-moz-opacity"] = "";
8669                 this.dom.style["-khtml-opacity"] = "";
8670             }
8671             return this;
8672         },
8673
8674         /**
8675          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8676          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8677          * @return {Roo.Element} this
8678          */
8679         hide : function(animate){
8680             this.setVisible(false, this.preanim(arguments, 0));
8681             return this;
8682         },
8683
8684         /**
8685         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8686         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8687          * @return {Roo.Element} this
8688          */
8689         show : function(animate){
8690             this.setVisible(true, this.preanim(arguments, 0));
8691             return this;
8692         },
8693
8694         /**
8695          * @private Test if size has a unit, otherwise appends the default
8696          */
8697         addUnits : function(size){
8698             return Roo.Element.addUnits(size, this.defaultUnit);
8699         },
8700
8701         /**
8702          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8703          * @return {Roo.Element} this
8704          */
8705         beginMeasure : function(){
8706             var el = this.dom;
8707             if(el.offsetWidth || el.offsetHeight){
8708                 return this; // offsets work already
8709             }
8710             var changed = [];
8711             var p = this.dom, b = document.body; // start with this element
8712             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8713                 var pe = Roo.get(p);
8714                 if(pe.getStyle('display') == 'none'){
8715                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8716                     p.style.visibility = "hidden";
8717                     p.style.display = "block";
8718                 }
8719                 p = p.parentNode;
8720             }
8721             this._measureChanged = changed;
8722             return this;
8723
8724         },
8725
8726         /**
8727          * Restores displays to before beginMeasure was called
8728          * @return {Roo.Element} this
8729          */
8730         endMeasure : function(){
8731             var changed = this._measureChanged;
8732             if(changed){
8733                 for(var i = 0, len = changed.length; i < len; i++) {
8734                     var r = changed[i];
8735                     r.el.style.visibility = r.visibility;
8736                     r.el.style.display = "none";
8737                 }
8738                 this._measureChanged = null;
8739             }
8740             return this;
8741         },
8742
8743         /**
8744         * Update the innerHTML of this element, optionally searching for and processing scripts
8745         * @param {String} html The new HTML
8746         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8747         * @param {Function} callback For async script loading you can be noticed when the update completes
8748         * @return {Roo.Element} this
8749          */
8750         update : function(html, loadScripts, callback){
8751             if(typeof html == "undefined"){
8752                 html = "";
8753             }
8754             if(loadScripts !== true){
8755                 this.dom.innerHTML = html;
8756                 if(typeof callback == "function"){
8757                     callback();
8758                 }
8759                 return this;
8760             }
8761             var id = Roo.id();
8762             var dom = this.dom;
8763
8764             html += '<span id="' + id + '"></span>';
8765
8766             E.onAvailable(id, function(){
8767                 var hd = document.getElementsByTagName("head")[0];
8768                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8769                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8770                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8771
8772                 var match;
8773                 while(match = re.exec(html)){
8774                     var attrs = match[1];
8775                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8776                     if(srcMatch && srcMatch[2]){
8777                        var s = document.createElement("script");
8778                        s.src = srcMatch[2];
8779                        var typeMatch = attrs.match(typeRe);
8780                        if(typeMatch && typeMatch[2]){
8781                            s.type = typeMatch[2];
8782                        }
8783                        hd.appendChild(s);
8784                     }else if(match[2] && match[2].length > 0){
8785                         if(window.execScript) {
8786                            window.execScript(match[2]);
8787                         } else {
8788                             /**
8789                              * eval:var:id
8790                              * eval:var:dom
8791                              * eval:var:html
8792                              * 
8793                              */
8794                            window.eval(match[2]);
8795                         }
8796                     }
8797                 }
8798                 var el = document.getElementById(id);
8799                 if(el){el.parentNode.removeChild(el);}
8800                 if(typeof callback == "function"){
8801                     callback();
8802                 }
8803             });
8804             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8805             return this;
8806         },
8807
8808         /**
8809          * Direct access to the UpdateManager update() method (takes the same parameters).
8810          * @param {String/Function} url The url for this request or a function to call to get the url
8811          * @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}
8812          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8813          * @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.
8814          * @return {Roo.Element} this
8815          */
8816         load : function(){
8817             var um = this.getUpdateManager();
8818             um.update.apply(um, arguments);
8819             return this;
8820         },
8821
8822         /**
8823         * Gets this element's UpdateManager
8824         * @return {Roo.UpdateManager} The UpdateManager
8825         */
8826         getUpdateManager : function(){
8827             if(!this.updateManager){
8828                 this.updateManager = new Roo.UpdateManager(this);
8829             }
8830             return this.updateManager;
8831         },
8832
8833         /**
8834          * Disables text selection for this element (normalized across browsers)
8835          * @return {Roo.Element} this
8836          */
8837         unselectable : function(){
8838             this.dom.unselectable = "on";
8839             this.swallowEvent("selectstart", true);
8840             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8841             this.addClass("x-unselectable");
8842             return this;
8843         },
8844
8845         /**
8846         * Calculates the x, y to center this element on the screen
8847         * @return {Array} The x, y values [x, y]
8848         */
8849         getCenterXY : function(){
8850             return this.getAlignToXY(document, 'c-c');
8851         },
8852
8853         /**
8854         * Centers the Element in either the viewport, or another Element.
8855         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8856         */
8857         center : function(centerIn){
8858             this.alignTo(centerIn || document, 'c-c');
8859             return this;
8860         },
8861
8862         /**
8863          * Tests various css rules/browsers to determine if this element uses a border box
8864          * @return {Boolean}
8865          */
8866         isBorderBox : function(){
8867             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8868         },
8869
8870         /**
8871          * Return a box {x, y, width, height} that can be used to set another elements
8872          * size/location to match this element.
8873          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8874          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8875          * @return {Object} box An object in the format {x, y, width, height}
8876          */
8877         getBox : function(contentBox, local){
8878             var xy;
8879             if(!local){
8880                 xy = this.getXY();
8881             }else{
8882                 var left = parseInt(this.getStyle("left"), 10) || 0;
8883                 var top = parseInt(this.getStyle("top"), 10) || 0;
8884                 xy = [left, top];
8885             }
8886             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8887             if(!contentBox){
8888                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8889             }else{
8890                 var l = this.getBorderWidth("l")+this.getPadding("l");
8891                 var r = this.getBorderWidth("r")+this.getPadding("r");
8892                 var t = this.getBorderWidth("t")+this.getPadding("t");
8893                 var b = this.getBorderWidth("b")+this.getPadding("b");
8894                 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)};
8895             }
8896             bx.right = bx.x + bx.width;
8897             bx.bottom = bx.y + bx.height;
8898             return bx;
8899         },
8900
8901         /**
8902          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8903          for more information about the sides.
8904          * @param {String} sides
8905          * @return {Number}
8906          */
8907         getFrameWidth : function(sides, onlyContentBox){
8908             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8909         },
8910
8911         /**
8912          * 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.
8913          * @param {Object} box The box to fill {x, y, width, height}
8914          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8915          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8916          * @return {Roo.Element} this
8917          */
8918         setBox : function(box, adjust, animate){
8919             var w = box.width, h = box.height;
8920             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8921                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8922                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8923             }
8924             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8925             return this;
8926         },
8927
8928         /**
8929          * Forces the browser to repaint this element
8930          * @return {Roo.Element} this
8931          */
8932          repaint : function(){
8933             var dom = this.dom;
8934             this.addClass("x-repaint");
8935             setTimeout(function(){
8936                 Roo.get(dom).removeClass("x-repaint");
8937             }, 1);
8938             return this;
8939         },
8940
8941         /**
8942          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8943          * then it returns the calculated width of the sides (see getPadding)
8944          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8945          * @return {Object/Number}
8946          */
8947         getMargins : function(side){
8948             if(!side){
8949                 return {
8950                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8951                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8952                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8953                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8954                 };
8955             }else{
8956                 return this.addStyles(side, El.margins);
8957              }
8958         },
8959
8960         // private
8961         addStyles : function(sides, styles){
8962             var val = 0, v, w;
8963             for(var i = 0, len = sides.length; i < len; i++){
8964                 v = this.getStyle(styles[sides.charAt(i)]);
8965                 if(v){
8966                      w = parseInt(v, 10);
8967                      if(w){ val += w; }
8968                 }
8969             }
8970             return val;
8971         },
8972
8973         /**
8974          * Creates a proxy element of this element
8975          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8976          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8977          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8978          * @return {Roo.Element} The new proxy element
8979          */
8980         createProxy : function(config, renderTo, matchBox){
8981             if(renderTo){
8982                 renderTo = Roo.getDom(renderTo);
8983             }else{
8984                 renderTo = document.body;
8985             }
8986             config = typeof config == "object" ?
8987                 config : {tag : "div", cls: config};
8988             var proxy = Roo.DomHelper.append(renderTo, config, true);
8989             if(matchBox){
8990                proxy.setBox(this.getBox());
8991             }
8992             return proxy;
8993         },
8994
8995         /**
8996          * Puts a mask over this element to disable user interaction. Requires core.css.
8997          * This method can only be applied to elements which accept child nodes.
8998          * @param {String} msg (optional) A message to display in the mask
8999          * @param {String} msgCls (optional) A css class to apply to the msg element
9000          * @return {Element} The mask  element
9001          */
9002         mask : function(msg, msgCls)
9003         {
9004             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9005                 this.setStyle("position", "relative");
9006             }
9007             if(!this._mask){
9008                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9009             }
9010             this.addClass("x-masked");
9011             this._mask.setDisplayed(true);
9012             
9013             // we wander
9014             var z = 0;
9015             var dom = this.dom;
9016             while (dom && dom.style) {
9017                 if (!isNaN(parseInt(dom.style.zIndex))) {
9018                     z = Math.max(z, parseInt(dom.style.zIndex));
9019                 }
9020                 dom = dom.parentNode;
9021             }
9022             // if we are masking the body - then it hides everything..
9023             if (this.dom == document.body) {
9024                 z = 1000000;
9025                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9026                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9027             }
9028            
9029             if(typeof msg == 'string'){
9030                 if(!this._maskMsg){
9031                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9032                 }
9033                 var mm = this._maskMsg;
9034                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9035                 if (mm.dom.firstChild) { // weird IE issue?
9036                     mm.dom.firstChild.innerHTML = msg;
9037                 }
9038                 mm.setDisplayed(true);
9039                 mm.center(this);
9040                 mm.setStyle('z-index', z + 102);
9041             }
9042             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9043                 this._mask.setHeight(this.getHeight());
9044             }
9045             this._mask.setStyle('z-index', z + 100);
9046             
9047             return this._mask;
9048         },
9049
9050         /**
9051          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9052          * it is cached for reuse.
9053          */
9054         unmask : function(removeEl){
9055             if(this._mask){
9056                 if(removeEl === true){
9057                     this._mask.remove();
9058                     delete this._mask;
9059                     if(this._maskMsg){
9060                         this._maskMsg.remove();
9061                         delete this._maskMsg;
9062                     }
9063                 }else{
9064                     this._mask.setDisplayed(false);
9065                     if(this._maskMsg){
9066                         this._maskMsg.setDisplayed(false);
9067                     }
9068                 }
9069             }
9070             this.removeClass("x-masked");
9071         },
9072
9073         /**
9074          * Returns true if this element is masked
9075          * @return {Boolean}
9076          */
9077         isMasked : function(){
9078             return this._mask && this._mask.isVisible();
9079         },
9080
9081         /**
9082          * Creates an iframe shim for this element to keep selects and other windowed objects from
9083          * showing through.
9084          * @return {Roo.Element} The new shim element
9085          */
9086         createShim : function(){
9087             var el = document.createElement('iframe');
9088             el.frameBorder = 'no';
9089             el.className = 'roo-shim';
9090             if(Roo.isIE && Roo.isSecure){
9091                 el.src = Roo.SSL_SECURE_URL;
9092             }
9093             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9094             shim.autoBoxAdjust = false;
9095             return shim;
9096         },
9097
9098         /**
9099          * Removes this element from the DOM and deletes it from the cache
9100          */
9101         remove : function(){
9102             if(this.dom.parentNode){
9103                 this.dom.parentNode.removeChild(this.dom);
9104             }
9105             delete El.cache[this.dom.id];
9106         },
9107
9108         /**
9109          * Sets up event handlers to add and remove a css class when the mouse is over this element
9110          * @param {String} className
9111          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9112          * mouseout events for children elements
9113          * @return {Roo.Element} this
9114          */
9115         addClassOnOver : function(className, preventFlicker){
9116             this.on("mouseover", function(){
9117                 Roo.fly(this, '_internal').addClass(className);
9118             }, this.dom);
9119             var removeFn = function(e){
9120                 if(preventFlicker !== true || !e.within(this, true)){
9121                     Roo.fly(this, '_internal').removeClass(className);
9122                 }
9123             };
9124             this.on("mouseout", removeFn, this.dom);
9125             return this;
9126         },
9127
9128         /**
9129          * Sets up event handlers to add and remove a css class when this element has the focus
9130          * @param {String} className
9131          * @return {Roo.Element} this
9132          */
9133         addClassOnFocus : function(className){
9134             this.on("focus", function(){
9135                 Roo.fly(this, '_internal').addClass(className);
9136             }, this.dom);
9137             this.on("blur", function(){
9138                 Roo.fly(this, '_internal').removeClass(className);
9139             }, this.dom);
9140             return this;
9141         },
9142         /**
9143          * 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)
9144          * @param {String} className
9145          * @return {Roo.Element} this
9146          */
9147         addClassOnClick : function(className){
9148             var dom = this.dom;
9149             this.on("mousedown", function(){
9150                 Roo.fly(dom, '_internal').addClass(className);
9151                 var d = Roo.get(document);
9152                 var fn = function(){
9153                     Roo.fly(dom, '_internal').removeClass(className);
9154                     d.removeListener("mouseup", fn);
9155                 };
9156                 d.on("mouseup", fn);
9157             });
9158             return this;
9159         },
9160
9161         /**
9162          * Stops the specified event from bubbling and optionally prevents the default action
9163          * @param {String} eventName
9164          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9165          * @return {Roo.Element} this
9166          */
9167         swallowEvent : function(eventName, preventDefault){
9168             var fn = function(e){
9169                 e.stopPropagation();
9170                 if(preventDefault){
9171                     e.preventDefault();
9172                 }
9173             };
9174             if(eventName instanceof Array){
9175                 for(var i = 0, len = eventName.length; i < len; i++){
9176                      this.on(eventName[i], fn);
9177                 }
9178                 return this;
9179             }
9180             this.on(eventName, fn);
9181             return this;
9182         },
9183
9184         /**
9185          * @private
9186          */
9187       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9188
9189         /**
9190          * Sizes this element to its parent element's dimensions performing
9191          * neccessary box adjustments.
9192          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9193          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9194          * @return {Roo.Element} this
9195          */
9196         fitToParent : function(monitorResize, targetParent) {
9197           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9198           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9199           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9200             return;
9201           }
9202           var p = Roo.get(targetParent || this.dom.parentNode);
9203           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9204           if (monitorResize === true) {
9205             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9206             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9207           }
9208           return this;
9209         },
9210
9211         /**
9212          * Gets the next sibling, skipping text nodes
9213          * @return {HTMLElement} The next sibling or null
9214          */
9215         getNextSibling : function(){
9216             var n = this.dom.nextSibling;
9217             while(n && n.nodeType != 1){
9218                 n = n.nextSibling;
9219             }
9220             return n;
9221         },
9222
9223         /**
9224          * Gets the previous sibling, skipping text nodes
9225          * @return {HTMLElement} The previous sibling or null
9226          */
9227         getPrevSibling : function(){
9228             var n = this.dom.previousSibling;
9229             while(n && n.nodeType != 1){
9230                 n = n.previousSibling;
9231             }
9232             return n;
9233         },
9234
9235
9236         /**
9237          * Appends the passed element(s) to this element
9238          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9239          * @return {Roo.Element} this
9240          */
9241         appendChild: function(el){
9242             el = Roo.get(el);
9243             el.appendTo(this);
9244             return this;
9245         },
9246
9247         /**
9248          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9249          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9250          * automatically generated with the specified attributes.
9251          * @param {HTMLElement} insertBefore (optional) a child element of this element
9252          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9253          * @return {Roo.Element} The new child element
9254          */
9255         createChild: function(config, insertBefore, returnDom){
9256             config = config || {tag:'div'};
9257             if(insertBefore){
9258                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9259             }
9260             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9261         },
9262
9263         /**
9264          * Appends this element to the passed element
9265          * @param {String/HTMLElement/Element} el The new parent element
9266          * @return {Roo.Element} this
9267          */
9268         appendTo: function(el){
9269             el = Roo.getDom(el);
9270             el.appendChild(this.dom);
9271             return this;
9272         },
9273
9274         /**
9275          * Inserts this element before the passed element in the DOM
9276          * @param {String/HTMLElement/Element} el The element to insert before
9277          * @return {Roo.Element} this
9278          */
9279         insertBefore: function(el){
9280             el = Roo.getDom(el);
9281             el.parentNode.insertBefore(this.dom, el);
9282             return this;
9283         },
9284
9285         /**
9286          * Inserts this element after the passed element in the DOM
9287          * @param {String/HTMLElement/Element} el The element to insert after
9288          * @return {Roo.Element} this
9289          */
9290         insertAfter: function(el){
9291             el = Roo.getDom(el);
9292             el.parentNode.insertBefore(this.dom, el.nextSibling);
9293             return this;
9294         },
9295
9296         /**
9297          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9298          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9299          * @return {Roo.Element} The new child
9300          */
9301         insertFirst: function(el, returnDom){
9302             el = el || {};
9303             if(typeof el == 'object' && !el.nodeType){ // dh config
9304                 return this.createChild(el, this.dom.firstChild, returnDom);
9305             }else{
9306                 el = Roo.getDom(el);
9307                 this.dom.insertBefore(el, this.dom.firstChild);
9308                 return !returnDom ? Roo.get(el) : el;
9309             }
9310         },
9311
9312         /**
9313          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9314          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9315          * @param {String} where (optional) 'before' or 'after' defaults to before
9316          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9317          * @return {Roo.Element} the inserted Element
9318          */
9319         insertSibling: function(el, where, returnDom){
9320             where = where ? where.toLowerCase() : 'before';
9321             el = el || {};
9322             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9323
9324             if(typeof el == 'object' && !el.nodeType){ // dh config
9325                 if(where == 'after' && !this.dom.nextSibling){
9326                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9327                 }else{
9328                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9329                 }
9330
9331             }else{
9332                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9333                             where == 'before' ? this.dom : this.dom.nextSibling);
9334                 if(!returnDom){
9335                     rt = Roo.get(rt);
9336                 }
9337             }
9338             return rt;
9339         },
9340
9341         /**
9342          * Creates and wraps this element with another element
9343          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9344          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9345          * @return {HTMLElement/Element} The newly created wrapper element
9346          */
9347         wrap: function(config, returnDom){
9348             if(!config){
9349                 config = {tag: "div"};
9350             }
9351             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9352             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9353             return newEl;
9354         },
9355
9356         /**
9357          * Replaces the passed element with this element
9358          * @param {String/HTMLElement/Element} el The element to replace
9359          * @return {Roo.Element} this
9360          */
9361         replace: function(el){
9362             el = Roo.get(el);
9363             this.insertBefore(el);
9364             el.remove();
9365             return this;
9366         },
9367
9368         /**
9369          * Inserts an html fragment into this element
9370          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9371          * @param {String} html The HTML fragment
9372          * @param {Boolean} returnEl True to return an Roo.Element
9373          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9374          */
9375         insertHtml : function(where, html, returnEl){
9376             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9377             return returnEl ? Roo.get(el) : el;
9378         },
9379
9380         /**
9381          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9382          * @param {Object} o The object with the attributes
9383          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9384          * @return {Roo.Element} this
9385          */
9386         set : function(o, useSet){
9387             var el = this.dom;
9388             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9389             for(var attr in o){
9390                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9391                 if(attr=="cls"){
9392                     el.className = o["cls"];
9393                 }else{
9394                     if(useSet) {
9395                         el.setAttribute(attr, o[attr]);
9396                     } else {
9397                         el[attr] = o[attr];
9398                     }
9399                 }
9400             }
9401             if(o.style){
9402                 Roo.DomHelper.applyStyles(el, o.style);
9403             }
9404             return this;
9405         },
9406
9407         /**
9408          * Convenience method for constructing a KeyMap
9409          * @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:
9410          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9411          * @param {Function} fn The function to call
9412          * @param {Object} scope (optional) The scope of the function
9413          * @return {Roo.KeyMap} The KeyMap created
9414          */
9415         addKeyListener : function(key, fn, scope){
9416             var config;
9417             if(typeof key != "object" || key instanceof Array){
9418                 config = {
9419                     key: key,
9420                     fn: fn,
9421                     scope: scope
9422                 };
9423             }else{
9424                 config = {
9425                     key : key.key,
9426                     shift : key.shift,
9427                     ctrl : key.ctrl,
9428                     alt : key.alt,
9429                     fn: fn,
9430                     scope: scope
9431                 };
9432             }
9433             return new Roo.KeyMap(this, config);
9434         },
9435
9436         /**
9437          * Creates a KeyMap for this element
9438          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9439          * @return {Roo.KeyMap} The KeyMap created
9440          */
9441         addKeyMap : function(config){
9442             return new Roo.KeyMap(this, config);
9443         },
9444
9445         /**
9446          * Returns true if this element is scrollable.
9447          * @return {Boolean}
9448          */
9449          isScrollable : function(){
9450             var dom = this.dom;
9451             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9452         },
9453
9454         /**
9455          * 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().
9456          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9457          * @param {Number} value The new scroll value
9458          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9459          * @return {Element} this
9460          */
9461
9462         scrollTo : function(side, value, animate){
9463             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9464             if(!animate || !A){
9465                 this.dom[prop] = value;
9466             }else{
9467                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9468                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9469             }
9470             return this;
9471         },
9472
9473         /**
9474          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9475          * within this element's scrollable range.
9476          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9477          * @param {Number} distance How far to scroll the element in pixels
9478          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9479          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9480          * was scrolled as far as it could go.
9481          */
9482          scroll : function(direction, distance, animate){
9483              if(!this.isScrollable()){
9484                  return;
9485              }
9486              var el = this.dom;
9487              var l = el.scrollLeft, t = el.scrollTop;
9488              var w = el.scrollWidth, h = el.scrollHeight;
9489              var cw = el.clientWidth, ch = el.clientHeight;
9490              direction = direction.toLowerCase();
9491              var scrolled = false;
9492              var a = this.preanim(arguments, 2);
9493              switch(direction){
9494                  case "l":
9495                  case "left":
9496                      if(w - l > cw){
9497                          var v = Math.min(l + distance, w-cw);
9498                          this.scrollTo("left", v, a);
9499                          scrolled = true;
9500                      }
9501                      break;
9502                 case "r":
9503                 case "right":
9504                      if(l > 0){
9505                          var v = Math.max(l - distance, 0);
9506                          this.scrollTo("left", v, a);
9507                          scrolled = true;
9508                      }
9509                      break;
9510                 case "t":
9511                 case "top":
9512                 case "up":
9513                      if(t > 0){
9514                          var v = Math.max(t - distance, 0);
9515                          this.scrollTo("top", v, a);
9516                          scrolled = true;
9517                      }
9518                      break;
9519                 case "b":
9520                 case "bottom":
9521                 case "down":
9522                      if(h - t > ch){
9523                          var v = Math.min(t + distance, h-ch);
9524                          this.scrollTo("top", v, a);
9525                          scrolled = true;
9526                      }
9527                      break;
9528              }
9529              return scrolled;
9530         },
9531
9532         /**
9533          * Translates the passed page coordinates into left/top css values for this element
9534          * @param {Number/Array} x The page x or an array containing [x, y]
9535          * @param {Number} y The page y
9536          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9537          */
9538         translatePoints : function(x, y){
9539             if(typeof x == 'object' || x instanceof Array){
9540                 y = x[1]; x = x[0];
9541             }
9542             var p = this.getStyle('position');
9543             var o = this.getXY();
9544
9545             var l = parseInt(this.getStyle('left'), 10);
9546             var t = parseInt(this.getStyle('top'), 10);
9547
9548             if(isNaN(l)){
9549                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9550             }
9551             if(isNaN(t)){
9552                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9553             }
9554
9555             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9556         },
9557
9558         /**
9559          * Returns the current scroll position of the element.
9560          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9561          */
9562         getScroll : function(){
9563             var d = this.dom, doc = document;
9564             if(d == doc || d == doc.body){
9565                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9566                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9567                 return {left: l, top: t};
9568             }else{
9569                 return {left: d.scrollLeft, top: d.scrollTop};
9570             }
9571         },
9572
9573         /**
9574          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9575          * are convert to standard 6 digit hex color.
9576          * @param {String} attr The css attribute
9577          * @param {String} defaultValue The default value to use when a valid color isn't found
9578          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9579          * YUI color anims.
9580          */
9581         getColor : function(attr, defaultValue, prefix){
9582             var v = this.getStyle(attr);
9583             if(!v || v == "transparent" || v == "inherit") {
9584                 return defaultValue;
9585             }
9586             var color = typeof prefix == "undefined" ? "#" : prefix;
9587             if(v.substr(0, 4) == "rgb("){
9588                 var rvs = v.slice(4, v.length -1).split(",");
9589                 for(var i = 0; i < 3; i++){
9590                     var h = parseInt(rvs[i]).toString(16);
9591                     if(h < 16){
9592                         h = "0" + h;
9593                     }
9594                     color += h;
9595                 }
9596             } else {
9597                 if(v.substr(0, 1) == "#"){
9598                     if(v.length == 4) {
9599                         for(var i = 1; i < 4; i++){
9600                             var c = v.charAt(i);
9601                             color +=  c + c;
9602                         }
9603                     }else if(v.length == 7){
9604                         color += v.substr(1);
9605                     }
9606                 }
9607             }
9608             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9609         },
9610
9611         /**
9612          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9613          * gradient background, rounded corners and a 4-way shadow.
9614          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9615          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9616          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9617          * @return {Roo.Element} this
9618          */
9619         boxWrap : function(cls){
9620             cls = cls || 'x-box';
9621             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9622             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9623             return el;
9624         },
9625
9626         /**
9627          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9628          * @param {String} namespace The namespace in which to look for the attribute
9629          * @param {String} name The attribute name
9630          * @return {String} The attribute value
9631          */
9632         getAttributeNS : Roo.isIE ? function(ns, name){
9633             var d = this.dom;
9634             var type = typeof d[ns+":"+name];
9635             if(type != 'undefined' && type != 'unknown'){
9636                 return d[ns+":"+name];
9637             }
9638             return d[name];
9639         } : function(ns, name){
9640             var d = this.dom;
9641             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9642         },
9643         
9644         
9645         /**
9646          * Sets or Returns the value the dom attribute value
9647          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9648          * @param {String} value (optional) The value to set the attribute to
9649          * @return {String} The attribute value
9650          */
9651         attr : function(name){
9652             if (arguments.length > 1) {
9653                 this.dom.setAttribute(name, arguments[1]);
9654                 return arguments[1];
9655             }
9656             if (typeof(name) == 'object') {
9657                 for(var i in name) {
9658                     this.attr(i, name[i]);
9659                 }
9660                 return name;
9661             }
9662             
9663             
9664             if (!this.dom.hasAttribute(name)) {
9665                 return undefined;
9666             }
9667             return this.dom.getAttribute(name);
9668         }
9669         
9670         
9671         
9672     };
9673
9674     var ep = El.prototype;
9675
9676     /**
9677      * Appends an event handler (Shorthand for addListener)
9678      * @param {String}   eventName     The type of event to append
9679      * @param {Function} fn        The method the event invokes
9680      * @param {Object} scope       (optional) The scope (this object) of the fn
9681      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9682      * @method
9683      */
9684     ep.on = ep.addListener;
9685         // backwards compat
9686     ep.mon = ep.addListener;
9687
9688     /**
9689      * Removes an event handler from this element (shorthand for removeListener)
9690      * @param {String} eventName the type of event to remove
9691      * @param {Function} fn the method the event invokes
9692      * @return {Roo.Element} this
9693      * @method
9694      */
9695     ep.un = ep.removeListener;
9696
9697     /**
9698      * true to automatically adjust width and height settings for box-model issues (default to true)
9699      */
9700     ep.autoBoxAdjust = true;
9701
9702     // private
9703     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9704
9705     // private
9706     El.addUnits = function(v, defaultUnit){
9707         if(v === "" || v == "auto"){
9708             return v;
9709         }
9710         if(v === undefined){
9711             return '';
9712         }
9713         if(typeof v == "number" || !El.unitPattern.test(v)){
9714             return v + (defaultUnit || 'px');
9715         }
9716         return v;
9717     };
9718
9719     // special markup used throughout Roo when box wrapping elements
9720     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>';
9721     /**
9722      * Visibility mode constant - Use visibility to hide element
9723      * @static
9724      * @type Number
9725      */
9726     El.VISIBILITY = 1;
9727     /**
9728      * Visibility mode constant - Use display to hide element
9729      * @static
9730      * @type Number
9731      */
9732     El.DISPLAY = 2;
9733
9734     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9735     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9736     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9737
9738
9739
9740     /**
9741      * @private
9742      */
9743     El.cache = {};
9744
9745     var docEl;
9746
9747     /**
9748      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9749      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9750      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9751      * @return {Element} The Element object
9752      * @static
9753      */
9754     El.get = function(el){
9755         var ex, elm, id;
9756         if(!el){ return null; }
9757         if(typeof el == "string"){ // element id
9758             if(!(elm = document.getElementById(el))){
9759                 return null;
9760             }
9761             if(ex = El.cache[el]){
9762                 ex.dom = elm;
9763             }else{
9764                 ex = El.cache[el] = new El(elm);
9765             }
9766             return ex;
9767         }else if(el.tagName){ // dom element
9768             if(!(id = el.id)){
9769                 id = Roo.id(el);
9770             }
9771             if(ex = El.cache[id]){
9772                 ex.dom = el;
9773             }else{
9774                 ex = El.cache[id] = new El(el);
9775             }
9776             return ex;
9777         }else if(el instanceof El){
9778             if(el != docEl){
9779                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9780                                                               // catch case where it hasn't been appended
9781                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9782             }
9783             return el;
9784         }else if(el.isComposite){
9785             return el;
9786         }else if(el instanceof Array){
9787             return El.select(el);
9788         }else if(el == document){
9789             // create a bogus element object representing the document object
9790             if(!docEl){
9791                 var f = function(){};
9792                 f.prototype = El.prototype;
9793                 docEl = new f();
9794                 docEl.dom = document;
9795             }
9796             return docEl;
9797         }
9798         return null;
9799     };
9800
9801     // private
9802     El.uncache = function(el){
9803         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9804             if(a[i]){
9805                 delete El.cache[a[i].id || a[i]];
9806             }
9807         }
9808     };
9809
9810     // private
9811     // Garbage collection - uncache elements/purge listeners on orphaned elements
9812     // so we don't hold a reference and cause the browser to retain them
9813     El.garbageCollect = function(){
9814         if(!Roo.enableGarbageCollector){
9815             clearInterval(El.collectorThread);
9816             return;
9817         }
9818         for(var eid in El.cache){
9819             var el = El.cache[eid], d = el.dom;
9820             // -------------------------------------------------------
9821             // Determining what is garbage:
9822             // -------------------------------------------------------
9823             // !d
9824             // dom node is null, definitely garbage
9825             // -------------------------------------------------------
9826             // !d.parentNode
9827             // no parentNode == direct orphan, definitely garbage
9828             // -------------------------------------------------------
9829             // !d.offsetParent && !document.getElementById(eid)
9830             // display none elements have no offsetParent so we will
9831             // also try to look it up by it's id. However, check
9832             // offsetParent first so we don't do unneeded lookups.
9833             // This enables collection of elements that are not orphans
9834             // directly, but somewhere up the line they have an orphan
9835             // parent.
9836             // -------------------------------------------------------
9837             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9838                 delete El.cache[eid];
9839                 if(d && Roo.enableListenerCollection){
9840                     E.purgeElement(d);
9841                 }
9842             }
9843         }
9844     }
9845     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9846
9847
9848     // dom is optional
9849     El.Flyweight = function(dom){
9850         this.dom = dom;
9851     };
9852     El.Flyweight.prototype = El.prototype;
9853
9854     El._flyweights = {};
9855     /**
9856      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9857      * the dom node can be overwritten by other code.
9858      * @param {String/HTMLElement} el The dom node or id
9859      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9860      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9861      * @static
9862      * @return {Element} The shared Element object
9863      */
9864     El.fly = function(el, named){
9865         named = named || '_global';
9866         el = Roo.getDom(el);
9867         if(!el){
9868             return null;
9869         }
9870         if(!El._flyweights[named]){
9871             El._flyweights[named] = new El.Flyweight();
9872         }
9873         El._flyweights[named].dom = el;
9874         return El._flyweights[named];
9875     };
9876
9877     /**
9878      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9879      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9880      * Shorthand of {@link Roo.Element#get}
9881      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9882      * @return {Element} The Element object
9883      * @member Roo
9884      * @method get
9885      */
9886     Roo.get = El.get;
9887     /**
9888      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9889      * the dom node can be overwritten by other code.
9890      * Shorthand of {@link Roo.Element#fly}
9891      * @param {String/HTMLElement} el The dom node or id
9892      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9893      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9894      * @static
9895      * @return {Element} The shared Element object
9896      * @member Roo
9897      * @method fly
9898      */
9899     Roo.fly = El.fly;
9900
9901     // speedy lookup for elements never to box adjust
9902     var noBoxAdjust = Roo.isStrict ? {
9903         select:1
9904     } : {
9905         input:1, select:1, textarea:1
9906     };
9907     if(Roo.isIE || Roo.isGecko){
9908         noBoxAdjust['button'] = 1;
9909     }
9910
9911
9912     Roo.EventManager.on(window, 'unload', function(){
9913         delete El.cache;
9914         delete El._flyweights;
9915     });
9916 })();
9917
9918
9919
9920
9921 if(Roo.DomQuery){
9922     Roo.Element.selectorFunction = Roo.DomQuery.select;
9923 }
9924
9925 Roo.Element.select = function(selector, unique, root){
9926     var els;
9927     if(typeof selector == "string"){
9928         els = Roo.Element.selectorFunction(selector, root);
9929     }else if(selector.length !== undefined){
9930         els = selector;
9931     }else{
9932         throw "Invalid selector";
9933     }
9934     if(unique === true){
9935         return new Roo.CompositeElement(els);
9936     }else{
9937         return new Roo.CompositeElementLite(els);
9938     }
9939 };
9940 /**
9941  * Selects elements based on the passed CSS selector to enable working on them as 1.
9942  * @param {String/Array} selector The CSS selector or an array of elements
9943  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9944  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9945  * @return {CompositeElementLite/CompositeElement}
9946  * @member Roo
9947  * @method select
9948  */
9949 Roo.select = Roo.Element.select;
9950
9951
9952
9953
9954
9955
9956
9957
9958
9959
9960
9961
9962
9963
9964 /*
9965  * Based on:
9966  * Ext JS Library 1.1.1
9967  * Copyright(c) 2006-2007, Ext JS, LLC.
9968  *
9969  * Originally Released Under LGPL - original licence link has changed is not relivant.
9970  *
9971  * Fork - LGPL
9972  * <script type="text/javascript">
9973  */
9974
9975
9976
9977 //Notifies Element that fx methods are available
9978 Roo.enableFx = true;
9979
9980 /**
9981  * @class Roo.Fx
9982  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9983  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9984  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9985  * Element effects to work.</p><br/>
9986  *
9987  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9988  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9989  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9990  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9991  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9992  * expected results and should be done with care.</p><br/>
9993  *
9994  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9995  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9996 <pre>
9997 Value  Description
9998 -----  -----------------------------
9999 tl     The top left corner
10000 t      The center of the top edge
10001 tr     The top right corner
10002 l      The center of the left edge
10003 r      The center of the right edge
10004 bl     The bottom left corner
10005 b      The center of the bottom edge
10006 br     The bottom right corner
10007 </pre>
10008  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10009  * below are common options that can be passed to any Fx method.</b>
10010  * @cfg {Function} callback A function called when the effect is finished
10011  * @cfg {Object} scope The scope of the effect function
10012  * @cfg {String} easing A valid Easing value for the effect
10013  * @cfg {String} afterCls A css class to apply after the effect
10014  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10015  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10016  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10017  * effects that end with the element being visually hidden, ignored otherwise)
10018  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10019  * a function which returns such a specification that will be applied to the Element after the effect finishes
10020  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10021  * @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
10022  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10023  */
10024 Roo.Fx = {
10025         /**
10026          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10027          * origin for the slide effect.  This function automatically handles wrapping the element with
10028          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10029          * Usage:
10030          *<pre><code>
10031 // default: slide the element in from the top
10032 el.slideIn();
10033
10034 // custom: slide the element in from the right with a 2-second duration
10035 el.slideIn('r', { duration: 2 });
10036
10037 // common config options shown with default values
10038 el.slideIn('t', {
10039     easing: 'easeOut',
10040     duration: .5
10041 });
10042 </code></pre>
10043          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10044          * @param {Object} options (optional) Object literal with any of the Fx config options
10045          * @return {Roo.Element} The Element
10046          */
10047     slideIn : function(anchor, o){
10048         var el = this.getFxEl();
10049         o = o || {};
10050
10051         el.queueFx(o, function(){
10052
10053             anchor = anchor || "t";
10054
10055             // fix display to visibility
10056             this.fixDisplay();
10057
10058             // restore values after effect
10059             var r = this.getFxRestore();
10060             var b = this.getBox();
10061             // fixed size for slide
10062             this.setSize(b);
10063
10064             // wrap if needed
10065             var wrap = this.fxWrap(r.pos, o, "hidden");
10066
10067             var st = this.dom.style;
10068             st.visibility = "visible";
10069             st.position = "absolute";
10070
10071             // clear out temp styles after slide and unwrap
10072             var after = function(){
10073                 el.fxUnwrap(wrap, r.pos, o);
10074                 st.width = r.width;
10075                 st.height = r.height;
10076                 el.afterFx(o);
10077             };
10078             // time to calc the positions
10079             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10080
10081             switch(anchor.toLowerCase()){
10082                 case "t":
10083                     wrap.setSize(b.width, 0);
10084                     st.left = st.bottom = "0";
10085                     a = {height: bh};
10086                 break;
10087                 case "l":
10088                     wrap.setSize(0, b.height);
10089                     st.right = st.top = "0";
10090                     a = {width: bw};
10091                 break;
10092                 case "r":
10093                     wrap.setSize(0, b.height);
10094                     wrap.setX(b.right);
10095                     st.left = st.top = "0";
10096                     a = {width: bw, points: pt};
10097                 break;
10098                 case "b":
10099                     wrap.setSize(b.width, 0);
10100                     wrap.setY(b.bottom);
10101                     st.left = st.top = "0";
10102                     a = {height: bh, points: pt};
10103                 break;
10104                 case "tl":
10105                     wrap.setSize(0, 0);
10106                     st.right = st.bottom = "0";
10107                     a = {width: bw, height: bh};
10108                 break;
10109                 case "bl":
10110                     wrap.setSize(0, 0);
10111                     wrap.setY(b.y+b.height);
10112                     st.right = st.top = "0";
10113                     a = {width: bw, height: bh, points: pt};
10114                 break;
10115                 case "br":
10116                     wrap.setSize(0, 0);
10117                     wrap.setXY([b.right, b.bottom]);
10118                     st.left = st.top = "0";
10119                     a = {width: bw, height: bh, points: pt};
10120                 break;
10121                 case "tr":
10122                     wrap.setSize(0, 0);
10123                     wrap.setX(b.x+b.width);
10124                     st.left = st.bottom = "0";
10125                     a = {width: bw, height: bh, points: pt};
10126                 break;
10127             }
10128             this.dom.style.visibility = "visible";
10129             wrap.show();
10130
10131             arguments.callee.anim = wrap.fxanim(a,
10132                 o,
10133                 'motion',
10134                 .5,
10135                 'easeOut', after);
10136         });
10137         return this;
10138     },
10139     
10140         /**
10141          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10142          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10143          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10144          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10145          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10146          * Usage:
10147          *<pre><code>
10148 // default: slide the element out to the top
10149 el.slideOut();
10150
10151 // custom: slide the element out to the right with a 2-second duration
10152 el.slideOut('r', { duration: 2 });
10153
10154 // common config options shown with default values
10155 el.slideOut('t', {
10156     easing: 'easeOut',
10157     duration: .5,
10158     remove: false,
10159     useDisplay: false
10160 });
10161 </code></pre>
10162          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10163          * @param {Object} options (optional) Object literal with any of the Fx config options
10164          * @return {Roo.Element} The Element
10165          */
10166     slideOut : function(anchor, o){
10167         var el = this.getFxEl();
10168         o = o || {};
10169
10170         el.queueFx(o, function(){
10171
10172             anchor = anchor || "t";
10173
10174             // restore values after effect
10175             var r = this.getFxRestore();
10176             
10177             var b = this.getBox();
10178             // fixed size for slide
10179             this.setSize(b);
10180
10181             // wrap if needed
10182             var wrap = this.fxWrap(r.pos, o, "visible");
10183
10184             var st = this.dom.style;
10185             st.visibility = "visible";
10186             st.position = "absolute";
10187
10188             wrap.setSize(b);
10189
10190             var after = function(){
10191                 if(o.useDisplay){
10192                     el.setDisplayed(false);
10193                 }else{
10194                     el.hide();
10195                 }
10196
10197                 el.fxUnwrap(wrap, r.pos, o);
10198
10199                 st.width = r.width;
10200                 st.height = r.height;
10201
10202                 el.afterFx(o);
10203             };
10204
10205             var a, zero = {to: 0};
10206             switch(anchor.toLowerCase()){
10207                 case "t":
10208                     st.left = st.bottom = "0";
10209                     a = {height: zero};
10210                 break;
10211                 case "l":
10212                     st.right = st.top = "0";
10213                     a = {width: zero};
10214                 break;
10215                 case "r":
10216                     st.left = st.top = "0";
10217                     a = {width: zero, points: {to:[b.right, b.y]}};
10218                 break;
10219                 case "b":
10220                     st.left = st.top = "0";
10221                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10222                 break;
10223                 case "tl":
10224                     st.right = st.bottom = "0";
10225                     a = {width: zero, height: zero};
10226                 break;
10227                 case "bl":
10228                     st.right = st.top = "0";
10229                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10230                 break;
10231                 case "br":
10232                     st.left = st.top = "0";
10233                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10234                 break;
10235                 case "tr":
10236                     st.left = st.bottom = "0";
10237                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10238                 break;
10239             }
10240
10241             arguments.callee.anim = wrap.fxanim(a,
10242                 o,
10243                 'motion',
10244                 .5,
10245                 "easeOut", after);
10246         });
10247         return this;
10248     },
10249
10250         /**
10251          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10252          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10253          * The element must be removed from the DOM using the 'remove' config option if desired.
10254          * Usage:
10255          *<pre><code>
10256 // default
10257 el.puff();
10258
10259 // common config options shown with default values
10260 el.puff({
10261     easing: 'easeOut',
10262     duration: .5,
10263     remove: false,
10264     useDisplay: false
10265 });
10266 </code></pre>
10267          * @param {Object} options (optional) Object literal with any of the Fx config options
10268          * @return {Roo.Element} The Element
10269          */
10270     puff : function(o){
10271         var el = this.getFxEl();
10272         o = o || {};
10273
10274         el.queueFx(o, function(){
10275             this.clearOpacity();
10276             this.show();
10277
10278             // restore values after effect
10279             var r = this.getFxRestore();
10280             var st = this.dom.style;
10281
10282             var after = function(){
10283                 if(o.useDisplay){
10284                     el.setDisplayed(false);
10285                 }else{
10286                     el.hide();
10287                 }
10288
10289                 el.clearOpacity();
10290
10291                 el.setPositioning(r.pos);
10292                 st.width = r.width;
10293                 st.height = r.height;
10294                 st.fontSize = '';
10295                 el.afterFx(o);
10296             };
10297
10298             var width = this.getWidth();
10299             var height = this.getHeight();
10300
10301             arguments.callee.anim = this.fxanim({
10302                     width : {to: this.adjustWidth(width * 2)},
10303                     height : {to: this.adjustHeight(height * 2)},
10304                     points : {by: [-(width * .5), -(height * .5)]},
10305                     opacity : {to: 0},
10306                     fontSize: {to:200, unit: "%"}
10307                 },
10308                 o,
10309                 'motion',
10310                 .5,
10311                 "easeOut", after);
10312         });
10313         return this;
10314     },
10315
10316         /**
10317          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10318          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10319          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10320          * Usage:
10321          *<pre><code>
10322 // default
10323 el.switchOff();
10324
10325 // all config options shown with default values
10326 el.switchOff({
10327     easing: 'easeIn',
10328     duration: .3,
10329     remove: false,
10330     useDisplay: false
10331 });
10332 </code></pre>
10333          * @param {Object} options (optional) Object literal with any of the Fx config options
10334          * @return {Roo.Element} The Element
10335          */
10336     switchOff : function(o){
10337         var el = this.getFxEl();
10338         o = o || {};
10339
10340         el.queueFx(o, function(){
10341             this.clearOpacity();
10342             this.clip();
10343
10344             // restore values after effect
10345             var r = this.getFxRestore();
10346             var st = this.dom.style;
10347
10348             var after = function(){
10349                 if(o.useDisplay){
10350                     el.setDisplayed(false);
10351                 }else{
10352                     el.hide();
10353                 }
10354
10355                 el.clearOpacity();
10356                 el.setPositioning(r.pos);
10357                 st.width = r.width;
10358                 st.height = r.height;
10359
10360                 el.afterFx(o);
10361             };
10362
10363             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10364                 this.clearOpacity();
10365                 (function(){
10366                     this.fxanim({
10367                         height:{to:1},
10368                         points:{by:[0, this.getHeight() * .5]}
10369                     }, o, 'motion', 0.3, 'easeIn', after);
10370                 }).defer(100, this);
10371             });
10372         });
10373         return this;
10374     },
10375
10376     /**
10377      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10378      * changed using the "attr" config option) and then fading back to the original color. If no original
10379      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10380      * Usage:
10381 <pre><code>
10382 // default: highlight background to yellow
10383 el.highlight();
10384
10385 // custom: highlight foreground text to blue for 2 seconds
10386 el.highlight("0000ff", { attr: 'color', duration: 2 });
10387
10388 // common config options shown with default values
10389 el.highlight("ffff9c", {
10390     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10391     endColor: (current color) or "ffffff",
10392     easing: 'easeIn',
10393     duration: 1
10394 });
10395 </code></pre>
10396      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10397      * @param {Object} options (optional) Object literal with any of the Fx config options
10398      * @return {Roo.Element} The Element
10399      */ 
10400     highlight : function(color, o){
10401         var el = this.getFxEl();
10402         o = o || {};
10403
10404         el.queueFx(o, function(){
10405             color = color || "ffff9c";
10406             attr = o.attr || "backgroundColor";
10407
10408             this.clearOpacity();
10409             this.show();
10410
10411             var origColor = this.getColor(attr);
10412             var restoreColor = this.dom.style[attr];
10413             endColor = (o.endColor || origColor) || "ffffff";
10414
10415             var after = function(){
10416                 el.dom.style[attr] = restoreColor;
10417                 el.afterFx(o);
10418             };
10419
10420             var a = {};
10421             a[attr] = {from: color, to: endColor};
10422             arguments.callee.anim = this.fxanim(a,
10423                 o,
10424                 'color',
10425                 1,
10426                 'easeIn', after);
10427         });
10428         return this;
10429     },
10430
10431    /**
10432     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10433     * Usage:
10434 <pre><code>
10435 // default: a single light blue ripple
10436 el.frame();
10437
10438 // custom: 3 red ripples lasting 3 seconds total
10439 el.frame("ff0000", 3, { duration: 3 });
10440
10441 // common config options shown with default values
10442 el.frame("C3DAF9", 1, {
10443     duration: 1 //duration of entire animation (not each individual ripple)
10444     // Note: Easing is not configurable and will be ignored if included
10445 });
10446 </code></pre>
10447     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10448     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10449     * @param {Object} options (optional) Object literal with any of the Fx config options
10450     * @return {Roo.Element} The Element
10451     */
10452     frame : function(color, count, o){
10453         var el = this.getFxEl();
10454         o = o || {};
10455
10456         el.queueFx(o, function(){
10457             color = color || "#C3DAF9";
10458             if(color.length == 6){
10459                 color = "#" + color;
10460             }
10461             count = count || 1;
10462             duration = o.duration || 1;
10463             this.show();
10464
10465             var b = this.getBox();
10466             var animFn = function(){
10467                 var proxy = this.createProxy({
10468
10469                      style:{
10470                         visbility:"hidden",
10471                         position:"absolute",
10472                         "z-index":"35000", // yee haw
10473                         border:"0px solid " + color
10474                      }
10475                   });
10476                 var scale = Roo.isBorderBox ? 2 : 1;
10477                 proxy.animate({
10478                     top:{from:b.y, to:b.y - 20},
10479                     left:{from:b.x, to:b.x - 20},
10480                     borderWidth:{from:0, to:10},
10481                     opacity:{from:1, to:0},
10482                     height:{from:b.height, to:(b.height + (20*scale))},
10483                     width:{from:b.width, to:(b.width + (20*scale))}
10484                 }, duration, function(){
10485                     proxy.remove();
10486                 });
10487                 if(--count > 0){
10488                      animFn.defer((duration/2)*1000, this);
10489                 }else{
10490                     el.afterFx(o);
10491                 }
10492             };
10493             animFn.call(this);
10494         });
10495         return this;
10496     },
10497
10498    /**
10499     * Creates a pause before any subsequent queued effects begin.  If there are
10500     * no effects queued after the pause it will have no effect.
10501     * Usage:
10502 <pre><code>
10503 el.pause(1);
10504 </code></pre>
10505     * @param {Number} seconds The length of time to pause (in seconds)
10506     * @return {Roo.Element} The Element
10507     */
10508     pause : function(seconds){
10509         var el = this.getFxEl();
10510         var o = {};
10511
10512         el.queueFx(o, function(){
10513             setTimeout(function(){
10514                 el.afterFx(o);
10515             }, seconds * 1000);
10516         });
10517         return this;
10518     },
10519
10520    /**
10521     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10522     * using the "endOpacity" config option.
10523     * Usage:
10524 <pre><code>
10525 // default: fade in from opacity 0 to 100%
10526 el.fadeIn();
10527
10528 // custom: fade in from opacity 0 to 75% over 2 seconds
10529 el.fadeIn({ endOpacity: .75, duration: 2});
10530
10531 // common config options shown with default values
10532 el.fadeIn({
10533     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10534     easing: 'easeOut',
10535     duration: .5
10536 });
10537 </code></pre>
10538     * @param {Object} options (optional) Object literal with any of the Fx config options
10539     * @return {Roo.Element} The Element
10540     */
10541     fadeIn : function(o){
10542         var el = this.getFxEl();
10543         o = o || {};
10544         el.queueFx(o, function(){
10545             this.setOpacity(0);
10546             this.fixDisplay();
10547             this.dom.style.visibility = 'visible';
10548             var to = o.endOpacity || 1;
10549             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10550                 o, null, .5, "easeOut", function(){
10551                 if(to == 1){
10552                     this.clearOpacity();
10553                 }
10554                 el.afterFx(o);
10555             });
10556         });
10557         return this;
10558     },
10559
10560    /**
10561     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10562     * using the "endOpacity" config option.
10563     * Usage:
10564 <pre><code>
10565 // default: fade out from the element's current opacity to 0
10566 el.fadeOut();
10567
10568 // custom: fade out from the element's current opacity to 25% over 2 seconds
10569 el.fadeOut({ endOpacity: .25, duration: 2});
10570
10571 // common config options shown with default values
10572 el.fadeOut({
10573     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10574     easing: 'easeOut',
10575     duration: .5
10576     remove: false,
10577     useDisplay: false
10578 });
10579 </code></pre>
10580     * @param {Object} options (optional) Object literal with any of the Fx config options
10581     * @return {Roo.Element} The Element
10582     */
10583     fadeOut : function(o){
10584         var el = this.getFxEl();
10585         o = o || {};
10586         el.queueFx(o, function(){
10587             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10588                 o, null, .5, "easeOut", function(){
10589                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10590                      this.dom.style.display = "none";
10591                 }else{
10592                      this.dom.style.visibility = "hidden";
10593                 }
10594                 this.clearOpacity();
10595                 el.afterFx(o);
10596             });
10597         });
10598         return this;
10599     },
10600
10601    /**
10602     * Animates the transition of an element's dimensions from a starting height/width
10603     * to an ending height/width.
10604     * Usage:
10605 <pre><code>
10606 // change height and width to 100x100 pixels
10607 el.scale(100, 100);
10608
10609 // common config options shown with default values.  The height and width will default to
10610 // the element's existing values if passed as null.
10611 el.scale(
10612     [element's width],
10613     [element's height], {
10614     easing: 'easeOut',
10615     duration: .35
10616 });
10617 </code></pre>
10618     * @param {Number} width  The new width (pass undefined to keep the original width)
10619     * @param {Number} height  The new height (pass undefined to keep the original height)
10620     * @param {Object} options (optional) Object literal with any of the Fx config options
10621     * @return {Roo.Element} The Element
10622     */
10623     scale : function(w, h, o){
10624         this.shift(Roo.apply({}, o, {
10625             width: w,
10626             height: h
10627         }));
10628         return this;
10629     },
10630
10631    /**
10632     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10633     * Any of these properties not specified in the config object will not be changed.  This effect 
10634     * requires that at least one new dimension, position or opacity setting must be passed in on
10635     * the config object in order for the function to have any effect.
10636     * Usage:
10637 <pre><code>
10638 // slide the element horizontally to x position 200 while changing the height and opacity
10639 el.shift({ x: 200, height: 50, opacity: .8 });
10640
10641 // common config options shown with default values.
10642 el.shift({
10643     width: [element's width],
10644     height: [element's height],
10645     x: [element's x position],
10646     y: [element's y position],
10647     opacity: [element's opacity],
10648     easing: 'easeOut',
10649     duration: .35
10650 });
10651 </code></pre>
10652     * @param {Object} options  Object literal with any of the Fx config options
10653     * @return {Roo.Element} The Element
10654     */
10655     shift : function(o){
10656         var el = this.getFxEl();
10657         o = o || {};
10658         el.queueFx(o, function(){
10659             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10660             if(w !== undefined){
10661                 a.width = {to: this.adjustWidth(w)};
10662             }
10663             if(h !== undefined){
10664                 a.height = {to: this.adjustHeight(h)};
10665             }
10666             if(x !== undefined || y !== undefined){
10667                 a.points = {to: [
10668                     x !== undefined ? x : this.getX(),
10669                     y !== undefined ? y : this.getY()
10670                 ]};
10671             }
10672             if(op !== undefined){
10673                 a.opacity = {to: op};
10674             }
10675             if(o.xy !== undefined){
10676                 a.points = {to: o.xy};
10677             }
10678             arguments.callee.anim = this.fxanim(a,
10679                 o, 'motion', .35, "easeOut", function(){
10680                 el.afterFx(o);
10681             });
10682         });
10683         return this;
10684     },
10685
10686         /**
10687          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10688          * ending point of the effect.
10689          * Usage:
10690          *<pre><code>
10691 // default: slide the element downward while fading out
10692 el.ghost();
10693
10694 // custom: slide the element out to the right with a 2-second duration
10695 el.ghost('r', { duration: 2 });
10696
10697 // common config options shown with default values
10698 el.ghost('b', {
10699     easing: 'easeOut',
10700     duration: .5
10701     remove: false,
10702     useDisplay: false
10703 });
10704 </code></pre>
10705          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10706          * @param {Object} options (optional) Object literal with any of the Fx config options
10707          * @return {Roo.Element} The Element
10708          */
10709     ghost : function(anchor, o){
10710         var el = this.getFxEl();
10711         o = o || {};
10712
10713         el.queueFx(o, function(){
10714             anchor = anchor || "b";
10715
10716             // restore values after effect
10717             var r = this.getFxRestore();
10718             var w = this.getWidth(),
10719                 h = this.getHeight();
10720
10721             var st = this.dom.style;
10722
10723             var after = function(){
10724                 if(o.useDisplay){
10725                     el.setDisplayed(false);
10726                 }else{
10727                     el.hide();
10728                 }
10729
10730                 el.clearOpacity();
10731                 el.setPositioning(r.pos);
10732                 st.width = r.width;
10733                 st.height = r.height;
10734
10735                 el.afterFx(o);
10736             };
10737
10738             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10739             switch(anchor.toLowerCase()){
10740                 case "t":
10741                     pt.by = [0, -h];
10742                 break;
10743                 case "l":
10744                     pt.by = [-w, 0];
10745                 break;
10746                 case "r":
10747                     pt.by = [w, 0];
10748                 break;
10749                 case "b":
10750                     pt.by = [0, h];
10751                 break;
10752                 case "tl":
10753                     pt.by = [-w, -h];
10754                 break;
10755                 case "bl":
10756                     pt.by = [-w, h];
10757                 break;
10758                 case "br":
10759                     pt.by = [w, h];
10760                 break;
10761                 case "tr":
10762                     pt.by = [w, -h];
10763                 break;
10764             }
10765
10766             arguments.callee.anim = this.fxanim(a,
10767                 o,
10768                 'motion',
10769                 .5,
10770                 "easeOut", after);
10771         });
10772         return this;
10773     },
10774
10775         /**
10776          * Ensures that all effects queued after syncFx is called on the element are
10777          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10778          * @return {Roo.Element} The Element
10779          */
10780     syncFx : function(){
10781         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10782             block : false,
10783             concurrent : true,
10784             stopFx : false
10785         });
10786         return this;
10787     },
10788
10789         /**
10790          * Ensures that all effects queued after sequenceFx is called on the element are
10791          * run in sequence.  This is the opposite of {@link #syncFx}.
10792          * @return {Roo.Element} The Element
10793          */
10794     sequenceFx : function(){
10795         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10796             block : false,
10797             concurrent : false,
10798             stopFx : false
10799         });
10800         return this;
10801     },
10802
10803         /* @private */
10804     nextFx : function(){
10805         var ef = this.fxQueue[0];
10806         if(ef){
10807             ef.call(this);
10808         }
10809     },
10810
10811         /**
10812          * Returns true if the element has any effects actively running or queued, else returns false.
10813          * @return {Boolean} True if element has active effects, else false
10814          */
10815     hasActiveFx : function(){
10816         return this.fxQueue && this.fxQueue[0];
10817     },
10818
10819         /**
10820          * Stops any running effects and clears the element's internal effects queue if it contains
10821          * any additional effects that haven't started yet.
10822          * @return {Roo.Element} The Element
10823          */
10824     stopFx : function(){
10825         if(this.hasActiveFx()){
10826             var cur = this.fxQueue[0];
10827             if(cur && cur.anim && cur.anim.isAnimated()){
10828                 this.fxQueue = [cur]; // clear out others
10829                 cur.anim.stop(true);
10830             }
10831         }
10832         return this;
10833     },
10834
10835         /* @private */
10836     beforeFx : function(o){
10837         if(this.hasActiveFx() && !o.concurrent){
10838            if(o.stopFx){
10839                this.stopFx();
10840                return true;
10841            }
10842            return false;
10843         }
10844         return true;
10845     },
10846
10847         /**
10848          * Returns true if the element is currently blocking so that no other effect can be queued
10849          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10850          * used to ensure that an effect initiated by a user action runs to completion prior to the
10851          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10852          * @return {Boolean} True if blocking, else false
10853          */
10854     hasFxBlock : function(){
10855         var q = this.fxQueue;
10856         return q && q[0] && q[0].block;
10857     },
10858
10859         /* @private */
10860     queueFx : function(o, fn){
10861         if(!this.fxQueue){
10862             this.fxQueue = [];
10863         }
10864         if(!this.hasFxBlock()){
10865             Roo.applyIf(o, this.fxDefaults);
10866             if(!o.concurrent){
10867                 var run = this.beforeFx(o);
10868                 fn.block = o.block;
10869                 this.fxQueue.push(fn);
10870                 if(run){
10871                     this.nextFx();
10872                 }
10873             }else{
10874                 fn.call(this);
10875             }
10876         }
10877         return this;
10878     },
10879
10880         /* @private */
10881     fxWrap : function(pos, o, vis){
10882         var wrap;
10883         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10884             var wrapXY;
10885             if(o.fixPosition){
10886                 wrapXY = this.getXY();
10887             }
10888             var div = document.createElement("div");
10889             div.style.visibility = vis;
10890             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10891             wrap.setPositioning(pos);
10892             if(wrap.getStyle("position") == "static"){
10893                 wrap.position("relative");
10894             }
10895             this.clearPositioning('auto');
10896             wrap.clip();
10897             wrap.dom.appendChild(this.dom);
10898             if(wrapXY){
10899                 wrap.setXY(wrapXY);
10900             }
10901         }
10902         return wrap;
10903     },
10904
10905         /* @private */
10906     fxUnwrap : function(wrap, pos, o){
10907         this.clearPositioning();
10908         this.setPositioning(pos);
10909         if(!o.wrap){
10910             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10911             wrap.remove();
10912         }
10913     },
10914
10915         /* @private */
10916     getFxRestore : function(){
10917         var st = this.dom.style;
10918         return {pos: this.getPositioning(), width: st.width, height : st.height};
10919     },
10920
10921         /* @private */
10922     afterFx : function(o){
10923         if(o.afterStyle){
10924             this.applyStyles(o.afterStyle);
10925         }
10926         if(o.afterCls){
10927             this.addClass(o.afterCls);
10928         }
10929         if(o.remove === true){
10930             this.remove();
10931         }
10932         Roo.callback(o.callback, o.scope, [this]);
10933         if(!o.concurrent){
10934             this.fxQueue.shift();
10935             this.nextFx();
10936         }
10937     },
10938
10939         /* @private */
10940     getFxEl : function(){ // support for composite element fx
10941         return Roo.get(this.dom);
10942     },
10943
10944         /* @private */
10945     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10946         animType = animType || 'run';
10947         opt = opt || {};
10948         var anim = Roo.lib.Anim[animType](
10949             this.dom, args,
10950             (opt.duration || defaultDur) || .35,
10951             (opt.easing || defaultEase) || 'easeOut',
10952             function(){
10953                 Roo.callback(cb, this);
10954             },
10955             this
10956         );
10957         opt.anim = anim;
10958         return anim;
10959     }
10960 };
10961
10962 // backwords compat
10963 Roo.Fx.resize = Roo.Fx.scale;
10964
10965 //When included, Roo.Fx is automatically applied to Element so that all basic
10966 //effects are available directly via the Element API
10967 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10968  * Based on:
10969  * Ext JS Library 1.1.1
10970  * Copyright(c) 2006-2007, Ext JS, LLC.
10971  *
10972  * Originally Released Under LGPL - original licence link has changed is not relivant.
10973  *
10974  * Fork - LGPL
10975  * <script type="text/javascript">
10976  */
10977
10978
10979 /**
10980  * @class Roo.CompositeElement
10981  * Standard composite class. Creates a Roo.Element for every element in the collection.
10982  * <br><br>
10983  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10984  * actions will be performed on all the elements in this collection.</b>
10985  * <br><br>
10986  * All methods return <i>this</i> and can be chained.
10987  <pre><code>
10988  var els = Roo.select("#some-el div.some-class", true);
10989  // or select directly from an existing element
10990  var el = Roo.get('some-el');
10991  el.select('div.some-class', true);
10992
10993  els.setWidth(100); // all elements become 100 width
10994  els.hide(true); // all elements fade out and hide
10995  // or
10996  els.setWidth(100).hide(true);
10997  </code></pre>
10998  */
10999 Roo.CompositeElement = function(els){
11000     this.elements = [];
11001     this.addElements(els);
11002 };
11003 Roo.CompositeElement.prototype = {
11004     isComposite: true,
11005     addElements : function(els){
11006         if(!els) {
11007             return this;
11008         }
11009         if(typeof els == "string"){
11010             els = Roo.Element.selectorFunction(els);
11011         }
11012         var yels = this.elements;
11013         var index = yels.length-1;
11014         for(var i = 0, len = els.length; i < len; i++) {
11015                 yels[++index] = Roo.get(els[i]);
11016         }
11017         return this;
11018     },
11019
11020     /**
11021     * Clears this composite and adds the elements returned by the passed selector.
11022     * @param {String/Array} els A string CSS selector, an array of elements or an element
11023     * @return {CompositeElement} this
11024     */
11025     fill : function(els){
11026         this.elements = [];
11027         this.add(els);
11028         return this;
11029     },
11030
11031     /**
11032     * Filters this composite to only elements that match the passed selector.
11033     * @param {String} selector A string CSS selector
11034     * @param {Boolean} inverse return inverse filter (not matches)
11035     * @return {CompositeElement} this
11036     */
11037     filter : function(selector, inverse){
11038         var els = [];
11039         inverse = inverse || false;
11040         this.each(function(el){
11041             var match = inverse ? !el.is(selector) : el.is(selector);
11042             if(match){
11043                 els[els.length] = el.dom;
11044             }
11045         });
11046         this.fill(els);
11047         return this;
11048     },
11049
11050     invoke : function(fn, args){
11051         var els = this.elements;
11052         for(var i = 0, len = els.length; i < len; i++) {
11053                 Roo.Element.prototype[fn].apply(els[i], args);
11054         }
11055         return this;
11056     },
11057     /**
11058     * Adds elements to this composite.
11059     * @param {String/Array} els A string CSS selector, an array of elements or an element
11060     * @return {CompositeElement} this
11061     */
11062     add : function(els){
11063         if(typeof els == "string"){
11064             this.addElements(Roo.Element.selectorFunction(els));
11065         }else if(els.length !== undefined){
11066             this.addElements(els);
11067         }else{
11068             this.addElements([els]);
11069         }
11070         return this;
11071     },
11072     /**
11073     * Calls the passed function passing (el, this, index) for each element in this composite.
11074     * @param {Function} fn The function to call
11075     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11076     * @return {CompositeElement} this
11077     */
11078     each : function(fn, scope){
11079         var els = this.elements;
11080         for(var i = 0, len = els.length; i < len; i++){
11081             if(fn.call(scope || els[i], els[i], this, i) === false) {
11082                 break;
11083             }
11084         }
11085         return this;
11086     },
11087
11088     /**
11089      * Returns the Element object at the specified index
11090      * @param {Number} index
11091      * @return {Roo.Element}
11092      */
11093     item : function(index){
11094         return this.elements[index] || null;
11095     },
11096
11097     /**
11098      * Returns the first Element
11099      * @return {Roo.Element}
11100      */
11101     first : function(){
11102         return this.item(0);
11103     },
11104
11105     /**
11106      * Returns the last Element
11107      * @return {Roo.Element}
11108      */
11109     last : function(){
11110         return this.item(this.elements.length-1);
11111     },
11112
11113     /**
11114      * Returns the number of elements in this composite
11115      * @return Number
11116      */
11117     getCount : function(){
11118         return this.elements.length;
11119     },
11120
11121     /**
11122      * Returns true if this composite contains the passed element
11123      * @return Boolean
11124      */
11125     contains : function(el){
11126         return this.indexOf(el) !== -1;
11127     },
11128
11129     /**
11130      * Returns true if this composite contains the passed element
11131      * @return Boolean
11132      */
11133     indexOf : function(el){
11134         return this.elements.indexOf(Roo.get(el));
11135     },
11136
11137
11138     /**
11139     * Removes the specified element(s).
11140     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11141     * or an array of any of those.
11142     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11143     * @return {CompositeElement} this
11144     */
11145     removeElement : function(el, removeDom){
11146         if(el instanceof Array){
11147             for(var i = 0, len = el.length; i < len; i++){
11148                 this.removeElement(el[i]);
11149             }
11150             return this;
11151         }
11152         var index = typeof el == 'number' ? el : this.indexOf(el);
11153         if(index !== -1){
11154             if(removeDom){
11155                 var d = this.elements[index];
11156                 if(d.dom){
11157                     d.remove();
11158                 }else{
11159                     d.parentNode.removeChild(d);
11160                 }
11161             }
11162             this.elements.splice(index, 1);
11163         }
11164         return this;
11165     },
11166
11167     /**
11168     * Replaces the specified element with the passed element.
11169     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11170     * to replace.
11171     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11172     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11173     * @return {CompositeElement} this
11174     */
11175     replaceElement : function(el, replacement, domReplace){
11176         var index = typeof el == 'number' ? el : this.indexOf(el);
11177         if(index !== -1){
11178             if(domReplace){
11179                 this.elements[index].replaceWith(replacement);
11180             }else{
11181                 this.elements.splice(index, 1, Roo.get(replacement))
11182             }
11183         }
11184         return this;
11185     },
11186
11187     /**
11188      * Removes all elements.
11189      */
11190     clear : function(){
11191         this.elements = [];
11192     }
11193 };
11194 (function(){
11195     Roo.CompositeElement.createCall = function(proto, fnName){
11196         if(!proto[fnName]){
11197             proto[fnName] = function(){
11198                 return this.invoke(fnName, arguments);
11199             };
11200         }
11201     };
11202     for(var fnName in Roo.Element.prototype){
11203         if(typeof Roo.Element.prototype[fnName] == "function"){
11204             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11205         }
11206     };
11207 })();
11208 /*
11209  * Based on:
11210  * Ext JS Library 1.1.1
11211  * Copyright(c) 2006-2007, Ext JS, LLC.
11212  *
11213  * Originally Released Under LGPL - original licence link has changed is not relivant.
11214  *
11215  * Fork - LGPL
11216  * <script type="text/javascript">
11217  */
11218
11219 /**
11220  * @class Roo.CompositeElementLite
11221  * @extends Roo.CompositeElement
11222  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11223  <pre><code>
11224  var els = Roo.select("#some-el div.some-class");
11225  // or select directly from an existing element
11226  var el = Roo.get('some-el');
11227  el.select('div.some-class');
11228
11229  els.setWidth(100); // all elements become 100 width
11230  els.hide(true); // all elements fade out and hide
11231  // or
11232  els.setWidth(100).hide(true);
11233  </code></pre><br><br>
11234  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11235  * actions will be performed on all the elements in this collection.</b>
11236  */
11237 Roo.CompositeElementLite = function(els){
11238     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11239     this.el = new Roo.Element.Flyweight();
11240 };
11241 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11242     addElements : function(els){
11243         if(els){
11244             if(els instanceof Array){
11245                 this.elements = this.elements.concat(els);
11246             }else{
11247                 var yels = this.elements;
11248                 var index = yels.length-1;
11249                 for(var i = 0, len = els.length; i < len; i++) {
11250                     yels[++index] = els[i];
11251                 }
11252             }
11253         }
11254         return this;
11255     },
11256     invoke : function(fn, args){
11257         var els = this.elements;
11258         var el = this.el;
11259         for(var i = 0, len = els.length; i < len; i++) {
11260             el.dom = els[i];
11261                 Roo.Element.prototype[fn].apply(el, args);
11262         }
11263         return this;
11264     },
11265     /**
11266      * Returns a flyweight Element of the dom element object at the specified index
11267      * @param {Number} index
11268      * @return {Roo.Element}
11269      */
11270     item : function(index){
11271         if(!this.elements[index]){
11272             return null;
11273         }
11274         this.el.dom = this.elements[index];
11275         return this.el;
11276     },
11277
11278     // fixes scope with flyweight
11279     addListener : function(eventName, handler, scope, opt){
11280         var els = this.elements;
11281         for(var i = 0, len = els.length; i < len; i++) {
11282             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11283         }
11284         return this;
11285     },
11286
11287     /**
11288     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11289     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11290     * a reference to the dom node, use el.dom.</b>
11291     * @param {Function} fn The function to call
11292     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11293     * @return {CompositeElement} this
11294     */
11295     each : function(fn, scope){
11296         var els = this.elements;
11297         var el = this.el;
11298         for(var i = 0, len = els.length; i < len; i++){
11299             el.dom = els[i];
11300                 if(fn.call(scope || el, el, this, i) === false){
11301                 break;
11302             }
11303         }
11304         return this;
11305     },
11306
11307     indexOf : function(el){
11308         return this.elements.indexOf(Roo.getDom(el));
11309     },
11310
11311     replaceElement : function(el, replacement, domReplace){
11312         var index = typeof el == 'number' ? el : this.indexOf(el);
11313         if(index !== -1){
11314             replacement = Roo.getDom(replacement);
11315             if(domReplace){
11316                 var d = this.elements[index];
11317                 d.parentNode.insertBefore(replacement, d);
11318                 d.parentNode.removeChild(d);
11319             }
11320             this.elements.splice(index, 1, replacement);
11321         }
11322         return this;
11323     }
11324 });
11325 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11326
11327 /*
11328  * Based on:
11329  * Ext JS Library 1.1.1
11330  * Copyright(c) 2006-2007, Ext JS, LLC.
11331  *
11332  * Originally Released Under LGPL - original licence link has changed is not relivant.
11333  *
11334  * Fork - LGPL
11335  * <script type="text/javascript">
11336  */
11337
11338  
11339
11340 /**
11341  * @class Roo.data.Connection
11342  * @extends Roo.util.Observable
11343  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11344  * either to a configured URL, or to a URL specified at request time.<br><br>
11345  * <p>
11346  * Requests made by this class are asynchronous, and will return immediately. No data from
11347  * the server will be available to the statement immediately following the {@link #request} call.
11348  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11349  * <p>
11350  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11351  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11352  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11353  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11354  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11355  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11356  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11357  * standard DOM methods.
11358  * @constructor
11359  * @param {Object} config a configuration object.
11360  */
11361 Roo.data.Connection = function(config){
11362     Roo.apply(this, config);
11363     this.addEvents({
11364         /**
11365          * @event beforerequest
11366          * Fires before a network request is made to retrieve a data object.
11367          * @param {Connection} conn This Connection object.
11368          * @param {Object} options The options config object passed to the {@link #request} method.
11369          */
11370         "beforerequest" : true,
11371         /**
11372          * @event requestcomplete
11373          * Fires if the request was successfully completed.
11374          * @param {Connection} conn This Connection object.
11375          * @param {Object} response The XHR object containing the response data.
11376          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11377          * @param {Object} options The options config object passed to the {@link #request} method.
11378          */
11379         "requestcomplete" : true,
11380         /**
11381          * @event requestexception
11382          * Fires if an error HTTP status was returned from the server.
11383          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11384          * @param {Connection} conn This Connection object.
11385          * @param {Object} response The XHR object containing the response data.
11386          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11387          * @param {Object} options The options config object passed to the {@link #request} method.
11388          */
11389         "requestexception" : true
11390     });
11391     Roo.data.Connection.superclass.constructor.call(this);
11392 };
11393
11394 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11395     /**
11396      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11397      */
11398     /**
11399      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11400      * extra parameters to each request made by this object. (defaults to undefined)
11401      */
11402     /**
11403      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11404      *  to each request made by this object. (defaults to undefined)
11405      */
11406     /**
11407      * @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)
11408      */
11409     /**
11410      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11411      */
11412     timeout : 30000,
11413     /**
11414      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11415      * @type Boolean
11416      */
11417     autoAbort:false,
11418
11419     /**
11420      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11421      * @type Boolean
11422      */
11423     disableCaching: true,
11424
11425     /**
11426      * Sends an HTTP request to a remote server.
11427      * @param {Object} options An object which may contain the following properties:<ul>
11428      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11429      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11430      * request, a url encoded string or a function to call to get either.</li>
11431      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11432      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11433      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11434      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11435      * <li>options {Object} The parameter to the request call.</li>
11436      * <li>success {Boolean} True if the request succeeded.</li>
11437      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11438      * </ul></li>
11439      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11440      * The callback is passed the following parameters:<ul>
11441      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11442      * <li>options {Object} The parameter to the request call.</li>
11443      * </ul></li>
11444      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11445      * The callback is passed the following parameters:<ul>
11446      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11447      * <li>options {Object} The parameter to the request call.</li>
11448      * </ul></li>
11449      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11450      * for the callback function. Defaults to the browser window.</li>
11451      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11452      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11453      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11454      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11455      * params for the post data. Any params will be appended to the URL.</li>
11456      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11457      * </ul>
11458      * @return {Number} transactionId
11459      */
11460     request : function(o){
11461         if(this.fireEvent("beforerequest", this, o) !== false){
11462             var p = o.params;
11463
11464             if(typeof p == "function"){
11465                 p = p.call(o.scope||window, o);
11466             }
11467             if(typeof p == "object"){
11468                 p = Roo.urlEncode(o.params);
11469             }
11470             if(this.extraParams){
11471                 var extras = Roo.urlEncode(this.extraParams);
11472                 p = p ? (p + '&' + extras) : extras;
11473             }
11474
11475             var url = o.url || this.url;
11476             if(typeof url == 'function'){
11477                 url = url.call(o.scope||window, o);
11478             }
11479
11480             if(o.form){
11481                 var form = Roo.getDom(o.form);
11482                 url = url || form.action;
11483
11484                 var enctype = form.getAttribute("enctype");
11485                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11486                     return this.doFormUpload(o, p, url);
11487                 }
11488                 var f = Roo.lib.Ajax.serializeForm(form);
11489                 p = p ? (p + '&' + f) : f;
11490             }
11491
11492             var hs = o.headers;
11493             if(this.defaultHeaders){
11494                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11495                 if(!o.headers){
11496                     o.headers = hs;
11497                 }
11498             }
11499
11500             var cb = {
11501                 success: this.handleResponse,
11502                 failure: this.handleFailure,
11503                 scope: this,
11504                 argument: {options: o},
11505                 timeout : o.timeout || this.timeout
11506             };
11507
11508             var method = o.method||this.method||(p ? "POST" : "GET");
11509
11510             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11511                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11512             }
11513
11514             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11515                 if(o.autoAbort){
11516                     this.abort();
11517                 }
11518             }else if(this.autoAbort !== false){
11519                 this.abort();
11520             }
11521
11522             if((method == 'GET' && p) || o.xmlData){
11523                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11524                 p = '';
11525             }
11526             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11527             return this.transId;
11528         }else{
11529             Roo.callback(o.callback, o.scope, [o, null, null]);
11530             return null;
11531         }
11532     },
11533
11534     /**
11535      * Determine whether this object has a request outstanding.
11536      * @param {Number} transactionId (Optional) defaults to the last transaction
11537      * @return {Boolean} True if there is an outstanding request.
11538      */
11539     isLoading : function(transId){
11540         if(transId){
11541             return Roo.lib.Ajax.isCallInProgress(transId);
11542         }else{
11543             return this.transId ? true : false;
11544         }
11545     },
11546
11547     /**
11548      * Aborts any outstanding request.
11549      * @param {Number} transactionId (Optional) defaults to the last transaction
11550      */
11551     abort : function(transId){
11552         if(transId || this.isLoading()){
11553             Roo.lib.Ajax.abort(transId || this.transId);
11554         }
11555     },
11556
11557     // private
11558     handleResponse : function(response){
11559         this.transId = false;
11560         var options = response.argument.options;
11561         response.argument = options ? options.argument : null;
11562         this.fireEvent("requestcomplete", this, response, options);
11563         Roo.callback(options.success, options.scope, [response, options]);
11564         Roo.callback(options.callback, options.scope, [options, true, response]);
11565     },
11566
11567     // private
11568     handleFailure : function(response, e){
11569         this.transId = false;
11570         var options = response.argument.options;
11571         response.argument = options ? options.argument : null;
11572         this.fireEvent("requestexception", this, response, options, e);
11573         Roo.callback(options.failure, options.scope, [response, options]);
11574         Roo.callback(options.callback, options.scope, [options, false, response]);
11575     },
11576
11577     // private
11578     doFormUpload : function(o, ps, url){
11579         var id = Roo.id();
11580         var frame = document.createElement('iframe');
11581         frame.id = id;
11582         frame.name = id;
11583         frame.className = 'x-hidden';
11584         if(Roo.isIE){
11585             frame.src = Roo.SSL_SECURE_URL;
11586         }
11587         document.body.appendChild(frame);
11588
11589         if(Roo.isIE){
11590            document.frames[id].name = id;
11591         }
11592
11593         var form = Roo.getDom(o.form);
11594         form.target = id;
11595         form.method = 'POST';
11596         form.enctype = form.encoding = 'multipart/form-data';
11597         if(url){
11598             form.action = url;
11599         }
11600
11601         var hiddens, hd;
11602         if(ps){ // add dynamic params
11603             hiddens = [];
11604             ps = Roo.urlDecode(ps, false);
11605             for(var k in ps){
11606                 if(ps.hasOwnProperty(k)){
11607                     hd = document.createElement('input');
11608                     hd.type = 'hidden';
11609                     hd.name = k;
11610                     hd.value = ps[k];
11611                     form.appendChild(hd);
11612                     hiddens.push(hd);
11613                 }
11614             }
11615         }
11616
11617         function cb(){
11618             var r = {  // bogus response object
11619                 responseText : '',
11620                 responseXML : null
11621             };
11622
11623             r.argument = o ? o.argument : null;
11624
11625             try { //
11626                 var doc;
11627                 if(Roo.isIE){
11628                     doc = frame.contentWindow.document;
11629                 }else {
11630                     doc = (frame.contentDocument || window.frames[id].document);
11631                 }
11632                 if(doc && doc.body){
11633                     r.responseText = doc.body.innerHTML;
11634                 }
11635                 if(doc && doc.XMLDocument){
11636                     r.responseXML = doc.XMLDocument;
11637                 }else {
11638                     r.responseXML = doc;
11639                 }
11640             }
11641             catch(e) {
11642                 // ignore
11643             }
11644
11645             Roo.EventManager.removeListener(frame, 'load', cb, this);
11646
11647             this.fireEvent("requestcomplete", this, r, o);
11648             Roo.callback(o.success, o.scope, [r, o]);
11649             Roo.callback(o.callback, o.scope, [o, true, r]);
11650
11651             setTimeout(function(){document.body.removeChild(frame);}, 100);
11652         }
11653
11654         Roo.EventManager.on(frame, 'load', cb, this);
11655         form.submit();
11656
11657         if(hiddens){ // remove dynamic params
11658             for(var i = 0, len = hiddens.length; i < len; i++){
11659                 form.removeChild(hiddens[i]);
11660             }
11661         }
11662     }
11663 });
11664 /*
11665  * Based on:
11666  * Ext JS Library 1.1.1
11667  * Copyright(c) 2006-2007, Ext JS, LLC.
11668  *
11669  * Originally Released Under LGPL - original licence link has changed is not relivant.
11670  *
11671  * Fork - LGPL
11672  * <script type="text/javascript">
11673  */
11674  
11675 /**
11676  * Global Ajax request class.
11677  * 
11678  * @class Roo.Ajax
11679  * @extends Roo.data.Connection
11680  * @static
11681  * 
11682  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11683  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11684  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11685  * @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)
11686  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11687  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11688  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11689  */
11690 Roo.Ajax = new Roo.data.Connection({
11691     // fix up the docs
11692     /**
11693      * @scope Roo.Ajax
11694      * @type {Boolear} 
11695      */
11696     autoAbort : false,
11697
11698     /**
11699      * Serialize the passed form into a url encoded string
11700      * @scope Roo.Ajax
11701      * @param {String/HTMLElement} form
11702      * @return {String}
11703      */
11704     serializeForm : function(form){
11705         return Roo.lib.Ajax.serializeForm(form);
11706     }
11707 });/*
11708  * Based on:
11709  * Ext JS Library 1.1.1
11710  * Copyright(c) 2006-2007, Ext JS, LLC.
11711  *
11712  * Originally Released Under LGPL - original licence link has changed is not relivant.
11713  *
11714  * Fork - LGPL
11715  * <script type="text/javascript">
11716  */
11717
11718  
11719 /**
11720  * @class Roo.UpdateManager
11721  * @extends Roo.util.Observable
11722  * Provides AJAX-style update for Element object.<br><br>
11723  * Usage:<br>
11724  * <pre><code>
11725  * // Get it from a Roo.Element object
11726  * var el = Roo.get("foo");
11727  * var mgr = el.getUpdateManager();
11728  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11729  * ...
11730  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11731  * <br>
11732  * // or directly (returns the same UpdateManager instance)
11733  * var mgr = new Roo.UpdateManager("myElementId");
11734  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11735  * mgr.on("update", myFcnNeedsToKnow);
11736  * <br>
11737    // short handed call directly from the element object
11738    Roo.get("foo").load({
11739         url: "bar.php",
11740         scripts:true,
11741         params: "for=bar",
11742         text: "Loading Foo..."
11743    });
11744  * </code></pre>
11745  * @constructor
11746  * Create new UpdateManager directly.
11747  * @param {String/HTMLElement/Roo.Element} el The element to update
11748  * @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).
11749  */
11750 Roo.UpdateManager = function(el, forceNew){
11751     el = Roo.get(el);
11752     if(!forceNew && el.updateManager){
11753         return el.updateManager;
11754     }
11755     /**
11756      * The Element object
11757      * @type Roo.Element
11758      */
11759     this.el = el;
11760     /**
11761      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11762      * @type String
11763      */
11764     this.defaultUrl = null;
11765
11766     this.addEvents({
11767         /**
11768          * @event beforeupdate
11769          * Fired before an update is made, return false from your handler and the update is cancelled.
11770          * @param {Roo.Element} el
11771          * @param {String/Object/Function} url
11772          * @param {String/Object} params
11773          */
11774         "beforeupdate": true,
11775         /**
11776          * @event update
11777          * Fired after successful update is made.
11778          * @param {Roo.Element} el
11779          * @param {Object} oResponseObject The response Object
11780          */
11781         "update": true,
11782         /**
11783          * @event failure
11784          * Fired on update failure.
11785          * @param {Roo.Element} el
11786          * @param {Object} oResponseObject The response Object
11787          */
11788         "failure": true
11789     });
11790     var d = Roo.UpdateManager.defaults;
11791     /**
11792      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11793      * @type String
11794      */
11795     this.sslBlankUrl = d.sslBlankUrl;
11796     /**
11797      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11798      * @type Boolean
11799      */
11800     this.disableCaching = d.disableCaching;
11801     /**
11802      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11803      * @type String
11804      */
11805     this.indicatorText = d.indicatorText;
11806     /**
11807      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11808      * @type String
11809      */
11810     this.showLoadIndicator = d.showLoadIndicator;
11811     /**
11812      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11813      * @type Number
11814      */
11815     this.timeout = d.timeout;
11816
11817     /**
11818      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11819      * @type Boolean
11820      */
11821     this.loadScripts = d.loadScripts;
11822
11823     /**
11824      * Transaction object of current executing transaction
11825      */
11826     this.transaction = null;
11827
11828     /**
11829      * @private
11830      */
11831     this.autoRefreshProcId = null;
11832     /**
11833      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11834      * @type Function
11835      */
11836     this.refreshDelegate = this.refresh.createDelegate(this);
11837     /**
11838      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11839      * @type Function
11840      */
11841     this.updateDelegate = this.update.createDelegate(this);
11842     /**
11843      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11844      * @type Function
11845      */
11846     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11847     /**
11848      * @private
11849      */
11850     this.successDelegate = this.processSuccess.createDelegate(this);
11851     /**
11852      * @private
11853      */
11854     this.failureDelegate = this.processFailure.createDelegate(this);
11855
11856     if(!this.renderer){
11857      /**
11858       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11859       */
11860     this.renderer = new Roo.UpdateManager.BasicRenderer();
11861     }
11862     
11863     Roo.UpdateManager.superclass.constructor.call(this);
11864 };
11865
11866 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11867     /**
11868      * Get the Element this UpdateManager is bound to
11869      * @return {Roo.Element} The element
11870      */
11871     getEl : function(){
11872         return this.el;
11873     },
11874     /**
11875      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11876      * @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:
11877 <pre><code>
11878 um.update({<br/>
11879     url: "your-url.php",<br/>
11880     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11881     callback: yourFunction,<br/>
11882     scope: yourObject, //(optional scope)  <br/>
11883     discardUrl: false, <br/>
11884     nocache: false,<br/>
11885     text: "Loading...",<br/>
11886     timeout: 30,<br/>
11887     scripts: false<br/>
11888 });
11889 </code></pre>
11890      * The only required property is url. The optional properties nocache, text and scripts
11891      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11892      * @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}
11893      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11894      * @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.
11895      */
11896     update : function(url, params, callback, discardUrl){
11897         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11898             var method = this.method,
11899                 cfg;
11900             if(typeof url == "object"){ // must be config object
11901                 cfg = url;
11902                 url = cfg.url;
11903                 params = params || cfg.params;
11904                 callback = callback || cfg.callback;
11905                 discardUrl = discardUrl || cfg.discardUrl;
11906                 if(callback && cfg.scope){
11907                     callback = callback.createDelegate(cfg.scope);
11908                 }
11909                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11910                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11911                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11912                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11913                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11914             }
11915             this.showLoading();
11916             if(!discardUrl){
11917                 this.defaultUrl = url;
11918             }
11919             if(typeof url == "function"){
11920                 url = url.call(this);
11921             }
11922
11923             method = method || (params ? "POST" : "GET");
11924             if(method == "GET"){
11925                 url = this.prepareUrl(url);
11926             }
11927
11928             var o = Roo.apply(cfg ||{}, {
11929                 url : url,
11930                 params: params,
11931                 success: this.successDelegate,
11932                 failure: this.failureDelegate,
11933                 callback: undefined,
11934                 timeout: (this.timeout*1000),
11935                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11936             });
11937             Roo.log("updated manager called with timeout of " + o.timeout);
11938             this.transaction = Roo.Ajax.request(o);
11939         }
11940     },
11941
11942     /**
11943      * 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.
11944      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11945      * @param {String/HTMLElement} form The form Id or form element
11946      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11947      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11948      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11949      */
11950     formUpdate : function(form, url, reset, callback){
11951         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11952             if(typeof url == "function"){
11953                 url = url.call(this);
11954             }
11955             form = Roo.getDom(form);
11956             this.transaction = Roo.Ajax.request({
11957                 form: form,
11958                 url:url,
11959                 success: this.successDelegate,
11960                 failure: this.failureDelegate,
11961                 timeout: (this.timeout*1000),
11962                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11963             });
11964             this.showLoading.defer(1, this);
11965         }
11966     },
11967
11968     /**
11969      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11970      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11971      */
11972     refresh : function(callback){
11973         if(this.defaultUrl == null){
11974             return;
11975         }
11976         this.update(this.defaultUrl, null, callback, true);
11977     },
11978
11979     /**
11980      * Set this element to auto refresh.
11981      * @param {Number} interval How often to update (in seconds).
11982      * @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)
11983      * @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}
11984      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11985      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11986      */
11987     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11988         if(refreshNow){
11989             this.update(url || this.defaultUrl, params, callback, true);
11990         }
11991         if(this.autoRefreshProcId){
11992             clearInterval(this.autoRefreshProcId);
11993         }
11994         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11995     },
11996
11997     /**
11998      * Stop auto refresh on this element.
11999      */
12000      stopAutoRefresh : function(){
12001         if(this.autoRefreshProcId){
12002             clearInterval(this.autoRefreshProcId);
12003             delete this.autoRefreshProcId;
12004         }
12005     },
12006
12007     isAutoRefreshing : function(){
12008        return this.autoRefreshProcId ? true : false;
12009     },
12010     /**
12011      * Called to update the element to "Loading" state. Override to perform custom action.
12012      */
12013     showLoading : function(){
12014         if(this.showLoadIndicator){
12015             this.el.update(this.indicatorText);
12016         }
12017     },
12018
12019     /**
12020      * Adds unique parameter to query string if disableCaching = true
12021      * @private
12022      */
12023     prepareUrl : function(url){
12024         if(this.disableCaching){
12025             var append = "_dc=" + (new Date().getTime());
12026             if(url.indexOf("?") !== -1){
12027                 url += "&" + append;
12028             }else{
12029                 url += "?" + append;
12030             }
12031         }
12032         return url;
12033     },
12034
12035     /**
12036      * @private
12037      */
12038     processSuccess : function(response){
12039         this.transaction = null;
12040         if(response.argument.form && response.argument.reset){
12041             try{ // put in try/catch since some older FF releases had problems with this
12042                 response.argument.form.reset();
12043             }catch(e){}
12044         }
12045         if(this.loadScripts){
12046             this.renderer.render(this.el, response, this,
12047                 this.updateComplete.createDelegate(this, [response]));
12048         }else{
12049             this.renderer.render(this.el, response, this);
12050             this.updateComplete(response);
12051         }
12052     },
12053
12054     updateComplete : function(response){
12055         this.fireEvent("update", this.el, response);
12056         if(typeof response.argument.callback == "function"){
12057             response.argument.callback(this.el, true, response);
12058         }
12059     },
12060
12061     /**
12062      * @private
12063      */
12064     processFailure : function(response){
12065         this.transaction = null;
12066         this.fireEvent("failure", this.el, response);
12067         if(typeof response.argument.callback == "function"){
12068             response.argument.callback(this.el, false, response);
12069         }
12070     },
12071
12072     /**
12073      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12074      * @param {Object} renderer The object implementing the render() method
12075      */
12076     setRenderer : function(renderer){
12077         this.renderer = renderer;
12078     },
12079
12080     getRenderer : function(){
12081        return this.renderer;
12082     },
12083
12084     /**
12085      * Set the defaultUrl used for updates
12086      * @param {String/Function} defaultUrl The url or a function to call to get the url
12087      */
12088     setDefaultUrl : function(defaultUrl){
12089         this.defaultUrl = defaultUrl;
12090     },
12091
12092     /**
12093      * Aborts the executing transaction
12094      */
12095     abort : function(){
12096         if(this.transaction){
12097             Roo.Ajax.abort(this.transaction);
12098         }
12099     },
12100
12101     /**
12102      * Returns true if an update is in progress
12103      * @return {Boolean}
12104      */
12105     isUpdating : function(){
12106         if(this.transaction){
12107             return Roo.Ajax.isLoading(this.transaction);
12108         }
12109         return false;
12110     }
12111 });
12112
12113 /**
12114  * @class Roo.UpdateManager.defaults
12115  * @static (not really - but it helps the doc tool)
12116  * The defaults collection enables customizing the default properties of UpdateManager
12117  */
12118    Roo.UpdateManager.defaults = {
12119        /**
12120          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12121          * @type Number
12122          */
12123          timeout : 30,
12124
12125          /**
12126          * True to process scripts by default (Defaults to false).
12127          * @type Boolean
12128          */
12129         loadScripts : false,
12130
12131         /**
12132         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12133         * @type String
12134         */
12135         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12136         /**
12137          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12138          * @type Boolean
12139          */
12140         disableCaching : false,
12141         /**
12142          * Whether to show indicatorText when loading (Defaults to true).
12143          * @type Boolean
12144          */
12145         showLoadIndicator : true,
12146         /**
12147          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12148          * @type String
12149          */
12150         indicatorText : '<div class="loading-indicator">Loading...</div>'
12151    };
12152
12153 /**
12154  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12155  *Usage:
12156  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12157  * @param {String/HTMLElement/Roo.Element} el The element to update
12158  * @param {String} url The url
12159  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12160  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12161  * @static
12162  * @deprecated
12163  * @member Roo.UpdateManager
12164  */
12165 Roo.UpdateManager.updateElement = function(el, url, params, options){
12166     var um = Roo.get(el, true).getUpdateManager();
12167     Roo.apply(um, options);
12168     um.update(url, params, options ? options.callback : null);
12169 };
12170 // alias for backwards compat
12171 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12172 /**
12173  * @class Roo.UpdateManager.BasicRenderer
12174  * Default Content renderer. Updates the elements innerHTML with the responseText.
12175  */
12176 Roo.UpdateManager.BasicRenderer = function(){};
12177
12178 Roo.UpdateManager.BasicRenderer.prototype = {
12179     /**
12180      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12181      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12182      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12183      * @param {Roo.Element} el The element being rendered
12184      * @param {Object} response The YUI Connect response object
12185      * @param {UpdateManager} updateManager The calling update manager
12186      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12187      */
12188      render : function(el, response, updateManager, callback){
12189         el.update(response.responseText, updateManager.loadScripts, callback);
12190     }
12191 };
12192 /*
12193  * Based on:
12194  * Roo JS
12195  * (c)) Alan Knowles
12196  * Licence : LGPL
12197  */
12198
12199
12200 /**
12201  * @class Roo.DomTemplate
12202  * @extends Roo.Template
12203  * An effort at a dom based template engine..
12204  *
12205  * Similar to XTemplate, except it uses dom parsing to create the template..
12206  *
12207  * Supported features:
12208  *
12209  *  Tags:
12210
12211 <pre><code>
12212       {a_variable} - output encoded.
12213       {a_variable.format:("Y-m-d")} - call a method on the variable
12214       {a_variable:raw} - unencoded output
12215       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12216       {a_variable:this.method_on_template(...)} - call a method on the template object.
12217  
12218 </code></pre>
12219  *  The tpl tag:
12220 <pre><code>
12221         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12222         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12223         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12224         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12225   
12226 </code></pre>
12227  *      
12228  */
12229 Roo.DomTemplate = function()
12230 {
12231      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12232      if (this.html) {
12233         this.compile();
12234      }
12235 };
12236
12237
12238 Roo.extend(Roo.DomTemplate, Roo.Template, {
12239     /**
12240      * id counter for sub templates.
12241      */
12242     id : 0,
12243     /**
12244      * flag to indicate if dom parser is inside a pre,
12245      * it will strip whitespace if not.
12246      */
12247     inPre : false,
12248     
12249     /**
12250      * The various sub templates
12251      */
12252     tpls : false,
12253     
12254     
12255     
12256     /**
12257      *
12258      * basic tag replacing syntax
12259      * WORD:WORD()
12260      *
12261      * // you can fake an object call by doing this
12262      *  x.t:(test,tesT) 
12263      * 
12264      */
12265     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12266     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12267     
12268     iterChild : function (node, method) {
12269         
12270         var oldPre = this.inPre;
12271         if (node.tagName == 'PRE') {
12272             this.inPre = true;
12273         }
12274         for( var i = 0; i < node.childNodes.length; i++) {
12275             method.call(this, node.childNodes[i]);
12276         }
12277         this.inPre = oldPre;
12278     },
12279     
12280     
12281     
12282     /**
12283      * compile the template
12284      *
12285      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12286      *
12287      */
12288     compile: function()
12289     {
12290         var s = this.html;
12291         
12292         // covert the html into DOM...
12293         var doc = false;
12294         var div =false;
12295         try {
12296             doc = document.implementation.createHTMLDocument("");
12297             doc.documentElement.innerHTML =   this.html  ;
12298             div = doc.documentElement;
12299         } catch (e) {
12300             // old IE... - nasty -- it causes all sorts of issues.. with
12301             // images getting pulled from server..
12302             div = document.createElement('div');
12303             div.innerHTML = this.html;
12304         }
12305         //doc.documentElement.innerHTML = htmlBody
12306          
12307         
12308         
12309         this.tpls = [];
12310         var _t = this;
12311         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12312         
12313         var tpls = this.tpls;
12314         
12315         // create a top level template from the snippet..
12316         
12317         //Roo.log(div.innerHTML);
12318         
12319         var tpl = {
12320             uid : 'master',
12321             id : this.id++,
12322             attr : false,
12323             value : false,
12324             body : div.innerHTML,
12325             
12326             forCall : false,
12327             execCall : false,
12328             dom : div,
12329             isTop : true
12330             
12331         };
12332         tpls.unshift(tpl);
12333         
12334         
12335         // compile them...
12336         this.tpls = [];
12337         Roo.each(tpls, function(tp){
12338             this.compileTpl(tp);
12339             this.tpls[tp.id] = tp;
12340         }, this);
12341         
12342         this.master = tpls[0];
12343         return this;
12344         
12345         
12346     },
12347     
12348     compileNode : function(node, istop) {
12349         // test for
12350         //Roo.log(node);
12351         
12352         
12353         // skip anything not a tag..
12354         if (node.nodeType != 1) {
12355             if (node.nodeType == 3 && !this.inPre) {
12356                 // reduce white space..
12357                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12358                 
12359             }
12360             return;
12361         }
12362         
12363         var tpl = {
12364             uid : false,
12365             id : false,
12366             attr : false,
12367             value : false,
12368             body : '',
12369             
12370             forCall : false,
12371             execCall : false,
12372             dom : false,
12373             isTop : istop
12374             
12375             
12376         };
12377         
12378         
12379         switch(true) {
12380             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12381             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12382             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12383             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12384             // no default..
12385         }
12386         
12387         
12388         if (!tpl.attr) {
12389             // just itterate children..
12390             this.iterChild(node,this.compileNode);
12391             return;
12392         }
12393         tpl.uid = this.id++;
12394         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12395         node.removeAttribute('roo-'+ tpl.attr);
12396         if (tpl.attr != 'name') {
12397             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12398             node.parentNode.replaceChild(placeholder,  node);
12399         } else {
12400             
12401             var placeholder =  document.createElement('span');
12402             placeholder.className = 'roo-tpl-' + tpl.value;
12403             node.parentNode.replaceChild(placeholder,  node);
12404         }
12405         
12406         // parent now sees '{domtplXXXX}
12407         this.iterChild(node,this.compileNode);
12408         
12409         // we should now have node body...
12410         var div = document.createElement('div');
12411         div.appendChild(node);
12412         tpl.dom = node;
12413         // this has the unfortunate side effect of converting tagged attributes
12414         // eg. href="{...}" into %7C...%7D
12415         // this has been fixed by searching for those combo's although it's a bit hacky..
12416         
12417         
12418         tpl.body = div.innerHTML;
12419         
12420         
12421          
12422         tpl.id = tpl.uid;
12423         switch(tpl.attr) {
12424             case 'for' :
12425                 switch (tpl.value) {
12426                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12427                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12428                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12429                 }
12430                 break;
12431             
12432             case 'exec':
12433                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12434                 break;
12435             
12436             case 'if':     
12437                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12438                 break;
12439             
12440             case 'name':
12441                 tpl.id  = tpl.value; // replace non characters???
12442                 break;
12443             
12444         }
12445         
12446         
12447         this.tpls.push(tpl);
12448         
12449         
12450         
12451     },
12452     
12453     
12454     
12455     
12456     /**
12457      * Compile a segment of the template into a 'sub-template'
12458      *
12459      * 
12460      * 
12461      *
12462      */
12463     compileTpl : function(tpl)
12464     {
12465         var fm = Roo.util.Format;
12466         var useF = this.disableFormats !== true;
12467         
12468         var sep = Roo.isGecko ? "+\n" : ",\n";
12469         
12470         var undef = function(str) {
12471             Roo.debug && Roo.log("Property not found :"  + str);
12472             return '';
12473         };
12474           
12475         //Roo.log(tpl.body);
12476         
12477         
12478         
12479         var fn = function(m, lbrace, name, format, args)
12480         {
12481             //Roo.log("ARGS");
12482             //Roo.log(arguments);
12483             args = args ? args.replace(/\\'/g,"'") : args;
12484             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12485             if (typeof(format) == 'undefined') {
12486                 format =  'htmlEncode'; 
12487             }
12488             if (format == 'raw' ) {
12489                 format = false;
12490             }
12491             
12492             if(name.substr(0, 6) == 'domtpl'){
12493                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12494             }
12495             
12496             // build an array of options to determine if value is undefined..
12497             
12498             // basically get 'xxxx.yyyy' then do
12499             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12500             //    (function () { Roo.log("Property not found"); return ''; })() :
12501             //    ......
12502             
12503             var udef_ar = [];
12504             var lookfor = '';
12505             Roo.each(name.split('.'), function(st) {
12506                 lookfor += (lookfor.length ? '.': '') + st;
12507                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12508             });
12509             
12510             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12511             
12512             
12513             if(format && useF){
12514                 
12515                 args = args ? ',' + args : "";
12516                  
12517                 if(format.substr(0, 5) != "this."){
12518                     format = "fm." + format + '(';
12519                 }else{
12520                     format = 'this.call("'+ format.substr(5) + '", ';
12521                     args = ", values";
12522                 }
12523                 
12524                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12525             }
12526              
12527             if (args && args.length) {
12528                 // called with xxyx.yuu:(test,test)
12529                 // change to ()
12530                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12531             }
12532             // raw.. - :raw modifier..
12533             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12534             
12535         };
12536         var body;
12537         // branched to use + in gecko and [].join() in others
12538         if(Roo.isGecko){
12539             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12540                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12541                     "';};};";
12542         }else{
12543             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12544             body.push(tpl.body.replace(/(\r\n|\n)/g,
12545                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12546             body.push("'].join('');};};");
12547             body = body.join('');
12548         }
12549         
12550         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12551        
12552         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12553         eval(body);
12554         
12555         return this;
12556     },
12557      
12558     /**
12559      * same as applyTemplate, except it's done to one of the subTemplates
12560      * when using named templates, you can do:
12561      *
12562      * var str = pl.applySubTemplate('your-name', values);
12563      *
12564      * 
12565      * @param {Number} id of the template
12566      * @param {Object} values to apply to template
12567      * @param {Object} parent (normaly the instance of this object)
12568      */
12569     applySubTemplate : function(id, values, parent)
12570     {
12571         
12572         
12573         var t = this.tpls[id];
12574         
12575         
12576         try { 
12577             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12578                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12579                 return '';
12580             }
12581         } catch(e) {
12582             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12583             Roo.log(values);
12584           
12585             return '';
12586         }
12587         try { 
12588             
12589             if(t.execCall && t.execCall.call(this, values, parent)){
12590                 return '';
12591             }
12592         } catch(e) {
12593             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12594             Roo.log(values);
12595             return '';
12596         }
12597         
12598         try {
12599             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12600             parent = t.target ? values : parent;
12601             if(t.forCall && vs instanceof Array){
12602                 var buf = [];
12603                 for(var i = 0, len = vs.length; i < len; i++){
12604                     try {
12605                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12606                     } catch (e) {
12607                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12608                         Roo.log(e.body);
12609                         //Roo.log(t.compiled);
12610                         Roo.log(vs[i]);
12611                     }   
12612                 }
12613                 return buf.join('');
12614             }
12615         } catch (e) {
12616             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12617             Roo.log(values);
12618             return '';
12619         }
12620         try {
12621             return t.compiled.call(this, vs, parent);
12622         } catch (e) {
12623             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12624             Roo.log(e.body);
12625             //Roo.log(t.compiled);
12626             Roo.log(values);
12627             return '';
12628         }
12629     },
12630
12631    
12632
12633     applyTemplate : function(values){
12634         return this.master.compiled.call(this, values, {});
12635         //var s = this.subs;
12636     },
12637
12638     apply : function(){
12639         return this.applyTemplate.apply(this, arguments);
12640     }
12641
12642  });
12643
12644 Roo.DomTemplate.from = function(el){
12645     el = Roo.getDom(el);
12646     return new Roo.Domtemplate(el.value || el.innerHTML);
12647 };/*
12648  * Based on:
12649  * Ext JS Library 1.1.1
12650  * Copyright(c) 2006-2007, Ext JS, LLC.
12651  *
12652  * Originally Released Under LGPL - original licence link has changed is not relivant.
12653  *
12654  * Fork - LGPL
12655  * <script type="text/javascript">
12656  */
12657
12658 /**
12659  * @class Roo.util.DelayedTask
12660  * Provides a convenient method of performing setTimeout where a new
12661  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12662  * You can use this class to buffer
12663  * the keypress events for a certain number of milliseconds, and perform only if they stop
12664  * for that amount of time.
12665  * @constructor The parameters to this constructor serve as defaults and are not required.
12666  * @param {Function} fn (optional) The default function to timeout
12667  * @param {Object} scope (optional) The default scope of that timeout
12668  * @param {Array} args (optional) The default Array of arguments
12669  */
12670 Roo.util.DelayedTask = function(fn, scope, args){
12671     var id = null, d, t;
12672
12673     var call = function(){
12674         var now = new Date().getTime();
12675         if(now - t >= d){
12676             clearInterval(id);
12677             id = null;
12678             fn.apply(scope, args || []);
12679         }
12680     };
12681     /**
12682      * Cancels any pending timeout and queues a new one
12683      * @param {Number} delay The milliseconds to delay
12684      * @param {Function} newFn (optional) Overrides function passed to constructor
12685      * @param {Object} newScope (optional) Overrides scope passed to constructor
12686      * @param {Array} newArgs (optional) Overrides args passed to constructor
12687      */
12688     this.delay = function(delay, newFn, newScope, newArgs){
12689         if(id && delay != d){
12690             this.cancel();
12691         }
12692         d = delay;
12693         t = new Date().getTime();
12694         fn = newFn || fn;
12695         scope = newScope || scope;
12696         args = newArgs || args;
12697         if(!id){
12698             id = setInterval(call, d);
12699         }
12700     };
12701
12702     /**
12703      * Cancel the last queued timeout
12704      */
12705     this.cancel = function(){
12706         if(id){
12707             clearInterval(id);
12708             id = null;
12709         }
12710     };
12711 };/*
12712  * Based on:
12713  * Ext JS Library 1.1.1
12714  * Copyright(c) 2006-2007, Ext JS, LLC.
12715  *
12716  * Originally Released Under LGPL - original licence link has changed is not relivant.
12717  *
12718  * Fork - LGPL
12719  * <script type="text/javascript">
12720  */
12721  
12722  
12723 Roo.util.TaskRunner = function(interval){
12724     interval = interval || 10;
12725     var tasks = [], removeQueue = [];
12726     var id = 0;
12727     var running = false;
12728
12729     var stopThread = function(){
12730         running = false;
12731         clearInterval(id);
12732         id = 0;
12733     };
12734
12735     var startThread = function(){
12736         if(!running){
12737             running = true;
12738             id = setInterval(runTasks, interval);
12739         }
12740     };
12741
12742     var removeTask = function(task){
12743         removeQueue.push(task);
12744         if(task.onStop){
12745             task.onStop();
12746         }
12747     };
12748
12749     var runTasks = function(){
12750         if(removeQueue.length > 0){
12751             for(var i = 0, len = removeQueue.length; i < len; i++){
12752                 tasks.remove(removeQueue[i]);
12753             }
12754             removeQueue = [];
12755             if(tasks.length < 1){
12756                 stopThread();
12757                 return;
12758             }
12759         }
12760         var now = new Date().getTime();
12761         for(var i = 0, len = tasks.length; i < len; ++i){
12762             var t = tasks[i];
12763             var itime = now - t.taskRunTime;
12764             if(t.interval <= itime){
12765                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12766                 t.taskRunTime = now;
12767                 if(rt === false || t.taskRunCount === t.repeat){
12768                     removeTask(t);
12769                     return;
12770                 }
12771             }
12772             if(t.duration && t.duration <= (now - t.taskStartTime)){
12773                 removeTask(t);
12774             }
12775         }
12776     };
12777
12778     /**
12779      * Queues a new task.
12780      * @param {Object} task
12781      */
12782     this.start = function(task){
12783         tasks.push(task);
12784         task.taskStartTime = new Date().getTime();
12785         task.taskRunTime = 0;
12786         task.taskRunCount = 0;
12787         startThread();
12788         return task;
12789     };
12790
12791     this.stop = function(task){
12792         removeTask(task);
12793         return task;
12794     };
12795
12796     this.stopAll = function(){
12797         stopThread();
12798         for(var i = 0, len = tasks.length; i < len; i++){
12799             if(tasks[i].onStop){
12800                 tasks[i].onStop();
12801             }
12802         }
12803         tasks = [];
12804         removeQueue = [];
12805     };
12806 };
12807
12808 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12809  * Based on:
12810  * Ext JS Library 1.1.1
12811  * Copyright(c) 2006-2007, Ext JS, LLC.
12812  *
12813  * Originally Released Under LGPL - original licence link has changed is not relivant.
12814  *
12815  * Fork - LGPL
12816  * <script type="text/javascript">
12817  */
12818
12819  
12820 /**
12821  * @class Roo.util.MixedCollection
12822  * @extends Roo.util.Observable
12823  * A Collection class that maintains both numeric indexes and keys and exposes events.
12824  * @constructor
12825  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12826  * collection (defaults to false)
12827  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12828  * and return the key value for that item.  This is used when available to look up the key on items that
12829  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12830  * equivalent to providing an implementation for the {@link #getKey} method.
12831  */
12832 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12833     this.items = [];
12834     this.map = {};
12835     this.keys = [];
12836     this.length = 0;
12837     this.addEvents({
12838         /**
12839          * @event clear
12840          * Fires when the collection is cleared.
12841          */
12842         "clear" : true,
12843         /**
12844          * @event add
12845          * Fires when an item is added to the collection.
12846          * @param {Number} index The index at which the item was added.
12847          * @param {Object} o The item added.
12848          * @param {String} key The key associated with the added item.
12849          */
12850         "add" : true,
12851         /**
12852          * @event replace
12853          * Fires when an item is replaced in the collection.
12854          * @param {String} key he key associated with the new added.
12855          * @param {Object} old The item being replaced.
12856          * @param {Object} new The new item.
12857          */
12858         "replace" : true,
12859         /**
12860          * @event remove
12861          * Fires when an item is removed from the collection.
12862          * @param {Object} o The item being removed.
12863          * @param {String} key (optional) The key associated with the removed item.
12864          */
12865         "remove" : true,
12866         "sort" : true
12867     });
12868     this.allowFunctions = allowFunctions === true;
12869     if(keyFn){
12870         this.getKey = keyFn;
12871     }
12872     Roo.util.MixedCollection.superclass.constructor.call(this);
12873 };
12874
12875 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12876     allowFunctions : false,
12877     
12878 /**
12879  * Adds an item to the collection.
12880  * @param {String} key The key to associate with the item
12881  * @param {Object} o The item to add.
12882  * @return {Object} The item added.
12883  */
12884     add : function(key, o){
12885         if(arguments.length == 1){
12886             o = arguments[0];
12887             key = this.getKey(o);
12888         }
12889         if(typeof key == "undefined" || key === null){
12890             this.length++;
12891             this.items.push(o);
12892             this.keys.push(null);
12893         }else{
12894             var old = this.map[key];
12895             if(old){
12896                 return this.replace(key, o);
12897             }
12898             this.length++;
12899             this.items.push(o);
12900             this.map[key] = o;
12901             this.keys.push(key);
12902         }
12903         this.fireEvent("add", this.length-1, o, key);
12904         return o;
12905     },
12906        
12907 /**
12908   * MixedCollection has a generic way to fetch keys if you implement getKey.
12909 <pre><code>
12910 // normal way
12911 var mc = new Roo.util.MixedCollection();
12912 mc.add(someEl.dom.id, someEl);
12913 mc.add(otherEl.dom.id, otherEl);
12914 //and so on
12915
12916 // using getKey
12917 var mc = new Roo.util.MixedCollection();
12918 mc.getKey = function(el){
12919    return el.dom.id;
12920 };
12921 mc.add(someEl);
12922 mc.add(otherEl);
12923
12924 // or via the constructor
12925 var mc = new Roo.util.MixedCollection(false, function(el){
12926    return el.dom.id;
12927 });
12928 mc.add(someEl);
12929 mc.add(otherEl);
12930 </code></pre>
12931  * @param o {Object} The item for which to find the key.
12932  * @return {Object} The key for the passed item.
12933  */
12934     getKey : function(o){
12935          return o.id; 
12936     },
12937    
12938 /**
12939  * Replaces an item in the collection.
12940  * @param {String} key The key associated with the item to replace, or the item to replace.
12941  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12942  * @return {Object}  The new item.
12943  */
12944     replace : function(key, o){
12945         if(arguments.length == 1){
12946             o = arguments[0];
12947             key = this.getKey(o);
12948         }
12949         var old = this.item(key);
12950         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12951              return this.add(key, o);
12952         }
12953         var index = this.indexOfKey(key);
12954         this.items[index] = o;
12955         this.map[key] = o;
12956         this.fireEvent("replace", key, old, o);
12957         return o;
12958     },
12959    
12960 /**
12961  * Adds all elements of an Array or an Object to the collection.
12962  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12963  * an Array of values, each of which are added to the collection.
12964  */
12965     addAll : function(objs){
12966         if(arguments.length > 1 || objs instanceof Array){
12967             var args = arguments.length > 1 ? arguments : objs;
12968             for(var i = 0, len = args.length; i < len; i++){
12969                 this.add(args[i]);
12970             }
12971         }else{
12972             for(var key in objs){
12973                 if(this.allowFunctions || typeof objs[key] != "function"){
12974                     this.add(key, objs[key]);
12975                 }
12976             }
12977         }
12978     },
12979    
12980 /**
12981  * Executes the specified function once for every item in the collection, passing each
12982  * item as the first and only parameter. returning false from the function will stop the iteration.
12983  * @param {Function} fn The function to execute for each item.
12984  * @param {Object} scope (optional) The scope in which to execute the function.
12985  */
12986     each : function(fn, scope){
12987         var items = [].concat(this.items); // each safe for removal
12988         for(var i = 0, len = items.length; i < len; i++){
12989             if(fn.call(scope || items[i], items[i], i, len) === false){
12990                 break;
12991             }
12992         }
12993     },
12994    
12995 /**
12996  * Executes the specified function once for every key in the collection, passing each
12997  * key, and its associated item as the first two parameters.
12998  * @param {Function} fn The function to execute for each item.
12999  * @param {Object} scope (optional) The scope in which to execute the function.
13000  */
13001     eachKey : function(fn, scope){
13002         for(var i = 0, len = this.keys.length; i < len; i++){
13003             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13004         }
13005     },
13006    
13007 /**
13008  * Returns the first item in the collection which elicits a true return value from the
13009  * passed selection function.
13010  * @param {Function} fn The selection function to execute for each item.
13011  * @param {Object} scope (optional) The scope in which to execute the function.
13012  * @return {Object} The first item in the collection which returned true from the selection function.
13013  */
13014     find : function(fn, scope){
13015         for(var i = 0, len = this.items.length; i < len; i++){
13016             if(fn.call(scope || window, this.items[i], this.keys[i])){
13017                 return this.items[i];
13018             }
13019         }
13020         return null;
13021     },
13022    
13023 /**
13024  * Inserts an item at the specified index in the collection.
13025  * @param {Number} index The index to insert the item at.
13026  * @param {String} key The key to associate with the new item, or the item itself.
13027  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13028  * @return {Object} The item inserted.
13029  */
13030     insert : function(index, key, o){
13031         if(arguments.length == 2){
13032             o = arguments[1];
13033             key = this.getKey(o);
13034         }
13035         if(index >= this.length){
13036             return this.add(key, o);
13037         }
13038         this.length++;
13039         this.items.splice(index, 0, o);
13040         if(typeof key != "undefined" && key != null){
13041             this.map[key] = o;
13042         }
13043         this.keys.splice(index, 0, key);
13044         this.fireEvent("add", index, o, key);
13045         return o;
13046     },
13047    
13048 /**
13049  * Removed an item from the collection.
13050  * @param {Object} o The item to remove.
13051  * @return {Object} The item removed.
13052  */
13053     remove : function(o){
13054         return this.removeAt(this.indexOf(o));
13055     },
13056    
13057 /**
13058  * Remove an item from a specified index in the collection.
13059  * @param {Number} index The index within the collection of the item to remove.
13060  */
13061     removeAt : function(index){
13062         if(index < this.length && index >= 0){
13063             this.length--;
13064             var o = this.items[index];
13065             this.items.splice(index, 1);
13066             var key = this.keys[index];
13067             if(typeof key != "undefined"){
13068                 delete this.map[key];
13069             }
13070             this.keys.splice(index, 1);
13071             this.fireEvent("remove", o, key);
13072         }
13073     },
13074    
13075 /**
13076  * Removed an item associated with the passed key fom the collection.
13077  * @param {String} key The key of the item to remove.
13078  */
13079     removeKey : function(key){
13080         return this.removeAt(this.indexOfKey(key));
13081     },
13082    
13083 /**
13084  * Returns the number of items in the collection.
13085  * @return {Number} the number of items in the collection.
13086  */
13087     getCount : function(){
13088         return this.length; 
13089     },
13090    
13091 /**
13092  * Returns index within the collection of the passed Object.
13093  * @param {Object} o The item to find the index of.
13094  * @return {Number} index of the item.
13095  */
13096     indexOf : function(o){
13097         if(!this.items.indexOf){
13098             for(var i = 0, len = this.items.length; i < len; i++){
13099                 if(this.items[i] == o) {
13100                     return i;
13101                 }
13102             }
13103             return -1;
13104         }else{
13105             return this.items.indexOf(o);
13106         }
13107     },
13108    
13109 /**
13110  * Returns index within the collection of the passed key.
13111  * @param {String} key The key to find the index of.
13112  * @return {Number} index of the key.
13113  */
13114     indexOfKey : function(key){
13115         if(!this.keys.indexOf){
13116             for(var i = 0, len = this.keys.length; i < len; i++){
13117                 if(this.keys[i] == key) {
13118                     return i;
13119                 }
13120             }
13121             return -1;
13122         }else{
13123             return this.keys.indexOf(key);
13124         }
13125     },
13126    
13127 /**
13128  * Returns the item associated with the passed key OR index. Key has priority over index.
13129  * @param {String/Number} key The key or index of the item.
13130  * @return {Object} The item associated with the passed key.
13131  */
13132     item : function(key){
13133         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13134         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13135     },
13136     
13137 /**
13138  * Returns the item at the specified index.
13139  * @param {Number} index The index of the item.
13140  * @return {Object}
13141  */
13142     itemAt : function(index){
13143         return this.items[index];
13144     },
13145     
13146 /**
13147  * Returns the item associated with the passed key.
13148  * @param {String/Number} key The key of the item.
13149  * @return {Object} The item associated with the passed key.
13150  */
13151     key : function(key){
13152         return this.map[key];
13153     },
13154    
13155 /**
13156  * Returns true if the collection contains the passed Object as an item.
13157  * @param {Object} o  The Object to look for in the collection.
13158  * @return {Boolean} True if the collection contains the Object as an item.
13159  */
13160     contains : function(o){
13161         return this.indexOf(o) != -1;
13162     },
13163    
13164 /**
13165  * Returns true if the collection contains the passed Object as a key.
13166  * @param {String} key The key to look for in the collection.
13167  * @return {Boolean} True if the collection contains the Object as a key.
13168  */
13169     containsKey : function(key){
13170         return typeof this.map[key] != "undefined";
13171     },
13172    
13173 /**
13174  * Removes all items from the collection.
13175  */
13176     clear : function(){
13177         this.length = 0;
13178         this.items = [];
13179         this.keys = [];
13180         this.map = {};
13181         this.fireEvent("clear");
13182     },
13183    
13184 /**
13185  * Returns the first item in the collection.
13186  * @return {Object} the first item in the collection..
13187  */
13188     first : function(){
13189         return this.items[0]; 
13190     },
13191    
13192 /**
13193  * Returns the last item in the collection.
13194  * @return {Object} the last item in the collection..
13195  */
13196     last : function(){
13197         return this.items[this.length-1];   
13198     },
13199     
13200     _sort : function(property, dir, fn){
13201         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13202         fn = fn || function(a, b){
13203             return a-b;
13204         };
13205         var c = [], k = this.keys, items = this.items;
13206         for(var i = 0, len = items.length; i < len; i++){
13207             c[c.length] = {key: k[i], value: items[i], index: i};
13208         }
13209         c.sort(function(a, b){
13210             var v = fn(a[property], b[property]) * dsc;
13211             if(v == 0){
13212                 v = (a.index < b.index ? -1 : 1);
13213             }
13214             return v;
13215         });
13216         for(var i = 0, len = c.length; i < len; i++){
13217             items[i] = c[i].value;
13218             k[i] = c[i].key;
13219         }
13220         this.fireEvent("sort", this);
13221     },
13222     
13223     /**
13224      * Sorts this collection with the passed comparison function
13225      * @param {String} direction (optional) "ASC" or "DESC"
13226      * @param {Function} fn (optional) comparison function
13227      */
13228     sort : function(dir, fn){
13229         this._sort("value", dir, fn);
13230     },
13231     
13232     /**
13233      * Sorts this collection by keys
13234      * @param {String} direction (optional) "ASC" or "DESC"
13235      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13236      */
13237     keySort : function(dir, fn){
13238         this._sort("key", dir, fn || function(a, b){
13239             return String(a).toUpperCase()-String(b).toUpperCase();
13240         });
13241     },
13242     
13243     /**
13244      * Returns a range of items in this collection
13245      * @param {Number} startIndex (optional) defaults to 0
13246      * @param {Number} endIndex (optional) default to the last item
13247      * @return {Array} An array of items
13248      */
13249     getRange : function(start, end){
13250         var items = this.items;
13251         if(items.length < 1){
13252             return [];
13253         }
13254         start = start || 0;
13255         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13256         var r = [];
13257         if(start <= end){
13258             for(var i = start; i <= end; i++) {
13259                     r[r.length] = items[i];
13260             }
13261         }else{
13262             for(var i = start; i >= end; i--) {
13263                     r[r.length] = items[i];
13264             }
13265         }
13266         return r;
13267     },
13268         
13269     /**
13270      * Filter the <i>objects</i> in this collection by a specific property. 
13271      * Returns a new collection that has been filtered.
13272      * @param {String} property A property on your objects
13273      * @param {String/RegExp} value Either string that the property values 
13274      * should start with or a RegExp to test against the property
13275      * @return {MixedCollection} The new filtered collection
13276      */
13277     filter : function(property, value){
13278         if(!value.exec){ // not a regex
13279             value = String(value);
13280             if(value.length == 0){
13281                 return this.clone();
13282             }
13283             value = new RegExp("^" + Roo.escapeRe(value), "i");
13284         }
13285         return this.filterBy(function(o){
13286             return o && value.test(o[property]);
13287         });
13288         },
13289     
13290     /**
13291      * Filter by a function. * Returns a new collection that has been filtered.
13292      * The passed function will be called with each 
13293      * object in the collection. If the function returns true, the value is included 
13294      * otherwise it is filtered.
13295      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13296      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13297      * @return {MixedCollection} The new filtered collection
13298      */
13299     filterBy : function(fn, scope){
13300         var r = new Roo.util.MixedCollection();
13301         r.getKey = this.getKey;
13302         var k = this.keys, it = this.items;
13303         for(var i = 0, len = it.length; i < len; i++){
13304             if(fn.call(scope||this, it[i], k[i])){
13305                                 r.add(k[i], it[i]);
13306                         }
13307         }
13308         return r;
13309     },
13310     
13311     /**
13312      * Creates a duplicate of this collection
13313      * @return {MixedCollection}
13314      */
13315     clone : function(){
13316         var r = new Roo.util.MixedCollection();
13317         var k = this.keys, it = this.items;
13318         for(var i = 0, len = it.length; i < len; i++){
13319             r.add(k[i], it[i]);
13320         }
13321         r.getKey = this.getKey;
13322         return r;
13323     }
13324 });
13325 /**
13326  * Returns the item associated with the passed key or index.
13327  * @method
13328  * @param {String/Number} key The key or index of the item.
13329  * @return {Object} The item associated with the passed key.
13330  */
13331 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13332  * Based on:
13333  * Ext JS Library 1.1.1
13334  * Copyright(c) 2006-2007, Ext JS, LLC.
13335  *
13336  * Originally Released Under LGPL - original licence link has changed is not relivant.
13337  *
13338  * Fork - LGPL
13339  * <script type="text/javascript">
13340  */
13341 /**
13342  * @class Roo.util.JSON
13343  * Modified version of Douglas Crockford"s json.js that doesn"t
13344  * mess with the Object prototype 
13345  * http://www.json.org/js.html
13346  * @singleton
13347  */
13348 Roo.util.JSON = new (function(){
13349     var useHasOwn = {}.hasOwnProperty ? true : false;
13350     
13351     // crashes Safari in some instances
13352     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13353     
13354     var pad = function(n) {
13355         return n < 10 ? "0" + n : n;
13356     };
13357     
13358     var m = {
13359         "\b": '\\b',
13360         "\t": '\\t',
13361         "\n": '\\n',
13362         "\f": '\\f',
13363         "\r": '\\r',
13364         '"' : '\\"',
13365         "\\": '\\\\'
13366     };
13367
13368     var encodeString = function(s){
13369         if (/["\\\x00-\x1f]/.test(s)) {
13370             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13371                 var c = m[b];
13372                 if(c){
13373                     return c;
13374                 }
13375                 c = b.charCodeAt();
13376                 return "\\u00" +
13377                     Math.floor(c / 16).toString(16) +
13378                     (c % 16).toString(16);
13379             }) + '"';
13380         }
13381         return '"' + s + '"';
13382     };
13383     
13384     var encodeArray = function(o){
13385         var a = ["["], b, i, l = o.length, v;
13386             for (i = 0; i < l; i += 1) {
13387                 v = o[i];
13388                 switch (typeof v) {
13389                     case "undefined":
13390                     case "function":
13391                     case "unknown":
13392                         break;
13393                     default:
13394                         if (b) {
13395                             a.push(',');
13396                         }
13397                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13398                         b = true;
13399                 }
13400             }
13401             a.push("]");
13402             return a.join("");
13403     };
13404     
13405     var encodeDate = function(o){
13406         return '"' + o.getFullYear() + "-" +
13407                 pad(o.getMonth() + 1) + "-" +
13408                 pad(o.getDate()) + "T" +
13409                 pad(o.getHours()) + ":" +
13410                 pad(o.getMinutes()) + ":" +
13411                 pad(o.getSeconds()) + '"';
13412     };
13413     
13414     /**
13415      * Encodes an Object, Array or other value
13416      * @param {Mixed} o The variable to encode
13417      * @return {String} The JSON string
13418      */
13419     this.encode = function(o)
13420     {
13421         // should this be extended to fully wrap stringify..
13422         
13423         if(typeof o == "undefined" || o === null){
13424             return "null";
13425         }else if(o instanceof Array){
13426             return encodeArray(o);
13427         }else if(o instanceof Date){
13428             return encodeDate(o);
13429         }else if(typeof o == "string"){
13430             return encodeString(o);
13431         }else if(typeof o == "number"){
13432             return isFinite(o) ? String(o) : "null";
13433         }else if(typeof o == "boolean"){
13434             return String(o);
13435         }else {
13436             var a = ["{"], b, i, v;
13437             for (i in o) {
13438                 if(!useHasOwn || o.hasOwnProperty(i)) {
13439                     v = o[i];
13440                     switch (typeof v) {
13441                     case "undefined":
13442                     case "function":
13443                     case "unknown":
13444                         break;
13445                     default:
13446                         if(b){
13447                             a.push(',');
13448                         }
13449                         a.push(this.encode(i), ":",
13450                                 v === null ? "null" : this.encode(v));
13451                         b = true;
13452                     }
13453                 }
13454             }
13455             a.push("}");
13456             return a.join("");
13457         }
13458     };
13459     
13460     /**
13461      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13462      * @param {String} json The JSON string
13463      * @return {Object} The resulting object
13464      */
13465     this.decode = function(json){
13466         
13467         return  /** eval:var:json */ eval("(" + json + ')');
13468     };
13469 })();
13470 /** 
13471  * Shorthand for {@link Roo.util.JSON#encode}
13472  * @member Roo encode 
13473  * @method */
13474 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13475 /** 
13476  * Shorthand for {@link Roo.util.JSON#decode}
13477  * @member Roo decode 
13478  * @method */
13479 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13480 /*
13481  * Based on:
13482  * Ext JS Library 1.1.1
13483  * Copyright(c) 2006-2007, Ext JS, LLC.
13484  *
13485  * Originally Released Under LGPL - original licence link has changed is not relivant.
13486  *
13487  * Fork - LGPL
13488  * <script type="text/javascript">
13489  */
13490  
13491 /**
13492  * @class Roo.util.Format
13493  * Reusable data formatting functions
13494  * @singleton
13495  */
13496 Roo.util.Format = function(){
13497     var trimRe = /^\s+|\s+$/g;
13498     return {
13499         /**
13500          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13501          * @param {String} value The string to truncate
13502          * @param {Number} length The maximum length to allow before truncating
13503          * @return {String} The converted text
13504          */
13505         ellipsis : function(value, len){
13506             if(value && value.length > len){
13507                 return value.substr(0, len-3)+"...";
13508             }
13509             return value;
13510         },
13511
13512         /**
13513          * Checks a reference and converts it to empty string if it is undefined
13514          * @param {Mixed} value Reference to check
13515          * @return {Mixed} Empty string if converted, otherwise the original value
13516          */
13517         undef : function(value){
13518             return typeof value != "undefined" ? value : "";
13519         },
13520
13521         /**
13522          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13523          * @param {String} value The string to encode
13524          * @return {String} The encoded text
13525          */
13526         htmlEncode : function(value){
13527             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13528         },
13529
13530         /**
13531          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13532          * @param {String} value The string to decode
13533          * @return {String} The decoded text
13534          */
13535         htmlDecode : function(value){
13536             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13537         },
13538
13539         /**
13540          * Trims any whitespace from either side of a string
13541          * @param {String} value The text to trim
13542          * @return {String} The trimmed text
13543          */
13544         trim : function(value){
13545             return String(value).replace(trimRe, "");
13546         },
13547
13548         /**
13549          * Returns a substring from within an original string
13550          * @param {String} value The original text
13551          * @param {Number} start The start index of the substring
13552          * @param {Number} length The length of the substring
13553          * @return {String} The substring
13554          */
13555         substr : function(value, start, length){
13556             return String(value).substr(start, length);
13557         },
13558
13559         /**
13560          * Converts a string to all lower case letters
13561          * @param {String} value The text to convert
13562          * @return {String} The converted text
13563          */
13564         lowercase : function(value){
13565             return String(value).toLowerCase();
13566         },
13567
13568         /**
13569          * Converts a string to all upper case letters
13570          * @param {String} value The text to convert
13571          * @return {String} The converted text
13572          */
13573         uppercase : function(value){
13574             return String(value).toUpperCase();
13575         },
13576
13577         /**
13578          * Converts the first character only of a string to upper case
13579          * @param {String} value The text to convert
13580          * @return {String} The converted text
13581          */
13582         capitalize : function(value){
13583             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13584         },
13585
13586         // private
13587         call : function(value, fn){
13588             if(arguments.length > 2){
13589                 var args = Array.prototype.slice.call(arguments, 2);
13590                 args.unshift(value);
13591                  
13592                 return /** eval:var:value */  eval(fn).apply(window, args);
13593             }else{
13594                 /** eval:var:value */
13595                 return /** eval:var:value */ eval(fn).call(window, value);
13596             }
13597         },
13598
13599        
13600         /**
13601          * safer version of Math.toFixed..??/
13602          * @param {Number/String} value The numeric value to format
13603          * @param {Number/String} value Decimal places 
13604          * @return {String} The formatted currency string
13605          */
13606         toFixed : function(v, n)
13607         {
13608             // why not use to fixed - precision is buggered???
13609             if (!n) {
13610                 return Math.round(v-0);
13611             }
13612             var fact = Math.pow(10,n+1);
13613             v = (Math.round((v-0)*fact))/fact;
13614             var z = (''+fact).substring(2);
13615             if (v == Math.floor(v)) {
13616                 return Math.floor(v) + '.' + z;
13617             }
13618             
13619             // now just padd decimals..
13620             var ps = String(v).split('.');
13621             var fd = (ps[1] + z);
13622             var r = fd.substring(0,n); 
13623             var rm = fd.substring(n); 
13624             if (rm < 5) {
13625                 return ps[0] + '.' + r;
13626             }
13627             r*=1; // turn it into a number;
13628             r++;
13629             if (String(r).length != n) {
13630                 ps[0]*=1;
13631                 ps[0]++;
13632                 r = String(r).substring(1); // chop the end off.
13633             }
13634             
13635             return ps[0] + '.' + r;
13636              
13637         },
13638         
13639         /**
13640          * Format a number as US currency
13641          * @param {Number/String} value The numeric value to format
13642          * @return {String} The formatted currency string
13643          */
13644         usMoney : function(v){
13645             return '$' + Roo.util.Format.number(v);
13646         },
13647         
13648         /**
13649          * Format a number
13650          * eventually this should probably emulate php's number_format
13651          * @param {Number/String} value The numeric value to format
13652          * @param {Number} decimals number of decimal places
13653          * @return {String} The formatted currency string
13654          */
13655         number : function(v,decimals)
13656         {
13657             // multiply and round.
13658             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13659             var mul = Math.pow(10, decimals);
13660             var zero = String(mul).substring(1);
13661             v = (Math.round((v-0)*mul))/mul;
13662             
13663             // if it's '0' number.. then
13664             
13665             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13666             v = String(v);
13667             var ps = v.split('.');
13668             var whole = ps[0];
13669             
13670             
13671             var r = /(\d+)(\d{3})/;
13672             // add comma's
13673             while (r.test(whole)) {
13674                 whole = whole.replace(r, '$1' + ',' + '$2');
13675             }
13676             
13677             
13678             var sub = ps[1] ?
13679                     // has decimals..
13680                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13681                     // does not have decimals
13682                     (decimals ? ('.' + zero) : '');
13683             
13684             
13685             return whole + sub ;
13686         },
13687         
13688         /**
13689          * Parse a value into a formatted date using the specified format pattern.
13690          * @param {Mixed} value The value to format
13691          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13692          * @return {String} The formatted date string
13693          */
13694         date : function(v, format){
13695             if(!v){
13696                 return "";
13697             }
13698             if(!(v instanceof Date)){
13699                 v = new Date(Date.parse(v));
13700             }
13701             return v.dateFormat(format || Roo.util.Format.defaults.date);
13702         },
13703
13704         /**
13705          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13706          * @param {String} format Any valid date format string
13707          * @return {Function} The date formatting function
13708          */
13709         dateRenderer : function(format){
13710             return function(v){
13711                 return Roo.util.Format.date(v, format);  
13712             };
13713         },
13714
13715         // private
13716         stripTagsRE : /<\/?[^>]+>/gi,
13717         
13718         /**
13719          * Strips all HTML tags
13720          * @param {Mixed} value The text from which to strip tags
13721          * @return {String} The stripped text
13722          */
13723         stripTags : function(v){
13724             return !v ? v : String(v).replace(this.stripTagsRE, "");
13725         }
13726     };
13727 }();
13728 Roo.util.Format.defaults = {
13729     date : 'd/M/Y'
13730 };/*
13731  * Based on:
13732  * Ext JS Library 1.1.1
13733  * Copyright(c) 2006-2007, Ext JS, LLC.
13734  *
13735  * Originally Released Under LGPL - original licence link has changed is not relivant.
13736  *
13737  * Fork - LGPL
13738  * <script type="text/javascript">
13739  */
13740
13741
13742  
13743
13744 /**
13745  * @class Roo.MasterTemplate
13746  * @extends Roo.Template
13747  * Provides a template that can have child templates. The syntax is:
13748 <pre><code>
13749 var t = new Roo.MasterTemplate(
13750         '&lt;select name="{name}"&gt;',
13751                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13752         '&lt;/select&gt;'
13753 );
13754 t.add('options', {value: 'foo', text: 'bar'});
13755 // or you can add multiple child elements in one shot
13756 t.addAll('options', [
13757     {value: 'foo', text: 'bar'},
13758     {value: 'foo2', text: 'bar2'},
13759     {value: 'foo3', text: 'bar3'}
13760 ]);
13761 // then append, applying the master template values
13762 t.append('my-form', {name: 'my-select'});
13763 </code></pre>
13764 * A name attribute for the child template is not required if you have only one child
13765 * template or you want to refer to them by index.
13766  */
13767 Roo.MasterTemplate = function(){
13768     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13769     this.originalHtml = this.html;
13770     var st = {};
13771     var m, re = this.subTemplateRe;
13772     re.lastIndex = 0;
13773     var subIndex = 0;
13774     while(m = re.exec(this.html)){
13775         var name = m[1], content = m[2];
13776         st[subIndex] = {
13777             name: name,
13778             index: subIndex,
13779             buffer: [],
13780             tpl : new Roo.Template(content)
13781         };
13782         if(name){
13783             st[name] = st[subIndex];
13784         }
13785         st[subIndex].tpl.compile();
13786         st[subIndex].tpl.call = this.call.createDelegate(this);
13787         subIndex++;
13788     }
13789     this.subCount = subIndex;
13790     this.subs = st;
13791 };
13792 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13793     /**
13794     * The regular expression used to match sub templates
13795     * @type RegExp
13796     * @property
13797     */
13798     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13799
13800     /**
13801      * Applies the passed values to a child template.
13802      * @param {String/Number} name (optional) The name or index of the child template
13803      * @param {Array/Object} values The values to be applied to the template
13804      * @return {MasterTemplate} this
13805      */
13806      add : function(name, values){
13807         if(arguments.length == 1){
13808             values = arguments[0];
13809             name = 0;
13810         }
13811         var s = this.subs[name];
13812         s.buffer[s.buffer.length] = s.tpl.apply(values);
13813         return this;
13814     },
13815
13816     /**
13817      * Applies all the passed values to a child template.
13818      * @param {String/Number} name (optional) The name or index of the child template
13819      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13820      * @param {Boolean} reset (optional) True to reset the template first
13821      * @return {MasterTemplate} this
13822      */
13823     fill : function(name, values, reset){
13824         var a = arguments;
13825         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13826             values = a[0];
13827             name = 0;
13828             reset = a[1];
13829         }
13830         if(reset){
13831             this.reset();
13832         }
13833         for(var i = 0, len = values.length; i < len; i++){
13834             this.add(name, values[i]);
13835         }
13836         return this;
13837     },
13838
13839     /**
13840      * Resets the template for reuse
13841      * @return {MasterTemplate} this
13842      */
13843      reset : function(){
13844         var s = this.subs;
13845         for(var i = 0; i < this.subCount; i++){
13846             s[i].buffer = [];
13847         }
13848         return this;
13849     },
13850
13851     applyTemplate : function(values){
13852         var s = this.subs;
13853         var replaceIndex = -1;
13854         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13855             return s[++replaceIndex].buffer.join("");
13856         });
13857         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13858     },
13859
13860     apply : function(){
13861         return this.applyTemplate.apply(this, arguments);
13862     },
13863
13864     compile : function(){return this;}
13865 });
13866
13867 /**
13868  * Alias for fill().
13869  * @method
13870  */
13871 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13872  /**
13873  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13874  * var tpl = Roo.MasterTemplate.from('element-id');
13875  * @param {String/HTMLElement} el
13876  * @param {Object} config
13877  * @static
13878  */
13879 Roo.MasterTemplate.from = function(el, config){
13880     el = Roo.getDom(el);
13881     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13882 };/*
13883  * Based on:
13884  * Ext JS Library 1.1.1
13885  * Copyright(c) 2006-2007, Ext JS, LLC.
13886  *
13887  * Originally Released Under LGPL - original licence link has changed is not relivant.
13888  *
13889  * Fork - LGPL
13890  * <script type="text/javascript">
13891  */
13892
13893  
13894 /**
13895  * @class Roo.util.CSS
13896  * Utility class for manipulating CSS rules
13897  * @singleton
13898  */
13899 Roo.util.CSS = function(){
13900         var rules = null;
13901         var doc = document;
13902
13903     var camelRe = /(-[a-z])/gi;
13904     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13905
13906    return {
13907    /**
13908     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13909     * tag and appended to the HEAD of the document.
13910     * @param {String|Object} cssText The text containing the css rules
13911     * @param {String} id An id to add to the stylesheet for later removal
13912     * @return {StyleSheet}
13913     */
13914     createStyleSheet : function(cssText, id){
13915         var ss;
13916         var head = doc.getElementsByTagName("head")[0];
13917         var nrules = doc.createElement("style");
13918         nrules.setAttribute("type", "text/css");
13919         if(id){
13920             nrules.setAttribute("id", id);
13921         }
13922         if (typeof(cssText) != 'string') {
13923             // support object maps..
13924             // not sure if this a good idea.. 
13925             // perhaps it should be merged with the general css handling
13926             // and handle js style props.
13927             var cssTextNew = [];
13928             for(var n in cssText) {
13929                 var citems = [];
13930                 for(var k in cssText[n]) {
13931                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13932                 }
13933                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13934                 
13935             }
13936             cssText = cssTextNew.join("\n");
13937             
13938         }
13939        
13940        
13941        if(Roo.isIE){
13942            head.appendChild(nrules);
13943            ss = nrules.styleSheet;
13944            ss.cssText = cssText;
13945        }else{
13946            try{
13947                 nrules.appendChild(doc.createTextNode(cssText));
13948            }catch(e){
13949                nrules.cssText = cssText; 
13950            }
13951            head.appendChild(nrules);
13952            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13953        }
13954        this.cacheStyleSheet(ss);
13955        return ss;
13956    },
13957
13958    /**
13959     * Removes a style or link tag by id
13960     * @param {String} id The id of the tag
13961     */
13962    removeStyleSheet : function(id){
13963        var existing = doc.getElementById(id);
13964        if(existing){
13965            existing.parentNode.removeChild(existing);
13966        }
13967    },
13968
13969    /**
13970     * Dynamically swaps an existing stylesheet reference for a new one
13971     * @param {String} id The id of an existing link tag to remove
13972     * @param {String} url The href of the new stylesheet to include
13973     */
13974    swapStyleSheet : function(id, url){
13975        this.removeStyleSheet(id);
13976        var ss = doc.createElement("link");
13977        ss.setAttribute("rel", "stylesheet");
13978        ss.setAttribute("type", "text/css");
13979        ss.setAttribute("id", id);
13980        ss.setAttribute("href", url);
13981        doc.getElementsByTagName("head")[0].appendChild(ss);
13982    },
13983    
13984    /**
13985     * Refresh the rule cache if you have dynamically added stylesheets
13986     * @return {Object} An object (hash) of rules indexed by selector
13987     */
13988    refreshCache : function(){
13989        return this.getRules(true);
13990    },
13991
13992    // private
13993    cacheStyleSheet : function(stylesheet){
13994        if(!rules){
13995            rules = {};
13996        }
13997        try{// try catch for cross domain access issue
13998            var ssRules = stylesheet.cssRules || stylesheet.rules;
13999            for(var j = ssRules.length-1; j >= 0; --j){
14000                rules[ssRules[j].selectorText] = ssRules[j];
14001            }
14002        }catch(e){}
14003    },
14004    
14005    /**
14006     * Gets all css rules for the document
14007     * @param {Boolean} refreshCache true to refresh the internal cache
14008     * @return {Object} An object (hash) of rules indexed by selector
14009     */
14010    getRules : function(refreshCache){
14011                 if(rules == null || refreshCache){
14012                         rules = {};
14013                         var ds = doc.styleSheets;
14014                         for(var i =0, len = ds.length; i < len; i++){
14015                             try{
14016                         this.cacheStyleSheet(ds[i]);
14017                     }catch(e){} 
14018                 }
14019                 }
14020                 return rules;
14021         },
14022         
14023         /**
14024     * Gets an an individual CSS rule by selector(s)
14025     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14026     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14027     * @return {CSSRule} The CSS rule or null if one is not found
14028     */
14029    getRule : function(selector, refreshCache){
14030                 var rs = this.getRules(refreshCache);
14031                 if(!(selector instanceof Array)){
14032                     return rs[selector];
14033                 }
14034                 for(var i = 0; i < selector.length; i++){
14035                         if(rs[selector[i]]){
14036                                 return rs[selector[i]];
14037                         }
14038                 }
14039                 return null;
14040         },
14041         
14042         
14043         /**
14044     * Updates a rule property
14045     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14046     * @param {String} property The css property
14047     * @param {String} value The new value for the property
14048     * @return {Boolean} true If a rule was found and updated
14049     */
14050    updateRule : function(selector, property, value){
14051                 if(!(selector instanceof Array)){
14052                         var rule = this.getRule(selector);
14053                         if(rule){
14054                                 rule.style[property.replace(camelRe, camelFn)] = value;
14055                                 return true;
14056                         }
14057                 }else{
14058                         for(var i = 0; i < selector.length; i++){
14059                                 if(this.updateRule(selector[i], property, value)){
14060                                         return true;
14061                                 }
14062                         }
14063                 }
14064                 return false;
14065         }
14066    };   
14067 }();/*
14068  * Based on:
14069  * Ext JS Library 1.1.1
14070  * Copyright(c) 2006-2007, Ext JS, LLC.
14071  *
14072  * Originally Released Under LGPL - original licence link has changed is not relivant.
14073  *
14074  * Fork - LGPL
14075  * <script type="text/javascript">
14076  */
14077
14078  
14079
14080 /**
14081  * @class Roo.util.ClickRepeater
14082  * @extends Roo.util.Observable
14083  * 
14084  * A wrapper class which can be applied to any element. Fires a "click" event while the
14085  * mouse is pressed. The interval between firings may be specified in the config but
14086  * defaults to 10 milliseconds.
14087  * 
14088  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14089  * 
14090  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14091  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14092  * Similar to an autorepeat key delay.
14093  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14094  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14095  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14096  *           "interval" and "delay" are ignored. "immediate" is honored.
14097  * @cfg {Boolean} preventDefault True to prevent the default click event
14098  * @cfg {Boolean} stopDefault True to stop the default click event
14099  * 
14100  * @history
14101  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14102  *     2007-02-02 jvs Renamed to ClickRepeater
14103  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14104  *
14105  *  @constructor
14106  * @param {String/HTMLElement/Element} el The element to listen on
14107  * @param {Object} config
14108  **/
14109 Roo.util.ClickRepeater = function(el, config)
14110 {
14111     this.el = Roo.get(el);
14112     this.el.unselectable();
14113
14114     Roo.apply(this, config);
14115
14116     this.addEvents({
14117     /**
14118      * @event mousedown
14119      * Fires when the mouse button is depressed.
14120      * @param {Roo.util.ClickRepeater} this
14121      */
14122         "mousedown" : true,
14123     /**
14124      * @event click
14125      * Fires on a specified interval during the time the element is pressed.
14126      * @param {Roo.util.ClickRepeater} this
14127      */
14128         "click" : true,
14129     /**
14130      * @event mouseup
14131      * Fires when the mouse key is released.
14132      * @param {Roo.util.ClickRepeater} this
14133      */
14134         "mouseup" : true
14135     });
14136
14137     this.el.on("mousedown", this.handleMouseDown, this);
14138     if(this.preventDefault || this.stopDefault){
14139         this.el.on("click", function(e){
14140             if(this.preventDefault){
14141                 e.preventDefault();
14142             }
14143             if(this.stopDefault){
14144                 e.stopEvent();
14145             }
14146         }, this);
14147     }
14148
14149     // allow inline handler
14150     if(this.handler){
14151         this.on("click", this.handler,  this.scope || this);
14152     }
14153
14154     Roo.util.ClickRepeater.superclass.constructor.call(this);
14155 };
14156
14157 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14158     interval : 20,
14159     delay: 250,
14160     preventDefault : true,
14161     stopDefault : false,
14162     timer : 0,
14163
14164     // private
14165     handleMouseDown : function(){
14166         clearTimeout(this.timer);
14167         this.el.blur();
14168         if(this.pressClass){
14169             this.el.addClass(this.pressClass);
14170         }
14171         this.mousedownTime = new Date();
14172
14173         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14174         this.el.on("mouseout", this.handleMouseOut, this);
14175
14176         this.fireEvent("mousedown", this);
14177         this.fireEvent("click", this);
14178         
14179         this.timer = this.click.defer(this.delay || this.interval, this);
14180     },
14181
14182     // private
14183     click : function(){
14184         this.fireEvent("click", this);
14185         this.timer = this.click.defer(this.getInterval(), this);
14186     },
14187
14188     // private
14189     getInterval: function(){
14190         if(!this.accelerate){
14191             return this.interval;
14192         }
14193         var pressTime = this.mousedownTime.getElapsed();
14194         if(pressTime < 500){
14195             return 400;
14196         }else if(pressTime < 1700){
14197             return 320;
14198         }else if(pressTime < 2600){
14199             return 250;
14200         }else if(pressTime < 3500){
14201             return 180;
14202         }else if(pressTime < 4400){
14203             return 140;
14204         }else if(pressTime < 5300){
14205             return 80;
14206         }else if(pressTime < 6200){
14207             return 50;
14208         }else{
14209             return 10;
14210         }
14211     },
14212
14213     // private
14214     handleMouseOut : function(){
14215         clearTimeout(this.timer);
14216         if(this.pressClass){
14217             this.el.removeClass(this.pressClass);
14218         }
14219         this.el.on("mouseover", this.handleMouseReturn, this);
14220     },
14221
14222     // private
14223     handleMouseReturn : function(){
14224         this.el.un("mouseover", this.handleMouseReturn);
14225         if(this.pressClass){
14226             this.el.addClass(this.pressClass);
14227         }
14228         this.click();
14229     },
14230
14231     // private
14232     handleMouseUp : function(){
14233         clearTimeout(this.timer);
14234         this.el.un("mouseover", this.handleMouseReturn);
14235         this.el.un("mouseout", this.handleMouseOut);
14236         Roo.get(document).un("mouseup", this.handleMouseUp);
14237         this.el.removeClass(this.pressClass);
14238         this.fireEvent("mouseup", this);
14239     }
14240 });/*
14241  * Based on:
14242  * Ext JS Library 1.1.1
14243  * Copyright(c) 2006-2007, Ext JS, LLC.
14244  *
14245  * Originally Released Under LGPL - original licence link has changed is not relivant.
14246  *
14247  * Fork - LGPL
14248  * <script type="text/javascript">
14249  */
14250
14251  
14252 /**
14253  * @class Roo.KeyNav
14254  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14255  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14256  * way to implement custom navigation schemes for any UI component.</p>
14257  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14258  * pageUp, pageDown, del, home, end.  Usage:</p>
14259  <pre><code>
14260 var nav = new Roo.KeyNav("my-element", {
14261     "left" : function(e){
14262         this.moveLeft(e.ctrlKey);
14263     },
14264     "right" : function(e){
14265         this.moveRight(e.ctrlKey);
14266     },
14267     "enter" : function(e){
14268         this.save();
14269     },
14270     scope : this
14271 });
14272 </code></pre>
14273  * @constructor
14274  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14275  * @param {Object} config The config
14276  */
14277 Roo.KeyNav = function(el, config){
14278     this.el = Roo.get(el);
14279     Roo.apply(this, config);
14280     if(!this.disabled){
14281         this.disabled = true;
14282         this.enable();
14283     }
14284 };
14285
14286 Roo.KeyNav.prototype = {
14287     /**
14288      * @cfg {Boolean} disabled
14289      * True to disable this KeyNav instance (defaults to false)
14290      */
14291     disabled : false,
14292     /**
14293      * @cfg {String} defaultEventAction
14294      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14295      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14296      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14297      */
14298     defaultEventAction: "stopEvent",
14299     /**
14300      * @cfg {Boolean} forceKeyDown
14301      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14302      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14303      * handle keydown instead of keypress.
14304      */
14305     forceKeyDown : false,
14306
14307     // private
14308     prepareEvent : function(e){
14309         var k = e.getKey();
14310         var h = this.keyToHandler[k];
14311         //if(h && this[h]){
14312         //    e.stopPropagation();
14313         //}
14314         if(Roo.isSafari && h && k >= 37 && k <= 40){
14315             e.stopEvent();
14316         }
14317     },
14318
14319     // private
14320     relay : function(e){
14321         var k = e.getKey();
14322         var h = this.keyToHandler[k];
14323         if(h && this[h]){
14324             if(this.doRelay(e, this[h], h) !== true){
14325                 e[this.defaultEventAction]();
14326             }
14327         }
14328     },
14329
14330     // private
14331     doRelay : function(e, h, hname){
14332         return h.call(this.scope || this, e);
14333     },
14334
14335     // possible handlers
14336     enter : false,
14337     left : false,
14338     right : false,
14339     up : false,
14340     down : false,
14341     tab : false,
14342     esc : false,
14343     pageUp : false,
14344     pageDown : false,
14345     del : false,
14346     home : false,
14347     end : false,
14348
14349     // quick lookup hash
14350     keyToHandler : {
14351         37 : "left",
14352         39 : "right",
14353         38 : "up",
14354         40 : "down",
14355         33 : "pageUp",
14356         34 : "pageDown",
14357         46 : "del",
14358         36 : "home",
14359         35 : "end",
14360         13 : "enter",
14361         27 : "esc",
14362         9  : "tab"
14363     },
14364
14365         /**
14366          * Enable this KeyNav
14367          */
14368         enable: function(){
14369                 if(this.disabled){
14370             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14371             // the EventObject will normalize Safari automatically
14372             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14373                 this.el.on("keydown", this.relay,  this);
14374             }else{
14375                 this.el.on("keydown", this.prepareEvent,  this);
14376                 this.el.on("keypress", this.relay,  this);
14377             }
14378                     this.disabled = false;
14379                 }
14380         },
14381
14382         /**
14383          * Disable this KeyNav
14384          */
14385         disable: function(){
14386                 if(!this.disabled){
14387                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14388                 this.el.un("keydown", this.relay);
14389             }else{
14390                 this.el.un("keydown", this.prepareEvent);
14391                 this.el.un("keypress", this.relay);
14392             }
14393                     this.disabled = true;
14394                 }
14395         }
14396 };/*
14397  * Based on:
14398  * Ext JS Library 1.1.1
14399  * Copyright(c) 2006-2007, Ext JS, LLC.
14400  *
14401  * Originally Released Under LGPL - original licence link has changed is not relivant.
14402  *
14403  * Fork - LGPL
14404  * <script type="text/javascript">
14405  */
14406
14407  
14408 /**
14409  * @class Roo.KeyMap
14410  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14411  * The constructor accepts the same config object as defined by {@link #addBinding}.
14412  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14413  * combination it will call the function with this signature (if the match is a multi-key
14414  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14415  * A KeyMap can also handle a string representation of keys.<br />
14416  * Usage:
14417  <pre><code>
14418 // map one key by key code
14419 var map = new Roo.KeyMap("my-element", {
14420     key: 13, // or Roo.EventObject.ENTER
14421     fn: myHandler,
14422     scope: myObject
14423 });
14424
14425 // map multiple keys to one action by string
14426 var map = new Roo.KeyMap("my-element", {
14427     key: "a\r\n\t",
14428     fn: myHandler,
14429     scope: myObject
14430 });
14431
14432 // map multiple keys to multiple actions by strings and array of codes
14433 var map = new Roo.KeyMap("my-element", [
14434     {
14435         key: [10,13],
14436         fn: function(){ alert("Return was pressed"); }
14437     }, {
14438         key: "abc",
14439         fn: function(){ alert('a, b or c was pressed'); }
14440     }, {
14441         key: "\t",
14442         ctrl:true,
14443         shift:true,
14444         fn: function(){ alert('Control + shift + tab was pressed.'); }
14445     }
14446 ]);
14447 </code></pre>
14448  * <b>Note: A KeyMap starts enabled</b>
14449  * @constructor
14450  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14451  * @param {Object} config The config (see {@link #addBinding})
14452  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14453  */
14454 Roo.KeyMap = function(el, config, eventName){
14455     this.el  = Roo.get(el);
14456     this.eventName = eventName || "keydown";
14457     this.bindings = [];
14458     if(config){
14459         this.addBinding(config);
14460     }
14461     this.enable();
14462 };
14463
14464 Roo.KeyMap.prototype = {
14465     /**
14466      * True to stop the event from bubbling and prevent the default browser action if the
14467      * key was handled by the KeyMap (defaults to false)
14468      * @type Boolean
14469      */
14470     stopEvent : false,
14471
14472     /**
14473      * Add a new binding to this KeyMap. The following config object properties are supported:
14474      * <pre>
14475 Property    Type             Description
14476 ----------  ---------------  ----------------------------------------------------------------------
14477 key         String/Array     A single keycode or an array of keycodes to handle
14478 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14479 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14480 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14481 fn          Function         The function to call when KeyMap finds the expected key combination
14482 scope       Object           The scope of the callback function
14483 </pre>
14484      *
14485      * Usage:
14486      * <pre><code>
14487 // Create a KeyMap
14488 var map = new Roo.KeyMap(document, {
14489     key: Roo.EventObject.ENTER,
14490     fn: handleKey,
14491     scope: this
14492 });
14493
14494 //Add a new binding to the existing KeyMap later
14495 map.addBinding({
14496     key: 'abc',
14497     shift: true,
14498     fn: handleKey,
14499     scope: this
14500 });
14501 </code></pre>
14502      * @param {Object/Array} config A single KeyMap config or an array of configs
14503      */
14504         addBinding : function(config){
14505         if(config instanceof Array){
14506             for(var i = 0, len = config.length; i < len; i++){
14507                 this.addBinding(config[i]);
14508             }
14509             return;
14510         }
14511         var keyCode = config.key,
14512             shift = config.shift, 
14513             ctrl = config.ctrl, 
14514             alt = config.alt,
14515             fn = config.fn,
14516             scope = config.scope;
14517         if(typeof keyCode == "string"){
14518             var ks = [];
14519             var keyString = keyCode.toUpperCase();
14520             for(var j = 0, len = keyString.length; j < len; j++){
14521                 ks.push(keyString.charCodeAt(j));
14522             }
14523             keyCode = ks;
14524         }
14525         var keyArray = keyCode instanceof Array;
14526         var handler = function(e){
14527             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14528                 var k = e.getKey();
14529                 if(keyArray){
14530                     for(var i = 0, len = keyCode.length; i < len; i++){
14531                         if(keyCode[i] == k){
14532                           if(this.stopEvent){
14533                               e.stopEvent();
14534                           }
14535                           fn.call(scope || window, k, e);
14536                           return;
14537                         }
14538                     }
14539                 }else{
14540                     if(k == keyCode){
14541                         if(this.stopEvent){
14542                            e.stopEvent();
14543                         }
14544                         fn.call(scope || window, k, e);
14545                     }
14546                 }
14547             }
14548         };
14549         this.bindings.push(handler);  
14550         },
14551
14552     /**
14553      * Shorthand for adding a single key listener
14554      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14555      * following options:
14556      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14557      * @param {Function} fn The function to call
14558      * @param {Object} scope (optional) The scope of the function
14559      */
14560     on : function(key, fn, scope){
14561         var keyCode, shift, ctrl, alt;
14562         if(typeof key == "object" && !(key instanceof Array)){
14563             keyCode = key.key;
14564             shift = key.shift;
14565             ctrl = key.ctrl;
14566             alt = key.alt;
14567         }else{
14568             keyCode = key;
14569         }
14570         this.addBinding({
14571             key: keyCode,
14572             shift: shift,
14573             ctrl: ctrl,
14574             alt: alt,
14575             fn: fn,
14576             scope: scope
14577         })
14578     },
14579
14580     // private
14581     handleKeyDown : function(e){
14582             if(this.enabled){ //just in case
14583             var b = this.bindings;
14584             for(var i = 0, len = b.length; i < len; i++){
14585                 b[i].call(this, e);
14586             }
14587             }
14588         },
14589         
14590         /**
14591          * Returns true if this KeyMap is enabled
14592          * @return {Boolean} 
14593          */
14594         isEnabled : function(){
14595             return this.enabled;  
14596         },
14597         
14598         /**
14599          * Enables this KeyMap
14600          */
14601         enable: function(){
14602                 if(!this.enabled){
14603                     this.el.on(this.eventName, this.handleKeyDown, this);
14604                     this.enabled = true;
14605                 }
14606         },
14607
14608         /**
14609          * Disable this KeyMap
14610          */
14611         disable: function(){
14612                 if(this.enabled){
14613                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14614                     this.enabled = false;
14615                 }
14616         }
14617 };/*
14618  * Based on:
14619  * Ext JS Library 1.1.1
14620  * Copyright(c) 2006-2007, Ext JS, LLC.
14621  *
14622  * Originally Released Under LGPL - original licence link has changed is not relivant.
14623  *
14624  * Fork - LGPL
14625  * <script type="text/javascript">
14626  */
14627
14628  
14629 /**
14630  * @class Roo.util.TextMetrics
14631  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14632  * wide, in pixels, a given block of text will be.
14633  * @singleton
14634  */
14635 Roo.util.TextMetrics = function(){
14636     var shared;
14637     return {
14638         /**
14639          * Measures the size of the specified text
14640          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14641          * that can affect the size of the rendered text
14642          * @param {String} text The text to measure
14643          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14644          * in order to accurately measure the text height
14645          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14646          */
14647         measure : function(el, text, fixedWidth){
14648             if(!shared){
14649                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14650             }
14651             shared.bind(el);
14652             shared.setFixedWidth(fixedWidth || 'auto');
14653             return shared.getSize(text);
14654         },
14655
14656         /**
14657          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14658          * the overhead of multiple calls to initialize the style properties on each measurement.
14659          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14660          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14661          * in order to accurately measure the text height
14662          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14663          */
14664         createInstance : function(el, fixedWidth){
14665             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14666         }
14667     };
14668 }();
14669
14670  
14671
14672 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14673     var ml = new Roo.Element(document.createElement('div'));
14674     document.body.appendChild(ml.dom);
14675     ml.position('absolute');
14676     ml.setLeftTop(-1000, -1000);
14677     ml.hide();
14678
14679     if(fixedWidth){
14680         ml.setWidth(fixedWidth);
14681     }
14682      
14683     var instance = {
14684         /**
14685          * Returns the size of the specified text based on the internal element's style and width properties
14686          * @memberOf Roo.util.TextMetrics.Instance#
14687          * @param {String} text The text to measure
14688          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14689          */
14690         getSize : function(text){
14691             ml.update(text);
14692             var s = ml.getSize();
14693             ml.update('');
14694             return s;
14695         },
14696
14697         /**
14698          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14699          * that can affect the size of the rendered text
14700          * @memberOf Roo.util.TextMetrics.Instance#
14701          * @param {String/HTMLElement} el The element, dom node or id
14702          */
14703         bind : function(el){
14704             ml.setStyle(
14705                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14706             );
14707         },
14708
14709         /**
14710          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14711          * to set a fixed width in order to accurately measure the text height.
14712          * @memberOf Roo.util.TextMetrics.Instance#
14713          * @param {Number} width The width to set on the element
14714          */
14715         setFixedWidth : function(width){
14716             ml.setWidth(width);
14717         },
14718
14719         /**
14720          * Returns the measured width of the specified text
14721          * @memberOf Roo.util.TextMetrics.Instance#
14722          * @param {String} text The text to measure
14723          * @return {Number} width The width in pixels
14724          */
14725         getWidth : function(text){
14726             ml.dom.style.width = 'auto';
14727             return this.getSize(text).width;
14728         },
14729
14730         /**
14731          * Returns the measured height of the specified text.  For multiline text, be sure to call
14732          * {@link #setFixedWidth} if necessary.
14733          * @memberOf Roo.util.TextMetrics.Instance#
14734          * @param {String} text The text to measure
14735          * @return {Number} height The height in pixels
14736          */
14737         getHeight : function(text){
14738             return this.getSize(text).height;
14739         }
14740     };
14741
14742     instance.bind(bindTo);
14743
14744     return instance;
14745 };
14746
14747 // backwards compat
14748 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14749  * Based on:
14750  * Ext JS Library 1.1.1
14751  * Copyright(c) 2006-2007, Ext JS, LLC.
14752  *
14753  * Originally Released Under LGPL - original licence link has changed is not relivant.
14754  *
14755  * Fork - LGPL
14756  * <script type="text/javascript">
14757  */
14758
14759 /**
14760  * @class Roo.state.Provider
14761  * Abstract base class for state provider implementations. This class provides methods
14762  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14763  * Provider interface.
14764  */
14765 Roo.state.Provider = function(){
14766     /**
14767      * @event statechange
14768      * Fires when a state change occurs.
14769      * @param {Provider} this This state provider
14770      * @param {String} key The state key which was changed
14771      * @param {String} value The encoded value for the state
14772      */
14773     this.addEvents({
14774         "statechange": true
14775     });
14776     this.state = {};
14777     Roo.state.Provider.superclass.constructor.call(this);
14778 };
14779 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14780     /**
14781      * Returns the current value for a key
14782      * @param {String} name The key name
14783      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14784      * @return {Mixed} The state data
14785      */
14786     get : function(name, defaultValue){
14787         return typeof this.state[name] == "undefined" ?
14788             defaultValue : this.state[name];
14789     },
14790     
14791     /**
14792      * Clears a value from the state
14793      * @param {String} name The key name
14794      */
14795     clear : function(name){
14796         delete this.state[name];
14797         this.fireEvent("statechange", this, name, null);
14798     },
14799     
14800     /**
14801      * Sets the value for a key
14802      * @param {String} name The key name
14803      * @param {Mixed} value The value to set
14804      */
14805     set : function(name, value){
14806         this.state[name] = value;
14807         this.fireEvent("statechange", this, name, value);
14808     },
14809     
14810     /**
14811      * Decodes a string previously encoded with {@link #encodeValue}.
14812      * @param {String} value The value to decode
14813      * @return {Mixed} The decoded value
14814      */
14815     decodeValue : function(cookie){
14816         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14817         var matches = re.exec(unescape(cookie));
14818         if(!matches || !matches[1]) {
14819             return; // non state cookie
14820         }
14821         var type = matches[1];
14822         var v = matches[2];
14823         switch(type){
14824             case "n":
14825                 return parseFloat(v);
14826             case "d":
14827                 return new Date(Date.parse(v));
14828             case "b":
14829                 return (v == "1");
14830             case "a":
14831                 var all = [];
14832                 var values = v.split("^");
14833                 for(var i = 0, len = values.length; i < len; i++){
14834                     all.push(this.decodeValue(values[i]));
14835                 }
14836                 return all;
14837            case "o":
14838                 var all = {};
14839                 var values = v.split("^");
14840                 for(var i = 0, len = values.length; i < len; i++){
14841                     var kv = values[i].split("=");
14842                     all[kv[0]] = this.decodeValue(kv[1]);
14843                 }
14844                 return all;
14845            default:
14846                 return v;
14847         }
14848     },
14849     
14850     /**
14851      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14852      * @param {Mixed} value The value to encode
14853      * @return {String} The encoded value
14854      */
14855     encodeValue : function(v){
14856         var enc;
14857         if(typeof v == "number"){
14858             enc = "n:" + v;
14859         }else if(typeof v == "boolean"){
14860             enc = "b:" + (v ? "1" : "0");
14861         }else if(v instanceof Date){
14862             enc = "d:" + v.toGMTString();
14863         }else if(v instanceof Array){
14864             var flat = "";
14865             for(var i = 0, len = v.length; i < len; i++){
14866                 flat += this.encodeValue(v[i]);
14867                 if(i != len-1) {
14868                     flat += "^";
14869                 }
14870             }
14871             enc = "a:" + flat;
14872         }else if(typeof v == "object"){
14873             var flat = "";
14874             for(var key in v){
14875                 if(typeof v[key] != "function"){
14876                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14877                 }
14878             }
14879             enc = "o:" + flat.substring(0, flat.length-1);
14880         }else{
14881             enc = "s:" + v;
14882         }
14883         return escape(enc);        
14884     }
14885 });
14886
14887 /*
14888  * Based on:
14889  * Ext JS Library 1.1.1
14890  * Copyright(c) 2006-2007, Ext JS, LLC.
14891  *
14892  * Originally Released Under LGPL - original licence link has changed is not relivant.
14893  *
14894  * Fork - LGPL
14895  * <script type="text/javascript">
14896  */
14897 /**
14898  * @class Roo.state.Manager
14899  * This is the global state manager. By default all components that are "state aware" check this class
14900  * for state information if you don't pass them a custom state provider. In order for this class
14901  * to be useful, it must be initialized with a provider when your application initializes.
14902  <pre><code>
14903 // in your initialization function
14904 init : function(){
14905    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14906    ...
14907    // supposed you have a {@link Roo.BorderLayout}
14908    var layout = new Roo.BorderLayout(...);
14909    layout.restoreState();
14910    // or a {Roo.BasicDialog}
14911    var dialog = new Roo.BasicDialog(...);
14912    dialog.restoreState();
14913  </code></pre>
14914  * @singleton
14915  */
14916 Roo.state.Manager = function(){
14917     var provider = new Roo.state.Provider();
14918     
14919     return {
14920         /**
14921          * Configures the default state provider for your application
14922          * @param {Provider} stateProvider The state provider to set
14923          */
14924         setProvider : function(stateProvider){
14925             provider = stateProvider;
14926         },
14927         
14928         /**
14929          * Returns the current value for a key
14930          * @param {String} name The key name
14931          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14932          * @return {Mixed} The state data
14933          */
14934         get : function(key, defaultValue){
14935             return provider.get(key, defaultValue);
14936         },
14937         
14938         /**
14939          * Sets the value for a key
14940          * @param {String} name The key name
14941          * @param {Mixed} value The state data
14942          */
14943          set : function(key, value){
14944             provider.set(key, value);
14945         },
14946         
14947         /**
14948          * Clears a value from the state
14949          * @param {String} name The key name
14950          */
14951         clear : function(key){
14952             provider.clear(key);
14953         },
14954         
14955         /**
14956          * Gets the currently configured state provider
14957          * @return {Provider} The state provider
14958          */
14959         getProvider : function(){
14960             return provider;
14961         }
14962     };
14963 }();
14964 /*
14965  * Based on:
14966  * Ext JS Library 1.1.1
14967  * Copyright(c) 2006-2007, Ext JS, LLC.
14968  *
14969  * Originally Released Under LGPL - original licence link has changed is not relivant.
14970  *
14971  * Fork - LGPL
14972  * <script type="text/javascript">
14973  */
14974 /**
14975  * @class Roo.state.CookieProvider
14976  * @extends Roo.state.Provider
14977  * The default Provider implementation which saves state via cookies.
14978  * <br />Usage:
14979  <pre><code>
14980    var cp = new Roo.state.CookieProvider({
14981        path: "/cgi-bin/",
14982        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14983        domain: "roojs.com"
14984    })
14985    Roo.state.Manager.setProvider(cp);
14986  </code></pre>
14987  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14988  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14989  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14990  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14991  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14992  * domain the page is running on including the 'www' like 'www.roojs.com')
14993  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14994  * @constructor
14995  * Create a new CookieProvider
14996  * @param {Object} config The configuration object
14997  */
14998 Roo.state.CookieProvider = function(config){
14999     Roo.state.CookieProvider.superclass.constructor.call(this);
15000     this.path = "/";
15001     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15002     this.domain = null;
15003     this.secure = false;
15004     Roo.apply(this, config);
15005     this.state = this.readCookies();
15006 };
15007
15008 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15009     // private
15010     set : function(name, value){
15011         if(typeof value == "undefined" || value === null){
15012             this.clear(name);
15013             return;
15014         }
15015         this.setCookie(name, value);
15016         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15017     },
15018
15019     // private
15020     clear : function(name){
15021         this.clearCookie(name);
15022         Roo.state.CookieProvider.superclass.clear.call(this, name);
15023     },
15024
15025     // private
15026     readCookies : function(){
15027         var cookies = {};
15028         var c = document.cookie + ";";
15029         var re = /\s?(.*?)=(.*?);/g;
15030         var matches;
15031         while((matches = re.exec(c)) != null){
15032             var name = matches[1];
15033             var value = matches[2];
15034             if(name && name.substring(0,3) == "ys-"){
15035                 cookies[name.substr(3)] = this.decodeValue(value);
15036             }
15037         }
15038         return cookies;
15039     },
15040
15041     // private
15042     setCookie : function(name, value){
15043         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15044            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15045            ((this.path == null) ? "" : ("; path=" + this.path)) +
15046            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15047            ((this.secure == true) ? "; secure" : "");
15048     },
15049
15050     // private
15051     clearCookie : function(name){
15052         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15053            ((this.path == null) ? "" : ("; path=" + this.path)) +
15054            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15055            ((this.secure == true) ? "; secure" : "");
15056     }
15057 });/*
15058  * Based on:
15059  * Ext JS Library 1.1.1
15060  * Copyright(c) 2006-2007, Ext JS, LLC.
15061  *
15062  * Originally Released Under LGPL - original licence link has changed is not relivant.
15063  *
15064  * Fork - LGPL
15065  * <script type="text/javascript">
15066  */
15067  
15068
15069 /**
15070  * @class Roo.ComponentMgr
15071  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15072  * @singleton
15073  */
15074 Roo.ComponentMgr = function(){
15075     var all = new Roo.util.MixedCollection();
15076
15077     return {
15078         /**
15079          * Registers a component.
15080          * @param {Roo.Component} c The component
15081          */
15082         register : function(c){
15083             all.add(c);
15084         },
15085
15086         /**
15087          * Unregisters a component.
15088          * @param {Roo.Component} c The component
15089          */
15090         unregister : function(c){
15091             all.remove(c);
15092         },
15093
15094         /**
15095          * Returns a component by id
15096          * @param {String} id The component id
15097          */
15098         get : function(id){
15099             return all.get(id);
15100         },
15101
15102         /**
15103          * Registers a function that will be called when a specified component is added to ComponentMgr
15104          * @param {String} id The component id
15105          * @param {Funtction} fn The callback function
15106          * @param {Object} scope The scope of the callback
15107          */
15108         onAvailable : function(id, fn, scope){
15109             all.on("add", function(index, o){
15110                 if(o.id == id){
15111                     fn.call(scope || o, o);
15112                     all.un("add", fn, scope);
15113                 }
15114             });
15115         }
15116     };
15117 }();/*
15118  * Based on:
15119  * Ext JS Library 1.1.1
15120  * Copyright(c) 2006-2007, Ext JS, LLC.
15121  *
15122  * Originally Released Under LGPL - original licence link has changed is not relivant.
15123  *
15124  * Fork - LGPL
15125  * <script type="text/javascript">
15126  */
15127  
15128 /**
15129  * @class Roo.Component
15130  * @extends Roo.util.Observable
15131  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15132  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15133  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15134  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15135  * All visual components (widgets) that require rendering into a layout should subclass Component.
15136  * @constructor
15137  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15138  * element and its id used as the component id.  If a string is passed, it is assumed to be the id of an existing element
15139  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15140  */
15141 Roo.Component = function(config){
15142     config = config || {};
15143     if(config.tagName || config.dom || typeof config == "string"){ // element object
15144         config = {el: config, id: config.id || config};
15145     }
15146     this.initialConfig = config;
15147
15148     Roo.apply(this, config);
15149     this.addEvents({
15150         /**
15151          * @event disable
15152          * Fires after the component is disabled.
15153              * @param {Roo.Component} this
15154              */
15155         disable : true,
15156         /**
15157          * @event enable
15158          * Fires after the component is enabled.
15159              * @param {Roo.Component} this
15160              */
15161         enable : true,
15162         /**
15163          * @event beforeshow
15164          * Fires before the component is shown.  Return false to stop the show.
15165              * @param {Roo.Component} this
15166              */
15167         beforeshow : true,
15168         /**
15169          * @event show
15170          * Fires after the component is shown.
15171              * @param {Roo.Component} this
15172              */
15173         show : true,
15174         /**
15175          * @event beforehide
15176          * Fires before the component is hidden. Return false to stop the hide.
15177              * @param {Roo.Component} this
15178              */
15179         beforehide : true,
15180         /**
15181          * @event hide
15182          * Fires after the component is hidden.
15183              * @param {Roo.Component} this
15184              */
15185         hide : true,
15186         /**
15187          * @event beforerender
15188          * Fires before the component is rendered. Return false to stop the render.
15189              * @param {Roo.Component} this
15190              */
15191         beforerender : true,
15192         /**
15193          * @event render
15194          * Fires after the component is rendered.
15195              * @param {Roo.Component} this
15196              */
15197         render : true,
15198         /**
15199          * @event beforedestroy
15200          * Fires before the component is destroyed. Return false to stop the destroy.
15201              * @param {Roo.Component} this
15202              */
15203         beforedestroy : true,
15204         /**
15205          * @event destroy
15206          * Fires after the component is destroyed.
15207              * @param {Roo.Component} this
15208              */
15209         destroy : true
15210     });
15211     if(!this.id){
15212         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15213     }
15214     Roo.ComponentMgr.register(this);
15215     Roo.Component.superclass.constructor.call(this);
15216     this.initComponent();
15217     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15218         this.render(this.renderTo);
15219         delete this.renderTo;
15220     }
15221 };
15222
15223 /** @private */
15224 Roo.Component.AUTO_ID = 1000;
15225
15226 Roo.extend(Roo.Component, Roo.util.Observable, {
15227     /**
15228      * @scope Roo.Component.prototype
15229      * @type {Boolean}
15230      * true if this component is hidden. Read-only.
15231      */
15232     hidden : false,
15233     /**
15234      * @type {Boolean}
15235      * true if this component is disabled. Read-only.
15236      */
15237     disabled : false,
15238     /**
15239      * @type {Boolean}
15240      * true if this component has been rendered. Read-only.
15241      */
15242     rendered : false,
15243     
15244     /** @cfg {String} disableClass
15245      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15246      */
15247     disabledClass : "x-item-disabled",
15248         /** @cfg {Boolean} allowDomMove
15249          * Whether the component can move the Dom node when rendering (defaults to true).
15250          */
15251     allowDomMove : true,
15252     /** @cfg {String} hideMode (display|visibility)
15253      * How this component should hidden. Supported values are
15254      * "visibility" (css visibility), "offsets" (negative offset position) and
15255      * "display" (css display) - defaults to "display".
15256      */
15257     hideMode: 'display',
15258
15259     /** @private */
15260     ctype : "Roo.Component",
15261
15262     /**
15263      * @cfg {String} actionMode 
15264      * which property holds the element that used for  hide() / show() / disable() / enable()
15265      * default is 'el' 
15266      */
15267     actionMode : "el",
15268
15269     /** @private */
15270     getActionEl : function(){
15271         return this[this.actionMode];
15272     },
15273
15274     initComponent : Roo.emptyFn,
15275     /**
15276      * If this is a lazy rendering component, render it to its container element.
15277      * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15278      */
15279     render : function(container, position){
15280         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15281             if(!container && this.el){
15282                 this.el = Roo.get(this.el);
15283                 container = this.el.dom.parentNode;
15284                 this.allowDomMove = false;
15285             }
15286             this.container = Roo.get(container);
15287             this.rendered = true;
15288             if(position !== undefined){
15289                 if(typeof position == 'number'){
15290                     position = this.container.dom.childNodes[position];
15291                 }else{
15292                     position = Roo.getDom(position);
15293                 }
15294             }
15295             this.onRender(this.container, position || null);
15296             if(this.cls){
15297                 this.el.addClass(this.cls);
15298                 delete this.cls;
15299             }
15300             if(this.style){
15301                 this.el.applyStyles(this.style);
15302                 delete this.style;
15303             }
15304             this.fireEvent("render", this);
15305             this.afterRender(this.container);
15306             if(this.hidden){
15307                 this.hide();
15308             }
15309             if(this.disabled){
15310                 this.disable();
15311             }
15312         }
15313         return this;
15314     },
15315
15316     /** @private */
15317     // default function is not really useful
15318     onRender : function(ct, position){
15319         if(this.el){
15320             this.el = Roo.get(this.el);
15321             if(this.allowDomMove !== false){
15322                 ct.dom.insertBefore(this.el.dom, position);
15323             }
15324         }
15325     },
15326
15327     /** @private */
15328     getAutoCreate : function(){
15329         var cfg = typeof this.autoCreate == "object" ?
15330                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15331         if(this.id && !cfg.id){
15332             cfg.id = this.id;
15333         }
15334         return cfg;
15335     },
15336
15337     /** @private */
15338     afterRender : Roo.emptyFn,
15339
15340     /**
15341      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15342      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15343      */
15344     destroy : function(){
15345         if(this.fireEvent("beforedestroy", this) !== false){
15346             this.purgeListeners();
15347             this.beforeDestroy();
15348             if(this.rendered){
15349                 this.el.removeAllListeners();
15350                 this.el.remove();
15351                 if(this.actionMode == "container"){
15352                     this.container.remove();
15353                 }
15354             }
15355             this.onDestroy();
15356             Roo.ComponentMgr.unregister(this);
15357             this.fireEvent("destroy", this);
15358         }
15359     },
15360
15361         /** @private */
15362     beforeDestroy : function(){
15363
15364     },
15365
15366         /** @private */
15367         onDestroy : function(){
15368
15369     },
15370
15371     /**
15372      * Returns the underlying {@link Roo.Element}.
15373      * @return {Roo.Element} The element
15374      */
15375     getEl : function(){
15376         return this.el;
15377     },
15378
15379     /**
15380      * Returns the id of this component.
15381      * @return {String}
15382      */
15383     getId : function(){
15384         return this.id;
15385     },
15386
15387     /**
15388      * Try to focus this component.
15389      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15390      * @return {Roo.Component} this
15391      */
15392     focus : function(selectText){
15393         if(this.rendered){
15394             this.el.focus();
15395             if(selectText === true){
15396                 this.el.dom.select();
15397             }
15398         }
15399         return this;
15400     },
15401
15402     /** @private */
15403     blur : function(){
15404         if(this.rendered){
15405             this.el.blur();
15406         }
15407         return this;
15408     },
15409
15410     /**
15411      * Disable this component.
15412      * @return {Roo.Component} this
15413      */
15414     disable : function(){
15415         if(this.rendered){
15416             this.onDisable();
15417         }
15418         this.disabled = true;
15419         this.fireEvent("disable", this);
15420         return this;
15421     },
15422
15423         // private
15424     onDisable : function(){
15425         this.getActionEl().addClass(this.disabledClass);
15426         this.el.dom.disabled = true;
15427     },
15428
15429     /**
15430      * Enable this component.
15431      * @return {Roo.Component} this
15432      */
15433     enable : function(){
15434         if(this.rendered){
15435             this.onEnable();
15436         }
15437         this.disabled = false;
15438         this.fireEvent("enable", this);
15439         return this;
15440     },
15441
15442         // private
15443     onEnable : function(){
15444         this.getActionEl().removeClass(this.disabledClass);
15445         this.el.dom.disabled = false;
15446     },
15447
15448     /**
15449      * Convenience function for setting disabled/enabled by boolean.
15450      * @param {Boolean} disabled
15451      */
15452     setDisabled : function(disabled){
15453         this[disabled ? "disable" : "enable"]();
15454     },
15455
15456     /**
15457      * Show this component.
15458      * @return {Roo.Component} this
15459      */
15460     show: function(){
15461         if(this.fireEvent("beforeshow", this) !== false){
15462             this.hidden = false;
15463             if(this.rendered){
15464                 this.onShow();
15465             }
15466             this.fireEvent("show", this);
15467         }
15468         return this;
15469     },
15470
15471     // private
15472     onShow : function(){
15473         var ae = this.getActionEl();
15474         if(this.hideMode == 'visibility'){
15475             ae.dom.style.visibility = "visible";
15476         }else if(this.hideMode == 'offsets'){
15477             ae.removeClass('x-hidden');
15478         }else{
15479             ae.dom.style.display = "";
15480         }
15481     },
15482
15483     /**
15484      * Hide this component.
15485      * @return {Roo.Component} this
15486      */
15487     hide: function(){
15488         if(this.fireEvent("beforehide", this) !== false){
15489             this.hidden = true;
15490             if(this.rendered){
15491                 this.onHide();
15492             }
15493             this.fireEvent("hide", this);
15494         }
15495         return this;
15496     },
15497
15498     // private
15499     onHide : function(){
15500         var ae = this.getActionEl();
15501         if(this.hideMode == 'visibility'){
15502             ae.dom.style.visibility = "hidden";
15503         }else if(this.hideMode == 'offsets'){
15504             ae.addClass('x-hidden');
15505         }else{
15506             ae.dom.style.display = "none";
15507         }
15508     },
15509
15510     /**
15511      * Convenience function to hide or show this component by boolean.
15512      * @param {Boolean} visible True to show, false to hide
15513      * @return {Roo.Component} this
15514      */
15515     setVisible: function(visible){
15516         if(visible) {
15517             this.show();
15518         }else{
15519             this.hide();
15520         }
15521         return this;
15522     },
15523
15524     /**
15525      * Returns true if this component is visible.
15526      */
15527     isVisible : function(){
15528         return this.getActionEl().isVisible();
15529     },
15530
15531     cloneConfig : function(overrides){
15532         overrides = overrides || {};
15533         var id = overrides.id || Roo.id();
15534         var cfg = Roo.applyIf(overrides, this.initialConfig);
15535         cfg.id = id; // prevent dup id
15536         return new this.constructor(cfg);
15537     }
15538 });/*
15539  * Based on:
15540  * Ext JS Library 1.1.1
15541  * Copyright(c) 2006-2007, Ext JS, LLC.
15542  *
15543  * Originally Released Under LGPL - original licence link has changed is not relivant.
15544  *
15545  * Fork - LGPL
15546  * <script type="text/javascript">
15547  */
15548
15549 /**
15550  * @class Roo.BoxComponent
15551  * @extends Roo.Component
15552  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15553  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15554  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15555  * layout containers.
15556  * @constructor
15557  * @param {Roo.Element/String/Object} config The configuration options.
15558  */
15559 Roo.BoxComponent = function(config){
15560     Roo.Component.call(this, config);
15561     this.addEvents({
15562         /**
15563          * @event resize
15564          * Fires after the component is resized.
15565              * @param {Roo.Component} this
15566              * @param {Number} adjWidth The box-adjusted width that was set
15567              * @param {Number} adjHeight The box-adjusted height that was set
15568              * @param {Number} rawWidth The width that was originally specified
15569              * @param {Number} rawHeight The height that was originally specified
15570              */
15571         resize : true,
15572         /**
15573          * @event move
15574          * Fires after the component is moved.
15575              * @param {Roo.Component} this
15576              * @param {Number} x The new x position
15577              * @param {Number} y The new y position
15578              */
15579         move : true
15580     });
15581 };
15582
15583 Roo.extend(Roo.BoxComponent, Roo.Component, {
15584     // private, set in afterRender to signify that the component has been rendered
15585     boxReady : false,
15586     // private, used to defer height settings to subclasses
15587     deferHeight: false,
15588     /** @cfg {Number} width
15589      * width (optional) size of component
15590      */
15591      /** @cfg {Number} height
15592      * height (optional) size of component
15593      */
15594      
15595     /**
15596      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15597      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15598      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15599      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15600      * @return {Roo.BoxComponent} this
15601      */
15602     setSize : function(w, h){
15603         // support for standard size objects
15604         if(typeof w == 'object'){
15605             h = w.height;
15606             w = w.width;
15607         }
15608         // not rendered
15609         if(!this.boxReady){
15610             this.width = w;
15611             this.height = h;
15612             return this;
15613         }
15614
15615         // prevent recalcs when not needed
15616         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15617             return this;
15618         }
15619         this.lastSize = {width: w, height: h};
15620
15621         var adj = this.adjustSize(w, h);
15622         var aw = adj.width, ah = adj.height;
15623         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15624             var rz = this.getResizeEl();
15625             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15626                 rz.setSize(aw, ah);
15627             }else if(!this.deferHeight && ah !== undefined){
15628                 rz.setHeight(ah);
15629             }else if(aw !== undefined){
15630                 rz.setWidth(aw);
15631             }
15632             this.onResize(aw, ah, w, h);
15633             this.fireEvent('resize', this, aw, ah, w, h);
15634         }
15635         return this;
15636     },
15637
15638     /**
15639      * Gets the current size of the component's underlying element.
15640      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15641      */
15642     getSize : function(){
15643         return this.el.getSize();
15644     },
15645
15646     /**
15647      * Gets the current XY position of the component's underlying element.
15648      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15649      * @return {Array} The XY position of the element (e.g., [100, 200])
15650      */
15651     getPosition : function(local){
15652         if(local === true){
15653             return [this.el.getLeft(true), this.el.getTop(true)];
15654         }
15655         return this.xy || this.el.getXY();
15656     },
15657
15658     /**
15659      * Gets the current box measurements of the component's underlying element.
15660      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15661      * @returns {Object} box An object in the format {x, y, width, height}
15662      */
15663     getBox : function(local){
15664         var s = this.el.getSize();
15665         if(local){
15666             s.x = this.el.getLeft(true);
15667             s.y = this.el.getTop(true);
15668         }else{
15669             var xy = this.xy || this.el.getXY();
15670             s.x = xy[0];
15671             s.y = xy[1];
15672         }
15673         return s;
15674     },
15675
15676     /**
15677      * Sets the current box measurements of the component's underlying element.
15678      * @param {Object} box An object in the format {x, y, width, height}
15679      * @returns {Roo.BoxComponent} this
15680      */
15681     updateBox : function(box){
15682         this.setSize(box.width, box.height);
15683         this.setPagePosition(box.x, box.y);
15684         return this;
15685     },
15686
15687     // protected
15688     getResizeEl : function(){
15689         return this.resizeEl || this.el;
15690     },
15691
15692     // protected
15693     getPositionEl : function(){
15694         return this.positionEl || this.el;
15695     },
15696
15697     /**
15698      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15699      * This method fires the move event.
15700      * @param {Number} left The new left
15701      * @param {Number} top The new top
15702      * @returns {Roo.BoxComponent} this
15703      */
15704     setPosition : function(x, y){
15705         this.x = x;
15706         this.y = y;
15707         if(!this.boxReady){
15708             return this;
15709         }
15710         var adj = this.adjustPosition(x, y);
15711         var ax = adj.x, ay = adj.y;
15712
15713         var el = this.getPositionEl();
15714         if(ax !== undefined || ay !== undefined){
15715             if(ax !== undefined && ay !== undefined){
15716                 el.setLeftTop(ax, ay);
15717             }else if(ax !== undefined){
15718                 el.setLeft(ax);
15719             }else if(ay !== undefined){
15720                 el.setTop(ay);
15721             }
15722             this.onPosition(ax, ay);
15723             this.fireEvent('move', this, ax, ay);
15724         }
15725         return this;
15726     },
15727
15728     /**
15729      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15730      * This method fires the move event.
15731      * @param {Number} x The new x position
15732      * @param {Number} y The new y position
15733      * @returns {Roo.BoxComponent} this
15734      */
15735     setPagePosition : function(x, y){
15736         this.pageX = x;
15737         this.pageY = y;
15738         if(!this.boxReady){
15739             return;
15740         }
15741         if(x === undefined || y === undefined){ // cannot translate undefined points
15742             return;
15743         }
15744         var p = this.el.translatePoints(x, y);
15745         this.setPosition(p.left, p.top);
15746         return this;
15747     },
15748
15749     // private
15750     onRender : function(ct, position){
15751         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15752         if(this.resizeEl){
15753             this.resizeEl = Roo.get(this.resizeEl);
15754         }
15755         if(this.positionEl){
15756             this.positionEl = Roo.get(this.positionEl);
15757         }
15758     },
15759
15760     // private
15761     afterRender : function(){
15762         Roo.BoxComponent.superclass.afterRender.call(this);
15763         this.boxReady = true;
15764         this.setSize(this.width, this.height);
15765         if(this.x || this.y){
15766             this.setPosition(this.x, this.y);
15767         }
15768         if(this.pageX || this.pageY){
15769             this.setPagePosition(this.pageX, this.pageY);
15770         }
15771     },
15772
15773     /**
15774      * Force the component's size to recalculate based on the underlying element's current height and width.
15775      * @returns {Roo.BoxComponent} this
15776      */
15777     syncSize : function(){
15778         delete this.lastSize;
15779         this.setSize(this.el.getWidth(), this.el.getHeight());
15780         return this;
15781     },
15782
15783     /**
15784      * Called after the component is resized, this method is empty by default but can be implemented by any
15785      * subclass that needs to perform custom logic after a resize occurs.
15786      * @param {Number} adjWidth The box-adjusted width that was set
15787      * @param {Number} adjHeight The box-adjusted height that was set
15788      * @param {Number} rawWidth The width that was originally specified
15789      * @param {Number} rawHeight The height that was originally specified
15790      */
15791     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15792
15793     },
15794
15795     /**
15796      * Called after the component is moved, this method is empty by default but can be implemented by any
15797      * subclass that needs to perform custom logic after a move occurs.
15798      * @param {Number} x The new x position
15799      * @param {Number} y The new y position
15800      */
15801     onPosition : function(x, y){
15802
15803     },
15804
15805     // private
15806     adjustSize : function(w, h){
15807         if(this.autoWidth){
15808             w = 'auto';
15809         }
15810         if(this.autoHeight){
15811             h = 'auto';
15812         }
15813         return {width : w, height: h};
15814     },
15815
15816     // private
15817     adjustPosition : function(x, y){
15818         return {x : x, y: y};
15819     }
15820 });/*
15821  * Original code for Roojs - LGPL
15822  * <script type="text/javascript">
15823  */
15824  
15825 /**
15826  * @class Roo.XComponent
15827  * A delayed Element creator...
15828  * Or a way to group chunks of interface together.
15829  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15830  *  used in conjunction with XComponent.build() it will create an instance of each element,
15831  *  then call addxtype() to build the User interface.
15832  * 
15833  * Mypart.xyx = new Roo.XComponent({
15834
15835     parent : 'Mypart.xyz', // empty == document.element.!!
15836     order : '001',
15837     name : 'xxxx'
15838     region : 'xxxx'
15839     disabled : function() {} 
15840      
15841     tree : function() { // return an tree of xtype declared components
15842         var MODULE = this;
15843         return 
15844         {
15845             xtype : 'NestedLayoutPanel',
15846             // technicall
15847         }
15848      ]
15849  *})
15850  *
15851  *
15852  * It can be used to build a big heiracy, with parent etc.
15853  * or you can just use this to render a single compoent to a dom element
15854  * MYPART.render(Roo.Element | String(id) | dom_element )
15855  *
15856  *
15857  * Usage patterns.
15858  *
15859  * Classic Roo
15860  *
15861  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15862  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15863  *
15864  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15865  *
15866  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15867  * - if mulitple topModules exist, the last one is defined as the top module.
15868  *
15869  * Embeded Roo
15870  * 
15871  * When the top level or multiple modules are to embedded into a existing HTML page,
15872  * the parent element can container '#id' of the element where the module will be drawn.
15873  *
15874  * Bootstrap Roo
15875  *
15876  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15877  * it relies more on a include mechanism, where sub modules are included into an outer page.
15878  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15879  * 
15880  * Bootstrap Roo Included elements
15881  *
15882  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15883  * hence confusing the component builder as it thinks there are multiple top level elements. 
15884  *
15885  * 
15886  * 
15887  * @extends Roo.util.Observable
15888  * @constructor
15889  * @param cfg {Object} configuration of component
15890  * 
15891  */
15892 Roo.XComponent = function(cfg) {
15893     Roo.apply(this, cfg);
15894     this.addEvents({ 
15895         /**
15896              * @event built
15897              * Fires when this the componnt is built
15898              * @param {Roo.XComponent} c the component
15899              */
15900         'built' : true
15901         
15902     });
15903     this.region = this.region || 'center'; // default..
15904     Roo.XComponent.register(this);
15905     this.modules = false;
15906     this.el = false; // where the layout goes..
15907     
15908     
15909 }
15910 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15911     /**
15912      * @property el
15913      * The created element (with Roo.factory())
15914      * @type {Roo.Layout}
15915      */
15916     el  : false,
15917     
15918     /**
15919      * @property el
15920      * for BC  - use el in new code
15921      * @type {Roo.Layout}
15922      */
15923     panel : false,
15924     
15925     /**
15926      * @property layout
15927      * for BC  - use el in new code
15928      * @type {Roo.Layout}
15929      */
15930     layout : false,
15931     
15932      /**
15933      * @cfg {Function|boolean} disabled
15934      * If this module is disabled by some rule, return true from the funtion
15935      */
15936     disabled : false,
15937     
15938     /**
15939      * @cfg {String} parent 
15940      * Name of parent element which it get xtype added to..
15941      */
15942     parent: false,
15943     
15944     /**
15945      * @cfg {String} order
15946      * Used to set the order in which elements are created (usefull for multiple tabs)
15947      */
15948     
15949     order : false,
15950     /**
15951      * @cfg {String} name
15952      * String to display while loading.
15953      */
15954     name : false,
15955     /**
15956      * @cfg {String} region
15957      * Region to render component to (defaults to center)
15958      */
15959     region : 'center',
15960     
15961     /**
15962      * @cfg {Array} items
15963      * A single item array - the first element is the root of the tree..
15964      * It's done this way to stay compatible with the Xtype system...
15965      */
15966     items : false,
15967     
15968     /**
15969      * @property _tree
15970      * The method that retuns the tree of parts that make up this compoennt 
15971      * @type {function}
15972      */
15973     _tree  : false,
15974     
15975      /**
15976      * render
15977      * render element to dom or tree
15978      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15979      */
15980     
15981     render : function(el)
15982     {
15983         
15984         el = el || false;
15985         var hp = this.parent ? 1 : 0;
15986         Roo.debug &&  Roo.log(this);
15987         
15988         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15989             // if parent is a '#.....' string, then let's use that..
15990             var ename = this.parent.substr(1);
15991             this.parent = false;
15992             Roo.debug && Roo.log(ename);
15993             switch (ename) {
15994                 case 'bootstrap-body' :
15995                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
15996                         this.parent = { el :  new  Roo.bootstrap.Body() };
15997                         Roo.debug && Roo.log("setting el to doc body");
15998                          
15999                     } else {
16000                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16001                     }
16002                     break;
16003                 case 'bootstrap':
16004                     this.parent = { el : true};
16005                     // fall through
16006                 default:
16007                     el = Roo.get(ename);
16008                     break;
16009             }
16010                 
16011             
16012             if (!el && !this.parent) {
16013                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16014                 return;
16015             }
16016         }
16017         Roo.debug && Roo.log("EL:");
16018         Roo.debug && Roo.log(el);
16019         Roo.debug && Roo.log("this.parent.el:");
16020         Roo.debug && Roo.log(this.parent.el);
16021         
16022         var tree = this._tree ? this._tree() : this.tree();
16023
16024         // altertive root elements ??? - we need a better way to indicate these.
16025         var is_alt = Roo.XComponent.is_alt || (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16026                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16027         
16028         if (!this.parent && is_alt) {
16029             //el = Roo.get(document.body);
16030             this.parent = { el : true };
16031         }
16032             
16033             
16034         
16035         if (!this.parent) {
16036             
16037             Roo.debug && Roo.log("no parent - creating one");
16038             
16039             el = el ? Roo.get(el) : false;      
16040             
16041             // it's a top level one..
16042             this.parent =  {
16043                 el : new Roo.BorderLayout(el || document.body, {
16044                 
16045                      center: {
16046                          titlebar: false,
16047                          autoScroll:false,
16048                          closeOnTab: true,
16049                          tabPosition: 'top',
16050                           //resizeTabs: true,
16051                          alwaysShowTabs: el && hp? false :  true,
16052                          hideTabs: el || !hp ? true :  false,
16053                          minTabWidth: 140
16054                      }
16055                  })
16056             };
16057         }
16058         
16059         if (!this.parent.el) {
16060                 // probably an old style ctor, which has been disabled.
16061                 return;
16062
16063         }
16064                 // The 'tree' method is  '_tree now' 
16065             
16066         tree.region = tree.region || this.region;
16067         var is_body = false;
16068         if (this.parent.el === true) {
16069             // bootstrap... - body..
16070             this.parent.el = Roo.factory(tree);
16071             is_body = true;
16072         }
16073         
16074         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16075         this.fireEvent('built', this);
16076         
16077         this.panel = this.el;
16078         this.layout = this.panel.layout;
16079         this.parentLayout = this.parent.layout  || false;  
16080          
16081     }
16082     
16083 });
16084
16085 Roo.apply(Roo.XComponent, {
16086     /**
16087      * @property  hideProgress
16088      * true to disable the building progress bar.. usefull on single page renders.
16089      * @type Boolean
16090      */
16091     hideProgress : false,
16092     /**
16093      * @property  buildCompleted
16094      * True when the builder has completed building the interface.
16095      * @type Boolean
16096      */
16097     buildCompleted : false,
16098      
16099     /**
16100      * @property  topModule
16101      * the upper most module - uses document.element as it's constructor.
16102      * @type Object
16103      */
16104      
16105     topModule  : false,
16106       
16107     /**
16108      * @property  modules
16109      * array of modules to be created by registration system.
16110      * @type {Array} of Roo.XComponent
16111      */
16112     
16113     modules : [],
16114     /**
16115      * @property  elmodules
16116      * array of modules to be created by which use #ID 
16117      * @type {Array} of Roo.XComponent
16118      */
16119      
16120     elmodules : [],
16121
16122      /**
16123      * @property  is_alt
16124      * Is an alternative Root - normally used by bootstrap or other systems,
16125      *    where the top element in the tree can wrap 'body' 
16126      * @type {boolean} true  (default false)
16127      */
16128      
16129     is_alt : false,
16130     /**
16131      * @property  build_from_html
16132      * Build elements from html - used by bootstrap HTML stuff 
16133      *    - this is cleared after build is completed
16134      * @type {boolean} true  (default false)
16135      */
16136      
16137     build_from_html : false,
16138     /**
16139      * Register components to be built later.
16140      *
16141      * This solves the following issues
16142      * - Building is not done on page load, but after an authentication process has occured.
16143      * - Interface elements are registered on page load
16144      * - Parent Interface elements may not be loaded before child, so this handles that..
16145      * 
16146      *
16147      * example:
16148      * 
16149      * MyApp.register({
16150           order : '000001',
16151           module : 'Pman.Tab.projectMgr',
16152           region : 'center',
16153           parent : 'Pman.layout',
16154           disabled : false,  // or use a function..
16155         })
16156      
16157      * * @param {Object} details about module
16158      */
16159     register : function(obj) {
16160                 
16161         Roo.XComponent.event.fireEvent('register', obj);
16162         switch(typeof(obj.disabled) ) {
16163                 
16164             case 'undefined':
16165                 break;
16166             
16167             case 'function':
16168                 if ( obj.disabled() ) {
16169                         return;
16170                 }
16171                 break;
16172             
16173             default:
16174                 if (obj.disabled) {
16175                         return;
16176                 }
16177                 break;
16178         }
16179                 
16180         this.modules.push(obj);
16181          
16182     },
16183     /**
16184      * convert a string to an object..
16185      * eg. 'AAA.BBB' -> finds AAA.BBB
16186
16187      */
16188     
16189     toObject : function(str)
16190     {
16191         if (!str || typeof(str) == 'object') {
16192             return str;
16193         }
16194         if (str.substring(0,1) == '#') {
16195             return str;
16196         }
16197
16198         var ar = str.split('.');
16199         var rt, o;
16200         rt = ar.shift();
16201             /** eval:var:o */
16202         try {
16203             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16204         } catch (e) {
16205             throw "Module not found : " + str;
16206         }
16207         
16208         if (o === false) {
16209             throw "Module not found : " + str;
16210         }
16211         Roo.each(ar, function(e) {
16212             if (typeof(o[e]) == 'undefined') {
16213                 throw "Module not found : " + str;
16214             }
16215             o = o[e];
16216         });
16217         
16218         return o;
16219         
16220     },
16221     
16222     
16223     /**
16224      * move modules into their correct place in the tree..
16225      * 
16226      */
16227     preBuild : function ()
16228     {
16229         var _t = this;
16230         Roo.each(this.modules , function (obj)
16231         {
16232             Roo.XComponent.event.fireEvent('beforebuild', obj);
16233             
16234             var opar = obj.parent;
16235             try { 
16236                 obj.parent = this.toObject(opar);
16237             } catch(e) {
16238                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16239                 return;
16240             }
16241             
16242             if (!obj.parent) {
16243                 Roo.debug && Roo.log("GOT top level module");
16244                 Roo.debug && Roo.log(obj);
16245                 obj.modules = new Roo.util.MixedCollection(false, 
16246                     function(o) { return o.order + '' }
16247                 );
16248                 this.topModule = obj;
16249                 return;
16250             }
16251                         // parent is a string (usually a dom element name..)
16252             if (typeof(obj.parent) == 'string') {
16253                 this.elmodules.push(obj);
16254                 return;
16255             }
16256             if (obj.parent.constructor != Roo.XComponent) {
16257                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16258             }
16259             if (!obj.parent.modules) {
16260                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16261                     function(o) { return o.order + '' }
16262                 );
16263             }
16264             if (obj.parent.disabled) {
16265                 obj.disabled = true;
16266             }
16267             obj.parent.modules.add(obj);
16268         }, this);
16269     },
16270     
16271      /**
16272      * make a list of modules to build.
16273      * @return {Array} list of modules. 
16274      */ 
16275     
16276     buildOrder : function()
16277     {
16278         var _this = this;
16279         var cmp = function(a,b) {   
16280             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16281         };
16282         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16283             throw "No top level modules to build";
16284         }
16285         
16286         // make a flat list in order of modules to build.
16287         var mods = this.topModule ? [ this.topModule ] : [];
16288                 
16289         
16290         // elmodules (is a list of DOM based modules )
16291         Roo.each(this.elmodules, function(e) {
16292             mods.push(e);
16293             if (!this.topModule &&
16294                 typeof(e.parent) == 'string' &&
16295                 e.parent.substring(0,1) == '#' &&
16296                 Roo.get(e.parent.substr(1))
16297                ) {
16298                 
16299                 _this.topModule = e;
16300             }
16301             
16302         });
16303
16304         
16305         // add modules to their parents..
16306         var addMod = function(m) {
16307             Roo.debug && Roo.log("build Order: add: " + m.name);
16308                 
16309             mods.push(m);
16310             if (m.modules && !m.disabled) {
16311                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16312                 m.modules.keySort('ASC',  cmp );
16313                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16314     
16315                 m.modules.each(addMod);
16316             } else {
16317                 Roo.debug && Roo.log("build Order: no child modules");
16318             }
16319             // not sure if this is used any more..
16320             if (m.finalize) {
16321                 m.finalize.name = m.name + " (clean up) ";
16322                 mods.push(m.finalize);
16323             }
16324             
16325         }
16326         if (this.topModule && this.topModule.modules) { 
16327             this.topModule.modules.keySort('ASC',  cmp );
16328             this.topModule.modules.each(addMod);
16329         } 
16330         return mods;
16331     },
16332     
16333      /**
16334      * Build the registered modules.
16335      * @param {Object} parent element.
16336      * @param {Function} optional method to call after module has been added.
16337      * 
16338      */ 
16339    
16340     build : function(opts) 
16341     {
16342         
16343         if (typeof(opts) != 'undefined') {
16344             Roo.apply(this,opts);
16345         }
16346         
16347         this.preBuild();
16348         var mods = this.buildOrder();
16349       
16350         //this.allmods = mods;
16351         //Roo.debug && Roo.log(mods);
16352         //return;
16353         if (!mods.length) { // should not happen
16354             throw "NO modules!!!";
16355         }
16356         
16357         
16358         var msg = "Building Interface...";
16359         // flash it up as modal - so we store the mask!?
16360         if (!this.hideProgress && Roo.MessageBox) {
16361             Roo.MessageBox.show({ title: 'loading' });
16362             Roo.MessageBox.show({
16363                title: "Please wait...",
16364                msg: msg,
16365                width:450,
16366                progress:true,
16367                closable:false,
16368                modal: false
16369               
16370             });
16371         }
16372         var total = mods.length;
16373         
16374         var _this = this;
16375         var progressRun = function() {
16376             if (!mods.length) {
16377                 Roo.debug && Roo.log('hide?');
16378                 if (!this.hideProgress && Roo.MessageBox) {
16379                     Roo.MessageBox.hide();
16380                 }
16381                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16382                 
16383                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16384                 
16385                 // THE END...
16386                 return false;   
16387             }
16388             
16389             var m = mods.shift();
16390             
16391             
16392             Roo.debug && Roo.log(m);
16393             // not sure if this is supported any more.. - modules that are are just function
16394             if (typeof(m) == 'function') { 
16395                 m.call(this);
16396                 return progressRun.defer(10, _this);
16397             } 
16398             
16399             
16400             msg = "Building Interface " + (total  - mods.length) + 
16401                     " of " + total + 
16402                     (m.name ? (' - ' + m.name) : '');
16403                         Roo.debug && Roo.log(msg);
16404             if (!this.hideProgress &&  Roo.MessageBox) { 
16405                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16406             }
16407             
16408          
16409             // is the module disabled?
16410             var disabled = (typeof(m.disabled) == 'function') ?
16411                 m.disabled.call(m.module.disabled) : m.disabled;    
16412             
16413             
16414             if (disabled) {
16415                 return progressRun(); // we do not update the display!
16416             }
16417             
16418             // now build 
16419             
16420                         
16421                         
16422             m.render();
16423             // it's 10 on top level, and 1 on others??? why...
16424             return progressRun.defer(10, _this);
16425              
16426         }
16427         progressRun.defer(1, _this);
16428      
16429         
16430         
16431     },
16432         
16433         
16434         /**
16435          * Event Object.
16436          *
16437          *
16438          */
16439         event: false, 
16440     /**
16441          * wrapper for event.on - aliased later..  
16442          * Typically use to register a event handler for register:
16443          *
16444          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16445          *
16446          */
16447     on : false
16448    
16449     
16450     
16451 });
16452
16453 Roo.XComponent.event = new Roo.util.Observable({
16454                 events : { 
16455                         /**
16456                          * @event register
16457                          * Fires when an Component is registered,
16458                          * set the disable property on the Component to stop registration.
16459                          * @param {Roo.XComponent} c the component being registerd.
16460                          * 
16461                          */
16462                         'register' : true,
16463             /**
16464                          * @event beforebuild
16465                          * Fires before each Component is built
16466                          * can be used to apply permissions.
16467                          * @param {Roo.XComponent} c the component being registerd.
16468                          * 
16469                          */
16470                         'beforebuild' : true,
16471                         /**
16472                          * @event buildcomplete
16473                          * Fires on the top level element when all elements have been built
16474                          * @param {Roo.XComponent} the top level component.
16475                          */
16476                         'buildcomplete' : true
16477                         
16478                 }
16479 });
16480
16481 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16482