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         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
64
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71     
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * Turn on debugging output (currently only the factory uses this)
90          * @type Boolean
91          */
92         
93         debug: false,
94
95         /**
96          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
97          * @type Boolean
98          */
99         enableGarbageCollector : true,
100
101         /**
102          * True to automatically purge event listeners after uncaching an element (defaults to false).
103          * Note: this only happens if enableGarbageCollector is true.
104          * @type Boolean
105          */
106         enableListenerCollection:false,
107
108         /**
109          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110          * the IE insecure content warning (defaults to javascript:false).
111          * @type String
112          */
113         SSL_SECURE_URL : "javascript:false",
114
115         /**
116          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
118          * @type String
119          */
120         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
121
122         emptyFn : function(){},
123         
124         /**
125          *  Clone the object
126          *
127          *
128          */
129         clone : function(obj){
130             if (obj === null || typeof obj !== 'object') {
131                 return obj;
132             }
133
134             var temp = obj.constructor(); // give temp the original obj's constructor
135             for (var key in obj) {
136                 temp[key] = Roo.clone(obj[key]);
137             }
138
139             return temp;
140         },
141         
142         /**
143          * Copies all the properties of config to obj if they don't already exist.
144          * @param {Object} obj The receiver of the properties
145          * @param {Object} config The source of the properties
146          * @return {Object} returns obj
147          */
148         applyIf : function(o, c){
149             if(o && c){
150                 for(var p in c){
151                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
152                 }
153             }
154             return o;
155         },
156
157         /**
158          * Applies event listeners to elements by selectors when the document is ready.
159          * The event name is specified with an @ suffix.
160 <pre><code>
161 Roo.addBehaviors({
162    // add a listener for click on all anchors in element with id foo
163    '#foo a@click' : function(e, t){
164        // do something
165    },
166
167    // add the same listener to multiple selectors (separated by comma BEFORE the @)
168    '#foo a, #bar span.some-class@mouseover' : function(){
169        // do something
170    }
171 });
172 </code></pre>
173          * @param {Object} obj The list of behaviors to apply
174          */
175         addBehaviors : function(o){
176             if(!Roo.isReady){
177                 Roo.onReady(function(){
178                     Roo.addBehaviors(o);
179                 });
180                 return;
181             }
182             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
183             for(var b in o){
184                 var parts = b.split('@');
185                 if(parts[1]){ // for Object prototype breakers
186                     var s = parts[0];
187                     if(!cache[s]){
188                         cache[s] = Roo.select(s);
189                     }
190                     cache[s].on(parts[1], o[b]);
191                 }
192             }
193             cache = null;
194         },
195
196         /**
197          * Generates unique ids. If the element already has an id, it is unchanged
198          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
199          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
200          * @return {String} The generated Id.
201          */
202         id : function(el, prefix){
203             prefix = prefix || "roo-gen";
204             el = Roo.getDom(el);
205             var id = prefix + (++idSeed);
206             return el ? (el.id ? el.id : (el.id = id)) : id;
207         },
208          
209        
210         /**
211          * Extends one class with another class and optionally overrides members with the passed literal. This class
212          * also adds the function "override()" to the class that can be used to override
213          * members on an instance.
214          * @param {Object} subclass The class inheriting the functionality
215          * @param {Object} superclass The class being extended
216          * @param {Object} overrides (optional) A literal with members
217          * @method extend
218          */
219         extend : function(){
220             // inline overrides
221             var io = function(o){
222                 for(var m in o){
223                     this[m] = o[m];
224                 }
225             };
226             return function(sb, sp, overrides){
227                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
228                     overrides = sp;
229                     sp = sb;
230                     sb = function(){sp.apply(this, arguments);};
231                 }
232                 var F = function(){}, sbp, spp = sp.prototype;
233                 F.prototype = spp;
234                 sbp = sb.prototype = new F();
235                 sbp.constructor=sb;
236                 sb.superclass=spp;
237                 
238                 if(spp.constructor == Object.prototype.constructor){
239                     spp.constructor=sp;
240                    
241                 }
242                 
243                 sb.override = function(o){
244                     Roo.override(sb, o);
245                 };
246                 sbp.override = io;
247                 Roo.override(sb, overrides);
248                 return sb;
249             };
250         }(),
251
252         /**
253          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
254          * Usage:<pre><code>
255 Roo.override(MyClass, {
256     newMethod1: function(){
257         // etc.
258     },
259     newMethod2: function(foo){
260         // etc.
261     }
262 });
263  </code></pre>
264          * @param {Object} origclass The class to override
265          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
266          * containing one or more methods.
267          * @method override
268          */
269         override : function(origclass, overrides){
270             if(overrides){
271                 var p = origclass.prototype;
272                 for(var method in overrides){
273                     p[method] = overrides[method];
274                 }
275             }
276         },
277         /**
278          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
279          * <pre><code>
280 Roo.namespace('Company', 'Company.data');
281 Company.Widget = function() { ... }
282 Company.data.CustomStore = function(config) { ... }
283 </code></pre>
284          * @param {String} namespace1
285          * @param {String} namespace2
286          * @param {String} etc
287          * @method namespace
288          */
289         namespace : function(){
290             var a=arguments, o=null, i, j, d, rt;
291             for (i=0; i<a.length; ++i) {
292                 d=a[i].split(".");
293                 rt = d[0];
294                 /** eval:var:o */
295                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
296                 for (j=1; j<d.length; ++j) {
297                     o[d[j]]=o[d[j]] || {};
298                     o=o[d[j]];
299                 }
300             }
301         },
302         /**
303          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
304          * <pre><code>
305 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
306 Roo.factory(conf, Roo.data);
307 </code></pre>
308          * @param {String} classname
309          * @param {String} namespace (optional)
310          * @method factory
311          */
312          
313         factory : function(c, ns)
314         {
315             // no xtype, no ns or c.xns - or forced off by c.xns
316             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
317                 return c;
318             }
319             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
320             if (c.constructor == ns[c.xtype]) {// already created...
321                 return c;
322             }
323             if (ns[c.xtype]) {
324                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
325                 var ret = new ns[c.xtype](c);
326                 ret.xns = false;
327                 return ret;
328             }
329             c.xns = false; // prevent recursion..
330             return c;
331         },
332          /**
333          * Logs to console if it can.
334          *
335          * @param {String|Object} string
336          * @method log
337          */
338         log : function(s)
339         {
340             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
341                 return; // alerT?
342             }
343             console.log(s);
344             
345         },
346         /**
347          * 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.
348          * @param {Object} o
349          * @return {String}
350          */
351         urlEncode : function(o){
352             if(!o){
353                 return "";
354             }
355             var buf = [];
356             for(var key in o){
357                 var ov = o[key], k = Roo.encodeURIComponent(key);
358                 var type = typeof ov;
359                 if(type == 'undefined'){
360                     buf.push(k, "=&");
361                 }else if(type != "function" && type != "object"){
362                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
363                 }else if(ov instanceof Array){
364                     if (ov.length) {
365                             for(var i = 0, len = ov.length; i < len; i++) {
366                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
367                             }
368                         } else {
369                             buf.push(k, "=&");
370                         }
371                 }
372             }
373             buf.pop();
374             return buf.join("");
375         },
376          /**
377          * Safe version of encodeURIComponent
378          * @param {String} data 
379          * @return {String} 
380          */
381         
382         encodeURIComponent : function (data)
383         {
384             try {
385                 return encodeURIComponent(data);
386             } catch(e) {} // should be an uri encode error.
387             
388             if (data == '' || data == null){
389                return '';
390             }
391             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
392             function nibble_to_hex(nibble){
393                 var chars = '0123456789ABCDEF';
394                 return chars.charAt(nibble);
395             }
396             data = data.toString();
397             var buffer = '';
398             for(var i=0; i<data.length; i++){
399                 var c = data.charCodeAt(i);
400                 var bs = new Array();
401                 if (c > 0x10000){
402                         // 4 bytes
403                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
404                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
405                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
406                     bs[3] = 0x80 | (c & 0x3F);
407                 }else if (c > 0x800){
408                          // 3 bytes
409                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
410                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
411                     bs[2] = 0x80 | (c & 0x3F);
412                 }else if (c > 0x80){
413                        // 2 bytes
414                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
415                     bs[1] = 0x80 | (c & 0x3F);
416                 }else{
417                         // 1 byte
418                     bs[0] = c;
419                 }
420                 for(var j=0; j<bs.length; j++){
421                     var b = bs[j];
422                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
423                             + nibble_to_hex(b &0x0F);
424                     buffer += '%'+hex;
425                }
426             }
427             return buffer;    
428              
429         },
430
431         /**
432          * 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]}.
433          * @param {String} string
434          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
435          * @return {Object} A literal with members
436          */
437         urlDecode : function(string, overwrite){
438             if(!string || !string.length){
439                 return {};
440             }
441             var obj = {};
442             var pairs = string.split('&');
443             var pair, name, value;
444             for(var i = 0, len = pairs.length; i < len; i++){
445                 pair = pairs[i].split('=');
446                 name = decodeURIComponent(pair[0]);
447                 value = decodeURIComponent(pair[1]);
448                 if(overwrite !== true){
449                     if(typeof obj[name] == "undefined"){
450                         obj[name] = value;
451                     }else if(typeof obj[name] == "string"){
452                         obj[name] = [obj[name]];
453                         obj[name].push(value);
454                     }else{
455                         obj[name].push(value);
456                     }
457                 }else{
458                     obj[name] = value;
459                 }
460             }
461             return obj;
462         },
463
464         /**
465          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
466          * passed array is not really an array, your function is called once with it.
467          * The supplied function is called with (Object item, Number index, Array allItems).
468          * @param {Array/NodeList/Mixed} array
469          * @param {Function} fn
470          * @param {Object} scope
471          */
472         each : function(array, fn, scope){
473             if(typeof array.length == "undefined" || typeof array == "string"){
474                 array = [array];
475             }
476             for(var i = 0, len = array.length; i < len; i++){
477                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
478             }
479         },
480
481         // deprecated
482         combine : function(){
483             var as = arguments, l = as.length, r = [];
484             for(var i = 0; i < l; i++){
485                 var a = as[i];
486                 if(a instanceof Array){
487                     r = r.concat(a);
488                 }else if(a.length !== undefined && !a.substr){
489                     r = r.concat(Array.prototype.slice.call(a, 0));
490                 }else{
491                     r.push(a);
492                 }
493             }
494             return r;
495         },
496
497         /**
498          * Escapes the passed string for use in a regular expression
499          * @param {String} str
500          * @return {String}
501          */
502         escapeRe : function(s) {
503             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
504         },
505
506         // internal
507         callback : function(cb, scope, args, delay){
508             if(typeof cb == "function"){
509                 if(delay){
510                     cb.defer(delay, scope, args || []);
511                 }else{
512                     cb.apply(scope, args || []);
513                 }
514             }
515         },
516
517         /**
518          * Return the dom node for the passed string (id), dom node, or Roo.Element
519          * @param {String/HTMLElement/Roo.Element} el
520          * @return HTMLElement
521          */
522         getDom : function(el){
523             if(!el){
524                 return null;
525             }
526             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
527         },
528
529         /**
530         * Shorthand for {@link Roo.ComponentMgr#get}
531         * @param {String} id
532         * @return Roo.Component
533         */
534         getCmp : function(id){
535             return Roo.ComponentMgr.get(id);
536         },
537          
538         num : function(v, defaultValue){
539             if(typeof v != 'number'){
540                 return defaultValue;
541             }
542             return v;
543         },
544
545         destroy : function(){
546             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
547                 var as = a[i];
548                 if(as){
549                     if(as.dom){
550                         as.removeAllListeners();
551                         as.remove();
552                         continue;
553                     }
554                     if(typeof as.purgeListeners == 'function'){
555                         as.purgeListeners();
556                     }
557                     if(typeof as.destroy == 'function'){
558                         as.destroy();
559                     }
560                 }
561             }
562         },
563
564         // inpired by a similar function in mootools library
565         /**
566          * Returns the type of object that is passed in. If the object passed in is null or undefined it
567          * return false otherwise it returns one of the following values:<ul>
568          * <li><b>string</b>: If the object passed is a string</li>
569          * <li><b>number</b>: If the object passed is a number</li>
570          * <li><b>boolean</b>: If the object passed is a boolean value</li>
571          * <li><b>function</b>: If the object passed is a function reference</li>
572          * <li><b>object</b>: If the object passed is an object</li>
573          * <li><b>array</b>: If the object passed is an array</li>
574          * <li><b>regexp</b>: If the object passed is a regular expression</li>
575          * <li><b>element</b>: If the object passed is a DOM Element</li>
576          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
577          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
578          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
579          * @param {Mixed} object
580          * @return {String}
581          */
582         type : function(o){
583             if(o === undefined || o === null){
584                 return false;
585             }
586             if(o.htmlElement){
587                 return 'element';
588             }
589             var t = typeof o;
590             if(t == 'object' && o.nodeName) {
591                 switch(o.nodeType) {
592                     case 1: return 'element';
593                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
594                 }
595             }
596             if(t == 'object' || t == 'function') {
597                 switch(o.constructor) {
598                     case Array: return 'array';
599                     case RegExp: return 'regexp';
600                 }
601                 if(typeof o.length == 'number' && typeof o.item == 'function') {
602                     return 'nodelist';
603                 }
604             }
605             return t;
606         },
607
608         /**
609          * Returns true if the passed value is null, undefined or an empty string (optional).
610          * @param {Mixed} value The value to test
611          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
612          * @return {Boolean}
613          */
614         isEmpty : function(v, allowBlank){
615             return v === null || v === undefined || (!allowBlank ? v === '' : false);
616         },
617         
618         /** @type Boolean */
619         isOpera : isOpera,
620         /** @type Boolean */
621         isSafari : isSafari,
622         /** @type Boolean */
623         isIE : isIE,
624         /** @type Boolean */
625         isIE7 : isIE7,
626         /** @type Boolean */
627         isGecko : isGecko,
628         /** @type Boolean */
629         isBorderBox : isBorderBox,
630         /** @type Boolean */
631         isWindows : isWindows,
632         /** @type Boolean */
633         isLinux : isLinux,
634         /** @type Boolean */
635         isMac : isMac,
636
637         /**
638          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
639          * you may want to set this to true.
640          * @type Boolean
641          */
642         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
643         
644         
645                 
646         /**
647          * Selects a single element as a Roo Element
648          * This is about as close as you can get to jQuery's $('do crazy stuff')
649          * @param {String} selector The selector/xpath query
650          * @param {Node} root (optional) The start of the query (defaults to document).
651          * @return {Roo.Element}
652          */
653         selectNode : function(selector, root) 
654         {
655             var node = Roo.DomQuery.selectNode(selector,root);
656             return node ? Roo.get(node) : new Roo.Element(false);
657         }
658         
659     });
660
661
662 })();
663
664 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
665                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
666 /*
667  * Based on:
668  * Ext JS Library 1.1.1
669  * Copyright(c) 2006-2007, Ext JS, LLC.
670  *
671  * Originally Released Under LGPL - original licence link has changed is not relivant.
672  *
673  * Fork - LGPL
674  * <script type="text/javascript">
675  */
676
677 (function() {    
678     // wrappedn so fnCleanup is not in global scope...
679     if(Roo.isIE) {
680         function fnCleanUp() {
681             var p = Function.prototype;
682             delete p.createSequence;
683             delete p.defer;
684             delete p.createDelegate;
685             delete p.createCallback;
686             delete p.createInterceptor;
687
688             window.detachEvent("onunload", fnCleanUp);
689         }
690         window.attachEvent("onunload", fnCleanUp);
691     }
692 })();
693
694
695 /**
696  * @class Function
697  * These functions are available on every Function object (any JavaScript function).
698  */
699 Roo.apply(Function.prototype, {
700      /**
701      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
702      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
703      * Will create a function that is bound to those 2 args.
704      * @return {Function} The new function
705     */
706     createCallback : function(/*args...*/){
707         // make args available, in function below
708         var args = arguments;
709         var method = this;
710         return function() {
711             return method.apply(window, args);
712         };
713     },
714
715     /**
716      * Creates a delegate (callback) that sets the scope to obj.
717      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
718      * Will create a function that is automatically scoped to this.
719      * @param {Object} obj (optional) The object for which the scope is set
720      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
721      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
722      *                                             if a number the args are inserted at the specified position
723      * @return {Function} The new function
724      */
725     createDelegate : function(obj, args, appendArgs){
726         var method = this;
727         return function() {
728             var callArgs = args || arguments;
729             if(appendArgs === true){
730                 callArgs = Array.prototype.slice.call(arguments, 0);
731                 callArgs = callArgs.concat(args);
732             }else if(typeof appendArgs == "number"){
733                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
734                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
735                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
736             }
737             return method.apply(obj || window, callArgs);
738         };
739     },
740
741     /**
742      * Calls this function after the number of millseconds specified.
743      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
744      * @param {Object} obj (optional) The object for which the scope is set
745      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
746      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
747      *                                             if a number the args are inserted at the specified position
748      * @return {Number} The timeout id that can be used with clearTimeout
749      */
750     defer : function(millis, obj, args, appendArgs){
751         var fn = this.createDelegate(obj, args, appendArgs);
752         if(millis){
753             return setTimeout(fn, millis);
754         }
755         fn();
756         return 0;
757     },
758     /**
759      * Create a combined function call sequence of the original function + the passed function.
760      * The resulting function returns the results of the original function.
761      * The passed fcn is called with the parameters of the original function
762      * @param {Function} fcn The function to sequence
763      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
764      * @return {Function} The new function
765      */
766     createSequence : function(fcn, scope){
767         if(typeof fcn != "function"){
768             return this;
769         }
770         var method = this;
771         return function() {
772             var retval = method.apply(this || window, arguments);
773             fcn.apply(scope || this || window, arguments);
774             return retval;
775         };
776     },
777
778     /**
779      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
780      * The resulting function returns the results of the original function.
781      * The passed fcn is called with the parameters of the original function.
782      * @addon
783      * @param {Function} fcn The function to call before the original
784      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
785      * @return {Function} The new function
786      */
787     createInterceptor : function(fcn, scope){
788         if(typeof fcn != "function"){
789             return this;
790         }
791         var method = this;
792         return function() {
793             fcn.target = this;
794             fcn.method = method;
795             if(fcn.apply(scope || this || window, arguments) === false){
796                 return;
797             }
798             return method.apply(this || window, arguments);
799         };
800     }
801 });
802 /*
803  * Based on:
804  * Ext JS Library 1.1.1
805  * Copyright(c) 2006-2007, Ext JS, LLC.
806  *
807  * Originally Released Under LGPL - original licence link has changed is not relivant.
808  *
809  * Fork - LGPL
810  * <script type="text/javascript">
811  */
812
813 Roo.applyIf(String, {
814     
815     /** @scope String */
816     
817     /**
818      * Escapes the passed string for ' and \
819      * @param {String} string The string to escape
820      * @return {String} The escaped string
821      * @static
822      */
823     escape : function(string) {
824         return string.replace(/('|\\)/g, "\\$1");
825     },
826
827     /**
828      * Pads the left side of a string with a specified character.  This is especially useful
829      * for normalizing number and date strings.  Example usage:
830      * <pre><code>
831 var s = String.leftPad('123', 5, '0');
832 // s now contains the string: '00123'
833 </code></pre>
834      * @param {String} string The original string
835      * @param {Number} size The total length of the output string
836      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
837      * @return {String} The padded string
838      * @static
839      */
840     leftPad : function (val, size, ch) {
841         var result = new String(val);
842         if(ch === null || ch === undefined || ch === '') {
843             ch = " ";
844         }
845         while (result.length < size) {
846             result = ch + result;
847         }
848         return result;
849     },
850
851     /**
852      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
853      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
854      * <pre><code>
855 var cls = 'my-class', text = 'Some text';
856 var s = String.format('<div class="{0}">{1}</div>', cls, text);
857 // s now contains the string: '<div class="my-class">Some text</div>'
858 </code></pre>
859      * @param {String} string The tokenized string to be formatted
860      * @param {String} value1 The value to replace token {0}
861      * @param {String} value2 Etc...
862      * @return {String} The formatted string
863      * @static
864      */
865     format : function(format){
866         var args = Array.prototype.slice.call(arguments, 1);
867         return format.replace(/\{(\d+)\}/g, function(m, i){
868             return Roo.util.Format.htmlEncode(args[i]);
869         });
870     }
871 });
872
873 /**
874  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
875  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
876  * they are already different, the first value passed in is returned.  Note that this method returns the new value
877  * but does not change the current string.
878  * <pre><code>
879 // alternate sort directions
880 sort = sort.toggle('ASC', 'DESC');
881
882 // instead of conditional logic:
883 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
884 </code></pre>
885  * @param {String} value The value to compare to the current string
886  * @param {String} other The new value to use if the string already equals the first value passed in
887  * @return {String} The new value
888  */
889  
890 String.prototype.toggle = function(value, other){
891     return this == value ? other : value;
892 };/*
893  * Based on:
894  * Ext JS Library 1.1.1
895  * Copyright(c) 2006-2007, Ext JS, LLC.
896  *
897  * Originally Released Under LGPL - original licence link has changed is not relivant.
898  *
899  * Fork - LGPL
900  * <script type="text/javascript">
901  */
902
903  /**
904  * @class Number
905  */
906 Roo.applyIf(Number.prototype, {
907     /**
908      * Checks whether or not the current number is within a desired range.  If the number is already within the
909      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
910      * exceeded.  Note that this method returns the constrained value but does not change the current number.
911      * @param {Number} min The minimum number in the range
912      * @param {Number} max The maximum number in the range
913      * @return {Number} The constrained value if outside the range, otherwise the current value
914      */
915     constrain : function(min, max){
916         return Math.min(Math.max(this, min), max);
917     }
918 });/*
919  * Based on:
920  * Ext JS Library 1.1.1
921  * Copyright(c) 2006-2007, Ext JS, LLC.
922  *
923  * Originally Released Under LGPL - original licence link has changed is not relivant.
924  *
925  * Fork - LGPL
926  * <script type="text/javascript">
927  */
928  /**
929  * @class Array
930  */
931 Roo.applyIf(Array.prototype, {
932     /**
933      * Checks whether or not the specified object exists in the array.
934      * @param {Object} o The object to check for
935      * @return {Number} The index of o in the array (or -1 if it is not found)
936      */
937     indexOf : function(o){
938        for (var i = 0, len = this.length; i < len; i++){
939               if(this[i] == o) return i;
940        }
941            return -1;
942     },
943
944     /**
945      * Removes the specified object from the array.  If the object is not found nothing happens.
946      * @param {Object} o The object to remove
947      */
948     remove : function(o){
949        var index = this.indexOf(o);
950        if(index != -1){
951            this.splice(index, 1);
952        }
953     },
954     /**
955      * Map (JS 1.6 compatibility)
956      * @param {Function} function  to call
957      */
958     map : function(fun )
959     {
960         var len = this.length >>> 0;
961         if (typeof fun != "function")
962             throw new TypeError();
963
964         var res = new Array(len);
965         var thisp = arguments[1];
966         for (var i = 0; i < len; i++)
967         {
968             if (i in this)
969                 res[i] = fun.call(thisp, this[i], i, this);
970         }
971
972         return res;
973     }
974     
975 });
976
977
978  /*
979  * Based on:
980  * Ext JS Library 1.1.1
981  * Copyright(c) 2006-2007, Ext JS, LLC.
982  *
983  * Originally Released Under LGPL - original licence link has changed is not relivant.
984  *
985  * Fork - LGPL
986  * <script type="text/javascript">
987  */
988
989 /**
990  * @class Date
991  *
992  * The date parsing and format syntax is a subset of
993  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
994  * supported will provide results equivalent to their PHP versions.
995  *
996  * Following is the list of all currently supported formats:
997  *<pre>
998 Sample date:
999 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1000
1001 Format  Output      Description
1002 ------  ----------  --------------------------------------------------------------
1003   d      10         Day of the month, 2 digits with leading zeros
1004   D      Wed        A textual representation of a day, three letters
1005   j      10         Day of the month without leading zeros
1006   l      Wednesday  A full textual representation of the day of the week
1007   S      th         English ordinal day of month suffix, 2 chars (use with j)
1008   w      3          Numeric representation of the day of the week
1009   z      9          The julian date, or day of the year (0-365)
1010   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1011   F      January    A full textual representation of the month
1012   m      01         Numeric representation of a month, with leading zeros
1013   M      Jan        Month name abbreviation, three letters
1014   n      1          Numeric representation of a month, without leading zeros
1015   t      31         Number of days in the given month
1016   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1017   Y      2007       A full numeric representation of a year, 4 digits
1018   y      07         A two digit representation of a year
1019   a      pm         Lowercase Ante meridiem and Post meridiem
1020   A      PM         Uppercase Ante meridiem and Post meridiem
1021   g      3          12-hour format of an hour without leading zeros
1022   G      15         24-hour format of an hour without leading zeros
1023   h      03         12-hour format of an hour with leading zeros
1024   H      15         24-hour format of an hour with leading zeros
1025   i      05         Minutes with leading zeros
1026   s      01         Seconds, with leading zeros
1027   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1028   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1029   T      CST        Timezone setting of the machine running the code
1030   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1031 </pre>
1032  *
1033  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1034  * <pre><code>
1035 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1036 document.write(dt.format('Y-m-d'));                         //2007-01-10
1037 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1038 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
1039  </code></pre>
1040  *
1041  * Here are some standard date/time patterns that you might find helpful.  They
1042  * are not part of the source of Date.js, but to use them you can simply copy this
1043  * block of code into any script that is included after Date.js and they will also become
1044  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1045  * <pre><code>
1046 Date.patterns = {
1047     ISO8601Long:"Y-m-d H:i:s",
1048     ISO8601Short:"Y-m-d",
1049     ShortDate: "n/j/Y",
1050     LongDate: "l, F d, Y",
1051     FullDateTime: "l, F d, Y g:i:s A",
1052     MonthDay: "F d",
1053     ShortTime: "g:i A",
1054     LongTime: "g:i:s A",
1055     SortableDateTime: "Y-m-d\\TH:i:s",
1056     UniversalSortableDateTime: "Y-m-d H:i:sO",
1057     YearMonth: "F, Y"
1058 };
1059 </code></pre>
1060  *
1061  * Example usage:
1062  * <pre><code>
1063 var dt = new Date();
1064 document.write(dt.format(Date.patterns.ShortDate));
1065  </code></pre>
1066  */
1067
1068 /*
1069  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1070  * They generate precompiled functions from date formats instead of parsing and
1071  * processing the pattern every time you format a date.  These functions are available
1072  * on every Date object (any javascript function).
1073  *
1074  * The original article and download are here:
1075  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1076  *
1077  */
1078  
1079  
1080  // was in core
1081 /**
1082  Returns the number of milliseconds between this date and date
1083  @param {Date} date (optional) Defaults to now
1084  @return {Number} The diff in milliseconds
1085  @member Date getElapsed
1086  */
1087 Date.prototype.getElapsed = function(date) {
1088         return Math.abs((date || new Date()).getTime()-this.getTime());
1089 };
1090 // was in date file..
1091
1092
1093 // private
1094 Date.parseFunctions = {count:0};
1095 // private
1096 Date.parseRegexes = [];
1097 // private
1098 Date.formatFunctions = {count:0};
1099
1100 // private
1101 Date.prototype.dateFormat = function(format) {
1102     if (Date.formatFunctions[format] == null) {
1103         Date.createNewFormat(format);
1104     }
1105     var func = Date.formatFunctions[format];
1106     return this[func]();
1107 };
1108
1109
1110 /**
1111  * Formats a date given the supplied format string
1112  * @param {String} format The format string
1113  * @return {String} The formatted date
1114  * @method
1115  */
1116 Date.prototype.format = Date.prototype.dateFormat;
1117
1118 // private
1119 Date.createNewFormat = function(format) {
1120     var funcName = "format" + Date.formatFunctions.count++;
1121     Date.formatFunctions[format] = funcName;
1122     var code = "Date.prototype." + funcName + " = function(){return ";
1123     var special = false;
1124     var ch = '';
1125     for (var i = 0; i < format.length; ++i) {
1126         ch = format.charAt(i);
1127         if (!special && ch == "\\") {
1128             special = true;
1129         }
1130         else if (special) {
1131             special = false;
1132             code += "'" + String.escape(ch) + "' + ";
1133         }
1134         else {
1135             code += Date.getFormatCode(ch);
1136         }
1137     }
1138     /** eval:var:zzzzzzzzzzzzz */
1139     eval(code.substring(0, code.length - 3) + ";}");
1140 };
1141
1142 // private
1143 Date.getFormatCode = function(character) {
1144     switch (character) {
1145     case "d":
1146         return "String.leftPad(this.getDate(), 2, '0') + ";
1147     case "D":
1148         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1149     case "j":
1150         return "this.getDate() + ";
1151     case "l":
1152         return "Date.dayNames[this.getDay()] + ";
1153     case "S":
1154         return "this.getSuffix() + ";
1155     case "w":
1156         return "this.getDay() + ";
1157     case "z":
1158         return "this.getDayOfYear() + ";
1159     case "W":
1160         return "this.getWeekOfYear() + ";
1161     case "F":
1162         return "Date.monthNames[this.getMonth()] + ";
1163     case "m":
1164         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1165     case "M":
1166         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1167     case "n":
1168         return "(this.getMonth() + 1) + ";
1169     case "t":
1170         return "this.getDaysInMonth() + ";
1171     case "L":
1172         return "(this.isLeapYear() ? 1 : 0) + ";
1173     case "Y":
1174         return "this.getFullYear() + ";
1175     case "y":
1176         return "('' + this.getFullYear()).substring(2, 4) + ";
1177     case "a":
1178         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1179     case "A":
1180         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1181     case "g":
1182         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1183     case "G":
1184         return "this.getHours() + ";
1185     case "h":
1186         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1187     case "H":
1188         return "String.leftPad(this.getHours(), 2, '0') + ";
1189     case "i":
1190         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1191     case "s":
1192         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1193     case "O":
1194         return "this.getGMTOffset() + ";
1195     case "P":
1196         return "this.getGMTColonOffset() + ";
1197     case "T":
1198         return "this.getTimezone() + ";
1199     case "Z":
1200         return "(this.getTimezoneOffset() * -60) + ";
1201     default:
1202         return "'" + String.escape(character) + "' + ";
1203     }
1204 };
1205
1206 /**
1207  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1208  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1209  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1210  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1211  * string or the parse operation will fail.
1212  * Example Usage:
1213 <pre><code>
1214 //dt = Fri May 25 2007 (current date)
1215 var dt = new Date();
1216
1217 //dt = Thu May 25 2006 (today's month/day in 2006)
1218 dt = Date.parseDate("2006", "Y");
1219
1220 //dt = Sun Jan 15 2006 (all date parts specified)
1221 dt = Date.parseDate("2006-1-15", "Y-m-d");
1222
1223 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1224 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1225 </code></pre>
1226  * @param {String} input The unparsed date as a string
1227  * @param {String} format The format the date is in
1228  * @return {Date} The parsed date
1229  * @static
1230  */
1231 Date.parseDate = function(input, format) {
1232     if (Date.parseFunctions[format] == null) {
1233         Date.createParser(format);
1234     }
1235     var func = Date.parseFunctions[format];
1236     return Date[func](input);
1237 };
1238 /**
1239  * @private
1240  */
1241 Date.createParser = function(format) {
1242     var funcName = "parse" + Date.parseFunctions.count++;
1243     var regexNum = Date.parseRegexes.length;
1244     var currentGroup = 1;
1245     Date.parseFunctions[format] = funcName;
1246
1247     var code = "Date." + funcName + " = function(input){\n"
1248         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1249         + "var d = new Date();\n"
1250         + "y = d.getFullYear();\n"
1251         + "m = d.getMonth();\n"
1252         + "d = d.getDate();\n"
1253         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1254         + "if (results && results.length > 0) {";
1255     var regex = "";
1256
1257     var special = false;
1258     var ch = '';
1259     for (var i = 0; i < format.length; ++i) {
1260         ch = format.charAt(i);
1261         if (!special && ch == "\\") {
1262             special = true;
1263         }
1264         else if (special) {
1265             special = false;
1266             regex += String.escape(ch);
1267         }
1268         else {
1269             var obj = Date.formatCodeToRegex(ch, currentGroup);
1270             currentGroup += obj.g;
1271             regex += obj.s;
1272             if (obj.g && obj.c) {
1273                 code += obj.c;
1274             }
1275         }
1276     }
1277
1278     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1279         + "{v = new Date(y, m, d, h, i, s);}\n"
1280         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1281         + "{v = new Date(y, m, d, h, i);}\n"
1282         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1283         + "{v = new Date(y, m, d, h);}\n"
1284         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1285         + "{v = new Date(y, m, d);}\n"
1286         + "else if (y >= 0 && m >= 0)\n"
1287         + "{v = new Date(y, m);}\n"
1288         + "else if (y >= 0)\n"
1289         + "{v = new Date(y);}\n"
1290         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1291         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1292         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1293         + ";}";
1294
1295     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1296     /** eval:var:zzzzzzzzzzzzz */
1297     eval(code);
1298 };
1299
1300 // private
1301 Date.formatCodeToRegex = function(character, currentGroup) {
1302     switch (character) {
1303     case "D":
1304         return {g:0,
1305         c:null,
1306         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1307     case "j":
1308         return {g:1,
1309             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1310             s:"(\\d{1,2})"}; // day of month without leading zeroes
1311     case "d":
1312         return {g:1,
1313             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1314             s:"(\\d{2})"}; // day of month with leading zeroes
1315     case "l":
1316         return {g:0,
1317             c:null,
1318             s:"(?:" + Date.dayNames.join("|") + ")"};
1319     case "S":
1320         return {g:0,
1321             c:null,
1322             s:"(?:st|nd|rd|th)"};
1323     case "w":
1324         return {g:0,
1325             c:null,
1326             s:"\\d"};
1327     case "z":
1328         return {g:0,
1329             c:null,
1330             s:"(?:\\d{1,3})"};
1331     case "W":
1332         return {g:0,
1333             c:null,
1334             s:"(?:\\d{2})"};
1335     case "F":
1336         return {g:1,
1337             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1338             s:"(" + Date.monthNames.join("|") + ")"};
1339     case "M":
1340         return {g:1,
1341             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1342             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1343     case "n":
1344         return {g:1,
1345             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1346             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1347     case "m":
1348         return {g:1,
1349             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1350             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1351     case "t":
1352         return {g:0,
1353             c:null,
1354             s:"\\d{1,2}"};
1355     case "L":
1356         return {g:0,
1357             c:null,
1358             s:"(?:1|0)"};
1359     case "Y":
1360         return {g:1,
1361             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1362             s:"(\\d{4})"};
1363     case "y":
1364         return {g:1,
1365             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1366                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1367             s:"(\\d{1,2})"};
1368     case "a":
1369         return {g:1,
1370             c:"if (results[" + currentGroup + "] == 'am') {\n"
1371                 + "if (h == 12) { h = 0; }\n"
1372                 + "} else { if (h < 12) { h += 12; }}",
1373             s:"(am|pm)"};
1374     case "A":
1375         return {g:1,
1376             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1377                 + "if (h == 12) { h = 0; }\n"
1378                 + "} else { if (h < 12) { h += 12; }}",
1379             s:"(AM|PM)"};
1380     case "g":
1381     case "G":
1382         return {g:1,
1383             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1384             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1385     case "h":
1386     case "H":
1387         return {g:1,
1388             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1389             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1390     case "i":
1391         return {g:1,
1392             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1393             s:"(\\d{2})"};
1394     case "s":
1395         return {g:1,
1396             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1397             s:"(\\d{2})"};
1398     case "O":
1399         return {g:1,
1400             c:[
1401                 "o = results[", currentGroup, "];\n",
1402                 "var sn = o.substring(0,1);\n", // get + / - sign
1403                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1404                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1405                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1406                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1407             ].join(""),
1408             s:"([+\-]\\d{2,4})"};
1409     
1410     
1411     case "P":
1412         return {g:1,
1413                 c:[
1414                    "o = results[", currentGroup, "];\n",
1415                    "var sn = o.substring(0,1);\n",
1416                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1417                    "var mn = o.substring(4,6) % 60;\n",
1418                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1419                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1420             ].join(""),
1421             s:"([+\-]\\d{4})"};
1422     case "T":
1423         return {g:0,
1424             c:null,
1425             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1426     case "Z":
1427         return {g:1,
1428             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1429                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1430             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1431     default:
1432         return {g:0,
1433             c:null,
1434             s:String.escape(character)};
1435     }
1436 };
1437
1438 /**
1439  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1440  * @return {String} The abbreviated timezone name (e.g. 'CST')
1441  */
1442 Date.prototype.getTimezone = function() {
1443     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1444 };
1445
1446 /**
1447  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1448  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1449  */
1450 Date.prototype.getGMTOffset = function() {
1451     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1452         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1453         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1454 };
1455
1456 /**
1457  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1458  * @return {String} 2-characters representing hours and 2-characters representing minutes
1459  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1460  */
1461 Date.prototype.getGMTColonOffset = function() {
1462         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1463                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1464                 + ":"
1465                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1466 }
1467
1468 /**
1469  * Get the numeric day number of the year, adjusted for leap year.
1470  * @return {Number} 0 through 364 (365 in leap years)
1471  */
1472 Date.prototype.getDayOfYear = function() {
1473     var num = 0;
1474     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1475     for (var i = 0; i < this.getMonth(); ++i) {
1476         num += Date.daysInMonth[i];
1477     }
1478     return num + this.getDate() - 1;
1479 };
1480
1481 /**
1482  * Get the string representation of the numeric week number of the year
1483  * (equivalent to the format specifier 'W').
1484  * @return {String} '00' through '52'
1485  */
1486 Date.prototype.getWeekOfYear = function() {
1487     // Skip to Thursday of this week
1488     var now = this.getDayOfYear() + (4 - this.getDay());
1489     // Find the first Thursday of the year
1490     var jan1 = new Date(this.getFullYear(), 0, 1);
1491     var then = (7 - jan1.getDay() + 4);
1492     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1493 };
1494
1495 /**
1496  * Whether or not the current date is in a leap year.
1497  * @return {Boolean} True if the current date is in a leap year, else false
1498  */
1499 Date.prototype.isLeapYear = function() {
1500     var year = this.getFullYear();
1501     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1502 };
1503
1504 /**
1505  * Get the first day of the current month, adjusted for leap year.  The returned value
1506  * is the numeric day index within the week (0-6) which can be used in conjunction with
1507  * the {@link #monthNames} array to retrieve the textual day name.
1508  * Example:
1509  *<pre><code>
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1512 </code></pre>
1513  * @return {Number} The day number (0-6)
1514  */
1515 Date.prototype.getFirstDayOfMonth = function() {
1516     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1517     return (day < 0) ? (day + 7) : day;
1518 };
1519
1520 /**
1521  * Get the last day of the current month, adjusted for leap year.  The returned value
1522  * is the numeric day index within the week (0-6) which can be used in conjunction with
1523  * the {@link #monthNames} array to retrieve the textual day name.
1524  * Example:
1525  *<pre><code>
1526 var dt = new Date('1/10/2007');
1527 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1528 </code></pre>
1529  * @return {Number} The day number (0-6)
1530  */
1531 Date.prototype.getLastDayOfMonth = function() {
1532     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1533     return (day < 0) ? (day + 7) : day;
1534 };
1535
1536
1537 /**
1538  * Get the first date of this date's month
1539  * @return {Date}
1540  */
1541 Date.prototype.getFirstDateOfMonth = function() {
1542     return new Date(this.getFullYear(), this.getMonth(), 1);
1543 };
1544
1545 /**
1546  * Get the last date of this date's month
1547  * @return {Date}
1548  */
1549 Date.prototype.getLastDateOfMonth = function() {
1550     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1551 };
1552 /**
1553  * Get the number of days in the current month, adjusted for leap year.
1554  * @return {Number} The number of days in the month
1555  */
1556 Date.prototype.getDaysInMonth = function() {
1557     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1558     return Date.daysInMonth[this.getMonth()];
1559 };
1560
1561 /**
1562  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1563  * @return {String} 'st, 'nd', 'rd' or 'th'
1564  */
1565 Date.prototype.getSuffix = function() {
1566     switch (this.getDate()) {
1567         case 1:
1568         case 21:
1569         case 31:
1570             return "st";
1571         case 2:
1572         case 22:
1573             return "nd";
1574         case 3:
1575         case 23:
1576             return "rd";
1577         default:
1578             return "th";
1579     }
1580 };
1581
1582 // private
1583 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1584
1585 /**
1586  * An array of textual month names.
1587  * Override these values for international dates, for example...
1588  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1589  * @type Array
1590  * @static
1591  */
1592 Date.monthNames =
1593    ["January",
1594     "February",
1595     "March",
1596     "April",
1597     "May",
1598     "June",
1599     "July",
1600     "August",
1601     "September",
1602     "October",
1603     "November",
1604     "December"];
1605
1606 /**
1607  * An array of textual day names.
1608  * Override these values for international dates, for example...
1609  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1610  * @type Array
1611  * @static
1612  */
1613 Date.dayNames =
1614    ["Sunday",
1615     "Monday",
1616     "Tuesday",
1617     "Wednesday",
1618     "Thursday",
1619     "Friday",
1620     "Saturday"];
1621
1622 // private
1623 Date.y2kYear = 50;
1624 // private
1625 Date.monthNumbers = {
1626     Jan:0,
1627     Feb:1,
1628     Mar:2,
1629     Apr:3,
1630     May:4,
1631     Jun:5,
1632     Jul:6,
1633     Aug:7,
1634     Sep:8,
1635     Oct:9,
1636     Nov:10,
1637     Dec:11};
1638
1639 /**
1640  * Creates and returns a new Date instance with the exact same date value as the called instance.
1641  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1642  * variable will also be changed.  When the intention is to create a new variable that will not
1643  * modify the original instance, you should create a clone.
1644  *
1645  * Example of correctly cloning a date:
1646  * <pre><code>
1647 //wrong way:
1648 var orig = new Date('10/1/2006');
1649 var copy = orig;
1650 copy.setDate(5);
1651 document.write(orig);  //returns 'Thu Oct 05 2006'!
1652
1653 //correct way:
1654 var orig = new Date('10/1/2006');
1655 var copy = orig.clone();
1656 copy.setDate(5);
1657 document.write(orig);  //returns 'Thu Oct 01 2006'
1658 </code></pre>
1659  * @return {Date} The new Date instance
1660  */
1661 Date.prototype.clone = function() {
1662         return new Date(this.getTime());
1663 };
1664
1665 /**
1666  * Clears any time information from this date
1667  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1668  @return {Date} this or the clone
1669  */
1670 Date.prototype.clearTime = function(clone){
1671     if(clone){
1672         return this.clone().clearTime();
1673     }
1674     this.setHours(0);
1675     this.setMinutes(0);
1676     this.setSeconds(0);
1677     this.setMilliseconds(0);
1678     return this;
1679 };
1680
1681 // private
1682 // safari setMonth is broken
1683 if(Roo.isSafari){
1684     Date.brokenSetMonth = Date.prototype.setMonth;
1685         Date.prototype.setMonth = function(num){
1686                 if(num <= -1){
1687                         var n = Math.ceil(-num);
1688                         var back_year = Math.ceil(n/12);
1689                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1690                         this.setFullYear(this.getFullYear() - back_year);
1691                         return Date.brokenSetMonth.call(this, month);
1692                 } else {
1693                         return Date.brokenSetMonth.apply(this, arguments);
1694                 }
1695         };
1696 }
1697
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.MILLI = "ms";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.SECOND = "s";
1706 /** Date interval constant 
1707 * @static 
1708 * @type String */
1709 Date.MINUTE = "mi";
1710 /** Date interval constant 
1711 * @static 
1712 * @type String */
1713 Date.HOUR = "h";
1714 /** Date interval constant 
1715 * @static 
1716 * @type String */
1717 Date.DAY = "d";
1718 /** Date interval constant 
1719 * @static 
1720 * @type String */
1721 Date.MONTH = "mo";
1722 /** Date interval constant 
1723 * @static 
1724 * @type String */
1725 Date.YEAR = "y";
1726
1727 /**
1728  * Provides a convenient method of performing basic date arithmetic.  This method
1729  * does not modify the Date instance being called - it creates and returns
1730  * a new Date instance containing the resulting date value.
1731  *
1732  * Examples:
1733  * <pre><code>
1734 //Basic usage:
1735 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1736 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1737
1738 //Negative values will subtract correctly:
1739 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1740 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1741
1742 //You can even chain several calls together in one line!
1743 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1744 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1745  </code></pre>
1746  *
1747  * @param {String} interval   A valid date interval enum value
1748  * @param {Number} value      The amount to add to the current date
1749  * @return {Date} The new Date instance
1750  */
1751 Date.prototype.add = function(interval, value){
1752   var d = this.clone();
1753   if (!interval || value === 0) return d;
1754   switch(interval.toLowerCase()){
1755     case Date.MILLI:
1756       d.setMilliseconds(this.getMilliseconds() + value);
1757       break;
1758     case Date.SECOND:
1759       d.setSeconds(this.getSeconds() + value);
1760       break;
1761     case Date.MINUTE:
1762       d.setMinutes(this.getMinutes() + value);
1763       break;
1764     case Date.HOUR:
1765       d.setHours(this.getHours() + value);
1766       break;
1767     case Date.DAY:
1768       d.setDate(this.getDate() + value);
1769       break;
1770     case Date.MONTH:
1771       var day = this.getDate();
1772       if(day > 28){
1773           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1774       }
1775       d.setDate(day);
1776       d.setMonth(this.getMonth() + value);
1777       break;
1778     case Date.YEAR:
1779       d.setFullYear(this.getFullYear() + value);
1780       break;
1781   }
1782   return d;
1783 };
1784 /*
1785  * Based on:
1786  * Ext JS Library 1.1.1
1787  * Copyright(c) 2006-2007, Ext JS, LLC.
1788  *
1789  * Originally Released Under LGPL - original licence link has changed is not relivant.
1790  *
1791  * Fork - LGPL
1792  * <script type="text/javascript">
1793  */
1794
1795 /**
1796  * @class Roo.lib.Dom
1797  * @static
1798  * 
1799  * Dom utils (from YIU afaik)
1800  * 
1801  **/
1802 Roo.lib.Dom = {
1803     /**
1804      * Get the view width
1805      * @param {Boolean} full True will get the full document, otherwise it's the view width
1806      * @return {Number} The width
1807      */
1808      
1809     getViewWidth : function(full) {
1810         return full ? this.getDocumentWidth() : this.getViewportWidth();
1811     },
1812     /**
1813      * Get the view height
1814      * @param {Boolean} full True will get the full document, otherwise it's the view height
1815      * @return {Number} The height
1816      */
1817     getViewHeight : function(full) {
1818         return full ? this.getDocumentHeight() : this.getViewportHeight();
1819     },
1820
1821     getDocumentHeight: function() {
1822         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1823         return Math.max(scrollHeight, this.getViewportHeight());
1824     },
1825
1826     getDocumentWidth: function() {
1827         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1828         return Math.max(scrollWidth, this.getViewportWidth());
1829     },
1830
1831     getViewportHeight: function() {
1832         var height = self.innerHeight;
1833         var mode = document.compatMode;
1834
1835         if ((mode || Roo.isIE) && !Roo.isOpera) {
1836             height = (mode == "CSS1Compat") ?
1837                      document.documentElement.clientHeight :
1838                      document.body.clientHeight;
1839         }
1840
1841         return height;
1842     },
1843
1844     getViewportWidth: function() {
1845         var width = self.innerWidth;
1846         var mode = document.compatMode;
1847
1848         if (mode || Roo.isIE) {
1849             width = (mode == "CSS1Compat") ?
1850                     document.documentElement.clientWidth :
1851                     document.body.clientWidth;
1852         }
1853         return width;
1854     },
1855
1856     isAncestor : function(p, c) {
1857         p = Roo.getDom(p);
1858         c = Roo.getDom(c);
1859         if (!p || !c) {
1860             return false;
1861         }
1862
1863         if (p.contains && !Roo.isSafari) {
1864             return p.contains(c);
1865         } else if (p.compareDocumentPosition) {
1866             return !!(p.compareDocumentPosition(c) & 16);
1867         } else {
1868             var parent = c.parentNode;
1869             while (parent) {
1870                 if (parent == p) {
1871                     return true;
1872                 }
1873                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1874                     return false;
1875                 }
1876                 parent = parent.parentNode;
1877             }
1878             return false;
1879         }
1880     },
1881
1882     getRegion : function(el) {
1883         return Roo.lib.Region.getRegion(el);
1884     },
1885
1886     getY : function(el) {
1887         return this.getXY(el)[1];
1888     },
1889
1890     getX : function(el) {
1891         return this.getXY(el)[0];
1892     },
1893
1894     getXY : function(el) {
1895         var p, pe, b, scroll, bd = document.body;
1896         el = Roo.getDom(el);
1897         var fly = Roo.lib.AnimBase.fly;
1898         if (el.getBoundingClientRect) {
1899             b = el.getBoundingClientRect();
1900             scroll = fly(document).getScroll();
1901             return [b.left + scroll.left, b.top + scroll.top];
1902         }
1903         var x = 0, y = 0;
1904
1905         p = el;
1906
1907         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1908
1909         while (p) {
1910
1911             x += p.offsetLeft;
1912             y += p.offsetTop;
1913
1914             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1915                 hasAbsolute = true;
1916             }
1917
1918             if (Roo.isGecko) {
1919                 pe = fly(p);
1920
1921                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1922                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1923
1924
1925                 x += bl;
1926                 y += bt;
1927
1928
1929                 if (p != el && pe.getStyle('overflow') != 'visible') {
1930                     x += bl;
1931                     y += bt;
1932                 }
1933             }
1934             p = p.offsetParent;
1935         }
1936
1937         if (Roo.isSafari && hasAbsolute) {
1938             x -= bd.offsetLeft;
1939             y -= bd.offsetTop;
1940         }
1941
1942         if (Roo.isGecko && !hasAbsolute) {
1943             var dbd = fly(bd);
1944             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1945             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1946         }
1947
1948         p = el.parentNode;
1949         while (p && p != bd) {
1950             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1951                 x -= p.scrollLeft;
1952                 y -= p.scrollTop;
1953             }
1954             p = p.parentNode;
1955         }
1956         return [x, y];
1957     },
1958  
1959   
1960
1961
1962     setXY : function(el, xy) {
1963         el = Roo.fly(el, '_setXY');
1964         el.position();
1965         var pts = el.translatePoints(xy);
1966         if (xy[0] !== false) {
1967             el.dom.style.left = pts.left + "px";
1968         }
1969         if (xy[1] !== false) {
1970             el.dom.style.top = pts.top + "px";
1971         }
1972     },
1973
1974     setX : function(el, x) {
1975         this.setXY(el, [x, false]);
1976     },
1977
1978     setY : function(el, y) {
1979         this.setXY(el, [false, y]);
1980     }
1981 };
1982 /*
1983  * Portions of this file are based on pieces of Yahoo User Interface Library
1984  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1985  * YUI licensed under the BSD License:
1986  * http://developer.yahoo.net/yui/license.txt
1987  * <script type="text/javascript">
1988  *
1989  */
1990
1991 Roo.lib.Event = function() {
1992     var loadComplete = false;
1993     var listeners = [];
1994     var unloadListeners = [];
1995     var retryCount = 0;
1996     var onAvailStack = [];
1997     var counter = 0;
1998     var lastError = null;
1999
2000     return {
2001         POLL_RETRYS: 200,
2002         POLL_INTERVAL: 20,
2003         EL: 0,
2004         TYPE: 1,
2005         FN: 2,
2006         WFN: 3,
2007         OBJ: 3,
2008         ADJ_SCOPE: 4,
2009         _interval: null,
2010
2011         startInterval: function() {
2012             if (!this._interval) {
2013                 var self = this;
2014                 var callback = function() {
2015                     self._tryPreloadAttach();
2016                 };
2017                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2018
2019             }
2020         },
2021
2022         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2023             onAvailStack.push({ id:         p_id,
2024                 fn:         p_fn,
2025                 obj:        p_obj,
2026                 override:   p_override,
2027                 checkReady: false    });
2028
2029             retryCount = this.POLL_RETRYS;
2030             this.startInterval();
2031         },
2032
2033
2034         addListener: function(el, eventName, fn) {
2035             el = Roo.getDom(el);
2036             if (!el || !fn) {
2037                 return false;
2038             }
2039
2040             if ("unload" == eventName) {
2041                 unloadListeners[unloadListeners.length] =
2042                 [el, eventName, fn];
2043                 return true;
2044             }
2045
2046             var wrappedFn = function(e) {
2047                 return fn(Roo.lib.Event.getEvent(e));
2048             };
2049
2050             var li = [el, eventName, fn, wrappedFn];
2051
2052             var index = listeners.length;
2053             listeners[index] = li;
2054
2055             this.doAdd(el, eventName, wrappedFn, false);
2056             return true;
2057
2058         },
2059
2060
2061         removeListener: function(el, eventName, fn) {
2062             var i, len;
2063
2064             el = Roo.getDom(el);
2065
2066             if(!fn) {
2067                 return this.purgeElement(el, false, eventName);
2068             }
2069
2070
2071             if ("unload" == eventName) {
2072
2073                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2074                     var li = unloadListeners[i];
2075                     if (li &&
2076                         li[0] == el &&
2077                         li[1] == eventName &&
2078                         li[2] == fn) {
2079                         unloadListeners.splice(i, 1);
2080                         return true;
2081                     }
2082                 }
2083
2084                 return false;
2085             }
2086
2087             var cacheItem = null;
2088
2089
2090             var index = arguments[3];
2091
2092             if ("undefined" == typeof index) {
2093                 index = this._getCacheIndex(el, eventName, fn);
2094             }
2095
2096             if (index >= 0) {
2097                 cacheItem = listeners[index];
2098             }
2099
2100             if (!el || !cacheItem) {
2101                 return false;
2102             }
2103
2104             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2105
2106             delete listeners[index][this.WFN];
2107             delete listeners[index][this.FN];
2108             listeners.splice(index, 1);
2109
2110             return true;
2111
2112         },
2113
2114
2115         getTarget: function(ev, resolveTextNode) {
2116             ev = ev.browserEvent || ev;
2117             var t = ev.target || ev.srcElement;
2118             return this.resolveTextNode(t);
2119         },
2120
2121
2122         resolveTextNode: function(node) {
2123             if (Roo.isSafari && node && 3 == node.nodeType) {
2124                 return node.parentNode;
2125             } else {
2126                 return node;
2127             }
2128         },
2129
2130
2131         getPageX: function(ev) {
2132             ev = ev.browserEvent || ev;
2133             var x = ev.pageX;
2134             if (!x && 0 !== x) {
2135                 x = ev.clientX || 0;
2136
2137                 if (Roo.isIE) {
2138                     x += this.getScroll()[1];
2139                 }
2140             }
2141
2142             return x;
2143         },
2144
2145
2146         getPageY: function(ev) {
2147             ev = ev.browserEvent || ev;
2148             var y = ev.pageY;
2149             if (!y && 0 !== y) {
2150                 y = ev.clientY || 0;
2151
2152                 if (Roo.isIE) {
2153                     y += this.getScroll()[0];
2154                 }
2155             }
2156
2157
2158             return y;
2159         },
2160
2161
2162         getXY: function(ev) {
2163             ev = ev.browserEvent || ev;
2164             return [this.getPageX(ev), this.getPageY(ev)];
2165         },
2166
2167
2168         getRelatedTarget: function(ev) {
2169             ev = ev.browserEvent || ev;
2170             var t = ev.relatedTarget;
2171             if (!t) {
2172                 if (ev.type == "mouseout") {
2173                     t = ev.toElement;
2174                 } else if (ev.type == "mouseover") {
2175                     t = ev.fromElement;
2176                 }
2177             }
2178
2179             return this.resolveTextNode(t);
2180         },
2181
2182
2183         getTime: function(ev) {
2184             ev = ev.browserEvent || ev;
2185             if (!ev.time) {
2186                 var t = new Date().getTime();
2187                 try {
2188                     ev.time = t;
2189                 } catch(ex) {
2190                     this.lastError = ex;
2191                     return t;
2192                 }
2193             }
2194
2195             return ev.time;
2196         },
2197
2198
2199         stopEvent: function(ev) {
2200             this.stopPropagation(ev);
2201             this.preventDefault(ev);
2202         },
2203
2204
2205         stopPropagation: function(ev) {
2206             ev = ev.browserEvent || ev;
2207             if (ev.stopPropagation) {
2208                 ev.stopPropagation();
2209             } else {
2210                 ev.cancelBubble = true;
2211             }
2212         },
2213
2214
2215         preventDefault: function(ev) {
2216             ev = ev.browserEvent || ev;
2217             if(ev.preventDefault) {
2218                 ev.preventDefault();
2219             } else {
2220                 ev.returnValue = false;
2221             }
2222         },
2223
2224
2225         getEvent: function(e) {
2226             var ev = e || window.event;
2227             if (!ev) {
2228                 var c = this.getEvent.caller;
2229                 while (c) {
2230                     ev = c.arguments[0];
2231                     if (ev && Event == ev.constructor) {
2232                         break;
2233                     }
2234                     c = c.caller;
2235                 }
2236             }
2237             return ev;
2238         },
2239
2240
2241         getCharCode: function(ev) {
2242             ev = ev.browserEvent || ev;
2243             return ev.charCode || ev.keyCode || 0;
2244         },
2245
2246
2247         _getCacheIndex: function(el, eventName, fn) {
2248             for (var i = 0,len = listeners.length; i < len; ++i) {
2249                 var li = listeners[i];
2250                 if (li &&
2251                     li[this.FN] == fn &&
2252                     li[this.EL] == el &&
2253                     li[this.TYPE] == eventName) {
2254                     return i;
2255                 }
2256             }
2257
2258             return -1;
2259         },
2260
2261
2262         elCache: {},
2263
2264
2265         getEl: function(id) {
2266             return document.getElementById(id);
2267         },
2268
2269
2270         clearCache: function() {
2271         },
2272
2273
2274         _load: function(e) {
2275             loadComplete = true;
2276             var EU = Roo.lib.Event;
2277
2278
2279             if (Roo.isIE) {
2280                 EU.doRemove(window, "load", EU._load);
2281             }
2282         },
2283
2284
2285         _tryPreloadAttach: function() {
2286
2287             if (this.locked) {
2288                 return false;
2289             }
2290
2291             this.locked = true;
2292
2293
2294             var tryAgain = !loadComplete;
2295             if (!tryAgain) {
2296                 tryAgain = (retryCount > 0);
2297             }
2298
2299
2300             var notAvail = [];
2301             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2302                 var item = onAvailStack[i];
2303                 if (item) {
2304                     var el = this.getEl(item.id);
2305
2306                     if (el) {
2307                         if (!item.checkReady ||
2308                             loadComplete ||
2309                             el.nextSibling ||
2310                             (document && document.body)) {
2311
2312                             var scope = el;
2313                             if (item.override) {
2314                                 if (item.override === true) {
2315                                     scope = item.obj;
2316                                 } else {
2317                                     scope = item.override;
2318                                 }
2319                             }
2320                             item.fn.call(scope, item.obj);
2321                             onAvailStack[i] = null;
2322                         }
2323                     } else {
2324                         notAvail.push(item);
2325                     }
2326                 }
2327             }
2328
2329             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2330
2331             if (tryAgain) {
2332
2333                 this.startInterval();
2334             } else {
2335                 clearInterval(this._interval);
2336                 this._interval = null;
2337             }
2338
2339             this.locked = false;
2340
2341             return true;
2342
2343         },
2344
2345
2346         purgeElement: function(el, recurse, eventName) {
2347             var elListeners = this.getListeners(el, eventName);
2348             if (elListeners) {
2349                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2350                     var l = elListeners[i];
2351                     this.removeListener(el, l.type, l.fn);
2352                 }
2353             }
2354
2355             if (recurse && el && el.childNodes) {
2356                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2357                     this.purgeElement(el.childNodes[i], recurse, eventName);
2358                 }
2359             }
2360         },
2361
2362
2363         getListeners: function(el, eventName) {
2364             var results = [], searchLists;
2365             if (!eventName) {
2366                 searchLists = [listeners, unloadListeners];
2367             } else if (eventName == "unload") {
2368                 searchLists = [unloadListeners];
2369             } else {
2370                 searchLists = [listeners];
2371             }
2372
2373             for (var j = 0; j < searchLists.length; ++j) {
2374                 var searchList = searchLists[j];
2375                 if (searchList && searchList.length > 0) {
2376                     for (var i = 0,len = searchList.length; i < len; ++i) {
2377                         var l = searchList[i];
2378                         if (l && l[this.EL] === el &&
2379                             (!eventName || eventName === l[this.TYPE])) {
2380                             results.push({
2381                                 type:   l[this.TYPE],
2382                                 fn:     l[this.FN],
2383                                 obj:    l[this.OBJ],
2384                                 adjust: l[this.ADJ_SCOPE],
2385                                 index:  i
2386                             });
2387                         }
2388                     }
2389                 }
2390             }
2391
2392             return (results.length) ? results : null;
2393         },
2394
2395
2396         _unload: function(e) {
2397
2398             var EU = Roo.lib.Event, i, j, l, len, index;
2399
2400             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2401                 l = unloadListeners[i];
2402                 if (l) {
2403                     var scope = window;
2404                     if (l[EU.ADJ_SCOPE]) {
2405                         if (l[EU.ADJ_SCOPE] === true) {
2406                             scope = l[EU.OBJ];
2407                         } else {
2408                             scope = l[EU.ADJ_SCOPE];
2409                         }
2410                     }
2411                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2412                     unloadListeners[i] = null;
2413                     l = null;
2414                     scope = null;
2415                 }
2416             }
2417
2418             unloadListeners = null;
2419
2420             if (listeners && listeners.length > 0) {
2421                 j = listeners.length;
2422                 while (j) {
2423                     index = j - 1;
2424                     l = listeners[index];
2425                     if (l) {
2426                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2427                                 l[EU.FN], index);
2428                     }
2429                     j = j - 1;
2430                 }
2431                 l = null;
2432
2433                 EU.clearCache();
2434             }
2435
2436             EU.doRemove(window, "unload", EU._unload);
2437
2438         },
2439
2440
2441         getScroll: function() {
2442             var dd = document.documentElement, db = document.body;
2443             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2444                 return [dd.scrollTop, dd.scrollLeft];
2445             } else if (db) {
2446                 return [db.scrollTop, db.scrollLeft];
2447             } else {
2448                 return [0, 0];
2449             }
2450         },
2451
2452
2453         doAdd: function () {
2454             if (window.addEventListener) {
2455                 return function(el, eventName, fn, capture) {
2456                     el.addEventListener(eventName, fn, (capture));
2457                 };
2458             } else if (window.attachEvent) {
2459                 return function(el, eventName, fn, capture) {
2460                     el.attachEvent("on" + eventName, fn);
2461                 };
2462             } else {
2463                 return function() {
2464                 };
2465             }
2466         }(),
2467
2468
2469         doRemove: function() {
2470             if (window.removeEventListener) {
2471                 return function (el, eventName, fn, capture) {
2472                     el.removeEventListener(eventName, fn, (capture));
2473                 };
2474             } else if (window.detachEvent) {
2475                 return function (el, eventName, fn) {
2476                     el.detachEvent("on" + eventName, fn);
2477                 };
2478             } else {
2479                 return function() {
2480                 };
2481             }
2482         }()
2483     };
2484     
2485 }();
2486 (function() {     
2487    
2488     var E = Roo.lib.Event;
2489     E.on = E.addListener;
2490     E.un = E.removeListener;
2491
2492     if (document && document.body) {
2493         E._load();
2494     } else {
2495         E.doAdd(window, "load", E._load);
2496     }
2497     E.doAdd(window, "unload", E._unload);
2498     E._tryPreloadAttach();
2499 })();
2500
2501 /*
2502  * Portions of this file are based on pieces of Yahoo User Interface Library
2503  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2504  * YUI licensed under the BSD License:
2505  * http://developer.yahoo.net/yui/license.txt
2506  * <script type="text/javascript">
2507  *
2508  */
2509
2510 (function() {
2511     /**
2512      * @class Roo.lib.Ajax
2513      *
2514      */
2515     Roo.lib.Ajax = {
2516         /**
2517          * @static 
2518          */
2519         request : function(method, uri, cb, data, options) {
2520             if(options){
2521                 var hs = options.headers;
2522                 if(hs){
2523                     for(var h in hs){
2524                         if(hs.hasOwnProperty(h)){
2525                             this.initHeader(h, hs[h], false);
2526                         }
2527                     }
2528                 }
2529                 if(options.xmlData){
2530                     this.initHeader('Content-Type', 'text/xml', false);
2531                     method = 'POST';
2532                     data = options.xmlData;
2533                 }
2534             }
2535
2536             return this.asyncRequest(method, uri, cb, data);
2537         },
2538
2539         serializeForm : function(form) {
2540             if(typeof form == 'string') {
2541                 form = (document.getElementById(form) || document.forms[form]);
2542             }
2543
2544             var el, name, val, disabled, data = '', hasSubmit = false;
2545             for (var i = 0; i < form.elements.length; i++) {
2546                 el = form.elements[i];
2547                 disabled = form.elements[i].disabled;
2548                 name = form.elements[i].name;
2549                 val = form.elements[i].value;
2550
2551                 if (!disabled && name){
2552                     switch (el.type)
2553                             {
2554                         case 'select-one':
2555                         case 'select-multiple':
2556                             for (var j = 0; j < el.options.length; j++) {
2557                                 if (el.options[j].selected) {
2558                                     if (Roo.isIE) {
2559                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2560                                     }
2561                                     else {
2562                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2563                                     }
2564                                 }
2565                             }
2566                             break;
2567                         case 'radio':
2568                         case 'checkbox':
2569                             if (el.checked) {
2570                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2571                             }
2572                             break;
2573                         case 'file':
2574
2575                         case undefined:
2576
2577                         case 'reset':
2578
2579                         case 'button':
2580
2581                             break;
2582                         case 'submit':
2583                             if(hasSubmit == false) {
2584                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2585                                 hasSubmit = true;
2586                             }
2587                             break;
2588                         default:
2589                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2590                             break;
2591                     }
2592                 }
2593             }
2594             data = data.substr(0, data.length - 1);
2595             return data;
2596         },
2597
2598         headers:{},
2599
2600         hasHeaders:false,
2601
2602         useDefaultHeader:true,
2603
2604         defaultPostHeader:'application/x-www-form-urlencoded',
2605
2606         useDefaultXhrHeader:true,
2607
2608         defaultXhrHeader:'XMLHttpRequest',
2609
2610         hasDefaultHeaders:true,
2611
2612         defaultHeaders:{},
2613
2614         poll:{},
2615
2616         timeout:{},
2617
2618         pollInterval:50,
2619
2620         transactionId:0,
2621
2622         setProgId:function(id)
2623         {
2624             this.activeX.unshift(id);
2625         },
2626
2627         setDefaultPostHeader:function(b)
2628         {
2629             this.useDefaultHeader = b;
2630         },
2631
2632         setDefaultXhrHeader:function(b)
2633         {
2634             this.useDefaultXhrHeader = b;
2635         },
2636
2637         setPollingInterval:function(i)
2638         {
2639             if (typeof i == 'number' && isFinite(i)) {
2640                 this.pollInterval = i;
2641             }
2642         },
2643
2644         createXhrObject:function(transactionId)
2645         {
2646             var obj,http;
2647             try
2648             {
2649
2650                 http = new XMLHttpRequest();
2651
2652                 obj = { conn:http, tId:transactionId };
2653             }
2654             catch(e)
2655             {
2656                 for (var i = 0; i < this.activeX.length; ++i) {
2657                     try
2658                     {
2659
2660                         http = new ActiveXObject(this.activeX[i]);
2661
2662                         obj = { conn:http, tId:transactionId };
2663                         break;
2664                     }
2665                     catch(e) {
2666                     }
2667                 }
2668             }
2669             finally
2670             {
2671                 return obj;
2672             }
2673         },
2674
2675         getConnectionObject:function()
2676         {
2677             var o;
2678             var tId = this.transactionId;
2679
2680             try
2681             {
2682                 o = this.createXhrObject(tId);
2683                 if (o) {
2684                     this.transactionId++;
2685                 }
2686             }
2687             catch(e) {
2688             }
2689             finally
2690             {
2691                 return o;
2692             }
2693         },
2694
2695         asyncRequest:function(method, uri, callback, postData)
2696         {
2697             var o = this.getConnectionObject();
2698
2699             if (!o) {
2700                 return null;
2701             }
2702             else {
2703                 o.conn.open(method, uri, true);
2704
2705                 if (this.useDefaultXhrHeader) {
2706                     if (!this.defaultHeaders['X-Requested-With']) {
2707                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2708                     }
2709                 }
2710
2711                 if(postData && this.useDefaultHeader){
2712                     this.initHeader('Content-Type', this.defaultPostHeader);
2713                 }
2714
2715                  if (this.hasDefaultHeaders || this.hasHeaders) {
2716                     this.setHeader(o);
2717                 }
2718
2719                 this.handleReadyState(o, callback);
2720                 o.conn.send(postData || null);
2721
2722                 return o;
2723             }
2724         },
2725
2726         handleReadyState:function(o, callback)
2727         {
2728             var oConn = this;
2729
2730             if (callback && callback.timeout) {
2731                 
2732                 this.timeout[o.tId] = window.setTimeout(function() {
2733                     oConn.abort(o, callback, true);
2734                 }, callback.timeout);
2735             }
2736
2737             this.poll[o.tId] = window.setInterval(
2738                     function() {
2739                         if (o.conn && o.conn.readyState == 4) {
2740                             window.clearInterval(oConn.poll[o.tId]);
2741                             delete oConn.poll[o.tId];
2742
2743                             if(callback && callback.timeout) {
2744                                 window.clearTimeout(oConn.timeout[o.tId]);
2745                                 delete oConn.timeout[o.tId];
2746                             }
2747
2748                             oConn.handleTransactionResponse(o, callback);
2749                         }
2750                     }
2751                     , this.pollInterval);
2752         },
2753
2754         handleTransactionResponse:function(o, callback, isAbort)
2755         {
2756
2757             if (!callback) {
2758                 this.releaseObject(o);
2759                 return;
2760             }
2761
2762             var httpStatus, responseObject;
2763
2764             try
2765             {
2766                 if (o.conn.status !== undefined && o.conn.status != 0) {
2767                     httpStatus = o.conn.status;
2768                 }
2769                 else {
2770                     httpStatus = 13030;
2771                 }
2772             }
2773             catch(e) {
2774
2775
2776                 httpStatus = 13030;
2777             }
2778
2779             if (httpStatus >= 200 && httpStatus < 300) {
2780                 responseObject = this.createResponseObject(o, callback.argument);
2781                 if (callback.success) {
2782                     if (!callback.scope) {
2783                         callback.success(responseObject);
2784                     }
2785                     else {
2786
2787
2788                         callback.success.apply(callback.scope, [responseObject]);
2789                     }
2790                 }
2791             }
2792             else {
2793                 switch (httpStatus) {
2794
2795                     case 12002:
2796                     case 12029:
2797                     case 12030:
2798                     case 12031:
2799                     case 12152:
2800                     case 13030:
2801                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2802                         if (callback.failure) {
2803                             if (!callback.scope) {
2804                                 callback.failure(responseObject);
2805                             }
2806                             else {
2807                                 callback.failure.apply(callback.scope, [responseObject]);
2808                             }
2809                         }
2810                         break;
2811                     default:
2812                         responseObject = this.createResponseObject(o, callback.argument);
2813                         if (callback.failure) {
2814                             if (!callback.scope) {
2815                                 callback.failure(responseObject);
2816                             }
2817                             else {
2818                                 callback.failure.apply(callback.scope, [responseObject]);
2819                             }
2820                         }
2821                 }
2822             }
2823
2824             this.releaseObject(o);
2825             responseObject = null;
2826         },
2827
2828         createResponseObject:function(o, callbackArg)
2829         {
2830             var obj = {};
2831             var headerObj = {};
2832
2833             try
2834             {
2835                 var headerStr = o.conn.getAllResponseHeaders();
2836                 var header = headerStr.split('\n');
2837                 for (var i = 0; i < header.length; i++) {
2838                     var delimitPos = header[i].indexOf(':');
2839                     if (delimitPos != -1) {
2840                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2841                     }
2842                 }
2843             }
2844             catch(e) {
2845             }
2846
2847             obj.tId = o.tId;
2848             obj.status = o.conn.status;
2849             obj.statusText = o.conn.statusText;
2850             obj.getResponseHeader = headerObj;
2851             obj.getAllResponseHeaders = headerStr;
2852             obj.responseText = o.conn.responseText;
2853             obj.responseXML = o.conn.responseXML;
2854
2855             if (typeof callbackArg !== undefined) {
2856                 obj.argument = callbackArg;
2857             }
2858
2859             return obj;
2860         },
2861
2862         createExceptionObject:function(tId, callbackArg, isAbort)
2863         {
2864             var COMM_CODE = 0;
2865             var COMM_ERROR = 'communication failure';
2866             var ABORT_CODE = -1;
2867             var ABORT_ERROR = 'transaction aborted';
2868
2869             var obj = {};
2870
2871             obj.tId = tId;
2872             if (isAbort) {
2873                 obj.status = ABORT_CODE;
2874                 obj.statusText = ABORT_ERROR;
2875             }
2876             else {
2877                 obj.status = COMM_CODE;
2878                 obj.statusText = COMM_ERROR;
2879             }
2880
2881             if (callbackArg) {
2882                 obj.argument = callbackArg;
2883             }
2884
2885             return obj;
2886         },
2887
2888         initHeader:function(label, value, isDefault)
2889         {
2890             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2891
2892             if (headerObj[label] === undefined) {
2893                 headerObj[label] = value;
2894             }
2895             else {
2896
2897
2898                 headerObj[label] = value + "," + headerObj[label];
2899             }
2900
2901             if (isDefault) {
2902                 this.hasDefaultHeaders = true;
2903             }
2904             else {
2905                 this.hasHeaders = true;
2906             }
2907         },
2908
2909
2910         setHeader:function(o)
2911         {
2912             if (this.hasDefaultHeaders) {
2913                 for (var prop in this.defaultHeaders) {
2914                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2915                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2916                     }
2917                 }
2918             }
2919
2920             if (this.hasHeaders) {
2921                 for (var prop in this.headers) {
2922                     if (this.headers.hasOwnProperty(prop)) {
2923                         o.conn.setRequestHeader(prop, this.headers[prop]);
2924                     }
2925                 }
2926                 this.headers = {};
2927                 this.hasHeaders = false;
2928             }
2929         },
2930
2931         resetDefaultHeaders:function() {
2932             delete this.defaultHeaders;
2933             this.defaultHeaders = {};
2934             this.hasDefaultHeaders = false;
2935         },
2936
2937         abort:function(o, callback, isTimeout)
2938         {
2939             if(this.isCallInProgress(o)) {
2940                 o.conn.abort();
2941                 window.clearInterval(this.poll[o.tId]);
2942                 delete this.poll[o.tId];
2943                 if (isTimeout) {
2944                     delete this.timeout[o.tId];
2945                 }
2946
2947                 this.handleTransactionResponse(o, callback, true);
2948
2949                 return true;
2950             }
2951             else {
2952                 return false;
2953             }
2954         },
2955
2956
2957         isCallInProgress:function(o)
2958         {
2959             if (o && o.conn) {
2960                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2961             }
2962             else {
2963
2964                 return false;
2965             }
2966         },
2967
2968
2969         releaseObject:function(o)
2970         {
2971
2972             o.conn = null;
2973
2974             o = null;
2975         },
2976
2977         activeX:[
2978         'MSXML2.XMLHTTP.3.0',
2979         'MSXML2.XMLHTTP',
2980         'Microsoft.XMLHTTP'
2981         ]
2982
2983
2984     };
2985 })();/*
2986  * Portions of this file are based on pieces of Yahoo User Interface Library
2987  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2988  * YUI licensed under the BSD License:
2989  * http://developer.yahoo.net/yui/license.txt
2990  * <script type="text/javascript">
2991  *
2992  */
2993
2994 Roo.lib.Region = function(t, r, b, l) {
2995     this.top = t;
2996     this[1] = t;
2997     this.right = r;
2998     this.bottom = b;
2999     this.left = l;
3000     this[0] = l;
3001 };
3002
3003
3004 Roo.lib.Region.prototype = {
3005     contains : function(region) {
3006         return ( region.left >= this.left &&
3007                  region.right <= this.right &&
3008                  region.top >= this.top &&
3009                  region.bottom <= this.bottom    );
3010
3011     },
3012
3013     getArea : function() {
3014         return ( (this.bottom - this.top) * (this.right - this.left) );
3015     },
3016
3017     intersect : function(region) {
3018         var t = Math.max(this.top, region.top);
3019         var r = Math.min(this.right, region.right);
3020         var b = Math.min(this.bottom, region.bottom);
3021         var l = Math.max(this.left, region.left);
3022
3023         if (b >= t && r >= l) {
3024             return new Roo.lib.Region(t, r, b, l);
3025         } else {
3026             return null;
3027         }
3028     },
3029     union : function(region) {
3030         var t = Math.min(this.top, region.top);
3031         var r = Math.max(this.right, region.right);
3032         var b = Math.max(this.bottom, region.bottom);
3033         var l = Math.min(this.left, region.left);
3034
3035         return new Roo.lib.Region(t, r, b, l);
3036     },
3037
3038     adjust : function(t, l, b, r) {
3039         this.top += t;
3040         this.left += l;
3041         this.right += r;
3042         this.bottom += b;
3043         return this;
3044     }
3045 };
3046
3047 Roo.lib.Region.getRegion = function(el) {
3048     var p = Roo.lib.Dom.getXY(el);
3049
3050     var t = p[1];
3051     var r = p[0] + el.offsetWidth;
3052     var b = p[1] + el.offsetHeight;
3053     var l = p[0];
3054
3055     return new Roo.lib.Region(t, r, b, l);
3056 };
3057 /*
3058  * Portions of this file are based on pieces of Yahoo User Interface Library
3059  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3060  * YUI licensed under the BSD License:
3061  * http://developer.yahoo.net/yui/license.txt
3062  * <script type="text/javascript">
3063  *
3064  */
3065 //@@dep Roo.lib.Region
3066
3067
3068 Roo.lib.Point = function(x, y) {
3069     if (x instanceof Array) {
3070         y = x[1];
3071         x = x[0];
3072     }
3073     this.x = this.right = this.left = this[0] = x;
3074     this.y = this.top = this.bottom = this[1] = y;
3075 };
3076
3077 Roo.lib.Point.prototype = new Roo.lib.Region();
3078 /*
3079  * Portions of this file are based on pieces of Yahoo User Interface Library
3080  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3081  * YUI licensed under the BSD License:
3082  * http://developer.yahoo.net/yui/license.txt
3083  * <script type="text/javascript">
3084  *
3085  */
3086  
3087 (function() {   
3088
3089     Roo.lib.Anim = {
3090         scroll : function(el, args, duration, easing, cb, scope) {
3091             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3092         },
3093
3094         motion : function(el, args, duration, easing, cb, scope) {
3095             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3096         },
3097
3098         color : function(el, args, duration, easing, cb, scope) {
3099             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3100         },
3101
3102         run : function(el, args, duration, easing, cb, scope, type) {
3103             type = type || Roo.lib.AnimBase;
3104             if (typeof easing == "string") {
3105                 easing = Roo.lib.Easing[easing];
3106             }
3107             var anim = new type(el, args, duration, easing);
3108             anim.animateX(function() {
3109                 Roo.callback(cb, scope);
3110             });
3111             return anim;
3112         }
3113     };
3114 })();/*
3115  * Portions of this file are based on pieces of Yahoo User Interface Library
3116  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3117  * YUI licensed under the BSD License:
3118  * http://developer.yahoo.net/yui/license.txt
3119  * <script type="text/javascript">
3120  *
3121  */
3122
3123 (function() {    
3124     var libFlyweight;
3125     
3126     function fly(el) {
3127         if (!libFlyweight) {
3128             libFlyweight = new Roo.Element.Flyweight();
3129         }
3130         libFlyweight.dom = el;
3131         return libFlyweight;
3132     }
3133
3134     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3135     
3136    
3137     
3138     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3139         if (el) {
3140             this.init(el, attributes, duration, method);
3141         }
3142     };
3143
3144     Roo.lib.AnimBase.fly = fly;
3145     
3146     
3147     
3148     Roo.lib.AnimBase.prototype = {
3149
3150         toString: function() {
3151             var el = this.getEl();
3152             var id = el.id || el.tagName;
3153             return ("Anim " + id);
3154         },
3155
3156         patterns: {
3157             noNegatives:        /width|height|opacity|padding/i,
3158             offsetAttribute:  /^((width|height)|(top|left))$/,
3159             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3160             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3161         },
3162
3163
3164         doMethod: function(attr, start, end) {
3165             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3166         },
3167
3168
3169         setAttribute: function(attr, val, unit) {
3170             if (this.patterns.noNegatives.test(attr)) {
3171                 val = (val > 0) ? val : 0;
3172             }
3173
3174             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3175         },
3176
3177
3178         getAttribute: function(attr) {
3179             var el = this.getEl();
3180             var val = fly(el).getStyle(attr);
3181
3182             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3183                 return parseFloat(val);
3184             }
3185
3186             var a = this.patterns.offsetAttribute.exec(attr) || [];
3187             var pos = !!( a[3] );
3188             var box = !!( a[2] );
3189
3190
3191             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3192                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3193             } else {
3194                 val = 0;
3195             }
3196
3197             return val;
3198         },
3199
3200
3201         getDefaultUnit: function(attr) {
3202             if (this.patterns.defaultUnit.test(attr)) {
3203                 return 'px';
3204             }
3205
3206             return '';
3207         },
3208
3209         animateX : function(callback, scope) {
3210             var f = function() {
3211                 this.onComplete.removeListener(f);
3212                 if (typeof callback == "function") {
3213                     callback.call(scope || this, this);
3214                 }
3215             };
3216             this.onComplete.addListener(f, this);
3217             this.animate();
3218         },
3219
3220
3221         setRuntimeAttribute: function(attr) {
3222             var start;
3223             var end;
3224             var attributes = this.attributes;
3225
3226             this.runtimeAttributes[attr] = {};
3227
3228             var isset = function(prop) {
3229                 return (typeof prop !== 'undefined');
3230             };
3231
3232             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3233                 return false;
3234             }
3235
3236             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3237
3238
3239             if (isset(attributes[attr]['to'])) {
3240                 end = attributes[attr]['to'];
3241             } else if (isset(attributes[attr]['by'])) {
3242                 if (start.constructor == Array) {
3243                     end = [];
3244                     for (var i = 0, len = start.length; i < len; ++i) {
3245                         end[i] = start[i] + attributes[attr]['by'][i];
3246                     }
3247                 } else {
3248                     end = start + attributes[attr]['by'];
3249                 }
3250             }
3251
3252             this.runtimeAttributes[attr].start = start;
3253             this.runtimeAttributes[attr].end = end;
3254
3255
3256             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3257         },
3258
3259
3260         init: function(el, attributes, duration, method) {
3261
3262             var isAnimated = false;
3263
3264
3265             var startTime = null;
3266
3267
3268             var actualFrames = 0;
3269
3270
3271             el = Roo.getDom(el);
3272
3273
3274             this.attributes = attributes || {};
3275
3276
3277             this.duration = duration || 1;
3278
3279
3280             this.method = method || Roo.lib.Easing.easeNone;
3281
3282
3283             this.useSeconds = true;
3284
3285
3286             this.currentFrame = 0;
3287
3288
3289             this.totalFrames = Roo.lib.AnimMgr.fps;
3290
3291
3292             this.getEl = function() {
3293                 return el;
3294             };
3295
3296
3297             this.isAnimated = function() {
3298                 return isAnimated;
3299             };
3300
3301
3302             this.getStartTime = function() {
3303                 return startTime;
3304             };
3305
3306             this.runtimeAttributes = {};
3307
3308
3309             this.animate = function() {
3310                 if (this.isAnimated()) {
3311                     return false;
3312                 }
3313
3314                 this.currentFrame = 0;
3315
3316                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3317
3318                 Roo.lib.AnimMgr.registerElement(this);
3319             };
3320
3321
3322             this.stop = function(finish) {
3323                 if (finish) {
3324                     this.currentFrame = this.totalFrames;
3325                     this._onTween.fire();
3326                 }
3327                 Roo.lib.AnimMgr.stop(this);
3328             };
3329
3330             var onStart = function() {
3331                 this.onStart.fire();
3332
3333                 this.runtimeAttributes = {};
3334                 for (var attr in this.attributes) {
3335                     this.setRuntimeAttribute(attr);
3336                 }
3337
3338                 isAnimated = true;
3339                 actualFrames = 0;
3340                 startTime = new Date();
3341             };
3342
3343
3344             var onTween = function() {
3345                 var data = {
3346                     duration: new Date() - this.getStartTime(),
3347                     currentFrame: this.currentFrame
3348                 };
3349
3350                 data.toString = function() {
3351                     return (
3352                             'duration: ' + data.duration +
3353                             ', currentFrame: ' + data.currentFrame
3354                             );
3355                 };
3356
3357                 this.onTween.fire(data);
3358
3359                 var runtimeAttributes = this.runtimeAttributes;
3360
3361                 for (var attr in runtimeAttributes) {
3362                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3363                 }
3364
3365                 actualFrames += 1;
3366             };
3367
3368             var onComplete = function() {
3369                 var actual_duration = (new Date() - startTime) / 1000 ;
3370
3371                 var data = {
3372                     duration: actual_duration,
3373                     frames: actualFrames,
3374                     fps: actualFrames / actual_duration
3375                 };
3376
3377                 data.toString = function() {
3378                     return (
3379                             'duration: ' + data.duration +
3380                             ', frames: ' + data.frames +
3381                             ', fps: ' + data.fps
3382                             );
3383                 };
3384
3385                 isAnimated = false;
3386                 actualFrames = 0;
3387                 this.onComplete.fire(data);
3388             };
3389
3390
3391             this._onStart = new Roo.util.Event(this);
3392             this.onStart = new Roo.util.Event(this);
3393             this.onTween = new Roo.util.Event(this);
3394             this._onTween = new Roo.util.Event(this);
3395             this.onComplete = new Roo.util.Event(this);
3396             this._onComplete = new Roo.util.Event(this);
3397             this._onStart.addListener(onStart);
3398             this._onTween.addListener(onTween);
3399             this._onComplete.addListener(onComplete);
3400         }
3401     };
3402 })();
3403 /*
3404  * Portions of this file are based on pieces of Yahoo User Interface Library
3405  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3406  * YUI licensed under the BSD License:
3407  * http://developer.yahoo.net/yui/license.txt
3408  * <script type="text/javascript">
3409  *
3410  */
3411
3412 Roo.lib.AnimMgr = new function() {
3413
3414         var thread = null;
3415
3416
3417         var queue = [];
3418
3419
3420         var tweenCount = 0;
3421
3422
3423         this.fps = 1000;
3424
3425
3426         this.delay = 1;
3427
3428
3429         this.registerElement = function(tween) {
3430             queue[queue.length] = tween;
3431             tweenCount += 1;
3432             tween._onStart.fire();
3433             this.start();
3434         };
3435
3436
3437         this.unRegister = function(tween, index) {
3438             tween._onComplete.fire();
3439             index = index || getIndex(tween);
3440             if (index != -1) {
3441                 queue.splice(index, 1);
3442             }
3443
3444             tweenCount -= 1;
3445             if (tweenCount <= 0) {
3446                 this.stop();
3447             }
3448         };
3449
3450
3451         this.start = function() {
3452             if (thread === null) {
3453                 thread = setInterval(this.run, this.delay);
3454             }
3455         };
3456
3457
3458         this.stop = function(tween) {
3459             if (!tween) {
3460                 clearInterval(thread);
3461
3462                 for (var i = 0, len = queue.length; i < len; ++i) {
3463                     if (queue[0].isAnimated()) {
3464                         this.unRegister(queue[0], 0);
3465                     }
3466                 }
3467
3468                 queue = [];
3469                 thread = null;
3470                 tweenCount = 0;
3471             }
3472             else {
3473                 this.unRegister(tween);
3474             }
3475         };
3476
3477
3478         this.run = function() {
3479             for (var i = 0, len = queue.length; i < len; ++i) {
3480                 var tween = queue[i];
3481                 if (!tween || !tween.isAnimated()) {
3482                     continue;
3483                 }
3484
3485                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3486                 {
3487                     tween.currentFrame += 1;
3488
3489                     if (tween.useSeconds) {
3490                         correctFrame(tween);
3491                     }
3492                     tween._onTween.fire();
3493                 }
3494                 else {
3495                     Roo.lib.AnimMgr.stop(tween, i);
3496                 }
3497             }
3498         };
3499
3500         var getIndex = function(anim) {
3501             for (var i = 0, len = queue.length; i < len; ++i) {
3502                 if (queue[i] == anim) {
3503                     return i;
3504                 }
3505             }
3506             return -1;
3507         };
3508
3509
3510         var correctFrame = function(tween) {
3511             var frames = tween.totalFrames;
3512             var frame = tween.currentFrame;
3513             var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3514             var elapsed = (new Date() - tween.getStartTime());
3515             var tweak = 0;
3516
3517             if (elapsed < tween.duration * 1000) {
3518                 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3519             } else {
3520                 tweak = frames - (frame + 1);
3521             }
3522             if (tweak > 0 && isFinite(tweak)) {
3523                 if (tween.currentFrame + tweak >= frames) {
3524                     tweak = frames - (frame + 1);
3525                 }
3526
3527                 tween.currentFrame += tweak;
3528             }
3529         };
3530     };/*
3531  * Portions of this file are based on pieces of Yahoo User Interface Library
3532  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3533  * YUI licensed under the BSD License:
3534  * http://developer.yahoo.net/yui/license.txt
3535  * <script type="text/javascript">
3536  *
3537  */
3538 Roo.lib.Bezier = new function() {
3539
3540         this.getPosition = function(points, t) {
3541             var n = points.length;
3542             var tmp = [];
3543
3544             for (var i = 0; i < n; ++i) {
3545                 tmp[i] = [points[i][0], points[i][1]];
3546             }
3547
3548             for (var j = 1; j < n; ++j) {
3549                 for (i = 0; i < n - j; ++i) {
3550                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3551                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3552                 }
3553             }
3554
3555             return [ tmp[0][0], tmp[0][1] ];
3556
3557         };
3558     };/*
3559  * Portions of this file are based on pieces of Yahoo User Interface Library
3560  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3561  * YUI licensed under the BSD License:
3562  * http://developer.yahoo.net/yui/license.txt
3563  * <script type="text/javascript">
3564  *
3565  */
3566 (function() {
3567
3568     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3569         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3570     };
3571
3572     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3573
3574     var fly = Roo.lib.AnimBase.fly;
3575     var Y = Roo.lib;
3576     var superclass = Y.ColorAnim.superclass;
3577     var proto = Y.ColorAnim.prototype;
3578
3579     proto.toString = function() {
3580         var el = this.getEl();
3581         var id = el.id || el.tagName;
3582         return ("ColorAnim " + id);
3583     };
3584
3585     proto.patterns.color = /color$/i;
3586     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3587     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3588     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3589     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3590
3591
3592     proto.parseColor = function(s) {
3593         if (s.length == 3) {
3594             return s;
3595         }
3596
3597         var c = this.patterns.hex.exec(s);
3598         if (c && c.length == 4) {
3599             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3600         }
3601
3602         c = this.patterns.rgb.exec(s);
3603         if (c && c.length == 4) {
3604             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3605         }
3606
3607         c = this.patterns.hex3.exec(s);
3608         if (c && c.length == 4) {
3609             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3610         }
3611
3612         return null;
3613     };
3614     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3615     proto.getAttribute = function(attr) {
3616         var el = this.getEl();
3617         if (this.patterns.color.test(attr)) {
3618             var val = fly(el).getStyle(attr);
3619
3620             if (this.patterns.transparent.test(val)) {
3621                 var parent = el.parentNode;
3622                 val = fly(parent).getStyle(attr);
3623
3624                 while (parent && this.patterns.transparent.test(val)) {
3625                     parent = parent.parentNode;
3626                     val = fly(parent).getStyle(attr);
3627                     if (parent.tagName.toUpperCase() == 'HTML') {
3628                         val = '#fff';
3629                     }
3630                 }
3631             }
3632         } else {
3633             val = superclass.getAttribute.call(this, attr);
3634         }
3635
3636         return val;
3637     };
3638     proto.getAttribute = function(attr) {
3639         var el = this.getEl();
3640         if (this.patterns.color.test(attr)) {
3641             var val = fly(el).getStyle(attr);
3642
3643             if (this.patterns.transparent.test(val)) {
3644                 var parent = el.parentNode;
3645                 val = fly(parent).getStyle(attr);
3646
3647                 while (parent && this.patterns.transparent.test(val)) {
3648                     parent = parent.parentNode;
3649                     val = fly(parent).getStyle(attr);
3650                     if (parent.tagName.toUpperCase() == 'HTML') {
3651                         val = '#fff';
3652                     }
3653                 }
3654             }
3655         } else {
3656             val = superclass.getAttribute.call(this, attr);
3657         }
3658
3659         return val;
3660     };
3661
3662     proto.doMethod = function(attr, start, end) {
3663         var val;
3664
3665         if (this.patterns.color.test(attr)) {
3666             val = [];
3667             for (var i = 0, len = start.length; i < len; ++i) {
3668                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3669             }
3670
3671             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3672         }
3673         else {
3674             val = superclass.doMethod.call(this, attr, start, end);
3675         }
3676
3677         return val;
3678     };
3679
3680     proto.setRuntimeAttribute = function(attr) {
3681         superclass.setRuntimeAttribute.call(this, attr);
3682
3683         if (this.patterns.color.test(attr)) {
3684             var attributes = this.attributes;
3685             var start = this.parseColor(this.runtimeAttributes[attr].start);
3686             var end = this.parseColor(this.runtimeAttributes[attr].end);
3687
3688             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3689                 end = this.parseColor(attributes[attr].by);
3690
3691                 for (var i = 0, len = start.length; i < len; ++i) {
3692                     end[i] = start[i] + end[i];
3693                 }
3694             }
3695
3696             this.runtimeAttributes[attr].start = start;
3697             this.runtimeAttributes[attr].end = end;
3698         }
3699     };
3700 })();
3701
3702 /*
3703  * Portions of this file are based on pieces of Yahoo User Interface Library
3704  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3705  * YUI licensed under the BSD License:
3706  * http://developer.yahoo.net/yui/license.txt
3707  * <script type="text/javascript">
3708  *
3709  */
3710 Roo.lib.Easing = {
3711
3712
3713     easeNone: function (t, b, c, d) {
3714         return c * t / d + b;
3715     },
3716
3717
3718     easeIn: function (t, b, c, d) {
3719         return c * (t /= d) * t + b;
3720     },
3721
3722
3723     easeOut: function (t, b, c, d) {
3724         return -c * (t /= d) * (t - 2) + b;
3725     },
3726
3727
3728     easeBoth: function (t, b, c, d) {
3729         if ((t /= d / 2) < 1) {
3730             return c / 2 * t * t + b;
3731         }
3732
3733         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3734     },
3735
3736
3737     easeInStrong: function (t, b, c, d) {
3738         return c * (t /= d) * t * t * t + b;
3739     },
3740
3741
3742     easeOutStrong: function (t, b, c, d) {
3743         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3744     },
3745
3746
3747     easeBothStrong: function (t, b, c, d) {
3748         if ((t /= d / 2) < 1) {
3749             return c / 2 * t * t * t * t + b;
3750         }
3751
3752         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3753     },
3754
3755
3756
3757     elasticIn: function (t, b, c, d, a, p) {
3758         if (t == 0) {
3759             return b;
3760         }
3761         if ((t /= d) == 1) {
3762             return b + c;
3763         }
3764         if (!p) {
3765             p = d * .3;
3766         }
3767
3768         if (!a || a < Math.abs(c)) {
3769             a = c;
3770             var s = p / 4;
3771         }
3772         else {
3773             var s = p / (2 * Math.PI) * Math.asin(c / a);
3774         }
3775
3776         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3777     },
3778
3779
3780     elasticOut: function (t, b, c, d, a, p) {
3781         if (t == 0) {
3782             return b;
3783         }
3784         if ((t /= d) == 1) {
3785             return b + c;
3786         }
3787         if (!p) {
3788             p = d * .3;
3789         }
3790
3791         if (!a || a < Math.abs(c)) {
3792             a = c;
3793             var s = p / 4;
3794         }
3795         else {
3796             var s = p / (2 * Math.PI) * Math.asin(c / a);
3797         }
3798
3799         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3800     },
3801
3802
3803     elasticBoth: function (t, b, c, d, a, p) {
3804         if (t == 0) {
3805             return b;
3806         }
3807
3808         if ((t /= d / 2) == 2) {
3809             return b + c;
3810         }
3811
3812         if (!p) {
3813             p = d * (.3 * 1.5);
3814         }
3815
3816         if (!a || a < Math.abs(c)) {
3817             a = c;
3818             var s = p / 4;
3819         }
3820         else {
3821             var s = p / (2 * Math.PI) * Math.asin(c / a);
3822         }
3823
3824         if (t < 1) {
3825             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3826                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3827         }
3828         return a * Math.pow(2, -10 * (t -= 1)) *
3829                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3830     },
3831
3832
3833
3834     backIn: function (t, b, c, d, s) {
3835         if (typeof s == 'undefined') {
3836             s = 1.70158;
3837         }
3838         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3839     },
3840
3841
3842     backOut: function (t, b, c, d, s) {
3843         if (typeof s == 'undefined') {
3844             s = 1.70158;
3845         }
3846         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3847     },
3848
3849
3850     backBoth: function (t, b, c, d, s) {
3851         if (typeof s == 'undefined') {
3852             s = 1.70158;
3853         }
3854
3855         if ((t /= d / 2 ) < 1) {
3856             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3857         }
3858         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3859     },
3860
3861
3862     bounceIn: function (t, b, c, d) {
3863         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3864     },
3865
3866
3867     bounceOut: function (t, b, c, d) {
3868         if ((t /= d) < (1 / 2.75)) {
3869             return c * (7.5625 * t * t) + b;
3870         } else if (t < (2 / 2.75)) {
3871             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3872         } else if (t < (2.5 / 2.75)) {
3873             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3874         }
3875         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3876     },
3877
3878
3879     bounceBoth: function (t, b, c, d) {
3880         if (t < d / 2) {
3881             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3882         }
3883         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3884     }
3885 };/*
3886  * Portions of this file are based on pieces of Yahoo User Interface Library
3887  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3888  * YUI licensed under the BSD License:
3889  * http://developer.yahoo.net/yui/license.txt
3890  * <script type="text/javascript">
3891  *
3892  */
3893     (function() {
3894         Roo.lib.Motion = function(el, attributes, duration, method) {
3895             if (el) {
3896                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3897             }
3898         };
3899
3900         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3901
3902
3903         var Y = Roo.lib;
3904         var superclass = Y.Motion.superclass;
3905         var proto = Y.Motion.prototype;
3906
3907         proto.toString = function() {
3908             var el = this.getEl();
3909             var id = el.id || el.tagName;
3910             return ("Motion " + id);
3911         };
3912
3913         proto.patterns.points = /^points$/i;
3914
3915         proto.setAttribute = function(attr, val, unit) {
3916             if (this.patterns.points.test(attr)) {
3917                 unit = unit || 'px';
3918                 superclass.setAttribute.call(this, 'left', val[0], unit);
3919                 superclass.setAttribute.call(this, 'top', val[1], unit);
3920             } else {
3921                 superclass.setAttribute.call(this, attr, val, unit);
3922             }
3923         };
3924
3925         proto.getAttribute = function(attr) {
3926             if (this.patterns.points.test(attr)) {
3927                 var val = [
3928                         superclass.getAttribute.call(this, 'left'),
3929                         superclass.getAttribute.call(this, 'top')
3930                         ];
3931             } else {
3932                 val = superclass.getAttribute.call(this, attr);
3933             }
3934
3935             return val;
3936         };
3937
3938         proto.doMethod = function(attr, start, end) {
3939             var val = null;
3940
3941             if (this.patterns.points.test(attr)) {
3942                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3943                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3944             } else {
3945                 val = superclass.doMethod.call(this, attr, start, end);
3946             }
3947             return val;
3948         };
3949
3950         proto.setRuntimeAttribute = function(attr) {
3951             if (this.patterns.points.test(attr)) {
3952                 var el = this.getEl();
3953                 var attributes = this.attributes;
3954                 var start;
3955                 var control = attributes['points']['control'] || [];
3956                 var end;
3957                 var i, len;
3958
3959                 if (control.length > 0 && !(control[0] instanceof Array)) {
3960                     control = [control];
3961                 } else {
3962                     var tmp = [];
3963                     for (i = 0,len = control.length; i < len; ++i) {
3964                         tmp[i] = control[i];
3965                     }
3966                     control = tmp;
3967                 }
3968
3969                 Roo.fly(el).position();
3970
3971                 if (isset(attributes['points']['from'])) {
3972                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3973                 }
3974                 else {
3975                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3976                 }
3977
3978                 start = this.getAttribute('points');
3979
3980
3981                 if (isset(attributes['points']['to'])) {
3982                     end = translateValues.call(this, attributes['points']['to'], start);
3983
3984                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3985                     for (i = 0,len = control.length; i < len; ++i) {
3986                         control[i] = translateValues.call(this, control[i], start);
3987                     }
3988
3989
3990                 } else if (isset(attributes['points']['by'])) {
3991                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3992
3993                     for (i = 0,len = control.length; i < len; ++i) {
3994                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3995                     }
3996                 }
3997
3998                 this.runtimeAttributes[attr] = [start];
3999
4000                 if (control.length > 0) {
4001                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4002                 }
4003
4004                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4005             }
4006             else {
4007                 superclass.setRuntimeAttribute.call(this, attr);
4008             }
4009         };
4010
4011         var translateValues = function(val, start) {
4012             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4013             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4014
4015             return val;
4016         };
4017
4018         var isset = function(prop) {
4019             return (typeof prop !== 'undefined');
4020         };
4021     })();
4022 /*
4023  * Portions of this file are based on pieces of Yahoo User Interface Library
4024  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4025  * YUI licensed under the BSD License:
4026  * http://developer.yahoo.net/yui/license.txt
4027  * <script type="text/javascript">
4028  *
4029  */
4030     (function() {
4031         Roo.lib.Scroll = function(el, attributes, duration, method) {
4032             if (el) {
4033                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4034             }
4035         };
4036
4037         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4038
4039
4040         var Y = Roo.lib;
4041         var superclass = Y.Scroll.superclass;
4042         var proto = Y.Scroll.prototype;
4043
4044         proto.toString = function() {
4045             var el = this.getEl();
4046             var id = el.id || el.tagName;
4047             return ("Scroll " + id);
4048         };
4049
4050         proto.doMethod = function(attr, start, end) {
4051             var val = null;
4052
4053             if (attr == 'scroll') {
4054                 val = [
4055                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4056                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4057                         ];
4058
4059             } else {
4060                 val = superclass.doMethod.call(this, attr, start, end);
4061             }
4062             return val;
4063         };
4064
4065         proto.getAttribute = function(attr) {
4066             var val = null;
4067             var el = this.getEl();
4068
4069             if (attr == 'scroll') {
4070                 val = [ el.scrollLeft, el.scrollTop ];
4071             } else {
4072                 val = superclass.getAttribute.call(this, attr);
4073             }
4074
4075             return val;
4076         };
4077
4078         proto.setAttribute = function(attr, val, unit) {
4079             var el = this.getEl();
4080
4081             if (attr == 'scroll') {
4082                 el.scrollLeft = val[0];
4083                 el.scrollTop = val[1];
4084             } else {
4085                 superclass.setAttribute.call(this, attr, val, unit);
4086             }
4087         };
4088     })();
4089 /*
4090  * Based on:
4091  * Ext JS Library 1.1.1
4092  * Copyright(c) 2006-2007, Ext JS, LLC.
4093  *
4094  * Originally Released Under LGPL - original licence link has changed is not relivant.
4095  *
4096  * Fork - LGPL
4097  * <script type="text/javascript">
4098  */
4099
4100
4101 // nasty IE9 hack - what a pile of crap that is..
4102
4103  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4104     Range.prototype.createContextualFragment = function (html) {
4105         var doc = window.document;
4106         var container = doc.createElement("div");
4107         container.innerHTML = html;
4108         var frag = doc.createDocumentFragment(), n;
4109         while ((n = container.firstChild)) {
4110             frag.appendChild(n);
4111         }
4112         return frag;
4113     };
4114 }
4115
4116 /**
4117  * @class Roo.DomHelper
4118  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4119  * 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>.
4120  * @singleton
4121  */
4122 Roo.DomHelper = function(){
4123     var tempTableEl = null;
4124     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4125     var tableRe = /^table|tbody|tr|td$/i;
4126     var xmlns = {};
4127     // build as innerHTML where available
4128     /** @ignore */
4129     var createHtml = function(o){
4130         if(typeof o == 'string'){
4131             return o;
4132         }
4133         var b = "";
4134         if(!o.tag){
4135             o.tag = "div";
4136         }
4137         b += "<" + o.tag;
4138         for(var attr in o){
4139             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4140             if(attr == "style"){
4141                 var s = o["style"];
4142                 if(typeof s == "function"){
4143                     s = s.call();
4144                 }
4145                 if(typeof s == "string"){
4146                     b += ' style="' + s + '"';
4147                 }else if(typeof s == "object"){
4148                     b += ' style="';
4149                     for(var key in s){
4150                         if(typeof s[key] != "function"){
4151                             b += key + ":" + s[key] + ";";
4152                         }
4153                     }
4154                     b += '"';
4155                 }
4156             }else{
4157                 if(attr == "cls"){
4158                     b += ' class="' + o["cls"] + '"';
4159                 }else if(attr == "htmlFor"){
4160                     b += ' for="' + o["htmlFor"] + '"';
4161                 }else{
4162                     b += " " + attr + '="' + o[attr] + '"';
4163                 }
4164             }
4165         }
4166         if(emptyTags.test(o.tag)){
4167             b += "/>";
4168         }else{
4169             b += ">";
4170             var cn = o.children || o.cn;
4171             if(cn){
4172                 //http://bugs.kde.org/show_bug.cgi?id=71506
4173                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4174                     for(var i = 0, len = cn.length; i < len; i++) {
4175                         b += createHtml(cn[i], b);
4176                     }
4177                 }else{
4178                     b += createHtml(cn, b);
4179                 }
4180             }
4181             if(o.html){
4182                 b += o.html;
4183             }
4184             b += "</" + o.tag + ">";
4185         }
4186         return b;
4187     };
4188
4189     // build as dom
4190     /** @ignore */
4191     var createDom = function(o, parentNode){
4192          
4193         // defininition craeted..
4194         var ns = false;
4195         if (o.ns && o.ns != 'html') {
4196                
4197             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4198                 xmlns[o.ns] = o.xmlns;
4199                 ns = o.xmlns;
4200             }
4201             if (typeof(xmlns[o.ns]) == 'undefined') {
4202                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4203             }
4204             ns = xmlns[o.ns];
4205         }
4206         
4207         
4208         if (typeof(o) == 'string') {
4209             return parentNode.appendChild(document.createTextNode(o));
4210         }
4211         o.tag = o.tag || div;
4212         if (o.ns && Roo.isIE) {
4213             ns = false;
4214             o.tag = o.ns + ':' + o.tag;
4215             
4216         }
4217         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4218         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4219         for(var attr in o){
4220             
4221             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4222                     attr == "style" || typeof o[attr] == "function") continue;
4223                     
4224             if(attr=="cls" && Roo.isIE){
4225                 el.className = o["cls"];
4226             }else{
4227                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4228                 else el[attr] = o[attr];
4229             }
4230         }
4231         Roo.DomHelper.applyStyles(el, o.style);
4232         var cn = o.children || o.cn;
4233         if(cn){
4234             //http://bugs.kde.org/show_bug.cgi?id=71506
4235              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4236                 for(var i = 0, len = cn.length; i < len; i++) {
4237                     createDom(cn[i], el);
4238                 }
4239             }else{
4240                 createDom(cn, el);
4241             }
4242         }
4243         if(o.html){
4244             el.innerHTML = o.html;
4245         }
4246         if(parentNode){
4247            parentNode.appendChild(el);
4248         }
4249         return el;
4250     };
4251
4252     var ieTable = function(depth, s, h, e){
4253         tempTableEl.innerHTML = [s, h, e].join('');
4254         var i = -1, el = tempTableEl;
4255         while(++i < depth){
4256             el = el.firstChild;
4257         }
4258         return el;
4259     };
4260
4261     // kill repeat to save bytes
4262     var ts = '<table>',
4263         te = '</table>',
4264         tbs = ts+'<tbody>',
4265         tbe = '</tbody>'+te,
4266         trs = tbs + '<tr>',
4267         tre = '</tr>'+tbe;
4268
4269     /**
4270      * @ignore
4271      * Nasty code for IE's broken table implementation
4272      */
4273     var insertIntoTable = function(tag, where, el, html){
4274         if(!tempTableEl){
4275             tempTableEl = document.createElement('div');
4276         }
4277         var node;
4278         var before = null;
4279         if(tag == 'td'){
4280             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4281                 return;
4282             }
4283             if(where == 'beforebegin'){
4284                 before = el;
4285                 el = el.parentNode;
4286             } else{
4287                 before = el.nextSibling;
4288                 el = el.parentNode;
4289             }
4290             node = ieTable(4, trs, html, tre);
4291         }
4292         else if(tag == 'tr'){
4293             if(where == 'beforebegin'){
4294                 before = el;
4295                 el = el.parentNode;
4296                 node = ieTable(3, tbs, html, tbe);
4297             } else if(where == 'afterend'){
4298                 before = el.nextSibling;
4299                 el = el.parentNode;
4300                 node = ieTable(3, tbs, html, tbe);
4301             } else{ // INTO a TR
4302                 if(where == 'afterbegin'){
4303                     before = el.firstChild;
4304                 }
4305                 node = ieTable(4, trs, html, tre);
4306             }
4307         } else if(tag == 'tbody'){
4308             if(where == 'beforebegin'){
4309                 before = el;
4310                 el = el.parentNode;
4311                 node = ieTable(2, ts, html, te);
4312             } else if(where == 'afterend'){
4313                 before = el.nextSibling;
4314                 el = el.parentNode;
4315                 node = ieTable(2, ts, html, te);
4316             } else{
4317                 if(where == 'afterbegin'){
4318                     before = el.firstChild;
4319                 }
4320                 node = ieTable(3, tbs, html, tbe);
4321             }
4322         } else{ // TABLE
4323             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4324                 return;
4325             }
4326             if(where == 'afterbegin'){
4327                 before = el.firstChild;
4328             }
4329             node = ieTable(2, ts, html, te);
4330         }
4331         el.insertBefore(node, before);
4332         return node;
4333     };
4334
4335     return {
4336     /** True to force the use of DOM instead of html fragments @type Boolean */
4337     useDom : false,
4338
4339     /**
4340      * Returns the markup for the passed Element(s) config
4341      * @param {Object} o The Dom object spec (and children)
4342      * @return {String}
4343      */
4344     markup : function(o){
4345         return createHtml(o);
4346     },
4347
4348     /**
4349      * Applies a style specification to an element
4350      * @param {String/HTMLElement} el The element to apply styles to
4351      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4352      * a function which returns such a specification.
4353      */
4354     applyStyles : function(el, styles){
4355         if(styles){
4356            el = Roo.fly(el);
4357            if(typeof styles == "string"){
4358                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4359                var matches;
4360                while ((matches = re.exec(styles)) != null){
4361                    el.setStyle(matches[1], matches[2]);
4362                }
4363            }else if (typeof styles == "object"){
4364                for (var style in styles){
4365                   el.setStyle(style, styles[style]);
4366                }
4367            }else if (typeof styles == "function"){
4368                 Roo.DomHelper.applyStyles(el, styles.call());
4369            }
4370         }
4371     },
4372
4373     /**
4374      * Inserts an HTML fragment into the Dom
4375      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4376      * @param {HTMLElement} el The context element
4377      * @param {String} html The HTML fragmenet
4378      * @return {HTMLElement} The new node
4379      */
4380     insertHtml : function(where, el, html){
4381         where = where.toLowerCase();
4382         if(el.insertAdjacentHTML){
4383             if(tableRe.test(el.tagName)){
4384                 var rs;
4385                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4386                     return rs;
4387                 }
4388             }
4389             switch(where){
4390                 case "beforebegin":
4391                     el.insertAdjacentHTML('BeforeBegin', html);
4392                     return el.previousSibling;
4393                 case "afterbegin":
4394                     el.insertAdjacentHTML('AfterBegin', html);
4395                     return el.firstChild;
4396                 case "beforeend":
4397                     el.insertAdjacentHTML('BeforeEnd', html);
4398                     return el.lastChild;
4399                 case "afterend":
4400                     el.insertAdjacentHTML('AfterEnd', html);
4401                     return el.nextSibling;
4402             }
4403             throw 'Illegal insertion point -> "' + where + '"';
4404         }
4405         var range = el.ownerDocument.createRange();
4406         var frag;
4407         switch(where){
4408              case "beforebegin":
4409                 range.setStartBefore(el);
4410                 frag = range.createContextualFragment(html);
4411                 el.parentNode.insertBefore(frag, el);
4412                 return el.previousSibling;
4413              case "afterbegin":
4414                 if(el.firstChild){
4415                     range.setStartBefore(el.firstChild);
4416                     frag = range.createContextualFragment(html);
4417                     el.insertBefore(frag, el.firstChild);
4418                     return el.firstChild;
4419                 }else{
4420                     el.innerHTML = html;
4421                     return el.firstChild;
4422                 }
4423             case "beforeend":
4424                 if(el.lastChild){
4425                     range.setStartAfter(el.lastChild);
4426                     frag = range.createContextualFragment(html);
4427                     el.appendChild(frag);
4428                     return el.lastChild;
4429                 }else{
4430                     el.innerHTML = html;
4431                     return el.lastChild;
4432                 }
4433             case "afterend":
4434                 range.setStartAfter(el);
4435                 frag = range.createContextualFragment(html);
4436                 el.parentNode.insertBefore(frag, el.nextSibling);
4437                 return el.nextSibling;
4438             }
4439             throw 'Illegal insertion point -> "' + where + '"';
4440     },
4441
4442     /**
4443      * Creates new Dom element(s) and inserts them before el
4444      * @param {String/HTMLElement/Element} el The context element
4445      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4446      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4447      * @return {HTMLElement/Roo.Element} The new node
4448      */
4449     insertBefore : function(el, o, returnElement){
4450         return this.doInsert(el, o, returnElement, "beforeBegin");
4451     },
4452
4453     /**
4454      * Creates new Dom element(s) and inserts them after el
4455      * @param {String/HTMLElement/Element} el The context element
4456      * @param {Object} o The Dom object spec (and children)
4457      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4458      * @return {HTMLElement/Roo.Element} The new node
4459      */
4460     insertAfter : function(el, o, returnElement){
4461         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4462     },
4463
4464     /**
4465      * Creates new Dom element(s) and inserts them as the first child of el
4466      * @param {String/HTMLElement/Element} el The context element
4467      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4468      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4469      * @return {HTMLElement/Roo.Element} The new node
4470      */
4471     insertFirst : function(el, o, returnElement){
4472         return this.doInsert(el, o, returnElement, "afterBegin");
4473     },
4474
4475     // private
4476     doInsert : function(el, o, returnElement, pos, sibling){
4477         el = Roo.getDom(el);
4478         var newNode;
4479         if(this.useDom || o.ns){
4480             newNode = createDom(o, null);
4481             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4482         }else{
4483             var html = createHtml(o);
4484             newNode = this.insertHtml(pos, el, html);
4485         }
4486         return returnElement ? Roo.get(newNode, true) : newNode;
4487     },
4488
4489     /**
4490      * Creates new Dom element(s) and appends them to el
4491      * @param {String/HTMLElement/Element} el The context element
4492      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4493      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4494      * @return {HTMLElement/Roo.Element} The new node
4495      */
4496     append : function(el, o, returnElement){
4497         el = Roo.getDom(el);
4498         var newNode;
4499         if(this.useDom || o.ns){
4500             newNode = createDom(o, null);
4501             el.appendChild(newNode);
4502         }else{
4503             var html = createHtml(o);
4504             newNode = this.insertHtml("beforeEnd", el, html);
4505         }
4506         return returnElement ? Roo.get(newNode, true) : newNode;
4507     },
4508
4509     /**
4510      * Creates new Dom element(s) and overwrites the contents of el with them
4511      * @param {String/HTMLElement/Element} el The context element
4512      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4513      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4514      * @return {HTMLElement/Roo.Element} The new node
4515      */
4516     overwrite : function(el, o, returnElement){
4517         el = Roo.getDom(el);
4518         if (o.ns) {
4519           
4520             while (el.childNodes.length) {
4521                 el.removeChild(el.firstChild);
4522             }
4523             createDom(o, el);
4524         } else {
4525             el.innerHTML = createHtml(o);   
4526         }
4527         
4528         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4529     },
4530
4531     /**
4532      * Creates a new Roo.DomHelper.Template from the Dom object spec
4533      * @param {Object} o The Dom object spec (and children)
4534      * @return {Roo.DomHelper.Template} The new template
4535      */
4536     createTemplate : function(o){
4537         var html = createHtml(o);
4538         return new Roo.Template(html);
4539     }
4540     };
4541 }();
4542 /*
4543  * Based on:
4544  * Ext JS Library 1.1.1
4545  * Copyright(c) 2006-2007, Ext JS, LLC.
4546  *
4547  * Originally Released Under LGPL - original licence link has changed is not relivant.
4548  *
4549  * Fork - LGPL
4550  * <script type="text/javascript">
4551  */
4552  
4553 /**
4554 * @class Roo.Template
4555 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4556 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4557 * Usage:
4558 <pre><code>
4559 var t = new Roo.Template({
4560     html :  '&lt;div name="{id}"&gt;' + 
4561         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4562         '&lt;/div&gt;',
4563     myformat: function (value, allValues) {
4564         return 'XX' + value;
4565     }
4566 });
4567 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4568 </code></pre>
4569 * For more information see this blog post with examples:
4570 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4571      - Create Elements using DOM, HTML fragments and Templates</a>. 
4572 * @constructor
4573 * @param {Object} cfg - Configuration object.
4574 */
4575 Roo.Template = function(cfg){
4576     // BC!
4577     if(cfg instanceof Array){
4578         cfg = cfg.join("");
4579     }else if(arguments.length > 1){
4580         cfg = Array.prototype.join.call(arguments, "");
4581     }
4582     
4583     
4584     if (typeof(cfg) == 'object') {
4585         Roo.apply(this,cfg)
4586     } else {
4587         // bc
4588         this.html = cfg;
4589     }
4590     if (this.url) {
4591         this.load();
4592     }
4593     
4594 };
4595 Roo.Template.prototype = {
4596     
4597     /**
4598      * @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..
4599      *                    it should be fixed so that template is observable...
4600      */
4601     url : false,
4602     /**
4603      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4604      */
4605     html : '',
4606     /**
4607      * Returns an HTML fragment of this template with the specified values applied.
4608      * @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'})
4609      * @return {String} The HTML fragment
4610      */
4611     applyTemplate : function(values){
4612         try {
4613            
4614             if(this.compiled){
4615                 return this.compiled(values);
4616             }
4617             var useF = this.disableFormats !== true;
4618             var fm = Roo.util.Format, tpl = this;
4619             var fn = function(m, name, format, args){
4620                 if(format && useF){
4621                     if(format.substr(0, 5) == "this."){
4622                         return tpl.call(format.substr(5), values[name], values);
4623                     }else{
4624                         if(args){
4625                             // quoted values are required for strings in compiled templates, 
4626                             // but for non compiled we need to strip them
4627                             // quoted reversed for jsmin
4628                             var re = /^\s*['"](.*)["']\s*$/;
4629                             args = args.split(',');
4630                             for(var i = 0, len = args.length; i < len; i++){
4631                                 args[i] = args[i].replace(re, "$1");
4632                             }
4633                             args = [values[name]].concat(args);
4634                         }else{
4635                             args = [values[name]];
4636                         }
4637                         return fm[format].apply(fm, args);
4638                     }
4639                 }else{
4640                     return values[name] !== undefined ? values[name] : "";
4641                 }
4642             };
4643             return this.html.replace(this.re, fn);
4644         } catch (e) {
4645             Roo.log(e);
4646             throw e;
4647         }
4648          
4649     },
4650     
4651     loading : false,
4652       
4653     load : function ()
4654     {
4655          
4656         if (this.loading) {
4657             return;
4658         }
4659         var _t = this;
4660         
4661         this.loading = true;
4662         this.compiled = false;
4663         
4664         var cx = new Roo.data.Connection();
4665         cx.request({
4666             url : this.url,
4667             method : 'GET',
4668             success : function (response) {
4669                 _t.loading = false;
4670                 _t.html = response.responseText;
4671                 _t.url = false;
4672                 _t.compile();
4673              },
4674             failure : function(response) {
4675                 Roo.log("Template failed to load from " + _t.url);
4676                 _t.loading = false;
4677             }
4678         });
4679     },
4680
4681     /**
4682      * Sets the HTML used as the template and optionally compiles it.
4683      * @param {String} html
4684      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4685      * @return {Roo.Template} this
4686      */
4687     set : function(html, compile){
4688         this.html = html;
4689         this.compiled = null;
4690         if(compile){
4691             this.compile();
4692         }
4693         return this;
4694     },
4695     
4696     /**
4697      * True to disable format functions (defaults to false)
4698      * @type Boolean
4699      */
4700     disableFormats : false,
4701     
4702     /**
4703     * The regular expression used to match template variables 
4704     * @type RegExp
4705     * @property 
4706     */
4707     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4708     
4709     /**
4710      * Compiles the template into an internal function, eliminating the RegEx overhead.
4711      * @return {Roo.Template} this
4712      */
4713     compile : function(){
4714         var fm = Roo.util.Format;
4715         var useF = this.disableFormats !== true;
4716         var sep = Roo.isGecko ? "+" : ",";
4717         var fn = function(m, name, format, args){
4718             if(format && useF){
4719                 args = args ? ',' + args : "";
4720                 if(format.substr(0, 5) != "this."){
4721                     format = "fm." + format + '(';
4722                 }else{
4723                     format = 'this.call("'+ format.substr(5) + '", ';
4724                     args = ", values";
4725                 }
4726             }else{
4727                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4728             }
4729             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4730         };
4731         var body;
4732         // branched to use + in gecko and [].join() in others
4733         if(Roo.isGecko){
4734             body = "this.compiled = function(values){ return '" +
4735                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4736                     "';};";
4737         }else{
4738             body = ["this.compiled = function(values){ return ['"];
4739             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4740             body.push("'].join('');};");
4741             body = body.join('');
4742         }
4743         /**
4744          * eval:var:values
4745          * eval:var:fm
4746          */
4747         eval(body);
4748         return this;
4749     },
4750     
4751     // private function used to call members
4752     call : function(fnName, value, allValues){
4753         return this[fnName](value, allValues);
4754     },
4755     
4756     /**
4757      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4758      * @param {String/HTMLElement/Roo.Element} el The context element
4759      * @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'})
4760      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4761      * @return {HTMLElement/Roo.Element} The new node or Element
4762      */
4763     insertFirst: function(el, values, returnElement){
4764         return this.doInsert('afterBegin', el, values, returnElement);
4765     },
4766
4767     /**
4768      * Applies the supplied values to the template and inserts the new node(s) before el.
4769      * @param {String/HTMLElement/Roo.Element} el The context element
4770      * @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'})
4771      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4772      * @return {HTMLElement/Roo.Element} The new node or Element
4773      */
4774     insertBefore: function(el, values, returnElement){
4775         return this.doInsert('beforeBegin', el, values, returnElement);
4776     },
4777
4778     /**
4779      * Applies the supplied values to the template and inserts the new node(s) after el.
4780      * @param {String/HTMLElement/Roo.Element} el The context element
4781      * @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'})
4782      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4783      * @return {HTMLElement/Roo.Element} The new node or Element
4784      */
4785     insertAfter : function(el, values, returnElement){
4786         return this.doInsert('afterEnd', el, values, returnElement);
4787     },
4788     
4789     /**
4790      * Applies the supplied values to the template and appends the new node(s) to el.
4791      * @param {String/HTMLElement/Roo.Element} el The context element
4792      * @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'})
4793      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4794      * @return {HTMLElement/Roo.Element} The new node or Element
4795      */
4796     append : function(el, values, returnElement){
4797         return this.doInsert('beforeEnd', el, values, returnElement);
4798     },
4799
4800     doInsert : function(where, el, values, returnEl){
4801         el = Roo.getDom(el);
4802         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4803         return returnEl ? Roo.get(newNode, true) : newNode;
4804     },
4805
4806     /**
4807      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4808      * @param {String/HTMLElement/Roo.Element} el The context element
4809      * @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'})
4810      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4811      * @return {HTMLElement/Roo.Element} The new node or Element
4812      */
4813     overwrite : function(el, values, returnElement){
4814         el = Roo.getDom(el);
4815         el.innerHTML = this.applyTemplate(values);
4816         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4817     }
4818 };
4819 /**
4820  * Alias for {@link #applyTemplate}
4821  * @method
4822  */
4823 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4824
4825 // backwards compat
4826 Roo.DomHelper.Template = Roo.Template;
4827
4828 /**
4829  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4830  * @param {String/HTMLElement} el A DOM element or its id
4831  * @returns {Roo.Template} The created template
4832  * @static
4833  */
4834 Roo.Template.from = function(el){
4835     el = Roo.getDom(el);
4836     return new Roo.Template(el.value || el.innerHTML);
4837 };/*
4838  * Based on:
4839  * Ext JS Library 1.1.1
4840  * Copyright(c) 2006-2007, Ext JS, LLC.
4841  *
4842  * Originally Released Under LGPL - original licence link has changed is not relivant.
4843  *
4844  * Fork - LGPL
4845  * <script type="text/javascript">
4846  */
4847  
4848
4849 /*
4850  * This is code is also distributed under MIT license for use
4851  * with jQuery and prototype JavaScript libraries.
4852  */
4853 /**
4854  * @class Roo.DomQuery
4855 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).
4856 <p>
4857 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>
4858
4859 <p>
4860 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.
4861 </p>
4862 <h4>Element Selectors:</h4>
4863 <ul class="list">
4864     <li> <b>*</b> any element</li>
4865     <li> <b>E</b> an element with the tag E</li>
4866     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4867     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4868     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4869     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4870 </ul>
4871 <h4>Attribute Selectors:</h4>
4872 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4873 <ul class="list">
4874     <li> <b>E[foo]</b> has an attribute "foo"</li>
4875     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4876     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4877     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4878     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4879     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4880     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4881 </ul>
4882 <h4>Pseudo Classes:</h4>
4883 <ul class="list">
4884     <li> <b>E:first-child</b> E is the first child of its parent</li>
4885     <li> <b>E:last-child</b> E is the last child of its parent</li>
4886     <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>
4887     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4888     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4889     <li> <b>E:only-child</b> E is the only child of its parent</li>
4890     <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>
4891     <li> <b>E:first</b> the first E in the resultset</li>
4892     <li> <b>E:last</b> the last E in the resultset</li>
4893     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4894     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4895     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4896     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4897     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4898     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4899     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4900     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4901     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4902 </ul>
4903 <h4>CSS Value Selectors:</h4>
4904 <ul class="list">
4905     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4906     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4907     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4908     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4909     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4910     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4911 </ul>
4912  * @singleton
4913  */
4914 Roo.DomQuery = function(){
4915     var cache = {}, simpleCache = {}, valueCache = {};
4916     var nonSpace = /\S/;
4917     var trimRe = /^\s+|\s+$/g;
4918     var tplRe = /\{(\d+)\}/g;
4919     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4920     var tagTokenRe = /^(#)?([\w-\*]+)/;
4921     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4922
4923     function child(p, index){
4924         var i = 0;
4925         var n = p.firstChild;
4926         while(n){
4927             if(n.nodeType == 1){
4928                if(++i == index){
4929                    return n;
4930                }
4931             }
4932             n = n.nextSibling;
4933         }
4934         return null;
4935     };
4936
4937     function next(n){
4938         while((n = n.nextSibling) && n.nodeType != 1);
4939         return n;
4940     };
4941
4942     function prev(n){
4943         while((n = n.previousSibling) && n.nodeType != 1);
4944         return n;
4945     };
4946
4947     function children(d){
4948         var n = d.firstChild, ni = -1;
4949             while(n){
4950                 var nx = n.nextSibling;
4951                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4952                     d.removeChild(n);
4953                 }else{
4954                     n.nodeIndex = ++ni;
4955                 }
4956                 n = nx;
4957             }
4958             return this;
4959         };
4960
4961     function byClassName(c, a, v){
4962         if(!v){
4963             return c;
4964         }
4965         var r = [], ri = -1, cn;
4966         for(var i = 0, ci; ci = c[i]; i++){
4967             if((' '+ci.className+' ').indexOf(v) != -1){
4968                 r[++ri] = ci;
4969             }
4970         }
4971         return r;
4972     };
4973
4974     function attrValue(n, attr){
4975         if(!n.tagName && typeof n.length != "undefined"){
4976             n = n[0];
4977         }
4978         if(!n){
4979             return null;
4980         }
4981         if(attr == "for"){
4982             return n.htmlFor;
4983         }
4984         if(attr == "class" || attr == "className"){
4985             return n.className;
4986         }
4987         return n.getAttribute(attr) || n[attr];
4988
4989     };
4990
4991     function getNodes(ns, mode, tagName){
4992         var result = [], ri = -1, cs;
4993         if(!ns){
4994             return result;
4995         }
4996         tagName = tagName || "*";
4997         if(typeof ns.getElementsByTagName != "undefined"){
4998             ns = [ns];
4999         }
5000         if(!mode){
5001             for(var i = 0, ni; ni = ns[i]; i++){
5002                 cs = ni.getElementsByTagName(tagName);
5003                 for(var j = 0, ci; ci = cs[j]; j++){
5004                     result[++ri] = ci;
5005                 }
5006             }
5007         }else if(mode == "/" || mode == ">"){
5008             var utag = tagName.toUpperCase();
5009             for(var i = 0, ni, cn; ni = ns[i]; i++){
5010                 cn = ni.children || ni.childNodes;
5011                 for(var j = 0, cj; cj = cn[j]; j++){
5012                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5013                         result[++ri] = cj;
5014                     }
5015                 }
5016             }
5017         }else if(mode == "+"){
5018             var utag = tagName.toUpperCase();
5019             for(var i = 0, n; n = ns[i]; i++){
5020                 while((n = n.nextSibling) && n.nodeType != 1);
5021                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5022                     result[++ri] = n;
5023                 }
5024             }
5025         }else if(mode == "~"){
5026             for(var i = 0, n; n = ns[i]; i++){
5027                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5028                 if(n){
5029                     result[++ri] = n;
5030                 }
5031             }
5032         }
5033         return result;
5034     };
5035
5036     function concat(a, b){
5037         if(b.slice){
5038             return a.concat(b);
5039         }
5040         for(var i = 0, l = b.length; i < l; i++){
5041             a[a.length] = b[i];
5042         }
5043         return a;
5044     }
5045
5046     function byTag(cs, tagName){
5047         if(cs.tagName || cs == document){
5048             cs = [cs];
5049         }
5050         if(!tagName){
5051             return cs;
5052         }
5053         var r = [], ri = -1;
5054         tagName = tagName.toLowerCase();
5055         for(var i = 0, ci; ci = cs[i]; i++){
5056             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5057                 r[++ri] = ci;
5058             }
5059         }
5060         return r;
5061     };
5062
5063     function byId(cs, attr, id){
5064         if(cs.tagName || cs == document){
5065             cs = [cs];
5066         }
5067         if(!id){
5068             return cs;
5069         }
5070         var r = [], ri = -1;
5071         for(var i = 0,ci; ci = cs[i]; i++){
5072             if(ci && ci.id == id){
5073                 r[++ri] = ci;
5074                 return r;
5075             }
5076         }
5077         return r;
5078     };
5079
5080     function byAttribute(cs, attr, value, op, custom){
5081         var r = [], ri = -1, st = custom=="{";
5082         var f = Roo.DomQuery.operators[op];
5083         for(var i = 0, ci; ci = cs[i]; i++){
5084             var a;
5085             if(st){
5086                 a = Roo.DomQuery.getStyle(ci, attr);
5087             }
5088             else if(attr == "class" || attr == "className"){
5089                 a = ci.className;
5090             }else if(attr == "for"){
5091                 a = ci.htmlFor;
5092             }else if(attr == "href"){
5093                 a = ci.getAttribute("href", 2);
5094             }else{
5095                 a = ci.getAttribute(attr);
5096             }
5097             if((f && f(a, value)) || (!f && a)){
5098                 r[++ri] = ci;
5099             }
5100         }
5101         return r;
5102     };
5103
5104     function byPseudo(cs, name, value){
5105         return Roo.DomQuery.pseudos[name](cs, value);
5106     };
5107
5108     // This is for IE MSXML which does not support expandos.
5109     // IE runs the same speed using setAttribute, however FF slows way down
5110     // and Safari completely fails so they need to continue to use expandos.
5111     var isIE = window.ActiveXObject ? true : false;
5112
5113     // this eval is stop the compressor from
5114     // renaming the variable to something shorter
5115     
5116     /** eval:var:batch */
5117     var batch = 30803; 
5118
5119     var key = 30803;
5120
5121     function nodupIEXml(cs){
5122         var d = ++key;
5123         cs[0].setAttribute("_nodup", d);
5124         var r = [cs[0]];
5125         for(var i = 1, len = cs.length; i < len; i++){
5126             var c = cs[i];
5127             if(!c.getAttribute("_nodup") != d){
5128                 c.setAttribute("_nodup", d);
5129                 r[r.length] = c;
5130             }
5131         }
5132         for(var i = 0, len = cs.length; i < len; i++){
5133             cs[i].removeAttribute("_nodup");
5134         }
5135         return r;
5136     }
5137
5138     function nodup(cs){
5139         if(!cs){
5140             return [];
5141         }
5142         var len = cs.length, c, i, r = cs, cj, ri = -1;
5143         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5144             return cs;
5145         }
5146         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5147             return nodupIEXml(cs);
5148         }
5149         var d = ++key;
5150         cs[0]._nodup = d;
5151         for(i = 1; c = cs[i]; i++){
5152             if(c._nodup != d){
5153                 c._nodup = d;
5154             }else{
5155                 r = [];
5156                 for(var j = 0; j < i; j++){
5157                     r[++ri] = cs[j];
5158                 }
5159                 for(j = i+1; cj = cs[j]; j++){
5160                     if(cj._nodup != d){
5161                         cj._nodup = d;
5162                         r[++ri] = cj;
5163                     }
5164                 }
5165                 return r;
5166             }
5167         }
5168         return r;
5169     }
5170
5171     function quickDiffIEXml(c1, c2){
5172         var d = ++key;
5173         for(var i = 0, len = c1.length; i < len; i++){
5174             c1[i].setAttribute("_qdiff", d);
5175         }
5176         var r = [];
5177         for(var i = 0, len = c2.length; i < len; i++){
5178             if(c2[i].getAttribute("_qdiff") != d){
5179                 r[r.length] = c2[i];
5180             }
5181         }
5182         for(var i = 0, len = c1.length; i < len; i++){
5183            c1[i].removeAttribute("_qdiff");
5184         }
5185         return r;
5186     }
5187
5188     function quickDiff(c1, c2){
5189         var len1 = c1.length;
5190         if(!len1){
5191             return c2;
5192         }
5193         if(isIE && c1[0].selectSingleNode){
5194             return quickDiffIEXml(c1, c2);
5195         }
5196         var d = ++key;
5197         for(var i = 0; i < len1; i++){
5198             c1[i]._qdiff = d;
5199         }
5200         var r = [];
5201         for(var i = 0, len = c2.length; i < len; i++){
5202             if(c2[i]._qdiff != d){
5203                 r[r.length] = c2[i];
5204             }
5205         }
5206         return r;
5207     }
5208
5209     function quickId(ns, mode, root, id){
5210         if(ns == root){
5211            var d = root.ownerDocument || root;
5212            return d.getElementById(id);
5213         }
5214         ns = getNodes(ns, mode, "*");
5215         return byId(ns, null, id);
5216     }
5217
5218     return {
5219         getStyle : function(el, name){
5220             return Roo.fly(el).getStyle(name);
5221         },
5222         /**
5223          * Compiles a selector/xpath query into a reusable function. The returned function
5224          * takes one parameter "root" (optional), which is the context node from where the query should start.
5225          * @param {String} selector The selector/xpath query
5226          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5227          * @return {Function}
5228          */
5229         compile : function(path, type){
5230             type = type || "select";
5231             
5232             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5233             var q = path, mode, lq;
5234             var tk = Roo.DomQuery.matchers;
5235             var tklen = tk.length;
5236             var mm;
5237
5238             // accept leading mode switch
5239             var lmode = q.match(modeRe);
5240             if(lmode && lmode[1]){
5241                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5242                 q = q.replace(lmode[1], "");
5243             }
5244             // strip leading slashes
5245             while(path.substr(0, 1)=="/"){
5246                 path = path.substr(1);
5247             }
5248
5249             while(q && lq != q){
5250                 lq = q;
5251                 var tm = q.match(tagTokenRe);
5252                 if(type == "select"){
5253                     if(tm){
5254                         if(tm[1] == "#"){
5255                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5256                         }else{
5257                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5258                         }
5259                         q = q.replace(tm[0], "");
5260                     }else if(q.substr(0, 1) != '@'){
5261                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5262                     }
5263                 }else{
5264                     if(tm){
5265                         if(tm[1] == "#"){
5266                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5267                         }else{
5268                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5269                         }
5270                         q = q.replace(tm[0], "");
5271                     }
5272                 }
5273                 while(!(mm = q.match(modeRe))){
5274                     var matched = false;
5275                     for(var j = 0; j < tklen; j++){
5276                         var t = tk[j];
5277                         var m = q.match(t.re);
5278                         if(m){
5279                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5280                                                     return m[i];
5281                                                 });
5282                             q = q.replace(m[0], "");
5283                             matched = true;
5284                             break;
5285                         }
5286                     }
5287                     // prevent infinite loop on bad selector
5288                     if(!matched){
5289                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5290                     }
5291                 }
5292                 if(mm[1]){
5293                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5294                     q = q.replace(mm[1], "");
5295                 }
5296             }
5297             fn[fn.length] = "return nodup(n);\n}";
5298             
5299              /** 
5300               * list of variables that need from compression as they are used by eval.
5301              *  eval:var:batch 
5302              *  eval:var:nodup
5303              *  eval:var:byTag
5304              *  eval:var:ById
5305              *  eval:var:getNodes
5306              *  eval:var:quickId
5307              *  eval:var:mode
5308              *  eval:var:root
5309              *  eval:var:n
5310              *  eval:var:byClassName
5311              *  eval:var:byPseudo
5312              *  eval:var:byAttribute
5313              *  eval:var:attrValue
5314              * 
5315              **/ 
5316             eval(fn.join(""));
5317             return f;
5318         },
5319
5320         /**
5321          * Selects a group of elements.
5322          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5323          * @param {Node} root (optional) The start of the query (defaults to document).
5324          * @return {Array}
5325          */
5326         select : function(path, root, type){
5327             if(!root || root == document){
5328                 root = document;
5329             }
5330             if(typeof root == "string"){
5331                 root = document.getElementById(root);
5332             }
5333             var paths = path.split(",");
5334             var results = [];
5335             for(var i = 0, len = paths.length; i < len; i++){
5336                 var p = paths[i].replace(trimRe, "");
5337                 if(!cache[p]){
5338                     cache[p] = Roo.DomQuery.compile(p);
5339                     if(!cache[p]){
5340                         throw p + " is not a valid selector";
5341                     }
5342                 }
5343                 var result = cache[p](root);
5344                 if(result && result != document){
5345                     results = results.concat(result);
5346                 }
5347             }
5348             if(paths.length > 1){
5349                 return nodup(results);
5350             }
5351             return results;
5352         },
5353
5354         /**
5355          * Selects a single element.
5356          * @param {String} selector The selector/xpath query
5357          * @param {Node} root (optional) The start of the query (defaults to document).
5358          * @return {Element}
5359          */
5360         selectNode : function(path, root){
5361             return Roo.DomQuery.select(path, root)[0];
5362         },
5363
5364         /**
5365          * Selects the value of a node, optionally replacing null with the defaultValue.
5366          * @param {String} selector The selector/xpath query
5367          * @param {Node} root (optional) The start of the query (defaults to document).
5368          * @param {String} defaultValue
5369          */
5370         selectValue : function(path, root, defaultValue){
5371             path = path.replace(trimRe, "");
5372             if(!valueCache[path]){
5373                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5374             }
5375             var n = valueCache[path](root);
5376             n = n[0] ? n[0] : n;
5377             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5378             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5379         },
5380
5381         /**
5382          * Selects the value of a node, parsing integers and floats.
5383          * @param {String} selector The selector/xpath query
5384          * @param {Node} root (optional) The start of the query (defaults to document).
5385          * @param {Number} defaultValue
5386          * @return {Number}
5387          */
5388         selectNumber : function(path, root, defaultValue){
5389             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5390             return parseFloat(v);
5391         },
5392
5393         /**
5394          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5395          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5396          * @param {String} selector The simple selector to test
5397          * @return {Boolean}
5398          */
5399         is : function(el, ss){
5400             if(typeof el == "string"){
5401                 el = document.getElementById(el);
5402             }
5403             var isArray = (el instanceof Array);
5404             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5405             return isArray ? (result.length == el.length) : (result.length > 0);
5406         },
5407
5408         /**
5409          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5410          * @param {Array} el An array of elements to filter
5411          * @param {String} selector The simple selector to test
5412          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5413          * the selector instead of the ones that match
5414          * @return {Array}
5415          */
5416         filter : function(els, ss, nonMatches){
5417             ss = ss.replace(trimRe, "");
5418             if(!simpleCache[ss]){
5419                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5420             }
5421             var result = simpleCache[ss](els);
5422             return nonMatches ? quickDiff(result, els) : result;
5423         },
5424
5425         /**
5426          * Collection of matching regular expressions and code snippets.
5427          */
5428         matchers : [{
5429                 re: /^\.([\w-]+)/,
5430                 select: 'n = byClassName(n, null, " {1} ");'
5431             }, {
5432                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5433                 select: 'n = byPseudo(n, "{1}", "{2}");'
5434             },{
5435                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5436                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5437             }, {
5438                 re: /^#([\w-]+)/,
5439                 select: 'n = byId(n, null, "{1}");'
5440             },{
5441                 re: /^@([\w-]+)/,
5442                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5443             }
5444         ],
5445
5446         /**
5447          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5448          * 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;.
5449          */
5450         operators : {
5451             "=" : function(a, v){
5452                 return a == v;
5453             },
5454             "!=" : function(a, v){
5455                 return a != v;
5456             },
5457             "^=" : function(a, v){
5458                 return a && a.substr(0, v.length) == v;
5459             },
5460             "$=" : function(a, v){
5461                 return a && a.substr(a.length-v.length) == v;
5462             },
5463             "*=" : function(a, v){
5464                 return a && a.indexOf(v) !== -1;
5465             },
5466             "%=" : function(a, v){
5467                 return (a % v) == 0;
5468             },
5469             "|=" : function(a, v){
5470                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5471             },
5472             "~=" : function(a, v){
5473                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5474             }
5475         },
5476
5477         /**
5478          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5479          * and the argument (if any) supplied in the selector.
5480          */
5481         pseudos : {
5482             "first-child" : function(c){
5483                 var r = [], ri = -1, n;
5484                 for(var i = 0, ci; ci = n = c[i]; i++){
5485                     while((n = n.previousSibling) && n.nodeType != 1);
5486                     if(!n){
5487                         r[++ri] = ci;
5488                     }
5489                 }
5490                 return r;
5491             },
5492
5493             "last-child" : function(c){
5494                 var r = [], ri = -1, n;
5495                 for(var i = 0, ci; ci = n = c[i]; i++){
5496                     while((n = n.nextSibling) && n.nodeType != 1);
5497                     if(!n){
5498                         r[++ri] = ci;
5499                     }
5500                 }
5501                 return r;
5502             },
5503
5504             "nth-child" : function(c, a) {
5505                 var r = [], ri = -1;
5506                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5507                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5508                 for(var i = 0, n; n = c[i]; i++){
5509                     var pn = n.parentNode;
5510                     if (batch != pn._batch) {
5511                         var j = 0;
5512                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5513                             if(cn.nodeType == 1){
5514                                cn.nodeIndex = ++j;
5515                             }
5516                         }
5517                         pn._batch = batch;
5518                     }
5519                     if (f == 1) {
5520                         if (l == 0 || n.nodeIndex == l){
5521                             r[++ri] = n;
5522                         }
5523                     } else if ((n.nodeIndex + l) % f == 0){
5524                         r[++ri] = n;
5525                     }
5526                 }
5527
5528                 return r;
5529             },
5530
5531             "only-child" : function(c){
5532                 var r = [], ri = -1;;
5533                 for(var i = 0, ci; ci = c[i]; i++){
5534                     if(!prev(ci) && !next(ci)){
5535                         r[++ri] = ci;
5536                     }
5537                 }
5538                 return r;
5539             },
5540
5541             "empty" : function(c){
5542                 var r = [], ri = -1;
5543                 for(var i = 0, ci; ci = c[i]; i++){
5544                     var cns = ci.childNodes, j = 0, cn, empty = true;
5545                     while(cn = cns[j]){
5546                         ++j;
5547                         if(cn.nodeType == 1 || cn.nodeType == 3){
5548                             empty = false;
5549                             break;
5550                         }
5551                     }
5552                     if(empty){
5553                         r[++ri] = ci;
5554                     }
5555                 }
5556                 return r;
5557             },
5558
5559             "contains" : function(c, v){
5560                 var r = [], ri = -1;
5561                 for(var i = 0, ci; ci = c[i]; i++){
5562                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5563                         r[++ri] = ci;
5564                     }
5565                 }
5566                 return r;
5567             },
5568
5569             "nodeValue" : function(c, v){
5570                 var r = [], ri = -1;
5571                 for(var i = 0, ci; ci = c[i]; i++){
5572                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5573                         r[++ri] = ci;
5574                     }
5575                 }
5576                 return r;
5577             },
5578
5579             "checked" : function(c){
5580                 var r = [], ri = -1;
5581                 for(var i = 0, ci; ci = c[i]; i++){
5582                     if(ci.checked == true){
5583                         r[++ri] = ci;
5584                     }
5585                 }
5586                 return r;
5587             },
5588
5589             "not" : function(c, ss){
5590                 return Roo.DomQuery.filter(c, ss, true);
5591             },
5592
5593             "odd" : function(c){
5594                 return this["nth-child"](c, "odd");
5595             },
5596
5597             "even" : function(c){
5598                 return this["nth-child"](c, "even");
5599             },
5600
5601             "nth" : function(c, a){
5602                 return c[a-1] || [];
5603             },
5604
5605             "first" : function(c){
5606                 return c[0] || [];
5607             },
5608
5609             "last" : function(c){
5610                 return c[c.length-1] || [];
5611             },
5612
5613             "has" : function(c, ss){
5614                 var s = Roo.DomQuery.select;
5615                 var r = [], ri = -1;
5616                 for(var i = 0, ci; ci = c[i]; i++){
5617                     if(s(ss, ci).length > 0){
5618                         r[++ri] = ci;
5619                     }
5620                 }
5621                 return r;
5622             },
5623
5624             "next" : function(c, ss){
5625                 var is = Roo.DomQuery.is;
5626                 var r = [], ri = -1;
5627                 for(var i = 0, ci; ci = c[i]; i++){
5628                     var n = next(ci);
5629                     if(n && is(n, ss)){
5630                         r[++ri] = ci;
5631                     }
5632                 }
5633                 return r;
5634             },
5635
5636             "prev" : function(c, ss){
5637                 var is = Roo.DomQuery.is;
5638                 var r = [], ri = -1;
5639                 for(var i = 0, ci; ci = c[i]; i++){
5640                     var n = prev(ci);
5641                     if(n && is(n, ss)){
5642                         r[++ri] = ci;
5643                     }
5644                 }
5645                 return r;
5646             }
5647         }
5648     };
5649 }();
5650
5651 /**
5652  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5653  * @param {String} path The selector/xpath query
5654  * @param {Node} root (optional) The start of the query (defaults to document).
5655  * @return {Array}
5656  * @member Roo
5657  * @method query
5658  */
5659 Roo.query = Roo.DomQuery.select;
5660 /*
5661  * Based on:
5662  * Ext JS Library 1.1.1
5663  * Copyright(c) 2006-2007, Ext JS, LLC.
5664  *
5665  * Originally Released Under LGPL - original licence link has changed is not relivant.
5666  *
5667  * Fork - LGPL
5668  * <script type="text/javascript">
5669  */
5670
5671 /**
5672  * @class Roo.util.Observable
5673  * Base class that provides a common interface for publishing events. Subclasses are expected to
5674  * to have a property "events" with all the events defined.<br>
5675  * For example:
5676  * <pre><code>
5677  Employee = function(name){
5678     this.name = name;
5679     this.addEvents({
5680         "fired" : true,
5681         "quit" : true
5682     });
5683  }
5684  Roo.extend(Employee, Roo.util.Observable);
5685 </code></pre>
5686  * @param {Object} config properties to use (incuding events / listeners)
5687  */
5688
5689 Roo.util.Observable = function(cfg){
5690     
5691     cfg = cfg|| {};
5692     this.addEvents(cfg.events || {});
5693     if (cfg.events) {
5694         delete cfg.events; // make sure
5695     }
5696      
5697     Roo.apply(this, cfg);
5698     
5699     if(this.listeners){
5700         this.on(this.listeners);
5701         delete this.listeners;
5702     }
5703 };
5704 Roo.util.Observable.prototype = {
5705     /** 
5706  * @cfg {Object} listeners  list of events and functions to call for this object, 
5707  * For example :
5708  * <pre><code>
5709     listeners :  { 
5710        'click' : function(e) {
5711            ..... 
5712         } ,
5713         .... 
5714     } 
5715   </code></pre>
5716  */
5717     
5718     
5719     /**
5720      * Fires the specified event with the passed parameters (minus the event name).
5721      * @param {String} eventName
5722      * @param {Object...} args Variable number of parameters are passed to handlers
5723      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5724      */
5725     fireEvent : function(){
5726         var ce = this.events[arguments[0].toLowerCase()];
5727         if(typeof ce == "object"){
5728             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5729         }else{
5730             return true;
5731         }
5732     },
5733
5734     // private
5735     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5736
5737     /**
5738      * Appends an event handler to this component
5739      * @param {String}   eventName The type of event to listen for
5740      * @param {Function} handler The method the event invokes
5741      * @param {Object}   scope (optional) The scope in which to execute the handler
5742      * function. The handler function's "this" context.
5743      * @param {Object}   options (optional) An object containing handler configuration
5744      * properties. This may contain any of the following properties:<ul>
5745      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5746      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5747      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5748      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5749      * by the specified number of milliseconds. If the event fires again within that time, the original
5750      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5751      * </ul><br>
5752      * <p>
5753      * <b>Combining Options</b><br>
5754      * Using the options argument, it is possible to combine different types of listeners:<br>
5755      * <br>
5756      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5757                 <pre><code>
5758                 el.on('click', this.onClick, this, {
5759                         single: true,
5760                 delay: 100,
5761                 forumId: 4
5762                 });
5763                 </code></pre>
5764      * <p>
5765      * <b>Attaching multiple handlers in 1 call</b><br>
5766      * The method also allows for a single argument to be passed which is a config object containing properties
5767      * which specify multiple handlers.
5768      * <pre><code>
5769                 el.on({
5770                         'click': {
5771                         fn: this.onClick,
5772                         scope: this,
5773                         delay: 100
5774                 }, 
5775                 'mouseover': {
5776                         fn: this.onMouseOver,
5777                         scope: this
5778                 },
5779                 'mouseout': {
5780                         fn: this.onMouseOut,
5781                         scope: this
5782                 }
5783                 });
5784                 </code></pre>
5785      * <p>
5786      * Or a shorthand syntax which passes the same scope object to all handlers:
5787         <pre><code>
5788                 el.on({
5789                         'click': this.onClick,
5790                 'mouseover': this.onMouseOver,
5791                 'mouseout': this.onMouseOut,
5792                 scope: this
5793                 });
5794                 </code></pre>
5795      */
5796     addListener : function(eventName, fn, scope, o){
5797         if(typeof eventName == "object"){
5798             o = eventName;
5799             for(var e in o){
5800                 if(this.filterOptRe.test(e)){
5801                     continue;
5802                 }
5803                 if(typeof o[e] == "function"){
5804                     // shared options
5805                     this.addListener(e, o[e], o.scope,  o);
5806                 }else{
5807                     // individual options
5808                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5809                 }
5810             }
5811             return;
5812         }
5813         o = (!o || typeof o == "boolean") ? {} : o;
5814         eventName = eventName.toLowerCase();
5815         var ce = this.events[eventName] || true;
5816         if(typeof ce == "boolean"){
5817             ce = new Roo.util.Event(this, eventName);
5818             this.events[eventName] = ce;
5819         }
5820         ce.addListener(fn, scope, o);
5821     },
5822
5823     /**
5824      * Removes a listener
5825      * @param {String}   eventName     The type of event to listen for
5826      * @param {Function} handler        The handler to remove
5827      * @param {Object}   scope  (optional) The scope (this object) for the handler
5828      */
5829     removeListener : function(eventName, fn, scope){
5830         var ce = this.events[eventName.toLowerCase()];
5831         if(typeof ce == "object"){
5832             ce.removeListener(fn, scope);
5833         }
5834     },
5835
5836     /**
5837      * Removes all listeners for this object
5838      */
5839     purgeListeners : function(){
5840         for(var evt in this.events){
5841             if(typeof this.events[evt] == "object"){
5842                  this.events[evt].clearListeners();
5843             }
5844         }
5845     },
5846
5847     relayEvents : function(o, events){
5848         var createHandler = function(ename){
5849             return function(){
5850                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5851             };
5852         };
5853         for(var i = 0, len = events.length; i < len; i++){
5854             var ename = events[i];
5855             if(!this.events[ename]){ this.events[ename] = true; };
5856             o.on(ename, createHandler(ename), this);
5857         }
5858     },
5859
5860     /**
5861      * Used to define events on this Observable
5862      * @param {Object} object The object with the events defined
5863      */
5864     addEvents : function(o){
5865         if(!this.events){
5866             this.events = {};
5867         }
5868         Roo.applyIf(this.events, o);
5869     },
5870
5871     /**
5872      * Checks to see if this object has any listeners for a specified event
5873      * @param {String} eventName The name of the event to check for
5874      * @return {Boolean} True if the event is being listened for, else false
5875      */
5876     hasListener : function(eventName){
5877         var e = this.events[eventName];
5878         return typeof e == "object" && e.listeners.length > 0;
5879     }
5880 };
5881 /**
5882  * Appends an event handler to this element (shorthand for addListener)
5883  * @param {String}   eventName     The type of event to listen for
5884  * @param {Function} handler        The method the event invokes
5885  * @param {Object}   scope (optional) The scope in which to execute the handler
5886  * function. The handler function's "this" context.
5887  * @param {Object}   options  (optional)
5888  * @method
5889  */
5890 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5891 /**
5892  * Removes a listener (shorthand for removeListener)
5893  * @param {String}   eventName     The type of event to listen for
5894  * @param {Function} handler        The handler to remove
5895  * @param {Object}   scope  (optional) The scope (this object) for the handler
5896  * @method
5897  */
5898 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5899
5900 /**
5901  * Starts capture on the specified Observable. All events will be passed
5902  * to the supplied function with the event name + standard signature of the event
5903  * <b>before</b> the event is fired. If the supplied function returns false,
5904  * the event will not fire.
5905  * @param {Observable} o The Observable to capture
5906  * @param {Function} fn The function to call
5907  * @param {Object} scope (optional) The scope (this object) for the fn
5908  * @static
5909  */
5910 Roo.util.Observable.capture = function(o, fn, scope){
5911     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5912 };
5913
5914 /**
5915  * Removes <b>all</b> added captures from the Observable.
5916  * @param {Observable} o The Observable to release
5917  * @static
5918  */
5919 Roo.util.Observable.releaseCapture = function(o){
5920     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5921 };
5922
5923 (function(){
5924
5925     var createBuffered = function(h, o, scope){
5926         var task = new Roo.util.DelayedTask();
5927         return function(){
5928             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5929         };
5930     };
5931
5932     var createSingle = function(h, e, fn, scope){
5933         return function(){
5934             e.removeListener(fn, scope);
5935             return h.apply(scope, arguments);
5936         };
5937     };
5938
5939     var createDelayed = function(h, o, scope){
5940         return function(){
5941             var args = Array.prototype.slice.call(arguments, 0);
5942             setTimeout(function(){
5943                 h.apply(scope, args);
5944             }, o.delay || 10);
5945         };
5946     };
5947
5948     Roo.util.Event = function(obj, name){
5949         this.name = name;
5950         this.obj = obj;
5951         this.listeners = [];
5952     };
5953
5954     Roo.util.Event.prototype = {
5955         addListener : function(fn, scope, options){
5956             var o = options || {};
5957             scope = scope || this.obj;
5958             if(!this.isListening(fn, scope)){
5959                 var l = {fn: fn, scope: scope, options: o};
5960                 var h = fn;
5961                 if(o.delay){
5962                     h = createDelayed(h, o, scope);
5963                 }
5964                 if(o.single){
5965                     h = createSingle(h, this, fn, scope);
5966                 }
5967                 if(o.buffer){
5968                     h = createBuffered(h, o, scope);
5969                 }
5970                 l.fireFn = h;
5971                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5972                     this.listeners.push(l);
5973                 }else{
5974                     this.listeners = this.listeners.slice(0);
5975                     this.listeners.push(l);
5976                 }
5977             }
5978         },
5979
5980         findListener : function(fn, scope){
5981             scope = scope || this.obj;
5982             var ls = this.listeners;
5983             for(var i = 0, len = ls.length; i < len; i++){
5984                 var l = ls[i];
5985                 if(l.fn == fn && l.scope == scope){
5986                     return i;
5987                 }
5988             }
5989             return -1;
5990         },
5991
5992         isListening : function(fn, scope){
5993             return this.findListener(fn, scope) != -1;
5994         },
5995
5996         removeListener : function(fn, scope){
5997             var index;
5998             if((index = this.findListener(fn, scope)) != -1){
5999                 if(!this.firing){
6000                     this.listeners.splice(index, 1);
6001                 }else{
6002                     this.listeners = this.listeners.slice(0);
6003                     this.listeners.splice(index, 1);
6004                 }
6005                 return true;
6006             }
6007             return false;
6008         },
6009
6010         clearListeners : function(){
6011             this.listeners = [];
6012         },
6013
6014         fire : function(){
6015             var ls = this.listeners, scope, len = ls.length;
6016             if(len > 0){
6017                 this.firing = true;
6018                 var args = Array.prototype.slice.call(arguments, 0);
6019                 for(var i = 0; i < len; i++){
6020                     var l = ls[i];
6021                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6022                         this.firing = false;
6023                         return false;
6024                     }
6025                 }
6026                 this.firing = false;
6027             }
6028             return true;
6029         }
6030     };
6031 })();/*
6032  * Based on:
6033  * Ext JS Library 1.1.1
6034  * Copyright(c) 2006-2007, Ext JS, LLC.
6035  *
6036  * Originally Released Under LGPL - original licence link has changed is not relivant.
6037  *
6038  * Fork - LGPL
6039  * <script type="text/javascript">
6040  */
6041
6042 /**
6043  * @class Roo.EventManager
6044  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6045  * several useful events directly.
6046  * See {@link Roo.EventObject} for more details on normalized event objects.
6047  * @singleton
6048  */
6049 Roo.EventManager = function(){
6050     var docReadyEvent, docReadyProcId, docReadyState = false;
6051     var resizeEvent, resizeTask, textEvent, textSize;
6052     var E = Roo.lib.Event;
6053     var D = Roo.lib.Dom;
6054
6055
6056     var fireDocReady = function(){
6057         if(!docReadyState){
6058             docReadyState = true;
6059             Roo.isReady = true;
6060             if(docReadyProcId){
6061                 clearInterval(docReadyProcId);
6062             }
6063             if(Roo.isGecko || Roo.isOpera) {
6064                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6065             }
6066             if(Roo.isIE){
6067                 var defer = document.getElementById("ie-deferred-loader");
6068                 if(defer){
6069                     defer.onreadystatechange = null;
6070                     defer.parentNode.removeChild(defer);
6071                 }
6072             }
6073             if(docReadyEvent){
6074                 docReadyEvent.fire();
6075                 docReadyEvent.clearListeners();
6076             }
6077         }
6078     };
6079     
6080     var initDocReady = function(){
6081         docReadyEvent = new Roo.util.Event();
6082         if(Roo.isGecko || Roo.isOpera) {
6083             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6084         }else if(Roo.isIE){
6085             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6086             var defer = document.getElementById("ie-deferred-loader");
6087             defer.onreadystatechange = function(){
6088                 if(this.readyState == "complete"){
6089                     fireDocReady();
6090                 }
6091             };
6092         }else if(Roo.isSafari){ 
6093             docReadyProcId = setInterval(function(){
6094                 var rs = document.readyState;
6095                 if(rs == "complete") {
6096                     fireDocReady();     
6097                  }
6098             }, 10);
6099         }
6100         // no matter what, make sure it fires on load
6101         E.on(window, "load", fireDocReady);
6102     };
6103
6104     var createBuffered = function(h, o){
6105         var task = new Roo.util.DelayedTask(h);
6106         return function(e){
6107             // create new event object impl so new events don't wipe out properties
6108             e = new Roo.EventObjectImpl(e);
6109             task.delay(o.buffer, h, null, [e]);
6110         };
6111     };
6112
6113     var createSingle = function(h, el, ename, fn){
6114         return function(e){
6115             Roo.EventManager.removeListener(el, ename, fn);
6116             h(e);
6117         };
6118     };
6119
6120     var createDelayed = function(h, o){
6121         return function(e){
6122             // create new event object impl so new events don't wipe out properties
6123             e = new Roo.EventObjectImpl(e);
6124             setTimeout(function(){
6125                 h(e);
6126             }, o.delay || 10);
6127         };
6128     };
6129
6130     var listen = function(element, ename, opt, fn, scope){
6131         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6132         fn = fn || o.fn; scope = scope || o.scope;
6133         var el = Roo.getDom(element);
6134         if(!el){
6135             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6136         }
6137         var h = function(e){
6138             e = Roo.EventObject.setEvent(e);
6139             var t;
6140             if(o.delegate){
6141                 t = e.getTarget(o.delegate, el);
6142                 if(!t){
6143                     return;
6144                 }
6145             }else{
6146                 t = e.target;
6147             }
6148             if(o.stopEvent === true){
6149                 e.stopEvent();
6150             }
6151             if(o.preventDefault === true){
6152                e.preventDefault();
6153             }
6154             if(o.stopPropagation === true){
6155                 e.stopPropagation();
6156             }
6157
6158             if(o.normalized === false){
6159                 e = e.browserEvent;
6160             }
6161
6162             fn.call(scope || el, e, t, o);
6163         };
6164         if(o.delay){
6165             h = createDelayed(h, o);
6166         }
6167         if(o.single){
6168             h = createSingle(h, el, ename, fn);
6169         }
6170         if(o.buffer){
6171             h = createBuffered(h, o);
6172         }
6173         fn._handlers = fn._handlers || [];
6174         fn._handlers.push([Roo.id(el), ename, h]);
6175
6176         E.on(el, ename, h);
6177         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6178             el.addEventListener("DOMMouseScroll", h, false);
6179             E.on(window, 'unload', function(){
6180                 el.removeEventListener("DOMMouseScroll", h, false);
6181             });
6182         }
6183         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6184             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6185         }
6186         return h;
6187     };
6188
6189     var stopListening = function(el, ename, fn){
6190         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6191         if(hds){
6192             for(var i = 0, len = hds.length; i < len; i++){
6193                 var h = hds[i];
6194                 if(h[0] == id && h[1] == ename){
6195                     hd = h[2];
6196                     hds.splice(i, 1);
6197                     break;
6198                 }
6199             }
6200         }
6201         E.un(el, ename, hd);
6202         el = Roo.getDom(el);
6203         if(ename == "mousewheel" && el.addEventListener){
6204             el.removeEventListener("DOMMouseScroll", hd, false);
6205         }
6206         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6207             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6208         }
6209     };
6210
6211     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6212     
6213     var pub = {
6214         
6215         
6216         /** 
6217          * Fix for doc tools
6218          * @scope Roo.EventManager
6219          */
6220         
6221         
6222         /** 
6223          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6224          * object with a Roo.EventObject
6225          * @param {Function} fn        The method the event invokes
6226          * @param {Object}   scope    An object that becomes the scope of the handler
6227          * @param {boolean}  override If true, the obj passed in becomes
6228          *                             the execution scope of the listener
6229          * @return {Function} The wrapped function
6230          * @deprecated
6231          */
6232         wrap : function(fn, scope, override){
6233             return function(e){
6234                 Roo.EventObject.setEvent(e);
6235                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6236             };
6237         },
6238         
6239         /**
6240      * Appends an event handler to an element (shorthand for addListener)
6241      * @param {String/HTMLElement}   element        The html element or id to assign the
6242      * @param {String}   eventName The type of event to listen for
6243      * @param {Function} handler The method the event invokes
6244      * @param {Object}   scope (optional) The scope in which to execute the handler
6245      * function. The handler function's "this" context.
6246      * @param {Object}   options (optional) An object containing handler configuration
6247      * properties. This may contain any of the following properties:<ul>
6248      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6249      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6250      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6251      * <li>preventDefault {Boolean} True to prevent the default action</li>
6252      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6253      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6254      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6255      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6256      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6257      * by the specified number of milliseconds. If the event fires again within that time, the original
6258      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6259      * </ul><br>
6260      * <p>
6261      * <b>Combining Options</b><br>
6262      * Using the options argument, it is possible to combine different types of listeners:<br>
6263      * <br>
6264      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6265      * Code:<pre><code>
6266 el.on('click', this.onClick, this, {
6267     single: true,
6268     delay: 100,
6269     stopEvent : true,
6270     forumId: 4
6271 });</code></pre>
6272      * <p>
6273      * <b>Attaching multiple handlers in 1 call</b><br>
6274       * The method also allows for a single argument to be passed which is a config object containing properties
6275      * which specify multiple handlers.
6276      * <p>
6277      * Code:<pre><code>
6278 el.on({
6279     'click' : {
6280         fn: this.onClick
6281         scope: this,
6282         delay: 100
6283     },
6284     'mouseover' : {
6285         fn: this.onMouseOver
6286         scope: this
6287     },
6288     'mouseout' : {
6289         fn: this.onMouseOut
6290         scope: this
6291     }
6292 });</code></pre>
6293      * <p>
6294      * Or a shorthand syntax:<br>
6295      * Code:<pre><code>
6296 el.on({
6297     'click' : this.onClick,
6298     'mouseover' : this.onMouseOver,
6299     'mouseout' : this.onMouseOut
6300     scope: this
6301 });</code></pre>
6302      */
6303         addListener : function(element, eventName, fn, scope, options){
6304             if(typeof eventName == "object"){
6305                 var o = eventName;
6306                 for(var e in o){
6307                     if(propRe.test(e)){
6308                         continue;
6309                     }
6310                     if(typeof o[e] == "function"){
6311                         // shared options
6312                         listen(element, e, o, o[e], o.scope);
6313                     }else{
6314                         // individual options
6315                         listen(element, e, o[e]);
6316                     }
6317                 }
6318                 return;
6319             }
6320             return listen(element, eventName, options, fn, scope);
6321         },
6322         
6323         /**
6324          * Removes an event handler
6325          *
6326          * @param {String/HTMLElement}   element        The id or html element to remove the 
6327          *                             event from
6328          * @param {String}   eventName     The type of event
6329          * @param {Function} fn
6330          * @return {Boolean} True if a listener was actually removed
6331          */
6332         removeListener : function(element, eventName, fn){
6333             return stopListening(element, eventName, fn);
6334         },
6335         
6336         /**
6337          * Fires when the document is ready (before onload and before images are loaded). Can be 
6338          * accessed shorthanded Roo.onReady().
6339          * @param {Function} fn        The method the event invokes
6340          * @param {Object}   scope    An  object that becomes the scope of the handler
6341          * @param {boolean}  options
6342          */
6343         onDocumentReady : function(fn, scope, options){
6344             if(docReadyState){ // if it already fired
6345                 docReadyEvent.addListener(fn, scope, options);
6346                 docReadyEvent.fire();
6347                 docReadyEvent.clearListeners();
6348                 return;
6349             }
6350             if(!docReadyEvent){
6351                 initDocReady();
6352             }
6353             docReadyEvent.addListener(fn, scope, options);
6354         },
6355         
6356         /**
6357          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6358          * @param {Function} fn        The method the event invokes
6359          * @param {Object}   scope    An object that becomes the scope of the handler
6360          * @param {boolean}  options
6361          */
6362         onWindowResize : function(fn, scope, options){
6363             if(!resizeEvent){
6364                 resizeEvent = new Roo.util.Event();
6365                 resizeTask = new Roo.util.DelayedTask(function(){
6366                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6367                 });
6368                 E.on(window, "resize", function(){
6369                     if(Roo.isIE){
6370                         resizeTask.delay(50);
6371                     }else{
6372                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6373                     }
6374                 });
6375             }
6376             resizeEvent.addListener(fn, scope, options);
6377         },
6378
6379         /**
6380          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6381          * @param {Function} fn        The method the event invokes
6382          * @param {Object}   scope    An object that becomes the scope of the handler
6383          * @param {boolean}  options
6384          */
6385         onTextResize : function(fn, scope, options){
6386             if(!textEvent){
6387                 textEvent = new Roo.util.Event();
6388                 var textEl = new Roo.Element(document.createElement('div'));
6389                 textEl.dom.className = 'x-text-resize';
6390                 textEl.dom.innerHTML = 'X';
6391                 textEl.appendTo(document.body);
6392                 textSize = textEl.dom.offsetHeight;
6393                 setInterval(function(){
6394                     if(textEl.dom.offsetHeight != textSize){
6395                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6396                     }
6397                 }, this.textResizeInterval);
6398             }
6399             textEvent.addListener(fn, scope, options);
6400         },
6401
6402         /**
6403          * Removes the passed window resize listener.
6404          * @param {Function} fn        The method the event invokes
6405          * @param {Object}   scope    The scope of handler
6406          */
6407         removeResizeListener : function(fn, scope){
6408             if(resizeEvent){
6409                 resizeEvent.removeListener(fn, scope);
6410             }
6411         },
6412
6413         // private
6414         fireResize : function(){
6415             if(resizeEvent){
6416                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6417             }   
6418         },
6419         /**
6420          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6421          */
6422         ieDeferSrc : false,
6423         /**
6424          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6425          */
6426         textResizeInterval : 50
6427     };
6428     
6429     /**
6430      * Fix for doc tools
6431      * @scopeAlias pub=Roo.EventManager
6432      */
6433     
6434      /**
6435      * Appends an event handler to an element (shorthand for addListener)
6436      * @param {String/HTMLElement}   element        The html element or id to assign the
6437      * @param {String}   eventName The type of event to listen for
6438      * @param {Function} handler The method the event invokes
6439      * @param {Object}   scope (optional) The scope in which to execute the handler
6440      * function. The handler function's "this" context.
6441      * @param {Object}   options (optional) An object containing handler configuration
6442      * properties. This may contain any of the following properties:<ul>
6443      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6444      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6445      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6446      * <li>preventDefault {Boolean} True to prevent the default action</li>
6447      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6448      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6449      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6450      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6451      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6452      * by the specified number of milliseconds. If the event fires again within that time, the original
6453      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6454      * </ul><br>
6455      * <p>
6456      * <b>Combining Options</b><br>
6457      * Using the options argument, it is possible to combine different types of listeners:<br>
6458      * <br>
6459      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6460      * Code:<pre><code>
6461 el.on('click', this.onClick, this, {
6462     single: true,
6463     delay: 100,
6464     stopEvent : true,
6465     forumId: 4
6466 });</code></pre>
6467      * <p>
6468      * <b>Attaching multiple handlers in 1 call</b><br>
6469       * The method also allows for a single argument to be passed which is a config object containing properties
6470      * which specify multiple handlers.
6471      * <p>
6472      * Code:<pre><code>
6473 el.on({
6474     'click' : {
6475         fn: this.onClick
6476         scope: this,
6477         delay: 100
6478     },
6479     'mouseover' : {
6480         fn: this.onMouseOver
6481         scope: this
6482     },
6483     'mouseout' : {
6484         fn: this.onMouseOut
6485         scope: this
6486     }
6487 });</code></pre>
6488      * <p>
6489      * Or a shorthand syntax:<br>
6490      * Code:<pre><code>
6491 el.on({
6492     'click' : this.onClick,
6493     'mouseover' : this.onMouseOver,
6494     'mouseout' : this.onMouseOut
6495     scope: this
6496 });</code></pre>
6497      */
6498     pub.on = pub.addListener;
6499     pub.un = pub.removeListener;
6500
6501     pub.stoppedMouseDownEvent = new Roo.util.Event();
6502     return pub;
6503 }();
6504 /**
6505   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6506   * @param {Function} fn        The method the event invokes
6507   * @param {Object}   scope    An  object that becomes the scope of the handler
6508   * @param {boolean}  override If true, the obj passed in becomes
6509   *                             the execution scope of the listener
6510   * @member Roo
6511   * @method onReady
6512  */
6513 Roo.onReady = Roo.EventManager.onDocumentReady;
6514
6515 Roo.onReady(function(){
6516     var bd = Roo.get(document.body);
6517     if(!bd){ return; }
6518
6519     var cls = [
6520             Roo.isIE ? "roo-ie"
6521             : Roo.isGecko ? "roo-gecko"
6522             : Roo.isOpera ? "roo-opera"
6523             : Roo.isSafari ? "roo-safari" : ""];
6524
6525     if(Roo.isMac){
6526         cls.push("roo-mac");
6527     }
6528     if(Roo.isLinux){
6529         cls.push("roo-linux");
6530     }
6531     if(Roo.isBorderBox){
6532         cls.push('roo-border-box');
6533     }
6534     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6535         var p = bd.dom.parentNode;
6536         if(p){
6537             p.className += ' roo-strict';
6538         }
6539     }
6540     bd.addClass(cls.join(' '));
6541 });
6542
6543 /**
6544  * @class Roo.EventObject
6545  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6546  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6547  * Example:
6548  * <pre><code>
6549  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6550     e.preventDefault();
6551     var target = e.getTarget();
6552     ...
6553  }
6554  var myDiv = Roo.get("myDiv");
6555  myDiv.on("click", handleClick);
6556  //or
6557  Roo.EventManager.on("myDiv", 'click', handleClick);
6558  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6559  </code></pre>
6560  * @singleton
6561  */
6562 Roo.EventObject = function(){
6563     
6564     var E = Roo.lib.Event;
6565     
6566     // safari keypress events for special keys return bad keycodes
6567     var safariKeys = {
6568         63234 : 37, // left
6569         63235 : 39, // right
6570         63232 : 38, // up
6571         63233 : 40, // down
6572         63276 : 33, // page up
6573         63277 : 34, // page down
6574         63272 : 46, // delete
6575         63273 : 36, // home
6576         63275 : 35  // end
6577     };
6578
6579     // normalize button clicks
6580     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6581                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6582
6583     Roo.EventObjectImpl = function(e){
6584         if(e){
6585             this.setEvent(e.browserEvent || e);
6586         }
6587     };
6588     Roo.EventObjectImpl.prototype = {
6589         /**
6590          * Used to fix doc tools.
6591          * @scope Roo.EventObject.prototype
6592          */
6593             
6594
6595         
6596         
6597         /** The normal browser event */
6598         browserEvent : null,
6599         /** The button pressed in a mouse event */
6600         button : -1,
6601         /** True if the shift key was down during the event */
6602         shiftKey : false,
6603         /** True if the control key was down during the event */
6604         ctrlKey : false,
6605         /** True if the alt key was down during the event */
6606         altKey : false,
6607
6608         /** Key constant 
6609         * @type Number */
6610         BACKSPACE : 8,
6611         /** Key constant 
6612         * @type Number */
6613         TAB : 9,
6614         /** Key constant 
6615         * @type Number */
6616         RETURN : 13,
6617         /** Key constant 
6618         * @type Number */
6619         ENTER : 13,
6620         /** Key constant 
6621         * @type Number */
6622         SHIFT : 16,
6623         /** Key constant 
6624         * @type Number */
6625         CONTROL : 17,
6626         /** Key constant 
6627         * @type Number */
6628         ESC : 27,
6629         /** Key constant 
6630         * @type Number */
6631         SPACE : 32,
6632         /** Key constant 
6633         * @type Number */
6634         PAGEUP : 33,
6635         /** Key constant 
6636         * @type Number */
6637         PAGEDOWN : 34,
6638         /** Key constant 
6639         * @type Number */
6640         END : 35,
6641         /** Key constant 
6642         * @type Number */
6643         HOME : 36,
6644         /** Key constant 
6645         * @type Number */
6646         LEFT : 37,
6647         /** Key constant 
6648         * @type Number */
6649         UP : 38,
6650         /** Key constant 
6651         * @type Number */
6652         RIGHT : 39,
6653         /** Key constant 
6654         * @type Number */
6655         DOWN : 40,
6656         /** Key constant 
6657         * @type Number */
6658         DELETE : 46,
6659         /** Key constant 
6660         * @type Number */
6661         F5 : 116,
6662
6663            /** @private */
6664         setEvent : function(e){
6665             if(e == this || (e && e.browserEvent)){ // already wrapped
6666                 return e;
6667             }
6668             this.browserEvent = e;
6669             if(e){
6670                 // normalize buttons
6671                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6672                 if(e.type == 'click' && this.button == -1){
6673                     this.button = 0;
6674                 }
6675                 this.type = e.type;
6676                 this.shiftKey = e.shiftKey;
6677                 // mac metaKey behaves like ctrlKey
6678                 this.ctrlKey = e.ctrlKey || e.metaKey;
6679                 this.altKey = e.altKey;
6680                 // in getKey these will be normalized for the mac
6681                 this.keyCode = e.keyCode;
6682                 // keyup warnings on firefox.
6683                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6684                 // cache the target for the delayed and or buffered events
6685                 this.target = E.getTarget(e);
6686                 // same for XY
6687                 this.xy = E.getXY(e);
6688             }else{
6689                 this.button = -1;
6690                 this.shiftKey = false;
6691                 this.ctrlKey = false;
6692                 this.altKey = false;
6693                 this.keyCode = 0;
6694                 this.charCode =0;
6695                 this.target = null;
6696                 this.xy = [0, 0];
6697             }
6698             return this;
6699         },
6700
6701         /**
6702          * Stop the event (preventDefault and stopPropagation)
6703          */
6704         stopEvent : function(){
6705             if(this.browserEvent){
6706                 if(this.browserEvent.type == 'mousedown'){
6707                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6708                 }
6709                 E.stopEvent(this.browserEvent);
6710             }
6711         },
6712
6713         /**
6714          * Prevents the browsers default handling of the event.
6715          */
6716         preventDefault : function(){
6717             if(this.browserEvent){
6718                 E.preventDefault(this.browserEvent);
6719             }
6720         },
6721
6722         /** @private */
6723         isNavKeyPress : function(){
6724             var k = this.keyCode;
6725             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6726             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6727         },
6728
6729         isSpecialKey : function(){
6730             var k = this.keyCode;
6731             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6732             (k == 16) || (k == 17) ||
6733             (k >= 18 && k <= 20) ||
6734             (k >= 33 && k <= 35) ||
6735             (k >= 36 && k <= 39) ||
6736             (k >= 44 && k <= 45);
6737         },
6738         /**
6739          * Cancels bubbling of the event.
6740          */
6741         stopPropagation : function(){
6742             if(this.browserEvent){
6743                 if(this.type == 'mousedown'){
6744                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6745                 }
6746                 E.stopPropagation(this.browserEvent);
6747             }
6748         },
6749
6750         /**
6751          * Gets the key code for the event.
6752          * @return {Number}
6753          */
6754         getCharCode : function(){
6755             return this.charCode || this.keyCode;
6756         },
6757
6758         /**
6759          * Returns a normalized keyCode for the event.
6760          * @return {Number} The key code
6761          */
6762         getKey : function(){
6763             var k = this.keyCode || this.charCode;
6764             return Roo.isSafari ? (safariKeys[k] || k) : k;
6765         },
6766
6767         /**
6768          * Gets the x coordinate of the event.
6769          * @return {Number}
6770          */
6771         getPageX : function(){
6772             return this.xy[0];
6773         },
6774
6775         /**
6776          * Gets the y coordinate of the event.
6777          * @return {Number}
6778          */
6779         getPageY : function(){
6780             return this.xy[1];
6781         },
6782
6783         /**
6784          * Gets the time of the event.
6785          * @return {Number}
6786          */
6787         getTime : function(){
6788             if(this.browserEvent){
6789                 return E.getTime(this.browserEvent);
6790             }
6791             return null;
6792         },
6793
6794         /**
6795          * Gets the page coordinates of the event.
6796          * @return {Array} The xy values like [x, y]
6797          */
6798         getXY : function(){
6799             return this.xy;
6800         },
6801
6802         /**
6803          * Gets the target for the event.
6804          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6805          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6806                 search as a number or element (defaults to 10 || document.body)
6807          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6808          * @return {HTMLelement}
6809          */
6810         getTarget : function(selector, maxDepth, returnEl){
6811             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6812         },
6813         /**
6814          * Gets the related target.
6815          * @return {HTMLElement}
6816          */
6817         getRelatedTarget : function(){
6818             if(this.browserEvent){
6819                 return E.getRelatedTarget(this.browserEvent);
6820             }
6821             return null;
6822         },
6823
6824         /**
6825          * Normalizes mouse wheel delta across browsers
6826          * @return {Number} The delta
6827          */
6828         getWheelDelta : function(){
6829             var e = this.browserEvent;
6830             var delta = 0;
6831             if(e.wheelDelta){ /* IE/Opera. */
6832                 delta = e.wheelDelta/120;
6833             }else if(e.detail){ /* Mozilla case. */
6834                 delta = -e.detail/3;
6835             }
6836             return delta;
6837         },
6838
6839         /**
6840          * Returns true if the control, meta, shift or alt key was pressed during this event.
6841          * @return {Boolean}
6842          */
6843         hasModifier : function(){
6844             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6845         },
6846
6847         /**
6848          * Returns true if the target of this event equals el or is a child of el
6849          * @param {String/HTMLElement/Element} el
6850          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6851          * @return {Boolean}
6852          */
6853         within : function(el, related){
6854             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6855             return t && Roo.fly(el).contains(t);
6856         },
6857
6858         getPoint : function(){
6859             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6860         }
6861     };
6862
6863     return new Roo.EventObjectImpl();
6864 }();
6865             
6866     /*
6867  * Based on:
6868  * Ext JS Library 1.1.1
6869  * Copyright(c) 2006-2007, Ext JS, LLC.
6870  *
6871  * Originally Released Under LGPL - original licence link has changed is not relivant.
6872  *
6873  * Fork - LGPL
6874  * <script type="text/javascript">
6875  */
6876
6877  
6878 // was in Composite Element!??!?!
6879  
6880 (function(){
6881     var D = Roo.lib.Dom;
6882     var E = Roo.lib.Event;
6883     var A = Roo.lib.Anim;
6884
6885     // local style camelizing for speed
6886     var propCache = {};
6887     var camelRe = /(-[a-z])/gi;
6888     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6889     var view = document.defaultView;
6890
6891 /**
6892  * @class Roo.Element
6893  * Represents an Element in the DOM.<br><br>
6894  * Usage:<br>
6895 <pre><code>
6896 var el = Roo.get("my-div");
6897
6898 // or with getEl
6899 var el = getEl("my-div");
6900
6901 // or with a DOM element
6902 var el = Roo.get(myDivElement);
6903 </code></pre>
6904  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6905  * each call instead of constructing a new one.<br><br>
6906  * <b>Animations</b><br />
6907  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6908  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6909 <pre>
6910 Option    Default   Description
6911 --------- --------  ---------------------------------------------
6912 duration  .35       The duration of the animation in seconds
6913 easing    easeOut   The YUI easing method
6914 callback  none      A function to execute when the anim completes
6915 scope     this      The scope (this) of the callback function
6916 </pre>
6917 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6918 * manipulate the animation. Here's an example:
6919 <pre><code>
6920 var el = Roo.get("my-div");
6921
6922 // no animation
6923 el.setWidth(100);
6924
6925 // default animation
6926 el.setWidth(100, true);
6927
6928 // animation with some options set
6929 el.setWidth(100, {
6930     duration: 1,
6931     callback: this.foo,
6932     scope: this
6933 });
6934
6935 // using the "anim" property to get the Anim object
6936 var opt = {
6937     duration: 1,
6938     callback: this.foo,
6939     scope: this
6940 };
6941 el.setWidth(100, opt);
6942 ...
6943 if(opt.anim.isAnimated()){
6944     opt.anim.stop();
6945 }
6946 </code></pre>
6947 * <b> Composite (Collections of) Elements</b><br />
6948  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6949  * @constructor Create a new Element directly.
6950  * @param {String/HTMLElement} element
6951  * @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).
6952  */
6953     Roo.Element = function(element, forceNew){
6954         var dom = typeof element == "string" ?
6955                 document.getElementById(element) : element;
6956         if(!dom){ // invalid id/element
6957             return null;
6958         }
6959         var id = dom.id;
6960         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6961             return Roo.Element.cache[id];
6962         }
6963
6964         /**
6965          * The DOM element
6966          * @type HTMLElement
6967          */
6968         this.dom = dom;
6969
6970         /**
6971          * The DOM element ID
6972          * @type String
6973          */
6974         this.id = id || Roo.id(dom);
6975     };
6976
6977     var El = Roo.Element;
6978
6979     El.prototype = {
6980         /**
6981          * The element's default display mode  (defaults to "")
6982          * @type String
6983          */
6984         originalDisplay : "",
6985
6986         visibilityMode : 1,
6987         /**
6988          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6989          * @type String
6990          */
6991         defaultUnit : "px",
6992         /**
6993          * Sets the element's visibility mode. When setVisible() is called it
6994          * will use this to determine whether to set the visibility or the display property.
6995          * @param visMode Element.VISIBILITY or Element.DISPLAY
6996          * @return {Roo.Element} this
6997          */
6998         setVisibilityMode : function(visMode){
6999             this.visibilityMode = visMode;
7000             return this;
7001         },
7002         /**
7003          * Convenience method for setVisibilityMode(Element.DISPLAY)
7004          * @param {String} display (optional) What to set display to when visible
7005          * @return {Roo.Element} this
7006          */
7007         enableDisplayMode : function(display){
7008             this.setVisibilityMode(El.DISPLAY);
7009             if(typeof display != "undefined") this.originalDisplay = display;
7010             return this;
7011         },
7012
7013         /**
7014          * 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)
7015          * @param {String} selector The simple selector to test
7016          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7017                 search as a number or element (defaults to 10 || document.body)
7018          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7019          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7020          */
7021         findParent : function(simpleSelector, maxDepth, returnEl){
7022             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7023             maxDepth = maxDepth || 50;
7024             if(typeof maxDepth != "number"){
7025                 stopEl = Roo.getDom(maxDepth);
7026                 maxDepth = 10;
7027             }
7028             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7029                 if(dq.is(p, simpleSelector)){
7030                     return returnEl ? Roo.get(p) : p;
7031                 }
7032                 depth++;
7033                 p = p.parentNode;
7034             }
7035             return null;
7036         },
7037
7038
7039         /**
7040          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7041          * @param {String} selector The simple selector to test
7042          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7043                 search as a number or element (defaults to 10 || document.body)
7044          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7045          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7046          */
7047         findParentNode : function(simpleSelector, maxDepth, returnEl){
7048             var p = Roo.fly(this.dom.parentNode, '_internal');
7049             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7050         },
7051
7052         /**
7053          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7054          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7055          * @param {String} selector The simple selector to test
7056          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7057                 search as a number or element (defaults to 10 || document.body)
7058          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7059          */
7060         up : function(simpleSelector, maxDepth){
7061             return this.findParentNode(simpleSelector, maxDepth, true);
7062         },
7063
7064
7065
7066         /**
7067          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7068          * @param {String} selector The simple selector to test
7069          * @return {Boolean} True if this element matches the selector, else false
7070          */
7071         is : function(simpleSelector){
7072             return Roo.DomQuery.is(this.dom, simpleSelector);
7073         },
7074
7075         /**
7076          * Perform animation on this element.
7077          * @param {Object} args The YUI animation control args
7078          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7079          * @param {Function} onComplete (optional) Function to call when animation completes
7080          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7081          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7082          * @return {Roo.Element} this
7083          */
7084         animate : function(args, duration, onComplete, easing, animType){
7085             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7086             return this;
7087         },
7088
7089         /*
7090          * @private Internal animation call
7091          */
7092         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7093             animType = animType || 'run';
7094             opt = opt || {};
7095             var anim = Roo.lib.Anim[animType](
7096                 this.dom, args,
7097                 (opt.duration || defaultDur) || .35,
7098                 (opt.easing || defaultEase) || 'easeOut',
7099                 function(){
7100                     Roo.callback(cb, this);
7101                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7102                 },
7103                 this
7104             );
7105             opt.anim = anim;
7106             return anim;
7107         },
7108
7109         // private legacy anim prep
7110         preanim : function(a, i){
7111             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7112         },
7113
7114         /**
7115          * Removes worthless text nodes
7116          * @param {Boolean} forceReclean (optional) By default the element
7117          * keeps track if it has been cleaned already so
7118          * you can call this over and over. However, if you update the element and
7119          * need to force a reclean, you can pass true.
7120          */
7121         clean : function(forceReclean){
7122             if(this.isCleaned && forceReclean !== true){
7123                 return this;
7124             }
7125             var ns = /\S/;
7126             var d = this.dom, n = d.firstChild, ni = -1;
7127             while(n){
7128                 var nx = n.nextSibling;
7129                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7130                     d.removeChild(n);
7131                 }else{
7132                     n.nodeIndex = ++ni;
7133                 }
7134                 n = nx;
7135             }
7136             this.isCleaned = true;
7137             return this;
7138         },
7139
7140         // private
7141         calcOffsetsTo : function(el){
7142             el = Roo.get(el);
7143             var d = el.dom;
7144             var restorePos = false;
7145             if(el.getStyle('position') == 'static'){
7146                 el.position('relative');
7147                 restorePos = true;
7148             }
7149             var x = 0, y =0;
7150             var op = this.dom;
7151             while(op && op != d && op.tagName != 'HTML'){
7152                 x+= op.offsetLeft;
7153                 y+= op.offsetTop;
7154                 op = op.offsetParent;
7155             }
7156             if(restorePos){
7157                 el.position('static');
7158             }
7159             return [x, y];
7160         },
7161
7162         /**
7163          * Scrolls this element into view within the passed container.
7164          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7165          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7166          * @return {Roo.Element} this
7167          */
7168         scrollIntoView : function(container, hscroll){
7169             var c = Roo.getDom(container) || document.body;
7170             var el = this.dom;
7171
7172             var o = this.calcOffsetsTo(c),
7173                 l = o[0],
7174                 t = o[1],
7175                 b = t+el.offsetHeight,
7176                 r = l+el.offsetWidth;
7177
7178             var ch = c.clientHeight;
7179             var ct = parseInt(c.scrollTop, 10);
7180             var cl = parseInt(c.scrollLeft, 10);
7181             var cb = ct + ch;
7182             var cr = cl + c.clientWidth;
7183
7184             if(t < ct){
7185                 c.scrollTop = t;
7186             }else if(b > cb){
7187                 c.scrollTop = b-ch;
7188             }
7189
7190             if(hscroll !== false){
7191                 if(l < cl){
7192                     c.scrollLeft = l;
7193                 }else if(r > cr){
7194                     c.scrollLeft = r-c.clientWidth;
7195                 }
7196             }
7197             return this;
7198         },
7199
7200         // private
7201         scrollChildIntoView : function(child, hscroll){
7202             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7203         },
7204
7205         /**
7206          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7207          * the new height may not be available immediately.
7208          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7209          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7210          * @param {Function} onComplete (optional) Function to call when animation completes
7211          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7212          * @return {Roo.Element} this
7213          */
7214         autoHeight : function(animate, duration, onComplete, easing){
7215             var oldHeight = this.getHeight();
7216             this.clip();
7217             this.setHeight(1); // force clipping
7218             setTimeout(function(){
7219                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7220                 if(!animate){
7221                     this.setHeight(height);
7222                     this.unclip();
7223                     if(typeof onComplete == "function"){
7224                         onComplete();
7225                     }
7226                 }else{
7227                     this.setHeight(oldHeight); // restore original height
7228                     this.setHeight(height, animate, duration, function(){
7229                         this.unclip();
7230                         if(typeof onComplete == "function") onComplete();
7231                     }.createDelegate(this), easing);
7232                 }
7233             }.createDelegate(this), 0);
7234             return this;
7235         },
7236
7237         /**
7238          * Returns true if this element is an ancestor of the passed element
7239          * @param {HTMLElement/String} el The element to check
7240          * @return {Boolean} True if this element is an ancestor of el, else false
7241          */
7242         contains : function(el){
7243             if(!el){return false;}
7244             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7245         },
7246
7247         /**
7248          * Checks whether the element is currently visible using both visibility and display properties.
7249          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7250          * @return {Boolean} True if the element is currently visible, else false
7251          */
7252         isVisible : function(deep) {
7253             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7254             if(deep !== true || !vis){
7255                 return vis;
7256             }
7257             var p = this.dom.parentNode;
7258             while(p && p.tagName.toLowerCase() != "body"){
7259                 if(!Roo.fly(p, '_isVisible').isVisible()){
7260                     return false;
7261                 }
7262                 p = p.parentNode;
7263             }
7264             return true;
7265         },
7266
7267         /**
7268          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7269          * @param {String} selector The CSS selector
7270          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7271          * @return {CompositeElement/CompositeElementLite} The composite element
7272          */
7273         select : function(selector, unique){
7274             return El.select(selector, unique, this.dom);
7275         },
7276
7277         /**
7278          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7279          * @param {String} selector The CSS selector
7280          * @return {Array} An array of the matched nodes
7281          */
7282         query : function(selector, unique){
7283             return Roo.DomQuery.select(selector, this.dom);
7284         },
7285
7286         /**
7287          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7288          * @param {String} selector The CSS selector
7289          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7290          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7291          */
7292         child : function(selector, returnDom){
7293             var n = Roo.DomQuery.selectNode(selector, this.dom);
7294             return returnDom ? n : Roo.get(n);
7295         },
7296
7297         /**
7298          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7299          * @param {String} selector The CSS selector
7300          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7301          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7302          */
7303         down : function(selector, returnDom){
7304             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7305             return returnDom ? n : Roo.get(n);
7306         },
7307
7308         /**
7309          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7310          * @param {String} group The group the DD object is member of
7311          * @param {Object} config The DD config object
7312          * @param {Object} overrides An object containing methods to override/implement on the DD object
7313          * @return {Roo.dd.DD} The DD object
7314          */
7315         initDD : function(group, config, overrides){
7316             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7317             return Roo.apply(dd, overrides);
7318         },
7319
7320         /**
7321          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7322          * @param {String} group The group the DDProxy object is member of
7323          * @param {Object} config The DDProxy config object
7324          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7325          * @return {Roo.dd.DDProxy} The DDProxy object
7326          */
7327         initDDProxy : function(group, config, overrides){
7328             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7329             return Roo.apply(dd, overrides);
7330         },
7331
7332         /**
7333          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7334          * @param {String} group The group the DDTarget object is member of
7335          * @param {Object} config The DDTarget config object
7336          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7337          * @return {Roo.dd.DDTarget} The DDTarget object
7338          */
7339         initDDTarget : function(group, config, overrides){
7340             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7341             return Roo.apply(dd, overrides);
7342         },
7343
7344         /**
7345          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7346          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7347          * @param {Boolean} visible Whether the element is visible
7348          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7349          * @return {Roo.Element} this
7350          */
7351          setVisible : function(visible, animate){
7352             if(!animate || !A){
7353                 if(this.visibilityMode == El.DISPLAY){
7354                     this.setDisplayed(visible);
7355                 }else{
7356                     this.fixDisplay();
7357                     this.dom.style.visibility = visible ? "visible" : "hidden";
7358                 }
7359             }else{
7360                 // closure for composites
7361                 var dom = this.dom;
7362                 var visMode = this.visibilityMode;
7363                 if(visible){
7364                     this.setOpacity(.01);
7365                     this.setVisible(true);
7366                 }
7367                 this.anim({opacity: { to: (visible?1:0) }},
7368                       this.preanim(arguments, 1),
7369                       null, .35, 'easeIn', function(){
7370                          if(!visible){
7371                              if(visMode == El.DISPLAY){
7372                                  dom.style.display = "none";
7373                              }else{
7374                                  dom.style.visibility = "hidden";
7375                              }
7376                              Roo.get(dom).setOpacity(1);
7377                          }
7378                      });
7379             }
7380             return this;
7381         },
7382
7383         /**
7384          * Returns true if display is not "none"
7385          * @return {Boolean}
7386          */
7387         isDisplayed : function() {
7388             return this.getStyle("display") != "none";
7389         },
7390
7391         /**
7392          * Toggles the element's visibility or display, depending on visibility mode.
7393          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7394          * @return {Roo.Element} this
7395          */
7396         toggle : function(animate){
7397             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7398             return this;
7399         },
7400
7401         /**
7402          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7403          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7404          * @return {Roo.Element} this
7405          */
7406         setDisplayed : function(value) {
7407             if(typeof value == "boolean"){
7408                value = value ? this.originalDisplay : "none";
7409             }
7410             this.setStyle("display", value);
7411             return this;
7412         },
7413
7414         /**
7415          * Tries to focus the element. Any exceptions are caught and ignored.
7416          * @return {Roo.Element} this
7417          */
7418         focus : function() {
7419             try{
7420                 this.dom.focus();
7421             }catch(e){}
7422             return this;
7423         },
7424
7425         /**
7426          * Tries to blur the element. Any exceptions are caught and ignored.
7427          * @return {Roo.Element} this
7428          */
7429         blur : function() {
7430             try{
7431                 this.dom.blur();
7432             }catch(e){}
7433             return this;
7434         },
7435
7436         /**
7437          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7438          * @param {String/Array} className The CSS class to add, or an array of classes
7439          * @return {Roo.Element} this
7440          */
7441         addClass : function(className){
7442             if(className instanceof Array){
7443                 for(var i = 0, len = className.length; i < len; i++) {
7444                     this.addClass(className[i]);
7445                 }
7446             }else{
7447                 if(className && !this.hasClass(className)){
7448                     this.dom.className = this.dom.className + " " + className;
7449                 }
7450             }
7451             return this;
7452         },
7453
7454         /**
7455          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7456          * @param {String/Array} className The CSS class to add, or an array of classes
7457          * @return {Roo.Element} this
7458          */
7459         radioClass : function(className){
7460             var siblings = this.dom.parentNode.childNodes;
7461             for(var i = 0; i < siblings.length; i++) {
7462                 var s = siblings[i];
7463                 if(s.nodeType == 1){
7464                     Roo.get(s).removeClass(className);
7465                 }
7466             }
7467             this.addClass(className);
7468             return this;
7469         },
7470
7471         /**
7472          * Removes one or more CSS classes from the element.
7473          * @param {String/Array} className The CSS class to remove, or an array of classes
7474          * @return {Roo.Element} this
7475          */
7476         removeClass : function(className){
7477             if(!className || !this.dom.className){
7478                 return this;
7479             }
7480             if(className instanceof Array){
7481                 for(var i = 0, len = className.length; i < len; i++) {
7482                     this.removeClass(className[i]);
7483                 }
7484             }else{
7485                 if(this.hasClass(className)){
7486                     var re = this.classReCache[className];
7487                     if (!re) {
7488                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7489                        this.classReCache[className] = re;
7490                     }
7491                     this.dom.className =
7492                         this.dom.className.replace(re, " ");
7493                 }
7494             }
7495             return this;
7496         },
7497
7498         // private
7499         classReCache: {},
7500
7501         /**
7502          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7503          * @param {String} className The CSS class to toggle
7504          * @return {Roo.Element} this
7505          */
7506         toggleClass : function(className){
7507             if(this.hasClass(className)){
7508                 this.removeClass(className);
7509             }else{
7510                 this.addClass(className);
7511             }
7512             return this;
7513         },
7514
7515         /**
7516          * Checks if the specified CSS class exists on this element's DOM node.
7517          * @param {String} className The CSS class to check for
7518          * @return {Boolean} True if the class exists, else false
7519          */
7520         hasClass : function(className){
7521             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7522         },
7523
7524         /**
7525          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7526          * @param {String} oldClassName The CSS class to replace
7527          * @param {String} newClassName The replacement CSS class
7528          * @return {Roo.Element} this
7529          */
7530         replaceClass : function(oldClassName, newClassName){
7531             this.removeClass(oldClassName);
7532             this.addClass(newClassName);
7533             return this;
7534         },
7535
7536         /**
7537          * Returns an object with properties matching the styles requested.
7538          * For example, el.getStyles('color', 'font-size', 'width') might return
7539          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7540          * @param {String} style1 A style name
7541          * @param {String} style2 A style name
7542          * @param {String} etc.
7543          * @return {Object} The style object
7544          */
7545         getStyles : function(){
7546             var a = arguments, len = a.length, r = {};
7547             for(var i = 0; i < len; i++){
7548                 r[a[i]] = this.getStyle(a[i]);
7549             }
7550             return r;
7551         },
7552
7553         /**
7554          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7555          * @param {String} property The style property whose value is returned.
7556          * @return {String} The current value of the style property for this element.
7557          */
7558         getStyle : function(){
7559             return view && view.getComputedStyle ?
7560                 function(prop){
7561                     var el = this.dom, v, cs, camel;
7562                     if(prop == 'float'){
7563                         prop = "cssFloat";
7564                     }
7565                     if(el.style && (v = el.style[prop])){
7566                         return v;
7567                     }
7568                     if(cs = view.getComputedStyle(el, "")){
7569                         if(!(camel = propCache[prop])){
7570                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7571                         }
7572                         return cs[camel];
7573                     }
7574                     return null;
7575                 } :
7576                 function(prop){
7577                     var el = this.dom, v, cs, camel;
7578                     if(prop == 'opacity'){
7579                         if(typeof el.style.filter == 'string'){
7580                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7581                             if(m){
7582                                 var fv = parseFloat(m[1]);
7583                                 if(!isNaN(fv)){
7584                                     return fv ? fv / 100 : 0;
7585                                 }
7586                             }
7587                         }
7588                         return 1;
7589                     }else if(prop == 'float'){
7590                         prop = "styleFloat";
7591                     }
7592                     if(!(camel = propCache[prop])){
7593                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7594                     }
7595                     if(v = el.style[camel]){
7596                         return v;
7597                     }
7598                     if(cs = el.currentStyle){
7599                         return cs[camel];
7600                     }
7601                     return null;
7602                 };
7603         }(),
7604
7605         /**
7606          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7607          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7608          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7609          * @return {Roo.Element} this
7610          */
7611         setStyle : function(prop, value){
7612             if(typeof prop == "string"){
7613                 
7614                 if (prop == 'float') {
7615                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7616                     return this;
7617                 }
7618                 
7619                 var camel;
7620                 if(!(camel = propCache[prop])){
7621                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7622                 }
7623                 
7624                 if(camel == 'opacity') {
7625                     this.setOpacity(value);
7626                 }else{
7627                     this.dom.style[camel] = value;
7628                 }
7629             }else{
7630                 for(var style in prop){
7631                     if(typeof prop[style] != "function"){
7632                        this.setStyle(style, prop[style]);
7633                     }
7634                 }
7635             }
7636             return this;
7637         },
7638
7639         /**
7640          * More flexible version of {@link #setStyle} for setting style properties.
7641          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7642          * a function which returns such a specification.
7643          * @return {Roo.Element} this
7644          */
7645         applyStyles : function(style){
7646             Roo.DomHelper.applyStyles(this.dom, style);
7647             return this;
7648         },
7649
7650         /**
7651           * 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).
7652           * @return {Number} The X position of the element
7653           */
7654         getX : function(){
7655             return D.getX(this.dom);
7656         },
7657
7658         /**
7659           * 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).
7660           * @return {Number} The Y position of the element
7661           */
7662         getY : function(){
7663             return D.getY(this.dom);
7664         },
7665
7666         /**
7667           * 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).
7668           * @return {Array} The XY position of the element
7669           */
7670         getXY : function(){
7671             return D.getXY(this.dom);
7672         },
7673
7674         /**
7675          * 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).
7676          * @param {Number} The X position of the element
7677          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7678          * @return {Roo.Element} this
7679          */
7680         setX : function(x, animate){
7681             if(!animate || !A){
7682                 D.setX(this.dom, x);
7683             }else{
7684                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7685             }
7686             return this;
7687         },
7688
7689         /**
7690          * 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).
7691          * @param {Number} The Y position of the element
7692          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7693          * @return {Roo.Element} this
7694          */
7695         setY : function(y, animate){
7696             if(!animate || !A){
7697                 D.setY(this.dom, y);
7698             }else{
7699                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7700             }
7701             return this;
7702         },
7703
7704         /**
7705          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7706          * @param {String} left The left CSS property value
7707          * @return {Roo.Element} this
7708          */
7709         setLeft : function(left){
7710             this.setStyle("left", this.addUnits(left));
7711             return this;
7712         },
7713
7714         /**
7715          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7716          * @param {String} top The top CSS property value
7717          * @return {Roo.Element} this
7718          */
7719         setTop : function(top){
7720             this.setStyle("top", this.addUnits(top));
7721             return this;
7722         },
7723
7724         /**
7725          * Sets the element's CSS right style.
7726          * @param {String} right The right CSS property value
7727          * @return {Roo.Element} this
7728          */
7729         setRight : function(right){
7730             this.setStyle("right", this.addUnits(right));
7731             return this;
7732         },
7733
7734         /**
7735          * Sets the element's CSS bottom style.
7736          * @param {String} bottom The bottom CSS property value
7737          * @return {Roo.Element} this
7738          */
7739         setBottom : function(bottom){
7740             this.setStyle("bottom", this.addUnits(bottom));
7741             return this;
7742         },
7743
7744         /**
7745          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7746          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7747          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7748          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7749          * @return {Roo.Element} this
7750          */
7751         setXY : function(pos, animate){
7752             if(!animate || !A){
7753                 D.setXY(this.dom, pos);
7754             }else{
7755                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7756             }
7757             return this;
7758         },
7759
7760         /**
7761          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7762          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7763          * @param {Number} x X value for new position (coordinates are page-based)
7764          * @param {Number} y Y value for new position (coordinates are page-based)
7765          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7766          * @return {Roo.Element} this
7767          */
7768         setLocation : function(x, y, animate){
7769             this.setXY([x, y], this.preanim(arguments, 2));
7770             return this;
7771         },
7772
7773         /**
7774          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7775          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7776          * @param {Number} x X value for new position (coordinates are page-based)
7777          * @param {Number} y Y value for new position (coordinates are page-based)
7778          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7779          * @return {Roo.Element} this
7780          */
7781         moveTo : function(x, y, animate){
7782             this.setXY([x, y], this.preanim(arguments, 2));
7783             return this;
7784         },
7785
7786         /**
7787          * Returns the region of the given element.
7788          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7789          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7790          */
7791         getRegion : function(){
7792             return D.getRegion(this.dom);
7793         },
7794
7795         /**
7796          * Returns the offset height of the element
7797          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7798          * @return {Number} The element's height
7799          */
7800         getHeight : function(contentHeight){
7801             var h = this.dom.offsetHeight || 0;
7802             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7803         },
7804
7805         /**
7806          * Returns the offset width of the element
7807          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7808          * @return {Number} The element's width
7809          */
7810         getWidth : function(contentWidth){
7811             var w = this.dom.offsetWidth || 0;
7812             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7813         },
7814
7815         /**
7816          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7817          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7818          * if a height has not been set using CSS.
7819          * @return {Number}
7820          */
7821         getComputedHeight : function(){
7822             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7823             if(!h){
7824                 h = parseInt(this.getStyle('height'), 10) || 0;
7825                 if(!this.isBorderBox()){
7826                     h += this.getFrameWidth('tb');
7827                 }
7828             }
7829             return h;
7830         },
7831
7832         /**
7833          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7834          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7835          * if a width has not been set using CSS.
7836          * @return {Number}
7837          */
7838         getComputedWidth : function(){
7839             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7840             if(!w){
7841                 w = parseInt(this.getStyle('width'), 10) || 0;
7842                 if(!this.isBorderBox()){
7843                     w += this.getFrameWidth('lr');
7844                 }
7845             }
7846             return w;
7847         },
7848
7849         /**
7850          * Returns the size of the element.
7851          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7852          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7853          */
7854         getSize : function(contentSize){
7855             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7856         },
7857
7858         /**
7859          * Returns the width and height of the viewport.
7860          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7861          */
7862         getViewSize : function(){
7863             var d = this.dom, doc = document, aw = 0, ah = 0;
7864             if(d == doc || d == doc.body){
7865                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7866             }else{
7867                 return {
7868                     width : d.clientWidth,
7869                     height: d.clientHeight
7870                 };
7871             }
7872         },
7873
7874         /**
7875          * Returns the value of the "value" attribute
7876          * @param {Boolean} asNumber true to parse the value as a number
7877          * @return {String/Number}
7878          */
7879         getValue : function(asNumber){
7880             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7881         },
7882
7883         // private
7884         adjustWidth : function(width){
7885             if(typeof width == "number"){
7886                 if(this.autoBoxAdjust && !this.isBorderBox()){
7887                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7888                 }
7889                 if(width < 0){
7890                     width = 0;
7891                 }
7892             }
7893             return width;
7894         },
7895
7896         // private
7897         adjustHeight : function(height){
7898             if(typeof height == "number"){
7899                if(this.autoBoxAdjust && !this.isBorderBox()){
7900                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7901                }
7902                if(height < 0){
7903                    height = 0;
7904                }
7905             }
7906             return height;
7907         },
7908
7909         /**
7910          * Set the width of the element
7911          * @param {Number} width The new width
7912          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7913          * @return {Roo.Element} this
7914          */
7915         setWidth : function(width, animate){
7916             width = this.adjustWidth(width);
7917             if(!animate || !A){
7918                 this.dom.style.width = this.addUnits(width);
7919             }else{
7920                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7921             }
7922             return this;
7923         },
7924
7925         /**
7926          * Set the height of the element
7927          * @param {Number} height The new height
7928          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7929          * @return {Roo.Element} this
7930          */
7931          setHeight : function(height, animate){
7932             height = this.adjustHeight(height);
7933             if(!animate || !A){
7934                 this.dom.style.height = this.addUnits(height);
7935             }else{
7936                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7937             }
7938             return this;
7939         },
7940
7941         /**
7942          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7943          * @param {Number} width The new width
7944          * @param {Number} height The new height
7945          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7946          * @return {Roo.Element} this
7947          */
7948          setSize : function(width, height, animate){
7949             if(typeof width == "object"){ // in case of object from getSize()
7950                 height = width.height; width = width.width;
7951             }
7952             width = this.adjustWidth(width); height = this.adjustHeight(height);
7953             if(!animate || !A){
7954                 this.dom.style.width = this.addUnits(width);
7955                 this.dom.style.height = this.addUnits(height);
7956             }else{
7957                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7958             }
7959             return this;
7960         },
7961
7962         /**
7963          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7964          * @param {Number} x X value for new position (coordinates are page-based)
7965          * @param {Number} y Y value for new position (coordinates are page-based)
7966          * @param {Number} width The new width
7967          * @param {Number} height The new height
7968          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7969          * @return {Roo.Element} this
7970          */
7971         setBounds : function(x, y, width, height, animate){
7972             if(!animate || !A){
7973                 this.setSize(width, height);
7974                 this.setLocation(x, y);
7975             }else{
7976                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7977                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7978                               this.preanim(arguments, 4), 'motion');
7979             }
7980             return this;
7981         },
7982
7983         /**
7984          * 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.
7985          * @param {Roo.lib.Region} region The region to fill
7986          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7987          * @return {Roo.Element} this
7988          */
7989         setRegion : function(region, animate){
7990             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7991             return this;
7992         },
7993
7994         /**
7995          * Appends an event handler
7996          *
7997          * @param {String}   eventName     The type of event to append
7998          * @param {Function} fn        The method the event invokes
7999          * @param {Object} scope       (optional) The scope (this object) of the fn
8000          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8001          */
8002         addListener : function(eventName, fn, scope, options){
8003             if (this.dom) {
8004                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8005             }
8006         },
8007
8008         /**
8009          * Removes an event handler from this element
8010          * @param {String} eventName the type of event to remove
8011          * @param {Function} fn the method the event invokes
8012          * @return {Roo.Element} this
8013          */
8014         removeListener : function(eventName, fn){
8015             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8016             return this;
8017         },
8018
8019         /**
8020          * Removes all previous added listeners from this element
8021          * @return {Roo.Element} this
8022          */
8023         removeAllListeners : function(){
8024             E.purgeElement(this.dom);
8025             return this;
8026         },
8027
8028         relayEvent : function(eventName, observable){
8029             this.on(eventName, function(e){
8030                 observable.fireEvent(eventName, e);
8031             });
8032         },
8033
8034         /**
8035          * Set the opacity of the element
8036          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8037          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8038          * @return {Roo.Element} this
8039          */
8040          setOpacity : function(opacity, animate){
8041             if(!animate || !A){
8042                 var s = this.dom.style;
8043                 if(Roo.isIE){
8044                     s.zoom = 1;
8045                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8046                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8047                 }else{
8048                     s.opacity = opacity;
8049                 }
8050             }else{
8051                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8052             }
8053             return this;
8054         },
8055
8056         /**
8057          * Gets the left X coordinate
8058          * @param {Boolean} local True to get the local css position instead of page coordinate
8059          * @return {Number}
8060          */
8061         getLeft : function(local){
8062             if(!local){
8063                 return this.getX();
8064             }else{
8065                 return parseInt(this.getStyle("left"), 10) || 0;
8066             }
8067         },
8068
8069         /**
8070          * Gets the right X coordinate of the element (element X position + element width)
8071          * @param {Boolean} local True to get the local css position instead of page coordinate
8072          * @return {Number}
8073          */
8074         getRight : function(local){
8075             if(!local){
8076                 return this.getX() + this.getWidth();
8077             }else{
8078                 return (this.getLeft(true) + this.getWidth()) || 0;
8079             }
8080         },
8081
8082         /**
8083          * Gets the top Y coordinate
8084          * @param {Boolean} local True to get the local css position instead of page coordinate
8085          * @return {Number}
8086          */
8087         getTop : function(local) {
8088             if(!local){
8089                 return this.getY();
8090             }else{
8091                 return parseInt(this.getStyle("top"), 10) || 0;
8092             }
8093         },
8094
8095         /**
8096          * Gets the bottom Y coordinate of the element (element Y position + element height)
8097          * @param {Boolean} local True to get the local css position instead of page coordinate
8098          * @return {Number}
8099          */
8100         getBottom : function(local){
8101             if(!local){
8102                 return this.getY() + this.getHeight();
8103             }else{
8104                 return (this.getTop(true) + this.getHeight()) || 0;
8105             }
8106         },
8107
8108         /**
8109         * Initializes positioning on this element. If a desired position is not passed, it will make the
8110         * the element positioned relative IF it is not already positioned.
8111         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8112         * @param {Number} zIndex (optional) The zIndex to apply
8113         * @param {Number} x (optional) Set the page X position
8114         * @param {Number} y (optional) Set the page Y position
8115         */
8116         position : function(pos, zIndex, x, y){
8117             if(!pos){
8118                if(this.getStyle('position') == 'static'){
8119                    this.setStyle('position', 'relative');
8120                }
8121             }else{
8122                 this.setStyle("position", pos);
8123             }
8124             if(zIndex){
8125                 this.setStyle("z-index", zIndex);
8126             }
8127             if(x !== undefined && y !== undefined){
8128                 this.setXY([x, y]);
8129             }else if(x !== undefined){
8130                 this.setX(x);
8131             }else if(y !== undefined){
8132                 this.setY(y);
8133             }
8134         },
8135
8136         /**
8137         * Clear positioning back to the default when the document was loaded
8138         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8139         * @return {Roo.Element} this
8140          */
8141         clearPositioning : function(value){
8142             value = value ||'';
8143             this.setStyle({
8144                 "left": value,
8145                 "right": value,
8146                 "top": value,
8147                 "bottom": value,
8148                 "z-index": "",
8149                 "position" : "static"
8150             });
8151             return this;
8152         },
8153
8154         /**
8155         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8156         * snapshot before performing an update and then restoring the element.
8157         * @return {Object}
8158         */
8159         getPositioning : function(){
8160             var l = this.getStyle("left");
8161             var t = this.getStyle("top");
8162             return {
8163                 "position" : this.getStyle("position"),
8164                 "left" : l,
8165                 "right" : l ? "" : this.getStyle("right"),
8166                 "top" : t,
8167                 "bottom" : t ? "" : this.getStyle("bottom"),
8168                 "z-index" : this.getStyle("z-index")
8169             };
8170         },
8171
8172         /**
8173          * Gets the width of the border(s) for the specified side(s)
8174          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8175          * passing lr would get the border (l)eft width + the border (r)ight width.
8176          * @return {Number} The width of the sides passed added together
8177          */
8178         getBorderWidth : function(side){
8179             return this.addStyles(side, El.borders);
8180         },
8181
8182         /**
8183          * Gets the width of the padding(s) for the specified side(s)
8184          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8185          * passing lr would get the padding (l)eft + the padding (r)ight.
8186          * @return {Number} The padding of the sides passed added together
8187          */
8188         getPadding : function(side){
8189             return this.addStyles(side, El.paddings);
8190         },
8191
8192         /**
8193         * Set positioning with an object returned by getPositioning().
8194         * @param {Object} posCfg
8195         * @return {Roo.Element} this
8196          */
8197         setPositioning : function(pc){
8198             this.applyStyles(pc);
8199             if(pc.right == "auto"){
8200                 this.dom.style.right = "";
8201             }
8202             if(pc.bottom == "auto"){
8203                 this.dom.style.bottom = "";
8204             }
8205             return this;
8206         },
8207
8208         // private
8209         fixDisplay : function(){
8210             if(this.getStyle("display") == "none"){
8211                 this.setStyle("visibility", "hidden");
8212                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8213                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8214                     this.setStyle("display", "block");
8215                 }
8216             }
8217         },
8218
8219         /**
8220          * Quick set left and top adding default units
8221          * @param {String} left The left CSS property value
8222          * @param {String} top The top CSS property value
8223          * @return {Roo.Element} this
8224          */
8225          setLeftTop : function(left, top){
8226             this.dom.style.left = this.addUnits(left);
8227             this.dom.style.top = this.addUnits(top);
8228             return this;
8229         },
8230
8231         /**
8232          * Move this element relative to its current position.
8233          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8234          * @param {Number} distance How far to move the element in pixels
8235          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8236          * @return {Roo.Element} this
8237          */
8238          move : function(direction, distance, animate){
8239             var xy = this.getXY();
8240             direction = direction.toLowerCase();
8241             switch(direction){
8242                 case "l":
8243                 case "left":
8244                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8245                     break;
8246                case "r":
8247                case "right":
8248                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8249                     break;
8250                case "t":
8251                case "top":
8252                case "up":
8253                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8254                     break;
8255                case "b":
8256                case "bottom":
8257                case "down":
8258                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8259                     break;
8260             }
8261             return this;
8262         },
8263
8264         /**
8265          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8266          * @return {Roo.Element} this
8267          */
8268         clip : function(){
8269             if(!this.isClipped){
8270                this.isClipped = true;
8271                this.originalClip = {
8272                    "o": this.getStyle("overflow"),
8273                    "x": this.getStyle("overflow-x"),
8274                    "y": this.getStyle("overflow-y")
8275                };
8276                this.setStyle("overflow", "hidden");
8277                this.setStyle("overflow-x", "hidden");
8278                this.setStyle("overflow-y", "hidden");
8279             }
8280             return this;
8281         },
8282
8283         /**
8284          *  Return clipping (overflow) to original clipping before clip() was called
8285          * @return {Roo.Element} this
8286          */
8287         unclip : function(){
8288             if(this.isClipped){
8289                 this.isClipped = false;
8290                 var o = this.originalClip;
8291                 if(o.o){this.setStyle("overflow", o.o);}
8292                 if(o.x){this.setStyle("overflow-x", o.x);}
8293                 if(o.y){this.setStyle("overflow-y", o.y);}
8294             }
8295             return this;
8296         },
8297
8298
8299         /**
8300          * Gets the x,y coordinates specified by the anchor position on the element.
8301          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8302          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8303          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8304          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8305          * @return {Array} [x, y] An array containing the element's x and y coordinates
8306          */
8307         getAnchorXY : function(anchor, local, s){
8308             //Passing a different size is useful for pre-calculating anchors,
8309             //especially for anchored animations that change the el size.
8310
8311             var w, h, vp = false;
8312             if(!s){
8313                 var d = this.dom;
8314                 if(d == document.body || d == document){
8315                     vp = true;
8316                     w = D.getViewWidth(); h = D.getViewHeight();
8317                 }else{
8318                     w = this.getWidth(); h = this.getHeight();
8319                 }
8320             }else{
8321                 w = s.width;  h = s.height;
8322             }
8323             var x = 0, y = 0, r = Math.round;
8324             switch((anchor || "tl").toLowerCase()){
8325                 case "c":
8326                     x = r(w*.5);
8327                     y = r(h*.5);
8328                 break;
8329                 case "t":
8330                     x = r(w*.5);
8331                     y = 0;
8332                 break;
8333                 case "l":
8334                     x = 0;
8335                     y = r(h*.5);
8336                 break;
8337                 case "r":
8338                     x = w;
8339                     y = r(h*.5);
8340                 break;
8341                 case "b":
8342                     x = r(w*.5);
8343                     y = h;
8344                 break;
8345                 case "tl":
8346                     x = 0;
8347                     y = 0;
8348                 break;
8349                 case "bl":
8350                     x = 0;
8351                     y = h;
8352                 break;
8353                 case "br":
8354                     x = w;
8355                     y = h;
8356                 break;
8357                 case "tr":
8358                     x = w;
8359                     y = 0;
8360                 break;
8361             }
8362             if(local === true){
8363                 return [x, y];
8364             }
8365             if(vp){
8366                 var sc = this.getScroll();
8367                 return [x + sc.left, y + sc.top];
8368             }
8369             //Add the element's offset xy
8370             var o = this.getXY();
8371             return [x+o[0], y+o[1]];
8372         },
8373
8374         /**
8375          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8376          * supported position values.
8377          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8378          * @param {String} position The position to align to.
8379          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8380          * @return {Array} [x, y]
8381          */
8382         getAlignToXY : function(el, p, o){
8383             el = Roo.get(el);
8384             var d = this.dom;
8385             if(!el.dom){
8386                 throw "Element.alignTo with an element that doesn't exist";
8387             }
8388             var c = false; //constrain to viewport
8389             var p1 = "", p2 = "";
8390             o = o || [0,0];
8391
8392             if(!p){
8393                 p = "tl-bl";
8394             }else if(p == "?"){
8395                 p = "tl-bl?";
8396             }else if(p.indexOf("-") == -1){
8397                 p = "tl-" + p;
8398             }
8399             p = p.toLowerCase();
8400             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8401             if(!m){
8402                throw "Element.alignTo with an invalid alignment " + p;
8403             }
8404             p1 = m[1]; p2 = m[2]; c = !!m[3];
8405
8406             //Subtract the aligned el's internal xy from the target's offset xy
8407             //plus custom offset to get the aligned el's new offset xy
8408             var a1 = this.getAnchorXY(p1, true);
8409             var a2 = el.getAnchorXY(p2, false);
8410             var x = a2[0] - a1[0] + o[0];
8411             var y = a2[1] - a1[1] + o[1];
8412             if(c){
8413                 //constrain the aligned el to viewport if necessary
8414                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8415                 // 5px of margin for ie
8416                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8417
8418                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8419                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8420                 //otherwise swap the aligned el to the opposite border of the target.
8421                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8422                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8423                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8424                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8425
8426                var doc = document;
8427                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8428                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8429
8430                if((x+w) > dw + scrollX){
8431                     x = swapX ? r.left-w : dw+scrollX-w;
8432                 }
8433                if(x < scrollX){
8434                    x = swapX ? r.right : scrollX;
8435                }
8436                if((y+h) > dh + scrollY){
8437                     y = swapY ? r.top-h : dh+scrollY-h;
8438                 }
8439                if (y < scrollY){
8440                    y = swapY ? r.bottom : scrollY;
8441                }
8442             }
8443             return [x,y];
8444         },
8445
8446         // private
8447         getConstrainToXY : function(){
8448             var os = {top:0, left:0, bottom:0, right: 0};
8449
8450             return function(el, local, offsets, proposedXY){
8451                 el = Roo.get(el);
8452                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8453
8454                 var vw, vh, vx = 0, vy = 0;
8455                 if(el.dom == document.body || el.dom == document){
8456                     vw = Roo.lib.Dom.getViewWidth();
8457                     vh = Roo.lib.Dom.getViewHeight();
8458                 }else{
8459                     vw = el.dom.clientWidth;
8460                     vh = el.dom.clientHeight;
8461                     if(!local){
8462                         var vxy = el.getXY();
8463                         vx = vxy[0];
8464                         vy = vxy[1];
8465                     }
8466                 }
8467
8468                 var s = el.getScroll();
8469
8470                 vx += offsets.left + s.left;
8471                 vy += offsets.top + s.top;
8472
8473                 vw -= offsets.right;
8474                 vh -= offsets.bottom;
8475
8476                 var vr = vx+vw;
8477                 var vb = vy+vh;
8478
8479                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8480                 var x = xy[0], y = xy[1];
8481                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8482
8483                 // only move it if it needs it
8484                 var moved = false;
8485
8486                 // first validate right/bottom
8487                 if((x + w) > vr){
8488                     x = vr - w;
8489                     moved = true;
8490                 }
8491                 if((y + h) > vb){
8492                     y = vb - h;
8493                     moved = true;
8494                 }
8495                 // then make sure top/left isn't negative
8496                 if(x < vx){
8497                     x = vx;
8498                     moved = true;
8499                 }
8500                 if(y < vy){
8501                     y = vy;
8502                     moved = true;
8503                 }
8504                 return moved ? [x, y] : false;
8505             };
8506         }(),
8507
8508         // private
8509         adjustForConstraints : function(xy, parent, offsets){
8510             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8511         },
8512
8513         /**
8514          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8515          * document it aligns it to the viewport.
8516          * The position parameter is optional, and can be specified in any one of the following formats:
8517          * <ul>
8518          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8519          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8520          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8521          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8522          *   <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
8523          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8524          * </ul>
8525          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8526          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8527          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8528          * that specified in order to enforce the viewport constraints.
8529          * Following are all of the supported anchor positions:
8530     <pre>
8531     Value  Description
8532     -----  -----------------------------
8533     tl     The top left corner (default)
8534     t      The center of the top edge
8535     tr     The top right corner
8536     l      The center of the left edge
8537     c      In the center of the element
8538     r      The center of the right edge
8539     bl     The bottom left corner
8540     b      The center of the bottom edge
8541     br     The bottom right corner
8542     </pre>
8543     Example Usage:
8544     <pre><code>
8545     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8546     el.alignTo("other-el");
8547
8548     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8549     el.alignTo("other-el", "tr?");
8550
8551     // align the bottom right corner of el with the center left edge of other-el
8552     el.alignTo("other-el", "br-l?");
8553
8554     // align the center of el with the bottom left corner of other-el and
8555     // adjust the x position by -6 pixels (and the y position by 0)
8556     el.alignTo("other-el", "c-bl", [-6, 0]);
8557     </code></pre>
8558          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8559          * @param {String} position The position to align to.
8560          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8561          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8562          * @return {Roo.Element} this
8563          */
8564         alignTo : function(element, position, offsets, animate){
8565             var xy = this.getAlignToXY(element, position, offsets);
8566             this.setXY(xy, this.preanim(arguments, 3));
8567             return this;
8568         },
8569
8570         /**
8571          * Anchors an element to another element and realigns it when the window is resized.
8572          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8573          * @param {String} position The position to align to.
8574          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8575          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8576          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8577          * is a number, it is used as the buffer delay (defaults to 50ms).
8578          * @param {Function} callback The function to call after the animation finishes
8579          * @return {Roo.Element} this
8580          */
8581         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8582             var action = function(){
8583                 this.alignTo(el, alignment, offsets, animate);
8584                 Roo.callback(callback, this);
8585             };
8586             Roo.EventManager.onWindowResize(action, this);
8587             var tm = typeof monitorScroll;
8588             if(tm != 'undefined'){
8589                 Roo.EventManager.on(window, 'scroll', action, this,
8590                     {buffer: tm == 'number' ? monitorScroll : 50});
8591             }
8592             action.call(this); // align immediately
8593             return this;
8594         },
8595         /**
8596          * Clears any opacity settings from this element. Required in some cases for IE.
8597          * @return {Roo.Element} this
8598          */
8599         clearOpacity : function(){
8600             if (window.ActiveXObject) {
8601                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8602                     this.dom.style.filter = "";
8603                 }
8604             } else {
8605                 this.dom.style.opacity = "";
8606                 this.dom.style["-moz-opacity"] = "";
8607                 this.dom.style["-khtml-opacity"] = "";
8608             }
8609             return this;
8610         },
8611
8612         /**
8613          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8614          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8615          * @return {Roo.Element} this
8616          */
8617         hide : function(animate){
8618             this.setVisible(false, this.preanim(arguments, 0));
8619             return this;
8620         },
8621
8622         /**
8623         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8624         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8625          * @return {Roo.Element} this
8626          */
8627         show : function(animate){
8628             this.setVisible(true, this.preanim(arguments, 0));
8629             return this;
8630         },
8631
8632         /**
8633          * @private Test if size has a unit, otherwise appends the default
8634          */
8635         addUnits : function(size){
8636             return Roo.Element.addUnits(size, this.defaultUnit);
8637         },
8638
8639         /**
8640          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8641          * @return {Roo.Element} this
8642          */
8643         beginMeasure : function(){
8644             var el = this.dom;
8645             if(el.offsetWidth || el.offsetHeight){
8646                 return this; // offsets work already
8647             }
8648             var changed = [];
8649             var p = this.dom, b = document.body; // start with this element
8650             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8651                 var pe = Roo.get(p);
8652                 if(pe.getStyle('display') == 'none'){
8653                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8654                     p.style.visibility = "hidden";
8655                     p.style.display = "block";
8656                 }
8657                 p = p.parentNode;
8658             }
8659             this._measureChanged = changed;
8660             return this;
8661
8662         },
8663
8664         /**
8665          * Restores displays to before beginMeasure was called
8666          * @return {Roo.Element} this
8667          */
8668         endMeasure : function(){
8669             var changed = this._measureChanged;
8670             if(changed){
8671                 for(var i = 0, len = changed.length; i < len; i++) {
8672                     var r = changed[i];
8673                     r.el.style.visibility = r.visibility;
8674                     r.el.style.display = "none";
8675                 }
8676                 this._measureChanged = null;
8677             }
8678             return this;
8679         },
8680
8681         /**
8682         * Update the innerHTML of this element, optionally searching for and processing scripts
8683         * @param {String} html The new HTML
8684         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8685         * @param {Function} callback For async script loading you can be noticed when the update completes
8686         * @return {Roo.Element} this
8687          */
8688         update : function(html, loadScripts, callback){
8689             if(typeof html == "undefined"){
8690                 html = "";
8691             }
8692             if(loadScripts !== true){
8693                 this.dom.innerHTML = html;
8694                 if(typeof callback == "function"){
8695                     callback();
8696                 }
8697                 return this;
8698             }
8699             var id = Roo.id();
8700             var dom = this.dom;
8701
8702             html += '<span id="' + id + '"></span>';
8703
8704             E.onAvailable(id, function(){
8705                 var hd = document.getElementsByTagName("head")[0];
8706                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8707                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8708                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8709
8710                 var match;
8711                 while(match = re.exec(html)){
8712                     var attrs = match[1];
8713                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8714                     if(srcMatch && srcMatch[2]){
8715                        var s = document.createElement("script");
8716                        s.src = srcMatch[2];
8717                        var typeMatch = attrs.match(typeRe);
8718                        if(typeMatch && typeMatch[2]){
8719                            s.type = typeMatch[2];
8720                        }
8721                        hd.appendChild(s);
8722                     }else if(match[2] && match[2].length > 0){
8723                         if(window.execScript) {
8724                            window.execScript(match[2]);
8725                         } else {
8726                             /**
8727                              * eval:var:id
8728                              * eval:var:dom
8729                              * eval:var:html
8730                              * 
8731                              */
8732                            window.eval(match[2]);
8733                         }
8734                     }
8735                 }
8736                 var el = document.getElementById(id);
8737                 if(el){el.parentNode.removeChild(el);}
8738                 if(typeof callback == "function"){
8739                     callback();
8740                 }
8741             });
8742             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8743             return this;
8744         },
8745
8746         /**
8747          * Direct access to the UpdateManager update() method (takes the same parameters).
8748          * @param {String/Function} url The url for this request or a function to call to get the url
8749          * @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}
8750          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8751          * @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.
8752          * @return {Roo.Element} this
8753          */
8754         load : function(){
8755             var um = this.getUpdateManager();
8756             um.update.apply(um, arguments);
8757             return this;
8758         },
8759
8760         /**
8761         * Gets this element's UpdateManager
8762         * @return {Roo.UpdateManager} The UpdateManager
8763         */
8764         getUpdateManager : function(){
8765             if(!this.updateManager){
8766                 this.updateManager = new Roo.UpdateManager(this);
8767             }
8768             return this.updateManager;
8769         },
8770
8771         /**
8772          * Disables text selection for this element (normalized across browsers)
8773          * @return {Roo.Element} this
8774          */
8775         unselectable : function(){
8776             this.dom.unselectable = "on";
8777             this.swallowEvent("selectstart", true);
8778             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8779             this.addClass("x-unselectable");
8780             return this;
8781         },
8782
8783         /**
8784         * Calculates the x, y to center this element on the screen
8785         * @return {Array} The x, y values [x, y]
8786         */
8787         getCenterXY : function(){
8788             return this.getAlignToXY(document, 'c-c');
8789         },
8790
8791         /**
8792         * Centers the Element in either the viewport, or another Element.
8793         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8794         */
8795         center : function(centerIn){
8796             this.alignTo(centerIn || document, 'c-c');
8797             return this;
8798         },
8799
8800         /**
8801          * Tests various css rules/browsers to determine if this element uses a border box
8802          * @return {Boolean}
8803          */
8804         isBorderBox : function(){
8805             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8806         },
8807
8808         /**
8809          * Return a box {x, y, width, height} that can be used to set another elements
8810          * size/location to match this element.
8811          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8812          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8813          * @return {Object} box An object in the format {x, y, width, height}
8814          */
8815         getBox : function(contentBox, local){
8816             var xy;
8817             if(!local){
8818                 xy = this.getXY();
8819             }else{
8820                 var left = parseInt(this.getStyle("left"), 10) || 0;
8821                 var top = parseInt(this.getStyle("top"), 10) || 0;
8822                 xy = [left, top];
8823             }
8824             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8825             if(!contentBox){
8826                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8827             }else{
8828                 var l = this.getBorderWidth("l")+this.getPadding("l");
8829                 var r = this.getBorderWidth("r")+this.getPadding("r");
8830                 var t = this.getBorderWidth("t")+this.getPadding("t");
8831                 var b = this.getBorderWidth("b")+this.getPadding("b");
8832                 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)};
8833             }
8834             bx.right = bx.x + bx.width;
8835             bx.bottom = bx.y + bx.height;
8836             return bx;
8837         },
8838
8839         /**
8840          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8841          for more information about the sides.
8842          * @param {String} sides
8843          * @return {Number}
8844          */
8845         getFrameWidth : function(sides, onlyContentBox){
8846             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8847         },
8848
8849         /**
8850          * 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.
8851          * @param {Object} box The box to fill {x, y, width, height}
8852          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8853          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8854          * @return {Roo.Element} this
8855          */
8856         setBox : function(box, adjust, animate){
8857             var w = box.width, h = box.height;
8858             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8859                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8860                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8861             }
8862             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8863             return this;
8864         },
8865
8866         /**
8867          * Forces the browser to repaint this element
8868          * @return {Roo.Element} this
8869          */
8870          repaint : function(){
8871             var dom = this.dom;
8872             this.addClass("x-repaint");
8873             setTimeout(function(){
8874                 Roo.get(dom).removeClass("x-repaint");
8875             }, 1);
8876             return this;
8877         },
8878
8879         /**
8880          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8881          * then it returns the calculated width of the sides (see getPadding)
8882          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8883          * @return {Object/Number}
8884          */
8885         getMargins : function(side){
8886             if(!side){
8887                 return {
8888                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8889                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8890                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8891                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8892                 };
8893             }else{
8894                 return this.addStyles(side, El.margins);
8895              }
8896         },
8897
8898         // private
8899         addStyles : function(sides, styles){
8900             var val = 0, v, w;
8901             for(var i = 0, len = sides.length; i < len; i++){
8902                 v = this.getStyle(styles[sides.charAt(i)]);
8903                 if(v){
8904                      w = parseInt(v, 10);
8905                      if(w){ val += w; }
8906                 }
8907             }
8908             return val;
8909         },
8910
8911         /**
8912          * Creates a proxy element of this element
8913          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8914          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8915          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8916          * @return {Roo.Element} The new proxy element
8917          */
8918         createProxy : function(config, renderTo, matchBox){
8919             if(renderTo){
8920                 renderTo = Roo.getDom(renderTo);
8921             }else{
8922                 renderTo = document.body;
8923             }
8924             config = typeof config == "object" ?
8925                 config : {tag : "div", cls: config};
8926             var proxy = Roo.DomHelper.append(renderTo, config, true);
8927             if(matchBox){
8928                proxy.setBox(this.getBox());
8929             }
8930             return proxy;
8931         },
8932
8933         /**
8934          * Puts a mask over this element to disable user interaction. Requires core.css.
8935          * This method can only be applied to elements which accept child nodes.
8936          * @param {String} msg (optional) A message to display in the mask
8937          * @param {String} msgCls (optional) A css class to apply to the msg element
8938          * @return {Element} The mask  element
8939          */
8940         mask : function(msg, msgCls)
8941         {
8942             if(this.getStyle("position") == "static"){
8943                 this.setStyle("position", "relative");
8944             }
8945             if(!this._mask){
8946                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8947             }
8948             this.addClass("x-masked");
8949             this._mask.setDisplayed(true);
8950             
8951             // we wander
8952             var z = 0;
8953             var dom = this.dom
8954             while (dom && dom.style) {
8955                 if (!isNaN(parseInt(dom.style.zIndex))) {
8956                     z = Math.max(z, parseInt(dom.style.zIndex));
8957                 }
8958                 dom = dom.parentNode;
8959             }
8960             // if we are masking the body - then it hides everything..
8961             if (this.dom == document.body) {
8962                 z = 1000000;
8963                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8964                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8965             }
8966            
8967             if(typeof msg == 'string'){
8968                 if(!this._maskMsg){
8969                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8970                 }
8971                 var mm = this._maskMsg;
8972                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8973                 mm.dom.firstChild.innerHTML = msg;
8974                 mm.setDisplayed(true);
8975                 mm.center(this);
8976                 mm.setStyle('z-index', z + 102);
8977             }
8978             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8979                 this._mask.setHeight(this.getHeight());
8980             }
8981             this._mask.setStyle('z-index', z + 100);
8982             
8983             return this._mask;
8984         },
8985
8986         /**
8987          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8988          * it is cached for reuse.
8989          */
8990         unmask : function(removeEl){
8991             if(this._mask){
8992                 if(removeEl === true){
8993                     this._mask.remove();
8994                     delete this._mask;
8995                     if(this._maskMsg){
8996                         this._maskMsg.remove();
8997                         delete this._maskMsg;
8998                     }
8999                 }else{
9000                     this._mask.setDisplayed(false);
9001                     if(this._maskMsg){
9002                         this._maskMsg.setDisplayed(false);
9003                     }
9004                 }
9005             }
9006             this.removeClass("x-masked");
9007         },
9008
9009         /**
9010          * Returns true if this element is masked
9011          * @return {Boolean}
9012          */
9013         isMasked : function(){
9014             return this._mask && this._mask.isVisible();
9015         },
9016
9017         /**
9018          * Creates an iframe shim for this element to keep selects and other windowed objects from
9019          * showing through.
9020          * @return {Roo.Element} The new shim element
9021          */
9022         createShim : function(){
9023             var el = document.createElement('iframe');
9024             el.frameBorder = 'no';
9025             el.className = 'roo-shim';
9026             if(Roo.isIE && Roo.isSecure){
9027                 el.src = Roo.SSL_SECURE_URL;
9028             }
9029             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9030             shim.autoBoxAdjust = false;
9031             return shim;
9032         },
9033
9034         /**
9035          * Removes this element from the DOM and deletes it from the cache
9036          */
9037         remove : function(){
9038             if(this.dom.parentNode){
9039                 this.dom.parentNode.removeChild(this.dom);
9040             }
9041             delete El.cache[this.dom.id];
9042         },
9043
9044         /**
9045          * Sets up event handlers to add and remove a css class when the mouse is over this element
9046          * @param {String} className
9047          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9048          * mouseout events for children elements
9049          * @return {Roo.Element} this
9050          */
9051         addClassOnOver : function(className, preventFlicker){
9052             this.on("mouseover", function(){
9053                 Roo.fly(this, '_internal').addClass(className);
9054             }, this.dom);
9055             var removeFn = function(e){
9056                 if(preventFlicker !== true || !e.within(this, true)){
9057                     Roo.fly(this, '_internal').removeClass(className);
9058                 }
9059             };
9060             this.on("mouseout", removeFn, this.dom);
9061             return this;
9062         },
9063
9064         /**
9065          * Sets up event handlers to add and remove a css class when this element has the focus
9066          * @param {String} className
9067          * @return {Roo.Element} this
9068          */
9069         addClassOnFocus : function(className){
9070             this.on("focus", function(){
9071                 Roo.fly(this, '_internal').addClass(className);
9072             }, this.dom);
9073             this.on("blur", function(){
9074                 Roo.fly(this, '_internal').removeClass(className);
9075             }, this.dom);
9076             return this;
9077         },
9078         /**
9079          * 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)
9080          * @param {String} className
9081          * @return {Roo.Element} this
9082          */
9083         addClassOnClick : function(className){
9084             var dom = this.dom;
9085             this.on("mousedown", function(){
9086                 Roo.fly(dom, '_internal').addClass(className);
9087                 var d = Roo.get(document);
9088                 var fn = function(){
9089                     Roo.fly(dom, '_internal').removeClass(className);
9090                     d.removeListener("mouseup", fn);
9091                 };
9092                 d.on("mouseup", fn);
9093             });
9094             return this;
9095         },
9096
9097         /**
9098          * Stops the specified event from bubbling and optionally prevents the default action
9099          * @param {String} eventName
9100          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9101          * @return {Roo.Element} this
9102          */
9103         swallowEvent : function(eventName, preventDefault){
9104             var fn = function(e){
9105                 e.stopPropagation();
9106                 if(preventDefault){
9107                     e.preventDefault();
9108                 }
9109             };
9110             if(eventName instanceof Array){
9111                 for(var i = 0, len = eventName.length; i < len; i++){
9112                      this.on(eventName[i], fn);
9113                 }
9114                 return this;
9115             }
9116             this.on(eventName, fn);
9117             return this;
9118         },
9119
9120         /**
9121          * @private
9122          */
9123       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9124
9125         /**
9126          * Sizes this element to its parent element's dimensions performing
9127          * neccessary box adjustments.
9128          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9129          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9130          * @return {Roo.Element} this
9131          */
9132         fitToParent : function(monitorResize, targetParent) {
9133           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9134           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9135           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9136             return;
9137           }
9138           var p = Roo.get(targetParent || this.dom.parentNode);
9139           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9140           if (monitorResize === true) {
9141             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9142             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9143           }
9144           return this;
9145         },
9146
9147         /**
9148          * Gets the next sibling, skipping text nodes
9149          * @return {HTMLElement} The next sibling or null
9150          */
9151         getNextSibling : function(){
9152             var n = this.dom.nextSibling;
9153             while(n && n.nodeType != 1){
9154                 n = n.nextSibling;
9155             }
9156             return n;
9157         },
9158
9159         /**
9160          * Gets the previous sibling, skipping text nodes
9161          * @return {HTMLElement} The previous sibling or null
9162          */
9163         getPrevSibling : function(){
9164             var n = this.dom.previousSibling;
9165             while(n && n.nodeType != 1){
9166                 n = n.previousSibling;
9167             }
9168             return n;
9169         },
9170
9171
9172         /**
9173          * Appends the passed element(s) to this element
9174          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9175          * @return {Roo.Element} this
9176          */
9177         appendChild: function(el){
9178             el = Roo.get(el);
9179             el.appendTo(this);
9180             return this;
9181         },
9182
9183         /**
9184          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9185          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9186          * automatically generated with the specified attributes.
9187          * @param {HTMLElement} insertBefore (optional) a child element of this element
9188          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9189          * @return {Roo.Element} The new child element
9190          */
9191         createChild: function(config, insertBefore, returnDom){
9192             config = config || {tag:'div'};
9193             if(insertBefore){
9194                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9195             }
9196             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9197         },
9198
9199         /**
9200          * Appends this element to the passed element
9201          * @param {String/HTMLElement/Element} el The new parent element
9202          * @return {Roo.Element} this
9203          */
9204         appendTo: function(el){
9205             el = Roo.getDom(el);
9206             el.appendChild(this.dom);
9207             return this;
9208         },
9209
9210         /**
9211          * Inserts this element before the passed element in the DOM
9212          * @param {String/HTMLElement/Element} el The element to insert before
9213          * @return {Roo.Element} this
9214          */
9215         insertBefore: function(el){
9216             el = Roo.getDom(el);
9217             el.parentNode.insertBefore(this.dom, el);
9218             return this;
9219         },
9220
9221         /**
9222          * Inserts this element after the passed element in the DOM
9223          * @param {String/HTMLElement/Element} el The element to insert after
9224          * @return {Roo.Element} this
9225          */
9226         insertAfter: function(el){
9227             el = Roo.getDom(el);
9228             el.parentNode.insertBefore(this.dom, el.nextSibling);
9229             return this;
9230         },
9231
9232         /**
9233          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9234          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9235          * @return {Roo.Element} The new child
9236          */
9237         insertFirst: function(el, returnDom){
9238             el = el || {};
9239             if(typeof el == 'object' && !el.nodeType){ // dh config
9240                 return this.createChild(el, this.dom.firstChild, returnDom);
9241             }else{
9242                 el = Roo.getDom(el);
9243                 this.dom.insertBefore(el, this.dom.firstChild);
9244                 return !returnDom ? Roo.get(el) : el;
9245             }
9246         },
9247
9248         /**
9249          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9250          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9251          * @param {String} where (optional) 'before' or 'after' defaults to before
9252          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9253          * @return {Roo.Element} the inserted Element
9254          */
9255         insertSibling: function(el, where, returnDom){
9256             where = where ? where.toLowerCase() : 'before';
9257             el = el || {};
9258             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9259
9260             if(typeof el == 'object' && !el.nodeType){ // dh config
9261                 if(where == 'after' && !this.dom.nextSibling){
9262                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9263                 }else{
9264                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9265                 }
9266
9267             }else{
9268                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9269                             where == 'before' ? this.dom : this.dom.nextSibling);
9270                 if(!returnDom){
9271                     rt = Roo.get(rt);
9272                 }
9273             }
9274             return rt;
9275         },
9276
9277         /**
9278          * Creates and wraps this element with another element
9279          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9280          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9281          * @return {HTMLElement/Element} The newly created wrapper element
9282          */
9283         wrap: function(config, returnDom){
9284             if(!config){
9285                 config = {tag: "div"};
9286             }
9287             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9288             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9289             return newEl;
9290         },
9291
9292         /**
9293          * Replaces the passed element with this element
9294          * @param {String/HTMLElement/Element} el The element to replace
9295          * @return {Roo.Element} this
9296          */
9297         replace: function(el){
9298             el = Roo.get(el);
9299             this.insertBefore(el);
9300             el.remove();
9301             return this;
9302         },
9303
9304         /**
9305          * Inserts an html fragment into this element
9306          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9307          * @param {String} html The HTML fragment
9308          * @param {Boolean} returnEl True to return an Roo.Element
9309          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9310          */
9311         insertHtml : function(where, html, returnEl){
9312             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9313             return returnEl ? Roo.get(el) : el;
9314         },
9315
9316         /**
9317          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9318          * @param {Object} o The object with the attributes
9319          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9320          * @return {Roo.Element} this
9321          */
9322         set : function(o, useSet){
9323             var el = this.dom;
9324             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9325             for(var attr in o){
9326                 if(attr == "style" || typeof o[attr] == "function") continue;
9327                 if(attr=="cls"){
9328                     el.className = o["cls"];
9329                 }else{
9330                     if(useSet) el.setAttribute(attr, o[attr]);
9331                     else el[attr] = o[attr];
9332                 }
9333             }
9334             if(o.style){
9335                 Roo.DomHelper.applyStyles(el, o.style);
9336             }
9337             return this;
9338         },
9339
9340         /**
9341          * Convenience method for constructing a KeyMap
9342          * @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:
9343          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9344          * @param {Function} fn The function to call
9345          * @param {Object} scope (optional) The scope of the function
9346          * @return {Roo.KeyMap} The KeyMap created
9347          */
9348         addKeyListener : function(key, fn, scope){
9349             var config;
9350             if(typeof key != "object" || key instanceof Array){
9351                 config = {
9352                     key: key,
9353                     fn: fn,
9354                     scope: scope
9355                 };
9356             }else{
9357                 config = {
9358                     key : key.key,
9359                     shift : key.shift,
9360                     ctrl : key.ctrl,
9361                     alt : key.alt,
9362                     fn: fn,
9363                     scope: scope
9364                 };
9365             }
9366             return new Roo.KeyMap(this, config);
9367         },
9368
9369         /**
9370          * Creates a KeyMap for this element
9371          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9372          * @return {Roo.KeyMap} The KeyMap created
9373          */
9374         addKeyMap : function(config){
9375             return new Roo.KeyMap(this, config);
9376         },
9377
9378         /**
9379          * Returns true if this element is scrollable.
9380          * @return {Boolean}
9381          */
9382          isScrollable : function(){
9383             var dom = this.dom;
9384             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9385         },
9386
9387         /**
9388          * 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().
9389          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9390          * @param {Number} value The new scroll value
9391          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9392          * @return {Element} this
9393          */
9394
9395         scrollTo : function(side, value, animate){
9396             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9397             if(!animate || !A){
9398                 this.dom[prop] = value;
9399             }else{
9400                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9401                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9402             }
9403             return this;
9404         },
9405
9406         /**
9407          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9408          * within this element's scrollable range.
9409          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9410          * @param {Number} distance How far to scroll the element in pixels
9411          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9412          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9413          * was scrolled as far as it could go.
9414          */
9415          scroll : function(direction, distance, animate){
9416              if(!this.isScrollable()){
9417                  return;
9418              }
9419              var el = this.dom;
9420              var l = el.scrollLeft, t = el.scrollTop;
9421              var w = el.scrollWidth, h = el.scrollHeight;
9422              var cw = el.clientWidth, ch = el.clientHeight;
9423              direction = direction.toLowerCase();
9424              var scrolled = false;
9425              var a = this.preanim(arguments, 2);
9426              switch(direction){
9427                  case "l":
9428                  case "left":
9429                      if(w - l > cw){
9430                          var v = Math.min(l + distance, w-cw);
9431                          this.scrollTo("left", v, a);
9432                          scrolled = true;
9433                      }
9434                      break;
9435                 case "r":
9436                 case "right":
9437                      if(l > 0){
9438                          var v = Math.max(l - distance, 0);
9439                          this.scrollTo("left", v, a);
9440                          scrolled = true;
9441                      }
9442                      break;
9443                 case "t":
9444                 case "top":
9445                 case "up":
9446                      if(t > 0){
9447                          var v = Math.max(t - distance, 0);
9448                          this.scrollTo("top", v, a);
9449                          scrolled = true;
9450                      }
9451                      break;
9452                 case "b":
9453                 case "bottom":
9454                 case "down":
9455                      if(h - t > ch){
9456                          var v = Math.min(t + distance, h-ch);
9457                          this.scrollTo("top", v, a);
9458                          scrolled = true;
9459                      }
9460                      break;
9461              }
9462              return scrolled;
9463         },
9464
9465         /**
9466          * Translates the passed page coordinates into left/top css values for this element
9467          * @param {Number/Array} x The page x or an array containing [x, y]
9468          * @param {Number} y The page y
9469          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9470          */
9471         translatePoints : function(x, y){
9472             if(typeof x == 'object' || x instanceof Array){
9473                 y = x[1]; x = x[0];
9474             }
9475             var p = this.getStyle('position');
9476             var o = this.getXY();
9477
9478             var l = parseInt(this.getStyle('left'), 10);
9479             var t = parseInt(this.getStyle('top'), 10);
9480
9481             if(isNaN(l)){
9482                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9483             }
9484             if(isNaN(t)){
9485                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9486             }
9487
9488             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9489         },
9490
9491         /**
9492          * Returns the current scroll position of the element.
9493          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9494          */
9495         getScroll : function(){
9496             var d = this.dom, doc = document;
9497             if(d == doc || d == doc.body){
9498                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9499                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9500                 return {left: l, top: t};
9501             }else{
9502                 return {left: d.scrollLeft, top: d.scrollTop};
9503             }
9504         },
9505
9506         /**
9507          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9508          * are convert to standard 6 digit hex color.
9509          * @param {String} attr The css attribute
9510          * @param {String} defaultValue The default value to use when a valid color isn't found
9511          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9512          * YUI color anims.
9513          */
9514         getColor : function(attr, defaultValue, prefix){
9515             var v = this.getStyle(attr);
9516             if(!v || v == "transparent" || v == "inherit") {
9517                 return defaultValue;
9518             }
9519             var color = typeof prefix == "undefined" ? "#" : prefix;
9520             if(v.substr(0, 4) == "rgb("){
9521                 var rvs = v.slice(4, v.length -1).split(",");
9522                 for(var i = 0; i < 3; i++){
9523                     var h = parseInt(rvs[i]).toString(16);
9524                     if(h < 16){
9525                         h = "0" + h;
9526                     }
9527                     color += h;
9528                 }
9529             } else {
9530                 if(v.substr(0, 1) == "#"){
9531                     if(v.length == 4) {
9532                         for(var i = 1; i < 4; i++){
9533                             var c = v.charAt(i);
9534                             color +=  c + c;
9535                         }
9536                     }else if(v.length == 7){
9537                         color += v.substr(1);
9538                     }
9539                 }
9540             }
9541             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9542         },
9543
9544         /**
9545          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9546          * gradient background, rounded corners and a 4-way shadow.
9547          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9548          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9549          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9550          * @return {Roo.Element} this
9551          */
9552         boxWrap : function(cls){
9553             cls = cls || 'x-box';
9554             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9555             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9556             return el;
9557         },
9558
9559         /**
9560          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9561          * @param {String} namespace The namespace in which to look for the attribute
9562          * @param {String} name The attribute name
9563          * @return {String} The attribute value
9564          */
9565         getAttributeNS : Roo.isIE ? function(ns, name){
9566             var d = this.dom;
9567             var type = typeof d[ns+":"+name];
9568             if(type != 'undefined' && type != 'unknown'){
9569                 return d[ns+":"+name];
9570             }
9571             return d[name];
9572         } : function(ns, name){
9573             var d = this.dom;
9574             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9575         },
9576         
9577         
9578         /**
9579          * Sets or Returns the value the dom attribute value
9580          * @param {String} name The attribute name
9581          * @param {String} value (optional) The value to set the attribute to
9582          * @return {String} The attribute value
9583          */
9584         attr : function(name){
9585             if (arguments.length > 1) {
9586                 this.dom.setAttribute(name, arguments[1]);
9587                 return arguments[1];
9588             }
9589             if (!this.dom.hasAttribute(name)) {
9590                 return undefined;
9591             }
9592             return this.dom.getAttribute(name);
9593         }
9594         
9595         
9596         
9597     };
9598
9599     var ep = El.prototype;
9600
9601     /**
9602      * Appends an event handler (Shorthand for addListener)
9603      * @param {String}   eventName     The type of event to append
9604      * @param {Function} fn        The method the event invokes
9605      * @param {Object} scope       (optional) The scope (this object) of the fn
9606      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9607      * @method
9608      */
9609     ep.on = ep.addListener;
9610         // backwards compat
9611     ep.mon = ep.addListener;
9612
9613     /**
9614      * Removes an event handler from this element (shorthand for removeListener)
9615      * @param {String} eventName the type of event to remove
9616      * @param {Function} fn the method the event invokes
9617      * @return {Roo.Element} this
9618      * @method
9619      */
9620     ep.un = ep.removeListener;
9621
9622     /**
9623      * true to automatically adjust width and height settings for box-model issues (default to true)
9624      */
9625     ep.autoBoxAdjust = true;
9626
9627     // private
9628     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9629
9630     // private
9631     El.addUnits = function(v, defaultUnit){
9632         if(v === "" || v == "auto"){
9633             return v;
9634         }
9635         if(v === undefined){
9636             return '';
9637         }
9638         if(typeof v == "number" || !El.unitPattern.test(v)){
9639             return v + (defaultUnit || 'px');
9640         }
9641         return v;
9642     };
9643
9644     // special markup used throughout Roo when box wrapping elements
9645     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>';
9646     /**
9647      * Visibility mode constant - Use visibility to hide element
9648      * @static
9649      * @type Number
9650      */
9651     El.VISIBILITY = 1;
9652     /**
9653      * Visibility mode constant - Use display to hide element
9654      * @static
9655      * @type Number
9656      */
9657     El.DISPLAY = 2;
9658
9659     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9660     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9661     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9662
9663
9664
9665     /**
9666      * @private
9667      */
9668     El.cache = {};
9669
9670     var docEl;
9671
9672     /**
9673      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9674      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9675      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9676      * @return {Element} The Element object
9677      * @static
9678      */
9679     El.get = function(el){
9680         var ex, elm, id;
9681         if(!el){ return null; }
9682         if(typeof el == "string"){ // element id
9683             if(!(elm = document.getElementById(el))){
9684                 return null;
9685             }
9686             if(ex = El.cache[el]){
9687                 ex.dom = elm;
9688             }else{
9689                 ex = El.cache[el] = new El(elm);
9690             }
9691             return ex;
9692         }else if(el.tagName){ // dom element
9693             if(!(id = el.id)){
9694                 id = Roo.id(el);
9695             }
9696             if(ex = El.cache[id]){
9697                 ex.dom = el;
9698             }else{
9699                 ex = El.cache[id] = new El(el);
9700             }
9701             return ex;
9702         }else if(el instanceof El){
9703             if(el != docEl){
9704                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9705                                                               // catch case where it hasn't been appended
9706                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9707             }
9708             return el;
9709         }else if(el.isComposite){
9710             return el;
9711         }else if(el instanceof Array){
9712             return El.select(el);
9713         }else if(el == document){
9714             // create a bogus element object representing the document object
9715             if(!docEl){
9716                 var f = function(){};
9717                 f.prototype = El.prototype;
9718                 docEl = new f();
9719                 docEl.dom = document;
9720             }
9721             return docEl;
9722         }
9723         return null;
9724     };
9725
9726     // private
9727     El.uncache = function(el){
9728         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9729             if(a[i]){
9730                 delete El.cache[a[i].id || a[i]];
9731             }
9732         }
9733     };
9734
9735     // private
9736     // Garbage collection - uncache elements/purge listeners on orphaned elements
9737     // so we don't hold a reference and cause the browser to retain them
9738     El.garbageCollect = function(){
9739         if(!Roo.enableGarbageCollector){
9740             clearInterval(El.collectorThread);
9741             return;
9742         }
9743         for(var eid in El.cache){
9744             var el = El.cache[eid], d = el.dom;
9745             // -------------------------------------------------------
9746             // Determining what is garbage:
9747             // -------------------------------------------------------
9748             // !d
9749             // dom node is null, definitely garbage
9750             // -------------------------------------------------------
9751             // !d.parentNode
9752             // no parentNode == direct orphan, definitely garbage
9753             // -------------------------------------------------------
9754             // !d.offsetParent && !document.getElementById(eid)
9755             // display none elements have no offsetParent so we will
9756             // also try to look it up by it's id. However, check
9757             // offsetParent first so we don't do unneeded lookups.
9758             // This enables collection of elements that are not orphans
9759             // directly, but somewhere up the line they have an orphan
9760             // parent.
9761             // -------------------------------------------------------
9762             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9763                 delete El.cache[eid];
9764                 if(d && Roo.enableListenerCollection){
9765                     E.purgeElement(d);
9766                 }
9767             }
9768         }
9769     }
9770     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9771
9772
9773     // dom is optional
9774     El.Flyweight = function(dom){
9775         this.dom = dom;
9776     };
9777     El.Flyweight.prototype = El.prototype;
9778
9779     El._flyweights = {};
9780     /**
9781      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9782      * the dom node can be overwritten by other code.
9783      * @param {String/HTMLElement} el The dom node or id
9784      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9785      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9786      * @static
9787      * @return {Element} The shared Element object
9788      */
9789     El.fly = function(el, named){
9790         named = named || '_global';
9791         el = Roo.getDom(el);
9792         if(!el){
9793             return null;
9794         }
9795         if(!El._flyweights[named]){
9796             El._flyweights[named] = new El.Flyweight();
9797         }
9798         El._flyweights[named].dom = el;
9799         return El._flyweights[named];
9800     };
9801
9802     /**
9803      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9804      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9805      * Shorthand of {@link Roo.Element#get}
9806      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9807      * @return {Element} The Element object
9808      * @member Roo
9809      * @method get
9810      */
9811     Roo.get = El.get;
9812     /**
9813      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9814      * the dom node can be overwritten by other code.
9815      * Shorthand of {@link Roo.Element#fly}
9816      * @param {String/HTMLElement} el The dom node or id
9817      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9818      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9819      * @static
9820      * @return {Element} The shared Element object
9821      * @member Roo
9822      * @method fly
9823      */
9824     Roo.fly = El.fly;
9825
9826     // speedy lookup for elements never to box adjust
9827     var noBoxAdjust = Roo.isStrict ? {
9828         select:1
9829     } : {
9830         input:1, select:1, textarea:1
9831     };
9832     if(Roo.isIE || Roo.isGecko){
9833         noBoxAdjust['button'] = 1;
9834     }
9835
9836
9837     Roo.EventManager.on(window, 'unload', function(){
9838         delete El.cache;
9839         delete El._flyweights;
9840     });
9841 })();
9842
9843
9844
9845
9846 if(Roo.DomQuery){
9847     Roo.Element.selectorFunction = Roo.DomQuery.select;
9848 }
9849
9850 Roo.Element.select = function(selector, unique, root){
9851     var els;
9852     if(typeof selector == "string"){
9853         els = Roo.Element.selectorFunction(selector, root);
9854     }else if(selector.length !== undefined){
9855         els = selector;
9856     }else{
9857         throw "Invalid selector";
9858     }
9859     if(unique === true){
9860         return new Roo.CompositeElement(els);
9861     }else{
9862         return new Roo.CompositeElementLite(els);
9863     }
9864 };
9865 /**
9866  * Selects elements based on the passed CSS selector to enable working on them as 1.
9867  * @param {String/Array} selector The CSS selector or an array of elements
9868  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9869  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9870  * @return {CompositeElementLite/CompositeElement}
9871  * @member Roo
9872  * @method select
9873  */
9874 Roo.select = Roo.Element.select;
9875
9876
9877
9878
9879
9880
9881
9882
9883
9884
9885
9886
9887
9888
9889 /*
9890  * Based on:
9891  * Ext JS Library 1.1.1
9892  * Copyright(c) 2006-2007, Ext JS, LLC.
9893  *
9894  * Originally Released Under LGPL - original licence link has changed is not relivant.
9895  *
9896  * Fork - LGPL
9897  * <script type="text/javascript">
9898  */
9899
9900
9901
9902 //Notifies Element that fx methods are available
9903 Roo.enableFx = true;
9904
9905 /**
9906  * @class Roo.Fx
9907  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9908  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9909  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9910  * Element effects to work.</p><br/>
9911  *
9912  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9913  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9914  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9915  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9916  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9917  * expected results and should be done with care.</p><br/>
9918  *
9919  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9920  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9921 <pre>
9922 Value  Description
9923 -----  -----------------------------
9924 tl     The top left corner
9925 t      The center of the top edge
9926 tr     The top right corner
9927 l      The center of the left edge
9928 r      The center of the right edge
9929 bl     The bottom left corner
9930 b      The center of the bottom edge
9931 br     The bottom right corner
9932 </pre>
9933  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9934  * below are common options that can be passed to any Fx method.</b>
9935  * @cfg {Function} callback A function called when the effect is finished
9936  * @cfg {Object} scope The scope of the effect function
9937  * @cfg {String} easing A valid Easing value for the effect
9938  * @cfg {String} afterCls A css class to apply after the effect
9939  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9940  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9941  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9942  * effects that end with the element being visually hidden, ignored otherwise)
9943  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9944  * a function which returns such a specification that will be applied to the Element after the effect finishes
9945  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9946  * @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
9947  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9948  */
9949 Roo.Fx = {
9950         /**
9951          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9952          * origin for the slide effect.  This function automatically handles wrapping the element with
9953          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9954          * Usage:
9955          *<pre><code>
9956 // default: slide the element in from the top
9957 el.slideIn();
9958
9959 // custom: slide the element in from the right with a 2-second duration
9960 el.slideIn('r', { duration: 2 });
9961
9962 // common config options shown with default values
9963 el.slideIn('t', {
9964     easing: 'easeOut',
9965     duration: .5
9966 });
9967 </code></pre>
9968          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9969          * @param {Object} options (optional) Object literal with any of the Fx config options
9970          * @return {Roo.Element} The Element
9971          */
9972     slideIn : function(anchor, o){
9973         var el = this.getFxEl();
9974         o = o || {};
9975
9976         el.queueFx(o, function(){
9977
9978             anchor = anchor || "t";
9979
9980             // fix display to visibility
9981             this.fixDisplay();
9982
9983             // restore values after effect
9984             var r = this.getFxRestore();
9985             var b = this.getBox();
9986             // fixed size for slide
9987             this.setSize(b);
9988
9989             // wrap if needed
9990             var wrap = this.fxWrap(r.pos, o, "hidden");
9991
9992             var st = this.dom.style;
9993             st.visibility = "visible";
9994             st.position = "absolute";
9995
9996             // clear out temp styles after slide and unwrap
9997             var after = function(){
9998                 el.fxUnwrap(wrap, r.pos, o);
9999                 st.width = r.width;
10000                 st.height = r.height;
10001                 el.afterFx(o);
10002             };
10003             // time to calc the positions
10004             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10005
10006             switch(anchor.toLowerCase()){
10007                 case "t":
10008                     wrap.setSize(b.width, 0);
10009                     st.left = st.bottom = "0";
10010                     a = {height: bh};
10011                 break;
10012                 case "l":
10013                     wrap.setSize(0, b.height);
10014                     st.right = st.top = "0";
10015                     a = {width: bw};
10016                 break;
10017                 case "r":
10018                     wrap.setSize(0, b.height);
10019                     wrap.setX(b.right);
10020                     st.left = st.top = "0";
10021                     a = {width: bw, points: pt};
10022                 break;
10023                 case "b":
10024                     wrap.setSize(b.width, 0);
10025                     wrap.setY(b.bottom);
10026                     st.left = st.top = "0";
10027                     a = {height: bh, points: pt};
10028                 break;
10029                 case "tl":
10030                     wrap.setSize(0, 0);
10031                     st.right = st.bottom = "0";
10032                     a = {width: bw, height: bh};
10033                 break;
10034                 case "bl":
10035                     wrap.setSize(0, 0);
10036                     wrap.setY(b.y+b.height);
10037                     st.right = st.top = "0";
10038                     a = {width: bw, height: bh, points: pt};
10039                 break;
10040                 case "br":
10041                     wrap.setSize(0, 0);
10042                     wrap.setXY([b.right, b.bottom]);
10043                     st.left = st.top = "0";
10044                     a = {width: bw, height: bh, points: pt};
10045                 break;
10046                 case "tr":
10047                     wrap.setSize(0, 0);
10048                     wrap.setX(b.x+b.width);
10049                     st.left = st.bottom = "0";
10050                     a = {width: bw, height: bh, points: pt};
10051                 break;
10052             }
10053             this.dom.style.visibility = "visible";
10054             wrap.show();
10055
10056             arguments.callee.anim = wrap.fxanim(a,
10057                 o,
10058                 'motion',
10059                 .5,
10060                 'easeOut', after);
10061         });
10062         return this;
10063     },
10064     
10065         /**
10066          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10067          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10068          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10069          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10070          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10071          * Usage:
10072          *<pre><code>
10073 // default: slide the element out to the top
10074 el.slideOut();
10075
10076 // custom: slide the element out to the right with a 2-second duration
10077 el.slideOut('r', { duration: 2 });
10078
10079 // common config options shown with default values
10080 el.slideOut('t', {
10081     easing: 'easeOut',
10082     duration: .5,
10083     remove: false,
10084     useDisplay: false
10085 });
10086 </code></pre>
10087          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10088          * @param {Object} options (optional) Object literal with any of the Fx config options
10089          * @return {Roo.Element} The Element
10090          */
10091     slideOut : function(anchor, o){
10092         var el = this.getFxEl();
10093         o = o || {};
10094
10095         el.queueFx(o, function(){
10096
10097             anchor = anchor || "t";
10098
10099             // restore values after effect
10100             var r = this.getFxRestore();
10101             
10102             var b = this.getBox();
10103             // fixed size for slide
10104             this.setSize(b);
10105
10106             // wrap if needed
10107             var wrap = this.fxWrap(r.pos, o, "visible");
10108
10109             var st = this.dom.style;
10110             st.visibility = "visible";
10111             st.position = "absolute";
10112
10113             wrap.setSize(b);
10114
10115             var after = function(){
10116                 if(o.useDisplay){
10117                     el.setDisplayed(false);
10118                 }else{
10119                     el.hide();
10120                 }
10121
10122                 el.fxUnwrap(wrap, r.pos, o);
10123
10124                 st.width = r.width;
10125                 st.height = r.height;
10126
10127                 el.afterFx(o);
10128             };
10129
10130             var a, zero = {to: 0};
10131             switch(anchor.toLowerCase()){
10132                 case "t":
10133                     st.left = st.bottom = "0";
10134                     a = {height: zero};
10135                 break;
10136                 case "l":
10137                     st.right = st.top = "0";
10138                     a = {width: zero};
10139                 break;
10140                 case "r":
10141                     st.left = st.top = "0";
10142                     a = {width: zero, points: {to:[b.right, b.y]}};
10143                 break;
10144                 case "b":
10145                     st.left = st.top = "0";
10146                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10147                 break;
10148                 case "tl":
10149                     st.right = st.bottom = "0";
10150                     a = {width: zero, height: zero};
10151                 break;
10152                 case "bl":
10153                     st.right = st.top = "0";
10154                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10155                 break;
10156                 case "br":
10157                     st.left = st.top = "0";
10158                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10159                 break;
10160                 case "tr":
10161                     st.left = st.bottom = "0";
10162                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10163                 break;
10164             }
10165
10166             arguments.callee.anim = wrap.fxanim(a,
10167                 o,
10168                 'motion',
10169                 .5,
10170                 "easeOut", after);
10171         });
10172         return this;
10173     },
10174
10175         /**
10176          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10177          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10178          * The element must be removed from the DOM using the 'remove' config option if desired.
10179          * Usage:
10180          *<pre><code>
10181 // default
10182 el.puff();
10183
10184 // common config options shown with default values
10185 el.puff({
10186     easing: 'easeOut',
10187     duration: .5,
10188     remove: false,
10189     useDisplay: false
10190 });
10191 </code></pre>
10192          * @param {Object} options (optional) Object literal with any of the Fx config options
10193          * @return {Roo.Element} The Element
10194          */
10195     puff : function(o){
10196         var el = this.getFxEl();
10197         o = o || {};
10198
10199         el.queueFx(o, function(){
10200             this.clearOpacity();
10201             this.show();
10202
10203             // restore values after effect
10204             var r = this.getFxRestore();
10205             var st = this.dom.style;
10206
10207             var after = function(){
10208                 if(o.useDisplay){
10209                     el.setDisplayed(false);
10210                 }else{
10211                     el.hide();
10212                 }
10213
10214                 el.clearOpacity();
10215
10216                 el.setPositioning(r.pos);
10217                 st.width = r.width;
10218                 st.height = r.height;
10219                 st.fontSize = '';
10220                 el.afterFx(o);
10221             };
10222
10223             var width = this.getWidth();
10224             var height = this.getHeight();
10225
10226             arguments.callee.anim = this.fxanim({
10227                     width : {to: this.adjustWidth(width * 2)},
10228                     height : {to: this.adjustHeight(height * 2)},
10229                     points : {by: [-(width * .5), -(height * .5)]},
10230                     opacity : {to: 0},
10231                     fontSize: {to:200, unit: "%"}
10232                 },
10233                 o,
10234                 'motion',
10235                 .5,
10236                 "easeOut", after);
10237         });
10238         return this;
10239     },
10240
10241         /**
10242          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10243          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10244          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10245          * Usage:
10246          *<pre><code>
10247 // default
10248 el.switchOff();
10249
10250 // all config options shown with default values
10251 el.switchOff({
10252     easing: 'easeIn',
10253     duration: .3,
10254     remove: false,
10255     useDisplay: false
10256 });
10257 </code></pre>
10258          * @param {Object} options (optional) Object literal with any of the Fx config options
10259          * @return {Roo.Element} The Element
10260          */
10261     switchOff : function(o){
10262         var el = this.getFxEl();
10263         o = o || {};
10264
10265         el.queueFx(o, function(){
10266             this.clearOpacity();
10267             this.clip();
10268
10269             // restore values after effect
10270             var r = this.getFxRestore();
10271             var st = this.dom.style;
10272
10273             var after = function(){
10274                 if(o.useDisplay){
10275                     el.setDisplayed(false);
10276                 }else{
10277                     el.hide();
10278                 }
10279
10280                 el.clearOpacity();
10281                 el.setPositioning(r.pos);
10282                 st.width = r.width;
10283                 st.height = r.height;
10284
10285                 el.afterFx(o);
10286             };
10287
10288             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10289                 this.clearOpacity();
10290                 (function(){
10291                     this.fxanim({
10292                         height:{to:1},
10293                         points:{by:[0, this.getHeight() * .5]}
10294                     }, o, 'motion', 0.3, 'easeIn', after);
10295                 }).defer(100, this);
10296             });
10297         });
10298         return this;
10299     },
10300
10301     /**
10302      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10303      * changed using the "attr" config option) and then fading back to the original color. If no original
10304      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10305      * Usage:
10306 <pre><code>
10307 // default: highlight background to yellow
10308 el.highlight();
10309
10310 // custom: highlight foreground text to blue for 2 seconds
10311 el.highlight("0000ff", { attr: 'color', duration: 2 });
10312
10313 // common config options shown with default values
10314 el.highlight("ffff9c", {
10315     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10316     endColor: (current color) or "ffffff",
10317     easing: 'easeIn',
10318     duration: 1
10319 });
10320 </code></pre>
10321      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10322      * @param {Object} options (optional) Object literal with any of the Fx config options
10323      * @return {Roo.Element} The Element
10324      */ 
10325     highlight : function(color, o){
10326         var el = this.getFxEl();
10327         o = o || {};
10328
10329         el.queueFx(o, function(){
10330             color = color || "ffff9c";
10331             attr = o.attr || "backgroundColor";
10332
10333             this.clearOpacity();
10334             this.show();
10335
10336             var origColor = this.getColor(attr);
10337             var restoreColor = this.dom.style[attr];
10338             endColor = (o.endColor || origColor) || "ffffff";
10339
10340             var after = function(){
10341                 el.dom.style[attr] = restoreColor;
10342                 el.afterFx(o);
10343             };
10344
10345             var a = {};
10346             a[attr] = {from: color, to: endColor};
10347             arguments.callee.anim = this.fxanim(a,
10348                 o,
10349                 'color',
10350                 1,
10351                 'easeIn', after);
10352         });
10353         return this;
10354     },
10355
10356    /**
10357     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10358     * Usage:
10359 <pre><code>
10360 // default: a single light blue ripple
10361 el.frame();
10362
10363 // custom: 3 red ripples lasting 3 seconds total
10364 el.frame("ff0000", 3, { duration: 3 });
10365
10366 // common config options shown with default values
10367 el.frame("C3DAF9", 1, {
10368     duration: 1 //duration of entire animation (not each individual ripple)
10369     // Note: Easing is not configurable and will be ignored if included
10370 });
10371 </code></pre>
10372     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10373     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10374     * @param {Object} options (optional) Object literal with any of the Fx config options
10375     * @return {Roo.Element} The Element
10376     */
10377     frame : function(color, count, o){
10378         var el = this.getFxEl();
10379         o = o || {};
10380
10381         el.queueFx(o, function(){
10382             color = color || "#C3DAF9";
10383             if(color.length == 6){
10384                 color = "#" + color;
10385             }
10386             count = count || 1;
10387             duration = o.duration || 1;
10388             this.show();
10389
10390             var b = this.getBox();
10391             var animFn = function(){
10392                 var proxy = this.createProxy({
10393
10394                      style:{
10395                         visbility:"hidden",
10396                         position:"absolute",
10397                         "z-index":"35000", // yee haw
10398                         border:"0px solid " + color
10399                      }
10400                   });
10401                 var scale = Roo.isBorderBox ? 2 : 1;
10402                 proxy.animate({
10403                     top:{from:b.y, to:b.y - 20},
10404                     left:{from:b.x, to:b.x - 20},
10405                     borderWidth:{from:0, to:10},
10406                     opacity:{from:1, to:0},
10407                     height:{from:b.height, to:(b.height + (20*scale))},
10408                     width:{from:b.width, to:(b.width + (20*scale))}
10409                 }, duration, function(){
10410                     proxy.remove();
10411                 });
10412                 if(--count > 0){
10413                      animFn.defer((duration/2)*1000, this);
10414                 }else{
10415                     el.afterFx(o);
10416                 }
10417             };
10418             animFn.call(this);
10419         });
10420         return this;
10421     },
10422
10423    /**
10424     * Creates a pause before any subsequent queued effects begin.  If there are
10425     * no effects queued after the pause it will have no effect.
10426     * Usage:
10427 <pre><code>
10428 el.pause(1);
10429 </code></pre>
10430     * @param {Number} seconds The length of time to pause (in seconds)
10431     * @return {Roo.Element} The Element
10432     */
10433     pause : function(seconds){
10434         var el = this.getFxEl();
10435         var o = {};
10436
10437         el.queueFx(o, function(){
10438             setTimeout(function(){
10439                 el.afterFx(o);
10440             }, seconds * 1000);
10441         });
10442         return this;
10443     },
10444
10445    /**
10446     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10447     * using the "endOpacity" config option.
10448     * Usage:
10449 <pre><code>
10450 // default: fade in from opacity 0 to 100%
10451 el.fadeIn();
10452
10453 // custom: fade in from opacity 0 to 75% over 2 seconds
10454 el.fadeIn({ endOpacity: .75, duration: 2});
10455
10456 // common config options shown with default values
10457 el.fadeIn({
10458     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10459     easing: 'easeOut',
10460     duration: .5
10461 });
10462 </code></pre>
10463     * @param {Object} options (optional) Object literal with any of the Fx config options
10464     * @return {Roo.Element} The Element
10465     */
10466     fadeIn : function(o){
10467         var el = this.getFxEl();
10468         o = o || {};
10469         el.queueFx(o, function(){
10470             this.setOpacity(0);
10471             this.fixDisplay();
10472             this.dom.style.visibility = 'visible';
10473             var to = o.endOpacity || 1;
10474             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10475                 o, null, .5, "easeOut", function(){
10476                 if(to == 1){
10477                     this.clearOpacity();
10478                 }
10479                 el.afterFx(o);
10480             });
10481         });
10482         return this;
10483     },
10484
10485    /**
10486     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10487     * using the "endOpacity" config option.
10488     * Usage:
10489 <pre><code>
10490 // default: fade out from the element's current opacity to 0
10491 el.fadeOut();
10492
10493 // custom: fade out from the element's current opacity to 25% over 2 seconds
10494 el.fadeOut({ endOpacity: .25, duration: 2});
10495
10496 // common config options shown with default values
10497 el.fadeOut({
10498     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10499     easing: 'easeOut',
10500     duration: .5
10501     remove: false,
10502     useDisplay: false
10503 });
10504 </code></pre>
10505     * @param {Object} options (optional) Object literal with any of the Fx config options
10506     * @return {Roo.Element} The Element
10507     */
10508     fadeOut : function(o){
10509         var el = this.getFxEl();
10510         o = o || {};
10511         el.queueFx(o, function(){
10512             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10513                 o, null, .5, "easeOut", function(){
10514                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10515                      this.dom.style.display = "none";
10516                 }else{
10517                      this.dom.style.visibility = "hidden";
10518                 }
10519                 this.clearOpacity();
10520                 el.afterFx(o);
10521             });
10522         });
10523         return this;
10524     },
10525
10526    /**
10527     * Animates the transition of an element's dimensions from a starting height/width
10528     * to an ending height/width.
10529     * Usage:
10530 <pre><code>
10531 // change height and width to 100x100 pixels
10532 el.scale(100, 100);
10533
10534 // common config options shown with default values.  The height and width will default to
10535 // the element's existing values if passed as null.
10536 el.scale(
10537     [element's width],
10538     [element's height], {
10539     easing: 'easeOut',
10540     duration: .35
10541 });
10542 </code></pre>
10543     * @param {Number} width  The new width (pass undefined to keep the original width)
10544     * @param {Number} height  The new height (pass undefined to keep the original height)
10545     * @param {Object} options (optional) Object literal with any of the Fx config options
10546     * @return {Roo.Element} The Element
10547     */
10548     scale : function(w, h, o){
10549         this.shift(Roo.apply({}, o, {
10550             width: w,
10551             height: h
10552         }));
10553         return this;
10554     },
10555
10556    /**
10557     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10558     * Any of these properties not specified in the config object will not be changed.  This effect 
10559     * requires that at least one new dimension, position or opacity setting must be passed in on
10560     * the config object in order for the function to have any effect.
10561     * Usage:
10562 <pre><code>
10563 // slide the element horizontally to x position 200 while changing the height and opacity
10564 el.shift({ x: 200, height: 50, opacity: .8 });
10565
10566 // common config options shown with default values.
10567 el.shift({
10568     width: [element's width],
10569     height: [element's height],
10570     x: [element's x position],
10571     y: [element's y position],
10572     opacity: [element's opacity],
10573     easing: 'easeOut',
10574     duration: .35
10575 });
10576 </code></pre>
10577     * @param {Object} options  Object literal with any of the Fx config options
10578     * @return {Roo.Element} The Element
10579     */
10580     shift : function(o){
10581         var el = this.getFxEl();
10582         o = o || {};
10583         el.queueFx(o, function(){
10584             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10585             if(w !== undefined){
10586                 a.width = {to: this.adjustWidth(w)};
10587             }
10588             if(h !== undefined){
10589                 a.height = {to: this.adjustHeight(h)};
10590             }
10591             if(x !== undefined || y !== undefined){
10592                 a.points = {to: [
10593                     x !== undefined ? x : this.getX(),
10594                     y !== undefined ? y : this.getY()
10595                 ]};
10596             }
10597             if(op !== undefined){
10598                 a.opacity = {to: op};
10599             }
10600             if(o.xy !== undefined){
10601                 a.points = {to: o.xy};
10602             }
10603             arguments.callee.anim = this.fxanim(a,
10604                 o, 'motion', .35, "easeOut", function(){
10605                 el.afterFx(o);
10606             });
10607         });
10608         return this;
10609     },
10610
10611         /**
10612          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10613          * ending point of the effect.
10614          * Usage:
10615          *<pre><code>
10616 // default: slide the element downward while fading out
10617 el.ghost();
10618
10619 // custom: slide the element out to the right with a 2-second duration
10620 el.ghost('r', { duration: 2 });
10621
10622 // common config options shown with default values
10623 el.ghost('b', {
10624     easing: 'easeOut',
10625     duration: .5
10626     remove: false,
10627     useDisplay: false
10628 });
10629 </code></pre>
10630          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10631          * @param {Object} options (optional) Object literal with any of the Fx config options
10632          * @return {Roo.Element} The Element
10633          */
10634     ghost : function(anchor, o){
10635         var el = this.getFxEl();
10636         o = o || {};
10637
10638         el.queueFx(o, function(){
10639             anchor = anchor || "b";
10640
10641             // restore values after effect
10642             var r = this.getFxRestore();
10643             var w = this.getWidth(),
10644                 h = this.getHeight();
10645
10646             var st = this.dom.style;
10647
10648             var after = function(){
10649                 if(o.useDisplay){
10650                     el.setDisplayed(false);
10651                 }else{
10652                     el.hide();
10653                 }
10654
10655                 el.clearOpacity();
10656                 el.setPositioning(r.pos);
10657                 st.width = r.width;
10658                 st.height = r.height;
10659
10660                 el.afterFx(o);
10661             };
10662
10663             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10664             switch(anchor.toLowerCase()){
10665                 case "t":
10666                     pt.by = [0, -h];
10667                 break;
10668                 case "l":
10669                     pt.by = [-w, 0];
10670                 break;
10671                 case "r":
10672                     pt.by = [w, 0];
10673                 break;
10674                 case "b":
10675                     pt.by = [0, h];
10676                 break;
10677                 case "tl":
10678                     pt.by = [-w, -h];
10679                 break;
10680                 case "bl":
10681                     pt.by = [-w, h];
10682                 break;
10683                 case "br":
10684                     pt.by = [w, h];
10685                 break;
10686                 case "tr":
10687                     pt.by = [w, -h];
10688                 break;
10689             }
10690
10691             arguments.callee.anim = this.fxanim(a,
10692                 o,
10693                 'motion',
10694                 .5,
10695                 "easeOut", after);
10696         });
10697         return this;
10698     },
10699
10700         /**
10701          * Ensures that all effects queued after syncFx is called on the element are
10702          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10703          * @return {Roo.Element} The Element
10704          */
10705     syncFx : function(){
10706         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10707             block : false,
10708             concurrent : true,
10709             stopFx : false
10710         });
10711         return this;
10712     },
10713
10714         /**
10715          * Ensures that all effects queued after sequenceFx is called on the element are
10716          * run in sequence.  This is the opposite of {@link #syncFx}.
10717          * @return {Roo.Element} The Element
10718          */
10719     sequenceFx : function(){
10720         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10721             block : false,
10722             concurrent : false,
10723             stopFx : false
10724         });
10725         return this;
10726     },
10727
10728         /* @private */
10729     nextFx : function(){
10730         var ef = this.fxQueue[0];
10731         if(ef){
10732             ef.call(this);
10733         }
10734     },
10735
10736         /**
10737          * Returns true if the element has any effects actively running or queued, else returns false.
10738          * @return {Boolean} True if element has active effects, else false
10739          */
10740     hasActiveFx : function(){
10741         return this.fxQueue && this.fxQueue[0];
10742     },
10743
10744         /**
10745          * Stops any running effects and clears the element's internal effects queue if it contains
10746          * any additional effects that haven't started yet.
10747          * @return {Roo.Element} The Element
10748          */
10749     stopFx : function(){
10750         if(this.hasActiveFx()){
10751             var cur = this.fxQueue[0];
10752             if(cur && cur.anim && cur.anim.isAnimated()){
10753                 this.fxQueue = [cur]; // clear out others
10754                 cur.anim.stop(true);
10755             }
10756         }
10757         return this;
10758     },
10759
10760         /* @private */
10761     beforeFx : function(o){
10762         if(this.hasActiveFx() && !o.concurrent){
10763            if(o.stopFx){
10764                this.stopFx();
10765                return true;
10766            }
10767            return false;
10768         }
10769         return true;
10770     },
10771
10772         /**
10773          * Returns true if the element is currently blocking so that no other effect can be queued
10774          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10775          * used to ensure that an effect initiated by a user action runs to completion prior to the
10776          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10777          * @return {Boolean} True if blocking, else false
10778          */
10779     hasFxBlock : function(){
10780         var q = this.fxQueue;
10781         return q && q[0] && q[0].block;
10782     },
10783
10784         /* @private */
10785     queueFx : function(o, fn){
10786         if(!this.fxQueue){
10787             this.fxQueue = [];
10788         }
10789         if(!this.hasFxBlock()){
10790             Roo.applyIf(o, this.fxDefaults);
10791             if(!o.concurrent){
10792                 var run = this.beforeFx(o);
10793                 fn.block = o.block;
10794                 this.fxQueue.push(fn);
10795                 if(run){
10796                     this.nextFx();
10797                 }
10798             }else{
10799                 fn.call(this);
10800             }
10801         }
10802         return this;
10803     },
10804
10805         /* @private */
10806     fxWrap : function(pos, o, vis){
10807         var wrap;
10808         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10809             var wrapXY;
10810             if(o.fixPosition){
10811                 wrapXY = this.getXY();
10812             }
10813             var div = document.createElement("div");
10814             div.style.visibility = vis;
10815             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10816             wrap.setPositioning(pos);
10817             if(wrap.getStyle("position") == "static"){
10818                 wrap.position("relative");
10819             }
10820             this.clearPositioning('auto');
10821             wrap.clip();
10822             wrap.dom.appendChild(this.dom);
10823             if(wrapXY){
10824                 wrap.setXY(wrapXY);
10825             }
10826         }
10827         return wrap;
10828     },
10829
10830         /* @private */
10831     fxUnwrap : function(wrap, pos, o){
10832         this.clearPositioning();
10833         this.setPositioning(pos);
10834         if(!o.wrap){
10835             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10836             wrap.remove();
10837         }
10838     },
10839
10840         /* @private */
10841     getFxRestore : function(){
10842         var st = this.dom.style;
10843         return {pos: this.getPositioning(), width: st.width, height : st.height};
10844     },
10845
10846         /* @private */
10847     afterFx : function(o){
10848         if(o.afterStyle){
10849             this.applyStyles(o.afterStyle);
10850         }
10851         if(o.afterCls){
10852             this.addClass(o.afterCls);
10853         }
10854         if(o.remove === true){
10855             this.remove();
10856         }
10857         Roo.callback(o.callback, o.scope, [this]);
10858         if(!o.concurrent){
10859             this.fxQueue.shift();
10860             this.nextFx();
10861         }
10862     },
10863
10864         /* @private */
10865     getFxEl : function(){ // support for composite element fx
10866         return Roo.get(this.dom);
10867     },
10868
10869         /* @private */
10870     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10871         animType = animType || 'run';
10872         opt = opt || {};
10873         var anim = Roo.lib.Anim[animType](
10874             this.dom, args,
10875             (opt.duration || defaultDur) || .35,
10876             (opt.easing || defaultEase) || 'easeOut',
10877             function(){
10878                 Roo.callback(cb, this);
10879             },
10880             this
10881         );
10882         opt.anim = anim;
10883         return anim;
10884     }
10885 };
10886
10887 // backwords compat
10888 Roo.Fx.resize = Roo.Fx.scale;
10889
10890 //When included, Roo.Fx is automatically applied to Element so that all basic
10891 //effects are available directly via the Element API
10892 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10893  * Based on:
10894  * Ext JS Library 1.1.1
10895  * Copyright(c) 2006-2007, Ext JS, LLC.
10896  *
10897  * Originally Released Under LGPL - original licence link has changed is not relivant.
10898  *
10899  * Fork - LGPL
10900  * <script type="text/javascript">
10901  */
10902
10903
10904 /**
10905  * @class Roo.CompositeElement
10906  * Standard composite class. Creates a Roo.Element for every element in the collection.
10907  * <br><br>
10908  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10909  * actions will be performed on all the elements in this collection.</b>
10910  * <br><br>
10911  * All methods return <i>this</i> and can be chained.
10912  <pre><code>
10913  var els = Roo.select("#some-el div.some-class", true);
10914  // or select directly from an existing element
10915  var el = Roo.get('some-el');
10916  el.select('div.some-class', true);
10917
10918  els.setWidth(100); // all elements become 100 width
10919  els.hide(true); // all elements fade out and hide
10920  // or
10921  els.setWidth(100).hide(true);
10922  </code></pre>
10923  */
10924 Roo.CompositeElement = function(els){
10925     this.elements = [];
10926     this.addElements(els);
10927 };
10928 Roo.CompositeElement.prototype = {
10929     isComposite: true,
10930     addElements : function(els){
10931         if(!els) return this;
10932         if(typeof els == "string"){
10933             els = Roo.Element.selectorFunction(els);
10934         }
10935         var yels = this.elements;
10936         var index = yels.length-1;
10937         for(var i = 0, len = els.length; i < len; i++) {
10938                 yels[++index] = Roo.get(els[i]);
10939         }
10940         return this;
10941     },
10942
10943     /**
10944     * Clears this composite and adds the elements returned by the passed selector.
10945     * @param {String/Array} els A string CSS selector, an array of elements or an element
10946     * @return {CompositeElement} this
10947     */
10948     fill : function(els){
10949         this.elements = [];
10950         this.add(els);
10951         return this;
10952     },
10953
10954     /**
10955     * Filters this composite to only elements that match the passed selector.
10956     * @param {String} selector A string CSS selector
10957     * @return {CompositeElement} this
10958     */
10959     filter : function(selector){
10960         var els = [];
10961         this.each(function(el){
10962             if(el.is(selector)){
10963                 els[els.length] = el.dom;
10964             }
10965         });
10966         this.fill(els);
10967         return this;
10968     },
10969
10970     invoke : function(fn, args){
10971         var els = this.elements;
10972         for(var i = 0, len = els.length; i < len; i++) {
10973                 Roo.Element.prototype[fn].apply(els[i], args);
10974         }
10975         return this;
10976     },
10977     /**
10978     * Adds elements to this composite.
10979     * @param {String/Array} els A string CSS selector, an array of elements or an element
10980     * @return {CompositeElement} this
10981     */
10982     add : function(els){
10983         if(typeof els == "string"){
10984             this.addElements(Roo.Element.selectorFunction(els));
10985         }else if(els.length !== undefined){
10986             this.addElements(els);
10987         }else{
10988             this.addElements([els]);
10989         }
10990         return this;
10991     },
10992     /**
10993     * Calls the passed function passing (el, this, index) for each element in this composite.
10994     * @param {Function} fn The function to call
10995     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10996     * @return {CompositeElement} this
10997     */
10998     each : function(fn, scope){
10999         var els = this.elements;
11000         for(var i = 0, len = els.length; i < len; i++){
11001             if(fn.call(scope || els[i], els[i], this, i) === false) {
11002                 break;
11003             }
11004         }
11005         return this;
11006     },
11007
11008     /**
11009      * Returns the Element object at the specified index
11010      * @param {Number} index
11011      * @return {Roo.Element}
11012      */
11013     item : function(index){
11014         return this.elements[index] || null;
11015     },
11016
11017     /**
11018      * Returns the first Element
11019      * @return {Roo.Element}
11020      */
11021     first : function(){
11022         return this.item(0);
11023     },
11024
11025     /**
11026      * Returns the last Element
11027      * @return {Roo.Element}
11028      */
11029     last : function(){
11030         return this.item(this.elements.length-1);
11031     },
11032
11033     /**
11034      * Returns the number of elements in this composite
11035      * @return Number
11036      */
11037     getCount : function(){
11038         return this.elements.length;
11039     },
11040
11041     /**
11042      * Returns true if this composite contains the passed element
11043      * @return Boolean
11044      */
11045     contains : function(el){
11046         return this.indexOf(el) !== -1;
11047     },
11048
11049     /**
11050      * Returns true if this composite contains the passed element
11051      * @return Boolean
11052      */
11053     indexOf : function(el){
11054         return this.elements.indexOf(Roo.get(el));
11055     },
11056
11057
11058     /**
11059     * Removes the specified element(s).
11060     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11061     * or an array of any of those.
11062     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11063     * @return {CompositeElement} this
11064     */
11065     removeElement : function(el, removeDom){
11066         if(el instanceof Array){
11067             for(var i = 0, len = el.length; i < len; i++){
11068                 this.removeElement(el[i]);
11069             }
11070             return this;
11071         }
11072         var index = typeof el == 'number' ? el : this.indexOf(el);
11073         if(index !== -1){
11074             if(removeDom){
11075                 var d = this.elements[index];
11076                 if(d.dom){
11077                     d.remove();
11078                 }else{
11079                     d.parentNode.removeChild(d);
11080                 }
11081             }
11082             this.elements.splice(index, 1);
11083         }
11084         return this;
11085     },
11086
11087     /**
11088     * Replaces the specified element with the passed element.
11089     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11090     * to replace.
11091     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11092     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11093     * @return {CompositeElement} this
11094     */
11095     replaceElement : function(el, replacement, domReplace){
11096         var index = typeof el == 'number' ? el : this.indexOf(el);
11097         if(index !== -1){
11098             if(domReplace){
11099                 this.elements[index].replaceWith(replacement);
11100             }else{
11101                 this.elements.splice(index, 1, Roo.get(replacement))
11102             }
11103         }
11104         return this;
11105     },
11106
11107     /**
11108      * Removes all elements.
11109      */
11110     clear : function(){
11111         this.elements = [];
11112     }
11113 };
11114 (function(){
11115     Roo.CompositeElement.createCall = function(proto, fnName){
11116         if(!proto[fnName]){
11117             proto[fnName] = function(){
11118                 return this.invoke(fnName, arguments);
11119             };
11120         }
11121     };
11122     for(var fnName in Roo.Element.prototype){
11123         if(typeof Roo.Element.prototype[fnName] == "function"){
11124             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11125         }
11126     };
11127 })();
11128 /*
11129  * Based on:
11130  * Ext JS Library 1.1.1
11131  * Copyright(c) 2006-2007, Ext JS, LLC.
11132  *
11133  * Originally Released Under LGPL - original licence link has changed is not relivant.
11134  *
11135  * Fork - LGPL
11136  * <script type="text/javascript">
11137  */
11138
11139 /**
11140  * @class Roo.CompositeElementLite
11141  * @extends Roo.CompositeElement
11142  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11143  <pre><code>
11144  var els = Roo.select("#some-el div.some-class");
11145  // or select directly from an existing element
11146  var el = Roo.get('some-el');
11147  el.select('div.some-class');
11148
11149  els.setWidth(100); // all elements become 100 width
11150  els.hide(true); // all elements fade out and hide
11151  // or
11152  els.setWidth(100).hide(true);
11153  </code></pre><br><br>
11154  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11155  * actions will be performed on all the elements in this collection.</b>
11156  */
11157 Roo.CompositeElementLite = function(els){
11158     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11159     this.el = new Roo.Element.Flyweight();
11160 };
11161 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11162     addElements : function(els){
11163         if(els){
11164             if(els instanceof Array){
11165                 this.elements = this.elements.concat(els);
11166             }else{
11167                 var yels = this.elements;
11168                 var index = yels.length-1;
11169                 for(var i = 0, len = els.length; i < len; i++) {
11170                     yels[++index] = els[i];
11171                 }
11172             }
11173         }
11174         return this;
11175     },
11176     invoke : function(fn, args){
11177         var els = this.elements;
11178         var el = this.el;
11179         for(var i = 0, len = els.length; i < len; i++) {
11180             el.dom = els[i];
11181                 Roo.Element.prototype[fn].apply(el, args);
11182         }
11183         return this;
11184     },
11185     /**
11186      * Returns a flyweight Element of the dom element object at the specified index
11187      * @param {Number} index
11188      * @return {Roo.Element}
11189      */
11190     item : function(index){
11191         if(!this.elements[index]){
11192             return null;
11193         }
11194         this.el.dom = this.elements[index];
11195         return this.el;
11196     },
11197
11198     // fixes scope with flyweight
11199     addListener : function(eventName, handler, scope, opt){
11200         var els = this.elements;
11201         for(var i = 0, len = els.length; i < len; i++) {
11202             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11203         }
11204         return this;
11205     },
11206
11207     /**
11208     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11209     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11210     * a reference to the dom node, use el.dom.</b>
11211     * @param {Function} fn The function to call
11212     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11213     * @return {CompositeElement} this
11214     */
11215     each : function(fn, scope){
11216         var els = this.elements;
11217         var el = this.el;
11218         for(var i = 0, len = els.length; i < len; i++){
11219             el.dom = els[i];
11220                 if(fn.call(scope || el, el, this, i) === false){
11221                 break;
11222             }
11223         }
11224         return this;
11225     },
11226
11227     indexOf : function(el){
11228         return this.elements.indexOf(Roo.getDom(el));
11229     },
11230
11231     replaceElement : function(el, replacement, domReplace){
11232         var index = typeof el == 'number' ? el : this.indexOf(el);
11233         if(index !== -1){
11234             replacement = Roo.getDom(replacement);
11235             if(domReplace){
11236                 var d = this.elements[index];
11237                 d.parentNode.insertBefore(replacement, d);
11238                 d.parentNode.removeChild(d);
11239             }
11240             this.elements.splice(index, 1, replacement);
11241         }
11242         return this;
11243     }
11244 });
11245 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11246
11247 /*
11248  * Based on:
11249  * Ext JS Library 1.1.1
11250  * Copyright(c) 2006-2007, Ext JS, LLC.
11251  *
11252  * Originally Released Under LGPL - original licence link has changed is not relivant.
11253  *
11254  * Fork - LGPL
11255  * <script type="text/javascript">
11256  */
11257
11258  
11259
11260 /**
11261  * @class Roo.data.Connection
11262  * @extends Roo.util.Observable
11263  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11264  * either to a configured URL, or to a URL specified at request time.<br><br>
11265  * <p>
11266  * Requests made by this class are asynchronous, and will return immediately. No data from
11267  * the server will be available to the statement immediately following the {@link #request} call.
11268  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11269  * <p>
11270  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11271  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11272  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11273  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11274  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11275  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11276  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11277  * standard DOM methods.
11278  * @constructor
11279  * @param {Object} config a configuration object.
11280  */
11281 Roo.data.Connection = function(config){
11282     Roo.apply(this, config);
11283     this.addEvents({
11284         /**
11285          * @event beforerequest
11286          * Fires before a network request is made to retrieve a data object.
11287          * @param {Connection} conn This Connection object.
11288          * @param {Object} options The options config object passed to the {@link #request} method.
11289          */
11290         "beforerequest" : true,
11291         /**
11292          * @event requestcomplete
11293          * Fires if the request was successfully completed.
11294          * @param {Connection} conn This Connection object.
11295          * @param {Object} response The XHR object containing the response data.
11296          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11297          * @param {Object} options The options config object passed to the {@link #request} method.
11298          */
11299         "requestcomplete" : true,
11300         /**
11301          * @event requestexception
11302          * Fires if an error HTTP status was returned from the server.
11303          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11304          * @param {Connection} conn This Connection object.
11305          * @param {Object} response The XHR object containing the response data.
11306          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11307          * @param {Object} options The options config object passed to the {@link #request} method.
11308          */
11309         "requestexception" : true
11310     });
11311     Roo.data.Connection.superclass.constructor.call(this);
11312 };
11313
11314 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11315     /**
11316      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11317      */
11318     /**
11319      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11320      * extra parameters to each request made by this object. (defaults to undefined)
11321      */
11322     /**
11323      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11324      *  to each request made by this object. (defaults to undefined)
11325      */
11326     /**
11327      * @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)
11328      */
11329     /**
11330      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11331      */
11332     timeout : 30000,
11333     /**
11334      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11335      * @type Boolean
11336      */
11337     autoAbort:false,
11338
11339     /**
11340      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11341      * @type Boolean
11342      */
11343     disableCaching: true,
11344
11345     /**
11346      * Sends an HTTP request to a remote server.
11347      * @param {Object} options An object which may contain the following properties:<ul>
11348      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11349      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11350      * request, a url encoded string or a function to call to get either.</li>
11351      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11352      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11353      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11354      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11355      * <li>options {Object} The parameter to the request call.</li>
11356      * <li>success {Boolean} True if the request succeeded.</li>
11357      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11358      * </ul></li>
11359      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11360      * The callback is passed the following parameters:<ul>
11361      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11362      * <li>options {Object} The parameter to the request call.</li>
11363      * </ul></li>
11364      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11365      * The callback is passed the following parameters:<ul>
11366      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11367      * <li>options {Object} The parameter to the request call.</li>
11368      * </ul></li>
11369      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11370      * for the callback function. Defaults to the browser window.</li>
11371      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11372      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11373      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11374      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11375      * params for the post data. Any params will be appended to the URL.</li>
11376      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11377      * </ul>
11378      * @return {Number} transactionId
11379      */
11380     request : function(o){
11381         if(this.fireEvent("beforerequest", this, o) !== false){
11382             var p = o.params;
11383
11384             if(typeof p == "function"){
11385                 p = p.call(o.scope||window, o);
11386             }
11387             if(typeof p == "object"){
11388                 p = Roo.urlEncode(o.params);
11389             }
11390             if(this.extraParams){
11391                 var extras = Roo.urlEncode(this.extraParams);
11392                 p = p ? (p + '&' + extras) : extras;
11393             }
11394
11395             var url = o.url || this.url;
11396             if(typeof url == 'function'){
11397                 url = url.call(o.scope||window, o);
11398             }
11399
11400             if(o.form){
11401                 var form = Roo.getDom(o.form);
11402                 url = url || form.action;
11403
11404                 var enctype = form.getAttribute("enctype");
11405                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11406                     return this.doFormUpload(o, p, url);
11407                 }
11408                 var f = Roo.lib.Ajax.serializeForm(form);
11409                 p = p ? (p + '&' + f) : f;
11410             }
11411
11412             var hs = o.headers;
11413             if(this.defaultHeaders){
11414                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11415                 if(!o.headers){
11416                     o.headers = hs;
11417                 }
11418             }
11419
11420             var cb = {
11421                 success: this.handleResponse,
11422                 failure: this.handleFailure,
11423                 scope: this,
11424                 argument: {options: o},
11425                 timeout : o.timeout || this.timeout
11426             };
11427
11428             var method = o.method||this.method||(p ? "POST" : "GET");
11429
11430             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11431                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11432             }
11433
11434             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11435                 if(o.autoAbort){
11436                     this.abort();
11437                 }
11438             }else if(this.autoAbort !== false){
11439                 this.abort();
11440             }
11441
11442             if((method == 'GET' && p) || o.xmlData){
11443                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11444                 p = '';
11445             }
11446             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11447             return this.transId;
11448         }else{
11449             Roo.callback(o.callback, o.scope, [o, null, null]);
11450             return null;
11451         }
11452     },
11453
11454     /**
11455      * Determine whether this object has a request outstanding.
11456      * @param {Number} transactionId (Optional) defaults to the last transaction
11457      * @return {Boolean} True if there is an outstanding request.
11458      */
11459     isLoading : function(transId){
11460         if(transId){
11461             return Roo.lib.Ajax.isCallInProgress(transId);
11462         }else{
11463             return this.transId ? true : false;
11464         }
11465     },
11466
11467     /**
11468      * Aborts any outstanding request.
11469      * @param {Number} transactionId (Optional) defaults to the last transaction
11470      */
11471     abort : function(transId){
11472         if(transId || this.isLoading()){
11473             Roo.lib.Ajax.abort(transId || this.transId);
11474         }
11475     },
11476
11477     // private
11478     handleResponse : function(response){
11479         this.transId = false;
11480         var options = response.argument.options;
11481         response.argument = options ? options.argument : null;
11482         this.fireEvent("requestcomplete", this, response, options);
11483         Roo.callback(options.success, options.scope, [response, options]);
11484         Roo.callback(options.callback, options.scope, [options, true, response]);
11485     },
11486
11487     // private
11488     handleFailure : function(response, e){
11489         this.transId = false;
11490         var options = response.argument.options;
11491         response.argument = options ? options.argument : null;
11492         this.fireEvent("requestexception", this, response, options, e);
11493         Roo.callback(options.failure, options.scope, [response, options]);
11494         Roo.callback(options.callback, options.scope, [options, false, response]);
11495     },
11496
11497     // private
11498     doFormUpload : function(o, ps, url){
11499         var id = Roo.id();
11500         var frame = document.createElement('iframe');
11501         frame.id = id;
11502         frame.name = id;
11503         frame.className = 'x-hidden';
11504         if(Roo.isIE){
11505             frame.src = Roo.SSL_SECURE_URL;
11506         }
11507         document.body.appendChild(frame);
11508
11509         if(Roo.isIE){
11510            document.frames[id].name = id;
11511         }
11512
11513         var form = Roo.getDom(o.form);
11514         form.target = id;
11515         form.method = 'POST';
11516         form.enctype = form.encoding = 'multipart/form-data';
11517         if(url){
11518             form.action = url;
11519         }
11520
11521         var hiddens, hd;
11522         if(ps){ // add dynamic params
11523             hiddens = [];
11524             ps = Roo.urlDecode(ps, false);
11525             for(var k in ps){
11526                 if(ps.hasOwnProperty(k)){
11527                     hd = document.createElement('input');
11528                     hd.type = 'hidden';
11529                     hd.name = k;
11530                     hd.value = ps[k];
11531                     form.appendChild(hd);
11532                     hiddens.push(hd);
11533                 }
11534             }
11535         }
11536
11537         function cb(){
11538             var r = {  // bogus response object
11539                 responseText : '',
11540                 responseXML : null
11541             };
11542
11543             r.argument = o ? o.argument : null;
11544
11545             try { //
11546                 var doc;
11547                 if(Roo.isIE){
11548                     doc = frame.contentWindow.document;
11549                 }else {
11550                     doc = (frame.contentDocument || window.frames[id].document);
11551                 }
11552                 if(doc && doc.body){
11553                     r.responseText = doc.body.innerHTML;
11554                 }
11555                 if(doc && doc.XMLDocument){
11556                     r.responseXML = doc.XMLDocument;
11557                 }else {
11558                     r.responseXML = doc;
11559                 }
11560             }
11561             catch(e) {
11562                 // ignore
11563             }
11564
11565             Roo.EventManager.removeListener(frame, 'load', cb, this);
11566
11567             this.fireEvent("requestcomplete", this, r, o);
11568             Roo.callback(o.success, o.scope, [r, o]);
11569             Roo.callback(o.callback, o.scope, [o, true, r]);
11570
11571             setTimeout(function(){document.body.removeChild(frame);}, 100);
11572         }
11573
11574         Roo.EventManager.on(frame, 'load', cb, this);
11575         form.submit();
11576
11577         if(hiddens){ // remove dynamic params
11578             for(var i = 0, len = hiddens.length; i < len; i++){
11579                 form.removeChild(hiddens[i]);
11580             }
11581         }
11582     }
11583 });
11584 /*
11585  * Based on:
11586  * Ext JS Library 1.1.1
11587  * Copyright(c) 2006-2007, Ext JS, LLC.
11588  *
11589  * Originally Released Under LGPL - original licence link has changed is not relivant.
11590  *
11591  * Fork - LGPL
11592  * <script type="text/javascript">
11593  */
11594  
11595 /**
11596  * Global Ajax request class.
11597  * 
11598  * @class Roo.Ajax
11599  * @extends Roo.data.Connection
11600  * @static
11601  * 
11602  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11603  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11604  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11605  * @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)
11606  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11607  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11608  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11609  */
11610 Roo.Ajax = new Roo.data.Connection({
11611     // fix up the docs
11612     /**
11613      * @scope Roo.Ajax
11614      * @type {Boolear} 
11615      */
11616     autoAbort : false,
11617
11618     /**
11619      * Serialize the passed form into a url encoded string
11620      * @scope Roo.Ajax
11621      * @param {String/HTMLElement} form
11622      * @return {String}
11623      */
11624     serializeForm : function(form){
11625         return Roo.lib.Ajax.serializeForm(form);
11626     }
11627 });/*
11628  * Based on:
11629  * Ext JS Library 1.1.1
11630  * Copyright(c) 2006-2007, Ext JS, LLC.
11631  *
11632  * Originally Released Under LGPL - original licence link has changed is not relivant.
11633  *
11634  * Fork - LGPL
11635  * <script type="text/javascript">
11636  */
11637
11638  
11639 /**
11640  * @class Roo.UpdateManager
11641  * @extends Roo.util.Observable
11642  * Provides AJAX-style update for Element object.<br><br>
11643  * Usage:<br>
11644  * <pre><code>
11645  * // Get it from a Roo.Element object
11646  * var el = Roo.get("foo");
11647  * var mgr = el.getUpdateManager();
11648  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11649  * ...
11650  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11651  * <br>
11652  * // or directly (returns the same UpdateManager instance)
11653  * var mgr = new Roo.UpdateManager("myElementId");
11654  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11655  * mgr.on("update", myFcnNeedsToKnow);
11656  * <br>
11657    // short handed call directly from the element object
11658    Roo.get("foo").load({
11659         url: "bar.php",
11660         scripts:true,
11661         params: "for=bar",
11662         text: "Loading Foo..."
11663    });
11664  * </code></pre>
11665  * @constructor
11666  * Create new UpdateManager directly.
11667  * @param {String/HTMLElement/Roo.Element} el The element to update
11668  * @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).
11669  */
11670 Roo.UpdateManager = function(el, forceNew){
11671     el = Roo.get(el);
11672     if(!forceNew && el.updateManager){
11673         return el.updateManager;
11674     }
11675     /**
11676      * The Element object
11677      * @type Roo.Element
11678      */
11679     this.el = el;
11680     /**
11681      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11682      * @type String
11683      */
11684     this.defaultUrl = null;
11685
11686     this.addEvents({
11687         /**
11688          * @event beforeupdate
11689          * Fired before an update is made, return false from your handler and the update is cancelled.
11690          * @param {Roo.Element} el
11691          * @param {String/Object/Function} url
11692          * @param {String/Object} params
11693          */
11694         "beforeupdate": true,
11695         /**
11696          * @event update
11697          * Fired after successful update is made.
11698          * @param {Roo.Element} el
11699          * @param {Object} oResponseObject The response Object
11700          */
11701         "update": true,
11702         /**
11703          * @event failure
11704          * Fired on update failure.
11705          * @param {Roo.Element} el
11706          * @param {Object} oResponseObject The response Object
11707          */
11708         "failure": true
11709     });
11710     var d = Roo.UpdateManager.defaults;
11711     /**
11712      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11713      * @type String
11714      */
11715     this.sslBlankUrl = d.sslBlankUrl;
11716     /**
11717      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11718      * @type Boolean
11719      */
11720     this.disableCaching = d.disableCaching;
11721     /**
11722      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11723      * @type String
11724      */
11725     this.indicatorText = d.indicatorText;
11726     /**
11727      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11728      * @type String
11729      */
11730     this.showLoadIndicator = d.showLoadIndicator;
11731     /**
11732      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11733      * @type Number
11734      */
11735     this.timeout = d.timeout;
11736
11737     /**
11738      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11739      * @type Boolean
11740      */
11741     this.loadScripts = d.loadScripts;
11742
11743     /**
11744      * Transaction object of current executing transaction
11745      */
11746     this.transaction = null;
11747
11748     /**
11749      * @private
11750      */
11751     this.autoRefreshProcId = null;
11752     /**
11753      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11754      * @type Function
11755      */
11756     this.refreshDelegate = this.refresh.createDelegate(this);
11757     /**
11758      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11759      * @type Function
11760      */
11761     this.updateDelegate = this.update.createDelegate(this);
11762     /**
11763      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11764      * @type Function
11765      */
11766     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11767     /**
11768      * @private
11769      */
11770     this.successDelegate = this.processSuccess.createDelegate(this);
11771     /**
11772      * @private
11773      */
11774     this.failureDelegate = this.processFailure.createDelegate(this);
11775
11776     if(!this.renderer){
11777      /**
11778       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11779       */
11780     this.renderer = new Roo.UpdateManager.BasicRenderer();
11781     }
11782     
11783     Roo.UpdateManager.superclass.constructor.call(this);
11784 };
11785
11786 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11787     /**
11788      * Get the Element this UpdateManager is bound to
11789      * @return {Roo.Element} The element
11790      */
11791     getEl : function(){
11792         return this.el;
11793     },
11794     /**
11795      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11796      * @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:
11797 <pre><code>
11798 um.update({<br/>
11799     url: "your-url.php",<br/>
11800     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11801     callback: yourFunction,<br/>
11802     scope: yourObject, //(optional scope)  <br/>
11803     discardUrl: false, <br/>
11804     nocache: false,<br/>
11805     text: "Loading...",<br/>
11806     timeout: 30,<br/>
11807     scripts: false<br/>
11808 });
11809 </code></pre>
11810      * The only required property is url. The optional properties nocache, text and scripts
11811      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11812      * @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}
11813      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11814      * @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.
11815      */
11816     update : function(url, params, callback, discardUrl){
11817         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11818             var method = this.method,
11819                 cfg;
11820             if(typeof url == "object"){ // must be config object
11821                 cfg = url;
11822                 url = cfg.url;
11823                 params = params || cfg.params;
11824                 callback = callback || cfg.callback;
11825                 discardUrl = discardUrl || cfg.discardUrl;
11826                 if(callback && cfg.scope){
11827                     callback = callback.createDelegate(cfg.scope);
11828                 }
11829                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11830                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11831                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11832                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11833                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11834             }
11835             this.showLoading();
11836             if(!discardUrl){
11837                 this.defaultUrl = url;
11838             }
11839             if(typeof url == "function"){
11840                 url = url.call(this);
11841             }
11842
11843             method = method || (params ? "POST" : "GET");
11844             if(method == "GET"){
11845                 url = this.prepareUrl(url);
11846             }
11847
11848             var o = Roo.apply(cfg ||{}, {
11849                 url : url,
11850                 params: params,
11851                 success: this.successDelegate,
11852                 failure: this.failureDelegate,
11853                 callback: undefined,
11854                 timeout: (this.timeout*1000),
11855                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11856             });
11857             Roo.log("updated manager called with timeout of " + o.timeout);
11858             this.transaction = Roo.Ajax.request(o);
11859         }
11860     },
11861
11862     /**
11863      * 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.
11864      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11865      * @param {String/HTMLElement} form The form Id or form element
11866      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11867      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11868      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11869      */
11870     formUpdate : function(form, url, reset, callback){
11871         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11872             if(typeof url == "function"){
11873                 url = url.call(this);
11874             }
11875             form = Roo.getDom(form);
11876             this.transaction = Roo.Ajax.request({
11877                 form: form,
11878                 url:url,
11879                 success: this.successDelegate,
11880                 failure: this.failureDelegate,
11881                 timeout: (this.timeout*1000),
11882                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11883             });
11884             this.showLoading.defer(1, this);
11885         }
11886     },
11887
11888     /**
11889      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11890      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11891      */
11892     refresh : function(callback){
11893         if(this.defaultUrl == null){
11894             return;
11895         }
11896         this.update(this.defaultUrl, null, callback, true);
11897     },
11898
11899     /**
11900      * Set this element to auto refresh.
11901      * @param {Number} interval How often to update (in seconds).
11902      * @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)
11903      * @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}
11904      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11905      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11906      */
11907     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11908         if(refreshNow){
11909             this.update(url || this.defaultUrl, params, callback, true);
11910         }
11911         if(this.autoRefreshProcId){
11912             clearInterval(this.autoRefreshProcId);
11913         }
11914         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11915     },
11916
11917     /**
11918      * Stop auto refresh on this element.
11919      */
11920      stopAutoRefresh : function(){
11921         if(this.autoRefreshProcId){
11922             clearInterval(this.autoRefreshProcId);
11923             delete this.autoRefreshProcId;
11924         }
11925     },
11926
11927     isAutoRefreshing : function(){
11928        return this.autoRefreshProcId ? true : false;
11929     },
11930     /**
11931      * Called to update the element to "Loading" state. Override to perform custom action.
11932      */
11933     showLoading : function(){
11934         if(this.showLoadIndicator){
11935             this.el.update(this.indicatorText);
11936         }
11937     },
11938
11939     /**
11940      * Adds unique parameter to query string if disableCaching = true
11941      * @private
11942      */
11943     prepareUrl : function(url){
11944         if(this.disableCaching){
11945             var append = "_dc=" + (new Date().getTime());
11946             if(url.indexOf("?") !== -1){
11947                 url += "&" + append;
11948             }else{
11949                 url += "?" + append;
11950             }
11951         }
11952         return url;
11953     },
11954
11955     /**
11956      * @private
11957      */
11958     processSuccess : function(response){
11959         this.transaction = null;
11960         if(response.argument.form && response.argument.reset){
11961             try{ // put in try/catch since some older FF releases had problems with this
11962                 response.argument.form.reset();
11963             }catch(e){}
11964         }
11965         if(this.loadScripts){
11966             this.renderer.render(this.el, response, this,
11967                 this.updateComplete.createDelegate(this, [response]));
11968         }else{
11969             this.renderer.render(this.el, response, this);
11970             this.updateComplete(response);
11971         }
11972     },
11973
11974     updateComplete : function(response){
11975         this.fireEvent("update", this.el, response);
11976         if(typeof response.argument.callback == "function"){
11977             response.argument.callback(this.el, true, response);
11978         }
11979     },
11980
11981     /**
11982      * @private
11983      */
11984     processFailure : function(response){
11985         this.transaction = null;
11986         this.fireEvent("failure", this.el, response);
11987         if(typeof response.argument.callback == "function"){
11988             response.argument.callback(this.el, false, response);
11989         }
11990     },
11991
11992     /**
11993      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11994      * @param {Object} renderer The object implementing the render() method
11995      */
11996     setRenderer : function(renderer){
11997         this.renderer = renderer;
11998     },
11999
12000     getRenderer : function(){
12001        return this.renderer;
12002     },
12003
12004     /**
12005      * Set the defaultUrl used for updates
12006      * @param {String/Function} defaultUrl The url or a function to call to get the url
12007      */
12008     setDefaultUrl : function(defaultUrl){
12009         this.defaultUrl = defaultUrl;
12010     },
12011
12012     /**
12013      * Aborts the executing transaction
12014      */
12015     abort : function(){
12016         if(this.transaction){
12017             Roo.Ajax.abort(this.transaction);
12018         }
12019     },
12020
12021     /**
12022      * Returns true if an update is in progress
12023      * @return {Boolean}
12024      */
12025     isUpdating : function(){
12026         if(this.transaction){
12027             return Roo.Ajax.isLoading(this.transaction);
12028         }
12029         return false;
12030     }
12031 });
12032
12033 /**
12034  * @class Roo.UpdateManager.defaults
12035  * @static (not really - but it helps the doc tool)
12036  * The defaults collection enables customizing the default properties of UpdateManager
12037  */
12038    Roo.UpdateManager.defaults = {
12039        /**
12040          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12041          * @type Number
12042          */
12043          timeout : 30,
12044
12045          /**
12046          * True to process scripts by default (Defaults to false).
12047          * @type Boolean
12048          */
12049         loadScripts : false,
12050
12051         /**
12052         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12053         * @type String
12054         */
12055         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12056         /**
12057          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12058          * @type Boolean
12059          */
12060         disableCaching : false,
12061         /**
12062          * Whether to show indicatorText when loading (Defaults to true).
12063          * @type Boolean
12064          */
12065         showLoadIndicator : true,
12066         /**
12067          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12068          * @type String
12069          */
12070         indicatorText : '<div class="loading-indicator">Loading...</div>'
12071    };
12072
12073 /**
12074  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12075  *Usage:
12076  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12077  * @param {String/HTMLElement/Roo.Element} el The element to update
12078  * @param {String} url The url
12079  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12080  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12081  * @static
12082  * @deprecated
12083  * @member Roo.UpdateManager
12084  */
12085 Roo.UpdateManager.updateElement = function(el, url, params, options){
12086     var um = Roo.get(el, true).getUpdateManager();
12087     Roo.apply(um, options);
12088     um.update(url, params, options ? options.callback : null);
12089 };
12090 // alias for backwards compat
12091 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12092 /**
12093  * @class Roo.UpdateManager.BasicRenderer
12094  * Default Content renderer. Updates the elements innerHTML with the responseText.
12095  */
12096 Roo.UpdateManager.BasicRenderer = function(){};
12097
12098 Roo.UpdateManager.BasicRenderer.prototype = {
12099     /**
12100      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12101      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12102      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12103      * @param {Roo.Element} el The element being rendered
12104      * @param {Object} response The YUI Connect response object
12105      * @param {UpdateManager} updateManager The calling update manager
12106      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12107      */
12108      render : function(el, response, updateManager, callback){
12109         el.update(response.responseText, updateManager.loadScripts, callback);
12110     }
12111 };
12112 /*
12113  * Based on:
12114  * Roo JS
12115  * (c)) Alan Knowles
12116  * Licence : LGPL
12117  */
12118
12119
12120 /**
12121  * @class Roo.DomTemplate
12122  * @extends Roo.Template
12123  * An effort at a dom based template engine..
12124  *
12125  * Similar to XTemplate, except it uses dom parsing to create the template..
12126  *
12127  * Supported features:
12128  *
12129  *  Tags:
12130
12131 <pre><code>
12132       {a_variable} - output encoded.
12133       {a_variable.format:("Y-m-d")} - call a method on the variable
12134       {a_variable:raw} - unencoded output
12135       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12136       {a_variable:this.method_on_template(...)} - call a method on the template object.
12137  
12138 </code></pre>
12139  *  The tpl tag:
12140 <pre><code>
12141         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12142         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12143         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12144         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12145   
12146 </code></pre>
12147  *      
12148  */
12149 Roo.DomTemplate = function()
12150 {
12151      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12152      if (this.html) {
12153         this.compile();
12154      }
12155 };
12156
12157
12158 Roo.extend(Roo.DomTemplate, Roo.Template, {
12159     /**
12160      * id counter for sub templates.
12161      */
12162     id : 0,
12163     /**
12164      * flag to indicate if dom parser is inside a pre,
12165      * it will strip whitespace if not.
12166      */
12167     inPre : false,
12168     
12169     /**
12170      * The various sub templates
12171      */
12172     tpls : false,
12173     
12174     
12175     
12176     /**
12177      *
12178      * basic tag replacing syntax
12179      * WORD:WORD()
12180      *
12181      * // you can fake an object call by doing this
12182      *  x.t:(test,tesT) 
12183      * 
12184      */
12185     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12186     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12187     
12188     iterChild : function (node, method) {
12189         
12190         var oldPre = this.inPre;
12191         if (node.tagName == 'PRE') {
12192             this.inPre = true;
12193         }
12194         for( var i = 0; i < node.childNodes.length; i++) {
12195             method.call(this, node.childNodes[i]);
12196         }
12197         this.inPre = oldPre;
12198     },
12199     
12200     
12201     
12202     /**
12203      * compile the template
12204      *
12205      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12206      *
12207      */
12208     compile: function()
12209     {
12210         var s = this.html;
12211         
12212         // covert the html into DOM...
12213         var doc = false;
12214         var div =false;
12215         try {
12216             doc = document.implementation.createHTMLDocument("");
12217             doc.documentElement.innerHTML =   this.html  ;
12218             div = doc.documentElement;
12219         } catch (e) {
12220             // old IE... - nasty -- it causes all sorts of issues.. with
12221             // images getting pulled from server..
12222             div = document.createElement('div');
12223             div.innerHTML = this.html;
12224         }
12225         //doc.documentElement.innerHTML = htmlBody
12226          
12227         
12228         
12229         this.tpls = [];
12230         var _t = this;
12231         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12232         
12233         var tpls = this.tpls;
12234         
12235         // create a top level template from the snippet..
12236         
12237         //Roo.log(div.innerHTML);
12238         
12239         var tpl = {
12240             uid : 'master',
12241             id : this.id++,
12242             attr : false,
12243             value : false,
12244             body : div.innerHTML,
12245             
12246             forCall : false,
12247             execCall : false,
12248             dom : div,
12249             isTop : true
12250             
12251         };
12252         tpls.unshift(tpl);
12253         
12254         
12255         // compile them...
12256         this.tpls = [];
12257         Roo.each(tpls, function(tp){
12258             this.compileTpl(tp);
12259             this.tpls[tp.id] = tp;
12260         }, this);
12261         
12262         this.master = tpls[0];
12263         return this;
12264         
12265         
12266     },
12267     
12268     compileNode : function(node, istop) {
12269         // test for
12270         //Roo.log(node);
12271         
12272         
12273         // skip anything not a tag..
12274         if (node.nodeType != 1) {
12275             if (node.nodeType == 3 && !this.inPre) {
12276                 // reduce white space..
12277                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12278                 
12279             }
12280             return;
12281         }
12282         
12283         var tpl = {
12284             uid : false,
12285             id : false,
12286             attr : false,
12287             value : false,
12288             body : '',
12289             
12290             forCall : false,
12291             execCall : false,
12292             dom : false,
12293             isTop : istop
12294             
12295             
12296         };
12297         
12298         
12299         switch(true) {
12300             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12301             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12302             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12303             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12304             // no default..
12305         }
12306         
12307         
12308         if (!tpl.attr) {
12309             // just itterate children..
12310             this.iterChild(node,this.compileNode);
12311             return;
12312         }
12313         tpl.uid = this.id++;
12314         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12315         node.removeAttribute('roo-'+ tpl.attr);
12316         if (tpl.attr != 'name') {
12317             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12318             node.parentNode.replaceChild(placeholder,  node);
12319         } else {
12320             
12321             var placeholder =  document.createElement('span');
12322             placeholder.className = 'roo-tpl-' + tpl.value;
12323             node.parentNode.replaceChild(placeholder,  node);
12324         }
12325         
12326         // parent now sees '{domtplXXXX}
12327         this.iterChild(node,this.compileNode);
12328         
12329         // we should now have node body...
12330         var div = document.createElement('div');
12331         div.appendChild(node);
12332         tpl.dom = node;
12333         // this has the unfortunate side effect of converting tagged attributes
12334         // eg. href="{...}" into %7C...%7D
12335         // this has been fixed by searching for those combo's although it's a bit hacky..
12336         
12337         
12338         tpl.body = div.innerHTML;
12339         
12340         
12341          
12342         tpl.id = tpl.uid;
12343         switch(tpl.attr) {
12344             case 'for' :
12345                 switch (tpl.value) {
12346                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12347                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12348                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12349                 }
12350                 break;
12351             
12352             case 'exec':
12353                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12354                 break;
12355             
12356             case 'if':     
12357                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12358                 break;
12359             
12360             case 'name':
12361                 tpl.id  = tpl.value; // replace non characters???
12362                 break;
12363             
12364         }
12365         
12366         
12367         this.tpls.push(tpl);
12368         
12369         
12370         
12371     },
12372     
12373     
12374     
12375     
12376     /**
12377      * Compile a segment of the template into a 'sub-template'
12378      *
12379      * 
12380      * 
12381      *
12382      */
12383     compileTpl : function(tpl)
12384     {
12385         var fm = Roo.util.Format;
12386         var useF = this.disableFormats !== true;
12387         
12388         var sep = Roo.isGecko ? "+\n" : ",\n";
12389         
12390         var undef = function(str) {
12391             Roo.debug && Roo.log("Property not found :"  + str);
12392             return '';
12393         };
12394           
12395         //Roo.log(tpl.body);
12396         
12397         
12398         
12399         var fn = function(m, lbrace, name, format, args)
12400         {
12401             //Roo.log("ARGS");
12402             //Roo.log(arguments);
12403             args = args ? args.replace(/\\'/g,"'") : args;
12404             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12405             if (typeof(format) == 'undefined') {
12406                 format =  'htmlEncode'; 
12407             }
12408             if (format == 'raw' ) {
12409                 format = false;
12410             }
12411             
12412             if(name.substr(0, 6) == 'domtpl'){
12413                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12414             }
12415             
12416             // build an array of options to determine if value is undefined..
12417             
12418             // basically get 'xxxx.yyyy' then do
12419             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12420             //    (function () { Roo.log("Property not found"); return ''; })() :
12421             //    ......
12422             
12423             var udef_ar = [];
12424             var lookfor = '';
12425             Roo.each(name.split('.'), function(st) {
12426                 lookfor += (lookfor.length ? '.': '') + st;
12427                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12428             });
12429             
12430             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12431             
12432             
12433             if(format && useF){
12434                 
12435                 args = args ? ',' + args : "";
12436                  
12437                 if(format.substr(0, 5) != "this."){
12438                     format = "fm." + format + '(';
12439                 }else{
12440                     format = 'this.call("'+ format.substr(5) + '", ';
12441                     args = ", values";
12442                 }
12443                 
12444                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12445             }
12446              
12447             if (args && args.length) {
12448                 // called with xxyx.yuu:(test,test)
12449                 // change to ()
12450                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12451             }
12452             // raw.. - :raw modifier..
12453             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12454             
12455         };
12456         var body;
12457         // branched to use + in gecko and [].join() in others
12458         if(Roo.isGecko){
12459             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12460                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12461                     "';};};";
12462         }else{
12463             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12464             body.push(tpl.body.replace(/(\r\n|\n)/g,
12465                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12466             body.push("'].join('');};};");
12467             body = body.join('');
12468         }
12469         
12470         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12471        
12472         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12473         eval(body);
12474         
12475         return this;
12476     },
12477      
12478     /**
12479      * same as applyTemplate, except it's done to one of the subTemplates
12480      * when using named templates, you can do:
12481      *
12482      * var str = pl.applySubTemplate('your-name', values);
12483      *
12484      * 
12485      * @param {Number} id of the template
12486      * @param {Object} values to apply to template
12487      * @param {Object} parent (normaly the instance of this object)
12488      */
12489     applySubTemplate : function(id, values, parent)
12490     {
12491         
12492         
12493         var t = this.tpls[id];
12494         
12495         
12496         try { 
12497             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12498                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12499                 return '';
12500             }
12501         } catch(e) {
12502             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12503             Roo.log(values);
12504           
12505             return '';
12506         }
12507         try { 
12508             
12509             if(t.execCall && t.execCall.call(this, values, parent)){
12510                 return '';
12511             }
12512         } catch(e) {
12513             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12514             Roo.log(values);
12515             return '';
12516         }
12517         
12518         try {
12519             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12520             parent = t.target ? values : parent;
12521             if(t.forCall && vs instanceof Array){
12522                 var buf = [];
12523                 for(var i = 0, len = vs.length; i < len; i++){
12524                     try {
12525                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12526                     } catch (e) {
12527                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12528                         Roo.log(e.body);
12529                         //Roo.log(t.compiled);
12530                         Roo.log(vs[i]);
12531                     }   
12532                 }
12533                 return buf.join('');
12534             }
12535         } catch (e) {
12536             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12537             Roo.log(values);
12538             return '';
12539         }
12540         try {
12541             return t.compiled.call(this, vs, parent);
12542         } catch (e) {
12543             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12544             Roo.log(e.body);
12545             //Roo.log(t.compiled);
12546             Roo.log(values);
12547             return '';
12548         }
12549     },
12550
12551    
12552
12553     applyTemplate : function(values){
12554         return this.master.compiled.call(this, values, {});
12555         //var s = this.subs;
12556     },
12557
12558     apply : function(){
12559         return this.applyTemplate.apply(this, arguments);
12560     }
12561
12562  });
12563
12564 Roo.DomTemplate.from = function(el){
12565     el = Roo.getDom(el);
12566     return new Roo.Domtemplate(el.value || el.innerHTML);
12567 };/*
12568  * Based on:
12569  * Ext JS Library 1.1.1
12570  * Copyright(c) 2006-2007, Ext JS, LLC.
12571  *
12572  * Originally Released Under LGPL - original licence link has changed is not relivant.
12573  *
12574  * Fork - LGPL
12575  * <script type="text/javascript">
12576  */
12577
12578 /**
12579  * @class Roo.util.DelayedTask
12580  * Provides a convenient method of performing setTimeout where a new
12581  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12582  * You can use this class to buffer
12583  * the keypress events for a certain number of milliseconds, and perform only if they stop
12584  * for that amount of time.
12585  * @constructor The parameters to this constructor serve as defaults and are not required.
12586  * @param {Function} fn (optional) The default function to timeout
12587  * @param {Object} scope (optional) The default scope of that timeout
12588  * @param {Array} args (optional) The default Array of arguments
12589  */
12590 Roo.util.DelayedTask = function(fn, scope, args){
12591     var id = null, d, t;
12592
12593     var call = function(){
12594         var now = new Date().getTime();
12595         if(now - t >= d){
12596             clearInterval(id);
12597             id = null;
12598             fn.apply(scope, args || []);
12599         }
12600     };
12601     /**
12602      * Cancels any pending timeout and queues a new one
12603      * @param {Number} delay The milliseconds to delay
12604      * @param {Function} newFn (optional) Overrides function passed to constructor
12605      * @param {Object} newScope (optional) Overrides scope passed to constructor
12606      * @param {Array} newArgs (optional) Overrides args passed to constructor
12607      */
12608     this.delay = function(delay, newFn, newScope, newArgs){
12609         if(id && delay != d){
12610             this.cancel();
12611         }
12612         d = delay;
12613         t = new Date().getTime();
12614         fn = newFn || fn;
12615         scope = newScope || scope;
12616         args = newArgs || args;
12617         if(!id){
12618             id = setInterval(call, d);
12619         }
12620     };
12621
12622     /**
12623      * Cancel the last queued timeout
12624      */
12625     this.cancel = function(){
12626         if(id){
12627             clearInterval(id);
12628             id = null;
12629         }
12630     };
12631 };/*
12632  * Based on:
12633  * Ext JS Library 1.1.1
12634  * Copyright(c) 2006-2007, Ext JS, LLC.
12635  *
12636  * Originally Released Under LGPL - original licence link has changed is not relivant.
12637  *
12638  * Fork - LGPL
12639  * <script type="text/javascript">
12640  */
12641  
12642  
12643 Roo.util.TaskRunner = function(interval){
12644     interval = interval || 10;
12645     var tasks = [], removeQueue = [];
12646     var id = 0;
12647     var running = false;
12648
12649     var stopThread = function(){
12650         running = false;
12651         clearInterval(id);
12652         id = 0;
12653     };
12654
12655     var startThread = function(){
12656         if(!running){
12657             running = true;
12658             id = setInterval(runTasks, interval);
12659         }
12660     };
12661
12662     var removeTask = function(task){
12663         removeQueue.push(task);
12664         if(task.onStop){
12665             task.onStop();
12666         }
12667     };
12668
12669     var runTasks = function(){
12670         if(removeQueue.length > 0){
12671             for(var i = 0, len = removeQueue.length; i < len; i++){
12672                 tasks.remove(removeQueue[i]);
12673             }
12674             removeQueue = [];
12675             if(tasks.length < 1){
12676                 stopThread();
12677                 return;
12678             }
12679         }
12680         var now = new Date().getTime();
12681         for(var i = 0, len = tasks.length; i < len; ++i){
12682             var t = tasks[i];
12683             var itime = now - t.taskRunTime;
12684             if(t.interval <= itime){
12685                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12686                 t.taskRunTime = now;
12687                 if(rt === false || t.taskRunCount === t.repeat){
12688                     removeTask(t);
12689                     return;
12690                 }
12691             }
12692             if(t.duration && t.duration <= (now - t.taskStartTime)){
12693                 removeTask(t);
12694             }
12695         }
12696     };
12697
12698     /**
12699      * Queues a new task.
12700      * @param {Object} task
12701      */
12702     this.start = function(task){
12703         tasks.push(task);
12704         task.taskStartTime = new Date().getTime();
12705         task.taskRunTime = 0;
12706         task.taskRunCount = 0;
12707         startThread();
12708         return task;
12709     };
12710
12711     this.stop = function(task){
12712         removeTask(task);
12713         return task;
12714     };
12715
12716     this.stopAll = function(){
12717         stopThread();
12718         for(var i = 0, len = tasks.length; i < len; i++){
12719             if(tasks[i].onStop){
12720                 tasks[i].onStop();
12721             }
12722         }
12723         tasks = [];
12724         removeQueue = [];
12725     };
12726 };
12727
12728 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12729  * Based on:
12730  * Ext JS Library 1.1.1
12731  * Copyright(c) 2006-2007, Ext JS, LLC.
12732  *
12733  * Originally Released Under LGPL - original licence link has changed is not relivant.
12734  *
12735  * Fork - LGPL
12736  * <script type="text/javascript">
12737  */
12738
12739  
12740 /**
12741  * @class Roo.util.MixedCollection
12742  * @extends Roo.util.Observable
12743  * A Collection class that maintains both numeric indexes and keys and exposes events.
12744  * @constructor
12745  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12746  * collection (defaults to false)
12747  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12748  * and return the key value for that item.  This is used when available to look up the key on items that
12749  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12750  * equivalent to providing an implementation for the {@link #getKey} method.
12751  */
12752 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12753     this.items = [];
12754     this.map = {};
12755     this.keys = [];
12756     this.length = 0;
12757     this.addEvents({
12758         /**
12759          * @event clear
12760          * Fires when the collection is cleared.
12761          */
12762         "clear" : true,
12763         /**
12764          * @event add
12765          * Fires when an item is added to the collection.
12766          * @param {Number} index The index at which the item was added.
12767          * @param {Object} o The item added.
12768          * @param {String} key The key associated with the added item.
12769          */
12770         "add" : true,
12771         /**
12772          * @event replace
12773          * Fires when an item is replaced in the collection.
12774          * @param {String} key he key associated with the new added.
12775          * @param {Object} old The item being replaced.
12776          * @param {Object} new The new item.
12777          */
12778         "replace" : true,
12779         /**
12780          * @event remove
12781          * Fires when an item is removed from the collection.
12782          * @param {Object} o The item being removed.
12783          * @param {String} key (optional) The key associated with the removed item.
12784          */
12785         "remove" : true,
12786         "sort" : true
12787     });
12788     this.allowFunctions = allowFunctions === true;
12789     if(keyFn){
12790         this.getKey = keyFn;
12791     }
12792     Roo.util.MixedCollection.superclass.constructor.call(this);
12793 };
12794
12795 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12796     allowFunctions : false,
12797     
12798 /**
12799  * Adds an item to the collection.
12800  * @param {String} key The key to associate with the item
12801  * @param {Object} o The item to add.
12802  * @return {Object} The item added.
12803  */
12804     add : function(key, o){
12805         if(arguments.length == 1){
12806             o = arguments[0];
12807             key = this.getKey(o);
12808         }
12809         if(typeof key == "undefined" || key === null){
12810             this.length++;
12811             this.items.push(o);
12812             this.keys.push(null);
12813         }else{
12814             var old = this.map[key];
12815             if(old){
12816                 return this.replace(key, o);
12817             }
12818             this.length++;
12819             this.items.push(o);
12820             this.map[key] = o;
12821             this.keys.push(key);
12822         }
12823         this.fireEvent("add", this.length-1, o, key);
12824         return o;
12825     },
12826        
12827 /**
12828   * MixedCollection has a generic way to fetch keys if you implement getKey.
12829 <pre><code>
12830 // normal way
12831 var mc = new Roo.util.MixedCollection();
12832 mc.add(someEl.dom.id, someEl);
12833 mc.add(otherEl.dom.id, otherEl);
12834 //and so on
12835
12836 // using getKey
12837 var mc = new Roo.util.MixedCollection();
12838 mc.getKey = function(el){
12839    return el.dom.id;
12840 };
12841 mc.add(someEl);
12842 mc.add(otherEl);
12843
12844 // or via the constructor
12845 var mc = new Roo.util.MixedCollection(false, function(el){
12846    return el.dom.id;
12847 });
12848 mc.add(someEl);
12849 mc.add(otherEl);
12850 </code></pre>
12851  * @param o {Object} The item for which to find the key.
12852  * @return {Object} The key for the passed item.
12853  */
12854     getKey : function(o){
12855          return o.id; 
12856     },
12857    
12858 /**
12859  * Replaces an item in the collection.
12860  * @param {String} key The key associated with the item to replace, or the item to replace.
12861  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12862  * @return {Object}  The new item.
12863  */
12864     replace : function(key, o){
12865         if(arguments.length == 1){
12866             o = arguments[0];
12867             key = this.getKey(o);
12868         }
12869         var old = this.item(key);
12870         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12871              return this.add(key, o);
12872         }
12873         var index = this.indexOfKey(key);
12874         this.items[index] = o;
12875         this.map[key] = o;
12876         this.fireEvent("replace", key, old, o);
12877         return o;
12878     },
12879    
12880 /**
12881  * Adds all elements of an Array or an Object to the collection.
12882  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12883  * an Array of values, each of which are added to the collection.
12884  */
12885     addAll : function(objs){
12886         if(arguments.length > 1 || objs instanceof Array){
12887             var args = arguments.length > 1 ? arguments : objs;
12888             for(var i = 0, len = args.length; i < len; i++){
12889                 this.add(args[i]);
12890             }
12891         }else{
12892             for(var key in objs){
12893                 if(this.allowFunctions || typeof objs[key] != "function"){
12894                     this.add(key, objs[key]);
12895                 }
12896             }
12897         }
12898     },
12899    
12900 /**
12901  * Executes the specified function once for every item in the collection, passing each
12902  * item as the first and only parameter. returning false from the function will stop the iteration.
12903  * @param {Function} fn The function to execute for each item.
12904  * @param {Object} scope (optional) The scope in which to execute the function.
12905  */
12906     each : function(fn, scope){
12907         var items = [].concat(this.items); // each safe for removal
12908         for(var i = 0, len = items.length; i < len; i++){
12909             if(fn.call(scope || items[i], items[i], i, len) === false){
12910                 break;
12911             }
12912         }
12913     },
12914    
12915 /**
12916  * Executes the specified function once for every key in the collection, passing each
12917  * key, and its associated item as the first two parameters.
12918  * @param {Function} fn The function to execute for each item.
12919  * @param {Object} scope (optional) The scope in which to execute the function.
12920  */
12921     eachKey : function(fn, scope){
12922         for(var i = 0, len = this.keys.length; i < len; i++){
12923             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12924         }
12925     },
12926    
12927 /**
12928  * Returns the first item in the collection which elicits a true return value from the
12929  * passed selection function.
12930  * @param {Function} fn The selection function to execute for each item.
12931  * @param {Object} scope (optional) The scope in which to execute the function.
12932  * @return {Object} The first item in the collection which returned true from the selection function.
12933  */
12934     find : function(fn, scope){
12935         for(var i = 0, len = this.items.length; i < len; i++){
12936             if(fn.call(scope || window, this.items[i], this.keys[i])){
12937                 return this.items[i];
12938             }
12939         }
12940         return null;
12941     },
12942    
12943 /**
12944  * Inserts an item at the specified index in the collection.
12945  * @param {Number} index The index to insert the item at.
12946  * @param {String} key The key to associate with the new item, or the item itself.
12947  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12948  * @return {Object} The item inserted.
12949  */
12950     insert : function(index, key, o){
12951         if(arguments.length == 2){
12952             o = arguments[1];
12953             key = this.getKey(o);
12954         }
12955         if(index >= this.length){
12956             return this.add(key, o);
12957         }
12958         this.length++;
12959         this.items.splice(index, 0, o);
12960         if(typeof key != "undefined" && key != null){
12961             this.map[key] = o;
12962         }
12963         this.keys.splice(index, 0, key);
12964         this.fireEvent("add", index, o, key);
12965         return o;
12966     },
12967    
12968 /**
12969  * Removed an item from the collection.
12970  * @param {Object} o The item to remove.
12971  * @return {Object} The item removed.
12972  */
12973     remove : function(o){
12974         return this.removeAt(this.indexOf(o));
12975     },
12976    
12977 /**
12978  * Remove an item from a specified index in the collection.
12979  * @param {Number} index The index within the collection of the item to remove.
12980  */
12981     removeAt : function(index){
12982         if(index < this.length && index >= 0){
12983             this.length--;
12984             var o = this.items[index];
12985             this.items.splice(index, 1);
12986             var key = this.keys[index];
12987             if(typeof key != "undefined"){
12988                 delete this.map[key];
12989             }
12990             this.keys.splice(index, 1);
12991             this.fireEvent("remove", o, key);
12992         }
12993     },
12994    
12995 /**
12996  * Removed an item associated with the passed key fom the collection.
12997  * @param {String} key The key of the item to remove.
12998  */
12999     removeKey : function(key){
13000         return this.removeAt(this.indexOfKey(key));
13001     },
13002    
13003 /**
13004  * Returns the number of items in the collection.
13005  * @return {Number} the number of items in the collection.
13006  */
13007     getCount : function(){
13008         return this.length; 
13009     },
13010    
13011 /**
13012  * Returns index within the collection of the passed Object.
13013  * @param {Object} o The item to find the index of.
13014  * @return {Number} index of the item.
13015  */
13016     indexOf : function(o){
13017         if(!this.items.indexOf){
13018             for(var i = 0, len = this.items.length; i < len; i++){
13019                 if(this.items[i] == o) return i;
13020             }
13021             return -1;
13022         }else{
13023             return this.items.indexOf(o);
13024         }
13025     },
13026    
13027 /**
13028  * Returns index within the collection of the passed key.
13029  * @param {String} key The key to find the index of.
13030  * @return {Number} index of the key.
13031  */
13032     indexOfKey : function(key){
13033         if(!this.keys.indexOf){
13034             for(var i = 0, len = this.keys.length; i < len; i++){
13035                 if(this.keys[i] == key) return i;
13036             }
13037             return -1;
13038         }else{
13039             return this.keys.indexOf(key);
13040         }
13041     },
13042    
13043 /**
13044  * Returns the item associated with the passed key OR index. Key has priority over index.
13045  * @param {String/Number} key The key or index of the item.
13046  * @return {Object} The item associated with the passed key.
13047  */
13048     item : function(key){
13049         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13050         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13051     },
13052     
13053 /**
13054  * Returns the item at the specified index.
13055  * @param {Number} index The index of the item.
13056  * @return {Object}
13057  */
13058     itemAt : function(index){
13059         return this.items[index];
13060     },
13061     
13062 /**
13063  * Returns the item associated with the passed key.
13064  * @param {String/Number} key The key of the item.
13065  * @return {Object} The item associated with the passed key.
13066  */
13067     key : function(key){
13068         return this.map[key];
13069     },
13070    
13071 /**
13072  * Returns true if the collection contains the passed Object as an item.
13073  * @param {Object} o  The Object to look for in the collection.
13074  * @return {Boolean} True if the collection contains the Object as an item.
13075  */
13076     contains : function(o){
13077         return this.indexOf(o) != -1;
13078     },
13079    
13080 /**
13081  * Returns true if the collection contains the passed Object as a key.
13082  * @param {String} key The key to look for in the collection.
13083  * @return {Boolean} True if the collection contains the Object as a key.
13084  */
13085     containsKey : function(key){
13086         return typeof this.map[key] != "undefined";
13087     },
13088    
13089 /**
13090  * Removes all items from the collection.
13091  */
13092     clear : function(){
13093         this.length = 0;
13094         this.items = [];
13095         this.keys = [];
13096         this.map = {};
13097         this.fireEvent("clear");
13098     },
13099    
13100 /**
13101  * Returns the first item in the collection.
13102  * @return {Object} the first item in the collection..
13103  */
13104     first : function(){
13105         return this.items[0]; 
13106     },
13107    
13108 /**
13109  * Returns the last item in the collection.
13110  * @return {Object} the last item in the collection..
13111  */
13112     last : function(){
13113         return this.items[this.length-1];   
13114     },
13115     
13116     _sort : function(property, dir, fn){
13117         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13118         fn = fn || function(a, b){
13119             return a-b;
13120         };
13121         var c = [], k = this.keys, items = this.items;
13122         for(var i = 0, len = items.length; i < len; i++){
13123             c[c.length] = {key: k[i], value: items[i], index: i};
13124         }
13125         c.sort(function(a, b){
13126             var v = fn(a[property], b[property]) * dsc;
13127             if(v == 0){
13128                 v = (a.index < b.index ? -1 : 1);
13129             }
13130             return v;
13131         });
13132         for(var i = 0, len = c.length; i < len; i++){
13133             items[i] = c[i].value;
13134             k[i] = c[i].key;
13135         }
13136         this.fireEvent("sort", this);
13137     },
13138     
13139     /**
13140      * Sorts this collection with the passed comparison function
13141      * @param {String} direction (optional) "ASC" or "DESC"
13142      * @param {Function} fn (optional) comparison function
13143      */
13144     sort : function(dir, fn){
13145         this._sort("value", dir, fn);
13146     },
13147     
13148     /**
13149      * Sorts this collection by keys
13150      * @param {String} direction (optional) "ASC" or "DESC"
13151      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13152      */
13153     keySort : function(dir, fn){
13154         this._sort("key", dir, fn || function(a, b){
13155             return String(a).toUpperCase()-String(b).toUpperCase();
13156         });
13157     },
13158     
13159     /**
13160      * Returns a range of items in this collection
13161      * @param {Number} startIndex (optional) defaults to 0
13162      * @param {Number} endIndex (optional) default to the last item
13163      * @return {Array} An array of items
13164      */
13165     getRange : function(start, end){
13166         var items = this.items;
13167         if(items.length < 1){
13168             return [];
13169         }
13170         start = start || 0;
13171         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13172         var r = [];
13173         if(start <= end){
13174             for(var i = start; i <= end; i++) {
13175                     r[r.length] = items[i];
13176             }
13177         }else{
13178             for(var i = start; i >= end; i--) {
13179                     r[r.length] = items[i];
13180             }
13181         }
13182         return r;
13183     },
13184         
13185     /**
13186      * Filter the <i>objects</i> in this collection by a specific property. 
13187      * Returns a new collection that has been filtered.
13188      * @param {String} property A property on your objects
13189      * @param {String/RegExp} value Either string that the property values 
13190      * should start with or a RegExp to test against the property
13191      * @return {MixedCollection} The new filtered collection
13192      */
13193     filter : function(property, value){
13194         if(!value.exec){ // not a regex
13195             value = String(value);
13196             if(value.length == 0){
13197                 return this.clone();
13198             }
13199             value = new RegExp("^" + Roo.escapeRe(value), "i");
13200         }
13201         return this.filterBy(function(o){
13202             return o && value.test(o[property]);
13203         });
13204         },
13205     
13206     /**
13207      * Filter by a function. * Returns a new collection that has been filtered.
13208      * The passed function will be called with each 
13209      * object in the collection. If the function returns true, the value is included 
13210      * otherwise it is filtered.
13211      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13212      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13213      * @return {MixedCollection} The new filtered collection
13214      */
13215     filterBy : function(fn, scope){
13216         var r = new Roo.util.MixedCollection();
13217         r.getKey = this.getKey;
13218         var k = this.keys, it = this.items;
13219         for(var i = 0, len = it.length; i < len; i++){
13220             if(fn.call(scope||this, it[i], k[i])){
13221                                 r.add(k[i], it[i]);
13222                         }
13223         }
13224         return r;
13225     },
13226     
13227     /**
13228      * Creates a duplicate of this collection
13229      * @return {MixedCollection}
13230      */
13231     clone : function(){
13232         var r = new Roo.util.MixedCollection();
13233         var k = this.keys, it = this.items;
13234         for(var i = 0, len = it.length; i < len; i++){
13235             r.add(k[i], it[i]);
13236         }
13237         r.getKey = this.getKey;
13238         return r;
13239     }
13240 });
13241 /**
13242  * Returns the item associated with the passed key or index.
13243  * @method
13244  * @param {String/Number} key The key or index of the item.
13245  * @return {Object} The item associated with the passed key.
13246  */
13247 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13248  * Based on:
13249  * Ext JS Library 1.1.1
13250  * Copyright(c) 2006-2007, Ext JS, LLC.
13251  *
13252  * Originally Released Under LGPL - original licence link has changed is not relivant.
13253  *
13254  * Fork - LGPL
13255  * <script type="text/javascript">
13256  */
13257 /**
13258  * @class Roo.util.JSON
13259  * Modified version of Douglas Crockford"s json.js that doesn"t
13260  * mess with the Object prototype 
13261  * http://www.json.org/js.html
13262  * @singleton
13263  */
13264 Roo.util.JSON = new (function(){
13265     var useHasOwn = {}.hasOwnProperty ? true : false;
13266     
13267     // crashes Safari in some instances
13268     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13269     
13270     var pad = function(n) {
13271         return n < 10 ? "0" + n : n;
13272     };
13273     
13274     var m = {
13275         "\b": '\\b',
13276         "\t": '\\t',
13277         "\n": '\\n',
13278         "\f": '\\f',
13279         "\r": '\\r',
13280         '"' : '\\"',
13281         "\\": '\\\\'
13282     };
13283
13284     var encodeString = function(s){
13285         if (/["\\\x00-\x1f]/.test(s)) {
13286             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13287                 var c = m[b];
13288                 if(c){
13289                     return c;
13290                 }
13291                 c = b.charCodeAt();
13292                 return "\\u00" +
13293                     Math.floor(c / 16).toString(16) +
13294                     (c % 16).toString(16);
13295             }) + '"';
13296         }
13297         return '"' + s + '"';
13298     };
13299     
13300     var encodeArray = function(o){
13301         var a = ["["], b, i, l = o.length, v;
13302             for (i = 0; i < l; i += 1) {
13303                 v = o[i];
13304                 switch (typeof v) {
13305                     case "undefined":
13306                     case "function":
13307                     case "unknown":
13308                         break;
13309                     default:
13310                         if (b) {
13311                             a.push(',');
13312                         }
13313                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13314                         b = true;
13315                 }
13316             }
13317             a.push("]");
13318             return a.join("");
13319     };
13320     
13321     var encodeDate = function(o){
13322         return '"' + o.getFullYear() + "-" +
13323                 pad(o.getMonth() + 1) + "-" +
13324                 pad(o.getDate()) + "T" +
13325                 pad(o.getHours()) + ":" +
13326                 pad(o.getMinutes()) + ":" +
13327                 pad(o.getSeconds()) + '"';
13328     };
13329     
13330     /**
13331      * Encodes an Object, Array or other value
13332      * @param {Mixed} o The variable to encode
13333      * @return {String} The JSON string
13334      */
13335     this.encode = function(o)
13336     {
13337         // should this be extended to fully wrap stringify..
13338         
13339         if(typeof o == "undefined" || o === null){
13340             return "null";
13341         }else if(o instanceof Array){
13342             return encodeArray(o);
13343         }else if(o instanceof Date){
13344             return encodeDate(o);
13345         }else if(typeof o == "string"){
13346             return encodeString(o);
13347         }else if(typeof o == "number"){
13348             return isFinite(o) ? String(o) : "null";
13349         }else if(typeof o == "boolean"){
13350             return String(o);
13351         }else {
13352             var a = ["{"], b, i, v;
13353             for (i in o) {
13354                 if(!useHasOwn || o.hasOwnProperty(i)) {
13355                     v = o[i];
13356                     switch (typeof v) {
13357                     case "undefined":
13358                     case "function":
13359                     case "unknown":
13360                         break;
13361                     default:
13362                         if(b){
13363                             a.push(',');
13364                         }
13365                         a.push(this.encode(i), ":",
13366                                 v === null ? "null" : this.encode(v));
13367                         b = true;
13368                     }
13369                 }
13370             }
13371             a.push("}");
13372             return a.join("");
13373         }
13374     };
13375     
13376     /**
13377      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13378      * @param {String} json The JSON string
13379      * @return {Object} The resulting object
13380      */
13381     this.decode = function(json){
13382         
13383         return  /** eval:var:json */ eval("(" + json + ')');
13384     };
13385 })();
13386 /** 
13387  * Shorthand for {@link Roo.util.JSON#encode}
13388  * @member Roo encode 
13389  * @method */
13390 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13391 /** 
13392  * Shorthand for {@link Roo.util.JSON#decode}
13393  * @member Roo decode 
13394  * @method */
13395 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13396 /*
13397  * Based on:
13398  * Ext JS Library 1.1.1
13399  * Copyright(c) 2006-2007, Ext JS, LLC.
13400  *
13401  * Originally Released Under LGPL - original licence link has changed is not relivant.
13402  *
13403  * Fork - LGPL
13404  * <script type="text/javascript">
13405  */
13406  
13407 /**
13408  * @class Roo.util.Format
13409  * Reusable data formatting functions
13410  * @singleton
13411  */
13412 Roo.util.Format = function(){
13413     var trimRe = /^\s+|\s+$/g;
13414     return {
13415         /**
13416          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13417          * @param {String} value The string to truncate
13418          * @param {Number} length The maximum length to allow before truncating
13419          * @return {String} The converted text
13420          */
13421         ellipsis : function(value, len){
13422             if(value && value.length > len){
13423                 return value.substr(0, len-3)+"...";
13424             }
13425             return value;
13426         },
13427
13428         /**
13429          * Checks a reference and converts it to empty string if it is undefined
13430          * @param {Mixed} value Reference to check
13431          * @return {Mixed} Empty string if converted, otherwise the original value
13432          */
13433         undef : function(value){
13434             return typeof value != "undefined" ? value : "";
13435         },
13436
13437         /**
13438          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13439          * @param {String} value The string to encode
13440          * @return {String} The encoded text
13441          */
13442         htmlEncode : function(value){
13443             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13444         },
13445
13446         /**
13447          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13448          * @param {String} value The string to decode
13449          * @return {String} The decoded text
13450          */
13451         htmlDecode : function(value){
13452             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13453         },
13454
13455         /**
13456          * Trims any whitespace from either side of a string
13457          * @param {String} value The text to trim
13458          * @return {String} The trimmed text
13459          */
13460         trim : function(value){
13461             return String(value).replace(trimRe, "");
13462         },
13463
13464         /**
13465          * Returns a substring from within an original string
13466          * @param {String} value The original text
13467          * @param {Number} start The start index of the substring
13468          * @param {Number} length The length of the substring
13469          * @return {String} The substring
13470          */
13471         substr : function(value, start, length){
13472             return String(value).substr(start, length);
13473         },
13474
13475         /**
13476          * Converts a string to all lower case letters
13477          * @param {String} value The text to convert
13478          * @return {String} The converted text
13479          */
13480         lowercase : function(value){
13481             return String(value).toLowerCase();
13482         },
13483
13484         /**
13485          * Converts a string to all upper case letters
13486          * @param {String} value The text to convert
13487          * @return {String} The converted text
13488          */
13489         uppercase : function(value){
13490             return String(value).toUpperCase();
13491         },
13492
13493         /**
13494          * Converts the first character only of a string to upper case
13495          * @param {String} value The text to convert
13496          * @return {String} The converted text
13497          */
13498         capitalize : function(value){
13499             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13500         },
13501
13502         // private
13503         call : function(value, fn){
13504             if(arguments.length > 2){
13505                 var args = Array.prototype.slice.call(arguments, 2);
13506                 args.unshift(value);
13507                  
13508                 return /** eval:var:value */  eval(fn).apply(window, args);
13509             }else{
13510                 /** eval:var:value */
13511                 return /** eval:var:value */ eval(fn).call(window, value);
13512             }
13513         },
13514
13515        
13516         /**
13517          * safer version of Math.toFixed..??/
13518          * @param {Number/String} value The numeric value to format
13519          * @param {Number/String} value Decimal places 
13520          * @return {String} The formatted currency string
13521          */
13522         toFixed : function(v, n)
13523         {
13524             // why not use to fixed - precision is buggered???
13525             if (!n) {
13526                 return Math.round(v-0);
13527             }
13528             var fact = Math.pow(10,n+1);
13529             v = (Math.round((v-0)*fact))/fact;
13530             var z = (''+fact).substring(2);
13531             if (v == Math.floor(v)) {
13532                 return Math.floor(v) + '.' + z;
13533             }
13534             
13535             // now just padd decimals..
13536             var ps = String(v).split('.');
13537             var fd = (ps[1] + z);
13538             var r = fd.substring(0,n); 
13539             var rm = fd.substring(n); 
13540             if (rm < 5) {
13541                 return ps[0] + '.' + r;
13542             }
13543             r*=1; // turn it into a number;
13544             r++;
13545             if (String(r).length != n) {
13546                 ps[0]*=1;
13547                 ps[0]++;
13548                 r = String(r).substring(1); // chop the end off.
13549             }
13550             
13551             return ps[0] + '.' + r;
13552              
13553         },
13554         
13555         /**
13556          * Format a number as US currency
13557          * @param {Number/String} value The numeric value to format
13558          * @return {String} The formatted currency string
13559          */
13560         usMoney : function(v){
13561             return '$' + Roo.util.Format.number(v);
13562         },
13563         
13564         /**
13565          * Format a number
13566          * eventually this should probably emulate php's number_format
13567          * @param {Number/String} value The numeric value to format
13568          * @param {Number} decimals number of decimal places
13569          * @return {String} The formatted currency string
13570          */
13571         number : function(v,decimals)
13572         {
13573             // multiply and round.
13574             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13575             var mul = Math.pow(10, decimals);
13576             var zero = String(mul).substring(1);
13577             v = (Math.round((v-0)*mul))/mul;
13578             
13579             // if it's '0' number.. then
13580             
13581             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13582             v = String(v);
13583             var ps = v.split('.');
13584             var whole = ps[0];
13585             
13586             
13587             var r = /(\d+)(\d{3})/;
13588             // add comma's
13589             while (r.test(whole)) {
13590                 whole = whole.replace(r, '$1' + ',' + '$2');
13591             }
13592             
13593             
13594             var sub = ps[1] ?
13595                     // has decimals..
13596                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13597                     // does not have decimals
13598                     (decimals ? ('.' + zero) : '');
13599             
13600             
13601             return whole + sub ;
13602         },
13603         
13604         /**
13605          * Parse a value into a formatted date using the specified format pattern.
13606          * @param {Mixed} value The value to format
13607          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13608          * @return {String} The formatted date string
13609          */
13610         date : function(v, format){
13611             if(!v){
13612                 return "";
13613             }
13614             if(!(v instanceof Date)){
13615                 v = new Date(Date.parse(v));
13616             }
13617             return v.dateFormat(format || "m/d/Y");
13618         },
13619
13620         /**
13621          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13622          * @param {String} format Any valid date format string
13623          * @return {Function} The date formatting function
13624          */
13625         dateRenderer : function(format){
13626             return function(v){
13627                 return Roo.util.Format.date(v, format);  
13628             };
13629         },
13630
13631         // private
13632         stripTagsRE : /<\/?[^>]+>/gi,
13633         
13634         /**
13635          * Strips all HTML tags
13636          * @param {Mixed} value The text from which to strip tags
13637          * @return {String} The stripped text
13638          */
13639         stripTags : function(v){
13640             return !v ? v : String(v).replace(this.stripTagsRE, "");
13641         }
13642     };
13643 }();/*
13644  * Based on:
13645  * Ext JS Library 1.1.1
13646  * Copyright(c) 2006-2007, Ext JS, LLC.
13647  *
13648  * Originally Released Under LGPL - original licence link has changed is not relivant.
13649  *
13650  * Fork - LGPL
13651  * <script type="text/javascript">
13652  */
13653
13654
13655  
13656
13657 /**
13658  * @class Roo.MasterTemplate
13659  * @extends Roo.Template
13660  * Provides a template that can have child templates. The syntax is:
13661 <pre><code>
13662 var t = new Roo.MasterTemplate(
13663         '&lt;select name="{name}"&gt;',
13664                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13665         '&lt;/select&gt;'
13666 );
13667 t.add('options', {value: 'foo', text: 'bar'});
13668 // or you can add multiple child elements in one shot
13669 t.addAll('options', [
13670     {value: 'foo', text: 'bar'},
13671     {value: 'foo2', text: 'bar2'},
13672     {value: 'foo3', text: 'bar3'}
13673 ]);
13674 // then append, applying the master template values
13675 t.append('my-form', {name: 'my-select'});
13676 </code></pre>
13677 * A name attribute for the child template is not required if you have only one child
13678 * template or you want to refer to them by index.
13679  */
13680 Roo.MasterTemplate = function(){
13681     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13682     this.originalHtml = this.html;
13683     var st = {};
13684     var m, re = this.subTemplateRe;
13685     re.lastIndex = 0;
13686     var subIndex = 0;
13687     while(m = re.exec(this.html)){
13688         var name = m[1], content = m[2];
13689         st[subIndex] = {
13690             name: name,
13691             index: subIndex,
13692             buffer: [],
13693             tpl : new Roo.Template(content)
13694         };
13695         if(name){
13696             st[name] = st[subIndex];
13697         }
13698         st[subIndex].tpl.compile();
13699         st[subIndex].tpl.call = this.call.createDelegate(this);
13700         subIndex++;
13701     }
13702     this.subCount = subIndex;
13703     this.subs = st;
13704 };
13705 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13706     /**
13707     * The regular expression used to match sub templates
13708     * @type RegExp
13709     * @property
13710     */
13711     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13712
13713     /**
13714      * Applies the passed values to a child template.
13715      * @param {String/Number} name (optional) The name or index of the child template
13716      * @param {Array/Object} values The values to be applied to the template
13717      * @return {MasterTemplate} this
13718      */
13719      add : function(name, values){
13720         if(arguments.length == 1){
13721             values = arguments[0];
13722             name = 0;
13723         }
13724         var s = this.subs[name];
13725         s.buffer[s.buffer.length] = s.tpl.apply(values);
13726         return this;
13727     },
13728
13729     /**
13730      * Applies all the passed values to a child template.
13731      * @param {String/Number} name (optional) The name or index of the child template
13732      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13733      * @param {Boolean} reset (optional) True to reset the template first
13734      * @return {MasterTemplate} this
13735      */
13736     fill : function(name, values, reset){
13737         var a = arguments;
13738         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13739             values = a[0];
13740             name = 0;
13741             reset = a[1];
13742         }
13743         if(reset){
13744             this.reset();
13745         }
13746         for(var i = 0, len = values.length; i < len; i++){
13747             this.add(name, values[i]);
13748         }
13749         return this;
13750     },
13751
13752     /**
13753      * Resets the template for reuse
13754      * @return {MasterTemplate} this
13755      */
13756      reset : function(){
13757         var s = this.subs;
13758         for(var i = 0; i < this.subCount; i++){
13759             s[i].buffer = [];
13760         }
13761         return this;
13762     },
13763
13764     applyTemplate : function(values){
13765         var s = this.subs;
13766         var replaceIndex = -1;
13767         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13768             return s[++replaceIndex].buffer.join("");
13769         });
13770         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13771     },
13772
13773     apply : function(){
13774         return this.applyTemplate.apply(this, arguments);
13775     },
13776
13777     compile : function(){return this;}
13778 });
13779
13780 /**
13781  * Alias for fill().
13782  * @method
13783  */
13784 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13785  /**
13786  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13787  * var tpl = Roo.MasterTemplate.from('element-id');
13788  * @param {String/HTMLElement} el
13789  * @param {Object} config
13790  * @static
13791  */
13792 Roo.MasterTemplate.from = function(el, config){
13793     el = Roo.getDom(el);
13794     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13795 };/*
13796  * Based on:
13797  * Ext JS Library 1.1.1
13798  * Copyright(c) 2006-2007, Ext JS, LLC.
13799  *
13800  * Originally Released Under LGPL - original licence link has changed is not relivant.
13801  *
13802  * Fork - LGPL
13803  * <script type="text/javascript">
13804  */
13805
13806  
13807 /**
13808  * @class Roo.util.CSS
13809  * Utility class for manipulating CSS rules
13810  * @singleton
13811  */
13812 Roo.util.CSS = function(){
13813         var rules = null;
13814         var doc = document;
13815
13816     var camelRe = /(-[a-z])/gi;
13817     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13818
13819    return {
13820    /**
13821     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13822     * tag and appended to the HEAD of the document.
13823     * @param {String|Object} cssText The text containing the css rules
13824     * @param {String} id An id to add to the stylesheet for later removal
13825     * @return {StyleSheet}
13826     */
13827     createStyleSheet : function(cssText, id){
13828         var ss;
13829         var head = doc.getElementsByTagName("head")[0];
13830         var nrules = doc.createElement("style");
13831         nrules.setAttribute("type", "text/css");
13832         if(id){
13833             nrules.setAttribute("id", id);
13834         }
13835         if (typeof(cssText) != 'string') {
13836             // support object maps..
13837             // not sure if this a good idea.. 
13838             // perhaps it should be merged with the general css handling
13839             // and handle js style props.
13840             var cssTextNew = [];
13841             for(var n in cssText) {
13842                 var citems = [];
13843                 for(var k in cssText[n]) {
13844                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13845                 }
13846                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13847                 
13848             }
13849             cssText = cssTextNew.join("\n");
13850             
13851         }
13852        
13853        
13854        if(Roo.isIE){
13855            head.appendChild(nrules);
13856            ss = nrules.styleSheet;
13857            ss.cssText = cssText;
13858        }else{
13859            try{
13860                 nrules.appendChild(doc.createTextNode(cssText));
13861            }catch(e){
13862                nrules.cssText = cssText; 
13863            }
13864            head.appendChild(nrules);
13865            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13866        }
13867        this.cacheStyleSheet(ss);
13868        return ss;
13869    },
13870
13871    /**
13872     * Removes a style or link tag by id
13873     * @param {String} id The id of the tag
13874     */
13875    removeStyleSheet : function(id){
13876        var existing = doc.getElementById(id);
13877        if(existing){
13878            existing.parentNode.removeChild(existing);
13879        }
13880    },
13881
13882    /**
13883     * Dynamically swaps an existing stylesheet reference for a new one
13884     * @param {String} id The id of an existing link tag to remove
13885     * @param {String} url The href of the new stylesheet to include
13886     */
13887    swapStyleSheet : function(id, url){
13888        this.removeStyleSheet(id);
13889        var ss = doc.createElement("link");
13890        ss.setAttribute("rel", "stylesheet");
13891        ss.setAttribute("type", "text/css");
13892        ss.setAttribute("id", id);
13893        ss.setAttribute("href", url);
13894        doc.getElementsByTagName("head")[0].appendChild(ss);
13895    },
13896    
13897    /**
13898     * Refresh the rule cache if you have dynamically added stylesheets
13899     * @return {Object} An object (hash) of rules indexed by selector
13900     */
13901    refreshCache : function(){
13902        return this.getRules(true);
13903    },
13904
13905    // private
13906    cacheStyleSheet : function(stylesheet){
13907        if(!rules){
13908            rules = {};
13909        }
13910        try{// try catch for cross domain access issue
13911            var ssRules = stylesheet.cssRules || stylesheet.rules;
13912            for(var j = ssRules.length-1; j >= 0; --j){
13913                rules[ssRules[j].selectorText] = ssRules[j];
13914            }
13915        }catch(e){}
13916    },
13917    
13918    /**
13919     * Gets all css rules for the document
13920     * @param {Boolean} refreshCache true to refresh the internal cache
13921     * @return {Object} An object (hash) of rules indexed by selector
13922     */
13923    getRules : function(refreshCache){
13924                 if(rules == null || refreshCache){
13925                         rules = {};
13926                         var ds = doc.styleSheets;
13927                         for(var i =0, len = ds.length; i < len; i++){
13928                             try{
13929                         this.cacheStyleSheet(ds[i]);
13930                     }catch(e){} 
13931                 }
13932                 }
13933                 return rules;
13934         },
13935         
13936         /**
13937     * Gets an an individual CSS rule by selector(s)
13938     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13939     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13940     * @return {CSSRule} The CSS rule or null if one is not found
13941     */
13942    getRule : function(selector, refreshCache){
13943                 var rs = this.getRules(refreshCache);
13944                 if(!(selector instanceof Array)){
13945                     return rs[selector];
13946                 }
13947                 for(var i = 0; i < selector.length; i++){
13948                         if(rs[selector[i]]){
13949                                 return rs[selector[i]];
13950                         }
13951                 }
13952                 return null;
13953         },
13954         
13955         
13956         /**
13957     * Updates a rule property
13958     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13959     * @param {String} property The css property
13960     * @param {String} value The new value for the property
13961     * @return {Boolean} true If a rule was found and updated
13962     */
13963    updateRule : function(selector, property, value){
13964                 if(!(selector instanceof Array)){
13965                         var rule = this.getRule(selector);
13966                         if(rule){
13967                                 rule.style[property.replace(camelRe, camelFn)] = value;
13968                                 return true;
13969                         }
13970                 }else{
13971                         for(var i = 0; i < selector.length; i++){
13972                                 if(this.updateRule(selector[i], property, value)){
13973                                         return true;
13974                                 }
13975                         }
13976                 }
13977                 return false;
13978         }
13979    };   
13980 }();/*
13981  * Based on:
13982  * Ext JS Library 1.1.1
13983  * Copyright(c) 2006-2007, Ext JS, LLC.
13984  *
13985  * Originally Released Under LGPL - original licence link has changed is not relivant.
13986  *
13987  * Fork - LGPL
13988  * <script type="text/javascript">
13989  */
13990
13991  
13992
13993 /**
13994  * @class Roo.util.ClickRepeater
13995  * @extends Roo.util.Observable
13996  * 
13997  * A wrapper class which can be applied to any element. Fires a "click" event while the
13998  * mouse is pressed. The interval between firings may be specified in the config but
13999  * defaults to 10 milliseconds.
14000  * 
14001  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14002  * 
14003  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14004  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14005  * Similar to an autorepeat key delay.
14006  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14007  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14008  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14009  *           "interval" and "delay" are ignored. "immediate" is honored.
14010  * @cfg {Boolean} preventDefault True to prevent the default click event
14011  * @cfg {Boolean} stopDefault True to stop the default click event
14012  * 
14013  * @history
14014  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14015  *     2007-02-02 jvs Renamed to ClickRepeater
14016  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14017  *
14018  *  @constructor
14019  * @param {String/HTMLElement/Element} el The element to listen on
14020  * @param {Object} config
14021  **/
14022 Roo.util.ClickRepeater = function(el, config)
14023 {
14024     this.el = Roo.get(el);
14025     this.el.unselectable();
14026
14027     Roo.apply(this, config);
14028
14029     this.addEvents({
14030     /**
14031      * @event mousedown
14032      * Fires when the mouse button is depressed.
14033      * @param {Roo.util.ClickRepeater} this
14034      */
14035         "mousedown" : true,
14036     /**
14037      * @event click
14038      * Fires on a specified interval during the time the element is pressed.
14039      * @param {Roo.util.ClickRepeater} this
14040      */
14041         "click" : true,
14042     /**
14043      * @event mouseup
14044      * Fires when the mouse key is released.
14045      * @param {Roo.util.ClickRepeater} this
14046      */
14047         "mouseup" : true
14048     });
14049
14050     this.el.on("mousedown", this.handleMouseDown, this);
14051     if(this.preventDefault || this.stopDefault){
14052         this.el.on("click", function(e){
14053             if(this.preventDefault){
14054                 e.preventDefault();
14055             }
14056             if(this.stopDefault){
14057                 e.stopEvent();
14058             }
14059         }, this);
14060     }
14061
14062     // allow inline handler
14063     if(this.handler){
14064         this.on("click", this.handler,  this.scope || this);
14065     }
14066
14067     Roo.util.ClickRepeater.superclass.constructor.call(this);
14068 };
14069
14070 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14071     interval : 20,
14072     delay: 250,
14073     preventDefault : true,
14074     stopDefault : false,
14075     timer : 0,
14076
14077     // private
14078     handleMouseDown : function(){
14079         clearTimeout(this.timer);
14080         this.el.blur();
14081         if(this.pressClass){
14082             this.el.addClass(this.pressClass);
14083         }
14084         this.mousedownTime = new Date();
14085
14086         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14087         this.el.on("mouseout", this.handleMouseOut, this);
14088
14089         this.fireEvent("mousedown", this);
14090         this.fireEvent("click", this);
14091         
14092         this.timer = this.click.defer(this.delay || this.interval, this);
14093     },
14094
14095     // private
14096     click : function(){
14097         this.fireEvent("click", this);
14098         this.timer = this.click.defer(this.getInterval(), this);
14099     },
14100
14101     // private
14102     getInterval: function(){
14103         if(!this.accelerate){
14104             return this.interval;
14105         }
14106         var pressTime = this.mousedownTime.getElapsed();
14107         if(pressTime < 500){
14108             return 400;
14109         }else if(pressTime < 1700){
14110             return 320;
14111         }else if(pressTime < 2600){
14112             return 250;
14113         }else if(pressTime < 3500){
14114             return 180;
14115         }else if(pressTime < 4400){
14116             return 140;
14117         }else if(pressTime < 5300){
14118             return 80;
14119         }else if(pressTime < 6200){
14120             return 50;
14121         }else{
14122             return 10;
14123         }
14124     },
14125
14126     // private
14127     handleMouseOut : function(){
14128         clearTimeout(this.timer);
14129         if(this.pressClass){
14130             this.el.removeClass(this.pressClass);
14131         }
14132         this.el.on("mouseover", this.handleMouseReturn, this);
14133     },
14134
14135     // private
14136     handleMouseReturn : function(){
14137         this.el.un("mouseover", this.handleMouseReturn);
14138         if(this.pressClass){
14139             this.el.addClass(this.pressClass);
14140         }
14141         this.click();
14142     },
14143
14144     // private
14145     handleMouseUp : function(){
14146         clearTimeout(this.timer);
14147         this.el.un("mouseover", this.handleMouseReturn);
14148         this.el.un("mouseout", this.handleMouseOut);
14149         Roo.get(document).un("mouseup", this.handleMouseUp);
14150         this.el.removeClass(this.pressClass);
14151         this.fireEvent("mouseup", this);
14152     }
14153 });/*
14154  * Based on:
14155  * Ext JS Library 1.1.1
14156  * Copyright(c) 2006-2007, Ext JS, LLC.
14157  *
14158  * Originally Released Under LGPL - original licence link has changed is not relivant.
14159  *
14160  * Fork - LGPL
14161  * <script type="text/javascript">
14162  */
14163
14164  
14165 /**
14166  * @class Roo.KeyNav
14167  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14168  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14169  * way to implement custom navigation schemes for any UI component.</p>
14170  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14171  * pageUp, pageDown, del, home, end.  Usage:</p>
14172  <pre><code>
14173 var nav = new Roo.KeyNav("my-element", {
14174     "left" : function(e){
14175         this.moveLeft(e.ctrlKey);
14176     },
14177     "right" : function(e){
14178         this.moveRight(e.ctrlKey);
14179     },
14180     "enter" : function(e){
14181         this.save();
14182     },
14183     scope : this
14184 });
14185 </code></pre>
14186  * @constructor
14187  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14188  * @param {Object} config The config
14189  */
14190 Roo.KeyNav = function(el, config){
14191     this.el = Roo.get(el);
14192     Roo.apply(this, config);
14193     if(!this.disabled){
14194         this.disabled = true;
14195         this.enable();
14196     }
14197 };
14198
14199 Roo.KeyNav.prototype = {
14200     /**
14201      * @cfg {Boolean} disabled
14202      * True to disable this KeyNav instance (defaults to false)
14203      */
14204     disabled : false,
14205     /**
14206      * @cfg {String} defaultEventAction
14207      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14208      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14209      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14210      */
14211     defaultEventAction: "stopEvent",
14212     /**
14213      * @cfg {Boolean} forceKeyDown
14214      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14215      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14216      * handle keydown instead of keypress.
14217      */
14218     forceKeyDown : false,
14219
14220     // private
14221     prepareEvent : function(e){
14222         var k = e.getKey();
14223         var h = this.keyToHandler[k];
14224         //if(h && this[h]){
14225         //    e.stopPropagation();
14226         //}
14227         if(Roo.isSafari && h && k >= 37 && k <= 40){
14228             e.stopEvent();
14229         }
14230     },
14231
14232     // private
14233     relay : function(e){
14234         var k = e.getKey();
14235         var h = this.keyToHandler[k];
14236         if(h && this[h]){
14237             if(this.doRelay(e, this[h], h) !== true){
14238                 e[this.defaultEventAction]();
14239             }
14240         }
14241     },
14242
14243     // private
14244     doRelay : function(e, h, hname){
14245         return h.call(this.scope || this, e);
14246     },
14247
14248     // possible handlers
14249     enter : false,
14250     left : false,
14251     right : false,
14252     up : false,
14253     down : false,
14254     tab : false,
14255     esc : false,
14256     pageUp : false,
14257     pageDown : false,
14258     del : false,
14259     home : false,
14260     end : false,
14261
14262     // quick lookup hash
14263     keyToHandler : {
14264         37 : "left",
14265         39 : "right",
14266         38 : "up",
14267         40 : "down",
14268         33 : "pageUp",
14269         34 : "pageDown",
14270         46 : "del",
14271         36 : "home",
14272         35 : "end",
14273         13 : "enter",
14274         27 : "esc",
14275         9  : "tab"
14276     },
14277
14278         /**
14279          * Enable this KeyNav
14280          */
14281         enable: function(){
14282                 if(this.disabled){
14283             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14284             // the EventObject will normalize Safari automatically
14285             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14286                 this.el.on("keydown", this.relay,  this);
14287             }else{
14288                 this.el.on("keydown", this.prepareEvent,  this);
14289                 this.el.on("keypress", this.relay,  this);
14290             }
14291                     this.disabled = false;
14292                 }
14293         },
14294
14295         /**
14296          * Disable this KeyNav
14297          */
14298         disable: function(){
14299                 if(!this.disabled){
14300                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14301                 this.el.un("keydown", this.relay);
14302             }else{
14303                 this.el.un("keydown", this.prepareEvent);
14304                 this.el.un("keypress", this.relay);
14305             }
14306                     this.disabled = true;
14307                 }
14308         }
14309 };/*
14310  * Based on:
14311  * Ext JS Library 1.1.1
14312  * Copyright(c) 2006-2007, Ext JS, LLC.
14313  *
14314  * Originally Released Under LGPL - original licence link has changed is not relivant.
14315  *
14316  * Fork - LGPL
14317  * <script type="text/javascript">
14318  */
14319
14320  
14321 /**
14322  * @class Roo.KeyMap
14323  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14324  * The constructor accepts the same config object as defined by {@link #addBinding}.
14325  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14326  * combination it will call the function with this signature (if the match is a multi-key
14327  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14328  * A KeyMap can also handle a string representation of keys.<br />
14329  * Usage:
14330  <pre><code>
14331 // map one key by key code
14332 var map = new Roo.KeyMap("my-element", {
14333     key: 13, // or Roo.EventObject.ENTER
14334     fn: myHandler,
14335     scope: myObject
14336 });
14337
14338 // map multiple keys to one action by string
14339 var map = new Roo.KeyMap("my-element", {
14340     key: "a\r\n\t",
14341     fn: myHandler,
14342     scope: myObject
14343 });
14344
14345 // map multiple keys to multiple actions by strings and array of codes
14346 var map = new Roo.KeyMap("my-element", [
14347     {
14348         key: [10,13],
14349         fn: function(){ alert("Return was pressed"); }
14350     }, {
14351         key: "abc",
14352         fn: function(){ alert('a, b or c was pressed'); }
14353     }, {
14354         key: "\t",
14355         ctrl:true,
14356         shift:true,
14357         fn: function(){ alert('Control + shift + tab was pressed.'); }
14358     }
14359 ]);
14360 </code></pre>
14361  * <b>Note: A KeyMap starts enabled</b>
14362  * @constructor
14363  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14364  * @param {Object} config The config (see {@link #addBinding})
14365  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14366  */
14367 Roo.KeyMap = function(el, config, eventName){
14368     this.el  = Roo.get(el);
14369     this.eventName = eventName || "keydown";
14370     this.bindings = [];
14371     if(config){
14372         this.addBinding(config);
14373     }
14374     this.enable();
14375 };
14376
14377 Roo.KeyMap.prototype = {
14378     /**
14379      * True to stop the event from bubbling and prevent the default browser action if the
14380      * key was handled by the KeyMap (defaults to false)
14381      * @type Boolean
14382      */
14383     stopEvent : false,
14384
14385     /**
14386      * Add a new binding to this KeyMap. The following config object properties are supported:
14387      * <pre>
14388 Property    Type             Description
14389 ----------  ---------------  ----------------------------------------------------------------------
14390 key         String/Array     A single keycode or an array of keycodes to handle
14391 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14392 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14393 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14394 fn          Function         The function to call when KeyMap finds the expected key combination
14395 scope       Object           The scope of the callback function
14396 </pre>
14397      *
14398      * Usage:
14399      * <pre><code>
14400 // Create a KeyMap
14401 var map = new Roo.KeyMap(document, {
14402     key: Roo.EventObject.ENTER,
14403     fn: handleKey,
14404     scope: this
14405 });
14406
14407 //Add a new binding to the existing KeyMap later
14408 map.addBinding({
14409     key: 'abc',
14410     shift: true,
14411     fn: handleKey,
14412     scope: this
14413 });
14414 </code></pre>
14415      * @param {Object/Array} config A single KeyMap config or an array of configs
14416      */
14417         addBinding : function(config){
14418         if(config instanceof Array){
14419             for(var i = 0, len = config.length; i < len; i++){
14420                 this.addBinding(config[i]);
14421             }
14422             return;
14423         }
14424         var keyCode = config.key,
14425             shift = config.shift, 
14426             ctrl = config.ctrl, 
14427             alt = config.alt,
14428             fn = config.fn,
14429             scope = config.scope;
14430         if(typeof keyCode == "string"){
14431             var ks = [];
14432             var keyString = keyCode.toUpperCase();
14433             for(var j = 0, len = keyString.length; j < len; j++){
14434                 ks.push(keyString.charCodeAt(j));
14435             }
14436             keyCode = ks;
14437         }
14438         var keyArray = keyCode instanceof Array;
14439         var handler = function(e){
14440             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14441                 var k = e.getKey();
14442                 if(keyArray){
14443                     for(var i = 0, len = keyCode.length; i < len; i++){
14444                         if(keyCode[i] == k){
14445                           if(this.stopEvent){
14446                               e.stopEvent();
14447                           }
14448                           fn.call(scope || window, k, e);
14449                           return;
14450                         }
14451                     }
14452                 }else{
14453                     if(k == keyCode){
14454                         if(this.stopEvent){
14455                            e.stopEvent();
14456                         }
14457                         fn.call(scope || window, k, e);
14458                     }
14459                 }
14460             }
14461         };
14462         this.bindings.push(handler);  
14463         },
14464
14465     /**
14466      * Shorthand for adding a single key listener
14467      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14468      * following options:
14469      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14470      * @param {Function} fn The function to call
14471      * @param {Object} scope (optional) The scope of the function
14472      */
14473     on : function(key, fn, scope){
14474         var keyCode, shift, ctrl, alt;
14475         if(typeof key == "object" && !(key instanceof Array)){
14476             keyCode = key.key;
14477             shift = key.shift;
14478             ctrl = key.ctrl;
14479             alt = key.alt;
14480         }else{
14481             keyCode = key;
14482         }
14483         this.addBinding({
14484             key: keyCode,
14485             shift: shift,
14486             ctrl: ctrl,
14487             alt: alt,
14488             fn: fn,
14489             scope: scope
14490         })
14491     },
14492
14493     // private
14494     handleKeyDown : function(e){
14495             if(this.enabled){ //just in case
14496             var b = this.bindings;
14497             for(var i = 0, len = b.length; i < len; i++){
14498                 b[i].call(this, e);
14499             }
14500             }
14501         },
14502         
14503         /**
14504          * Returns true if this KeyMap is enabled
14505          * @return {Boolean} 
14506          */
14507         isEnabled : function(){
14508             return this.enabled;  
14509         },
14510         
14511         /**
14512          * Enables this KeyMap
14513          */
14514         enable: function(){
14515                 if(!this.enabled){
14516                     this.el.on(this.eventName, this.handleKeyDown, this);
14517                     this.enabled = true;
14518                 }
14519         },
14520
14521         /**
14522          * Disable this KeyMap
14523          */
14524         disable: function(){
14525                 if(this.enabled){
14526                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14527                     this.enabled = false;
14528                 }
14529         }
14530 };/*
14531  * Based on:
14532  * Ext JS Library 1.1.1
14533  * Copyright(c) 2006-2007, Ext JS, LLC.
14534  *
14535  * Originally Released Under LGPL - original licence link has changed is not relivant.
14536  *
14537  * Fork - LGPL
14538  * <script type="text/javascript">
14539  */
14540
14541  
14542 /**
14543  * @class Roo.util.TextMetrics
14544  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14545  * wide, in pixels, a given block of text will be.
14546  * @singleton
14547  */
14548 Roo.util.TextMetrics = function(){
14549     var shared;
14550     return {
14551         /**
14552          * Measures the size of the specified text
14553          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14554          * that can affect the size of the rendered text
14555          * @param {String} text The text to measure
14556          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14557          * in order to accurately measure the text height
14558          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14559          */
14560         measure : function(el, text, fixedWidth){
14561             if(!shared){
14562                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14563             }
14564             shared.bind(el);
14565             shared.setFixedWidth(fixedWidth || 'auto');
14566             return shared.getSize(text);
14567         },
14568
14569         /**
14570          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14571          * the overhead of multiple calls to initialize the style properties on each measurement.
14572          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14573          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14574          * in order to accurately measure the text height
14575          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14576          */
14577         createInstance : function(el, fixedWidth){
14578             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14579         }
14580     };
14581 }();
14582
14583  
14584
14585 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14586     var ml = new Roo.Element(document.createElement('div'));
14587     document.body.appendChild(ml.dom);
14588     ml.position('absolute');
14589     ml.setLeftTop(-1000, -1000);
14590     ml.hide();
14591
14592     if(fixedWidth){
14593         ml.setWidth(fixedWidth);
14594     }
14595      
14596     var instance = {
14597         /**
14598          * Returns the size of the specified text based on the internal element's style and width properties
14599          * @memberOf Roo.util.TextMetrics.Instance#
14600          * @param {String} text The text to measure
14601          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14602          */
14603         getSize : function(text){
14604             ml.update(text);
14605             var s = ml.getSize();
14606             ml.update('');
14607             return s;
14608         },
14609
14610         /**
14611          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14612          * that can affect the size of the rendered text
14613          * @memberOf Roo.util.TextMetrics.Instance#
14614          * @param {String/HTMLElement} el The element, dom node or id
14615          */
14616         bind : function(el){
14617             ml.setStyle(
14618                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14619             );
14620         },
14621
14622         /**
14623          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14624          * to set a fixed width in order to accurately measure the text height.
14625          * @memberOf Roo.util.TextMetrics.Instance#
14626          * @param {Number} width The width to set on the element
14627          */
14628         setFixedWidth : function(width){
14629             ml.setWidth(width);
14630         },
14631
14632         /**
14633          * Returns the measured width of the specified text
14634          * @memberOf Roo.util.TextMetrics.Instance#
14635          * @param {String} text The text to measure
14636          * @return {Number} width The width in pixels
14637          */
14638         getWidth : function(text){
14639             ml.dom.style.width = 'auto';
14640             return this.getSize(text).width;
14641         },
14642
14643         /**
14644          * Returns the measured height of the specified text.  For multiline text, be sure to call
14645          * {@link #setFixedWidth} if necessary.
14646          * @memberOf Roo.util.TextMetrics.Instance#
14647          * @param {String} text The text to measure
14648          * @return {Number} height The height in pixels
14649          */
14650         getHeight : function(text){
14651             return this.getSize(text).height;
14652         }
14653     };
14654
14655     instance.bind(bindTo);
14656
14657     return instance;
14658 };
14659
14660 // backwards compat
14661 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14662  * Based on:
14663  * Ext JS Library 1.1.1
14664  * Copyright(c) 2006-2007, Ext JS, LLC.
14665  *
14666  * Originally Released Under LGPL - original licence link has changed is not relivant.
14667  *
14668  * Fork - LGPL
14669  * <script type="text/javascript">
14670  */
14671
14672 /**
14673  * @class Roo.state.Provider
14674  * Abstract base class for state provider implementations. This class provides methods
14675  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14676  * Provider interface.
14677  */
14678 Roo.state.Provider = function(){
14679     /**
14680      * @event statechange
14681      * Fires when a state change occurs.
14682      * @param {Provider} this This state provider
14683      * @param {String} key The state key which was changed
14684      * @param {String} value The encoded value for the state
14685      */
14686     this.addEvents({
14687         "statechange": true
14688     });
14689     this.state = {};
14690     Roo.state.Provider.superclass.constructor.call(this);
14691 };
14692 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14693     /**
14694      * Returns the current value for a key
14695      * @param {String} name The key name
14696      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14697      * @return {Mixed} The state data
14698      */
14699     get : function(name, defaultValue){
14700         return typeof this.state[name] == "undefined" ?
14701             defaultValue : this.state[name];
14702     },
14703     
14704     /**
14705      * Clears a value from the state
14706      * @param {String} name The key name
14707      */
14708     clear : function(name){
14709         delete this.state[name];
14710         this.fireEvent("statechange", this, name, null);
14711     },
14712     
14713     /**
14714      * Sets the value for a key
14715      * @param {String} name The key name
14716      * @param {Mixed} value The value to set
14717      */
14718     set : function(name, value){
14719         this.state[name] = value;
14720         this.fireEvent("statechange", this, name, value);
14721     },
14722     
14723     /**
14724      * Decodes a string previously encoded with {@link #encodeValue}.
14725      * @param {String} value The value to decode
14726      * @return {Mixed} The decoded value
14727      */
14728     decodeValue : function(cookie){
14729         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14730         var matches = re.exec(unescape(cookie));
14731         if(!matches || !matches[1]) return; // non state cookie
14732         var type = matches[1];
14733         var v = matches[2];
14734         switch(type){
14735             case "n":
14736                 return parseFloat(v);
14737             case "d":
14738                 return new Date(Date.parse(v));
14739             case "b":
14740                 return (v == "1");
14741             case "a":
14742                 var all = [];
14743                 var values = v.split("^");
14744                 for(var i = 0, len = values.length; i < len; i++){
14745                     all.push(this.decodeValue(values[i]));
14746                 }
14747                 return all;
14748            case "o":
14749                 var all = {};
14750                 var values = v.split("^");
14751                 for(var i = 0, len = values.length; i < len; i++){
14752                     var kv = values[i].split("=");
14753                     all[kv[0]] = this.decodeValue(kv[1]);
14754                 }
14755                 return all;
14756            default:
14757                 return v;
14758         }
14759     },
14760     
14761     /**
14762      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14763      * @param {Mixed} value The value to encode
14764      * @return {String} The encoded value
14765      */
14766     encodeValue : function(v){
14767         var enc;
14768         if(typeof v == "number"){
14769             enc = "n:" + v;
14770         }else if(typeof v == "boolean"){
14771             enc = "b:" + (v ? "1" : "0");
14772         }else if(v instanceof Date){
14773             enc = "d:" + v.toGMTString();
14774         }else if(v instanceof Array){
14775             var flat = "";
14776             for(var i = 0, len = v.length; i < len; i++){
14777                 flat += this.encodeValue(v[i]);
14778                 if(i != len-1) flat += "^";
14779             }
14780             enc = "a:" + flat;
14781         }else if(typeof v == "object"){
14782             var flat = "";
14783             for(var key in v){
14784                 if(typeof v[key] != "function"){
14785                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14786                 }
14787             }
14788             enc = "o:" + flat.substring(0, flat.length-1);
14789         }else{
14790             enc = "s:" + v;
14791         }
14792         return escape(enc);        
14793     }
14794 });
14795
14796 /*
14797  * Based on:
14798  * Ext JS Library 1.1.1
14799  * Copyright(c) 2006-2007, Ext JS, LLC.
14800  *
14801  * Originally Released Under LGPL - original licence link has changed is not relivant.
14802  *
14803  * Fork - LGPL
14804  * <script type="text/javascript">
14805  */
14806 /**
14807  * @class Roo.state.Manager
14808  * This is the global state manager. By default all components that are "state aware" check this class
14809  * for state information if you don't pass them a custom state provider. In order for this class
14810  * to be useful, it must be initialized with a provider when your application initializes.
14811  <pre><code>
14812 // in your initialization function
14813 init : function(){
14814    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14815    ...
14816    // supposed you have a {@link Roo.BorderLayout}
14817    var layout = new Roo.BorderLayout(...);
14818    layout.restoreState();
14819    // or a {Roo.BasicDialog}
14820    var dialog = new Roo.BasicDialog(...);
14821    dialog.restoreState();
14822  </code></pre>
14823  * @singleton
14824  */
14825 Roo.state.Manager = function(){
14826     var provider = new Roo.state.Provider();
14827     
14828     return {
14829         /**
14830          * Configures the default state provider for your application
14831          * @param {Provider} stateProvider The state provider to set
14832          */
14833         setProvider : function(stateProvider){
14834             provider = stateProvider;
14835         },
14836         
14837         /**
14838          * Returns the current value for a key
14839          * @param {String} name The key name
14840          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14841          * @return {Mixed} The state data
14842          */
14843         get : function(key, defaultValue){
14844             return provider.get(key, defaultValue);
14845         },
14846         
14847         /**
14848          * Sets the value for a key
14849          * @param {String} name The key name
14850          * @param {Mixed} value The state data
14851          */
14852          set : function(key, value){
14853             provider.set(key, value);
14854         },
14855         
14856         /**
14857          * Clears a value from the state
14858          * @param {String} name The key name
14859          */
14860         clear : function(key){
14861             provider.clear(key);
14862         },
14863         
14864         /**
14865          * Gets the currently configured state provider
14866          * @return {Provider} The state provider
14867          */
14868         getProvider : function(){
14869             return provider;
14870         }
14871     };
14872 }();
14873 /*
14874  * Based on:
14875  * Ext JS Library 1.1.1
14876  * Copyright(c) 2006-2007, Ext JS, LLC.
14877  *
14878  * Originally Released Under LGPL - original licence link has changed is not relivant.
14879  *
14880  * Fork - LGPL
14881  * <script type="text/javascript">
14882  */
14883 /**
14884  * @class Roo.state.CookieProvider
14885  * @extends Roo.state.Provider
14886  * The default Provider implementation which saves state via cookies.
14887  * <br />Usage:
14888  <pre><code>
14889    var cp = new Roo.state.CookieProvider({
14890        path: "/cgi-bin/",
14891        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14892        domain: "roojs.com"
14893    })
14894    Roo.state.Manager.setProvider(cp);
14895  </code></pre>
14896  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14897  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14898  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14899  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14900  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14901  * domain the page is running on including the 'www' like 'www.roojs.com')
14902  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14903  * @constructor
14904  * Create a new CookieProvider
14905  * @param {Object} config The configuration object
14906  */
14907 Roo.state.CookieProvider = function(config){
14908     Roo.state.CookieProvider.superclass.constructor.call(this);
14909     this.path = "/";
14910     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14911     this.domain = null;
14912     this.secure = false;
14913     Roo.apply(this, config);
14914     this.state = this.readCookies();
14915 };
14916
14917 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14918     // private
14919     set : function(name, value){
14920         if(typeof value == "undefined" || value === null){
14921             this.clear(name);
14922             return;
14923         }
14924         this.setCookie(name, value);
14925         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14926     },
14927
14928     // private
14929     clear : function(name){
14930         this.clearCookie(name);
14931         Roo.state.CookieProvider.superclass.clear.call(this, name);
14932     },
14933
14934     // private
14935     readCookies : function(){
14936         var cookies = {};
14937         var c = document.cookie + ";";
14938         var re = /\s?(.*?)=(.*?);/g;
14939         var matches;
14940         while((matches = re.exec(c)) != null){
14941             var name = matches[1];
14942             var value = matches[2];
14943             if(name && name.substring(0,3) == "ys-"){
14944                 cookies[name.substr(3)] = this.decodeValue(value);
14945             }
14946         }
14947         return cookies;
14948     },
14949
14950     // private
14951     setCookie : function(name, value){
14952         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14953            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14954            ((this.path == null) ? "" : ("; path=" + this.path)) +
14955            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14956            ((this.secure == true) ? "; secure" : "");
14957     },
14958
14959     // private
14960     clearCookie : function(name){
14961         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14962            ((this.path == null) ? "" : ("; path=" + this.path)) +
14963            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14964            ((this.secure == true) ? "; secure" : "");
14965     }
14966 });