Roo/XComponent.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isGecko = !isSafari && ua.indexOf("gecko") > -1,
61         isBorderBox = isIE && !isStrict,
62         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64         isLinux = (ua.indexOf("linux") != -1),
65         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66         isIOS = /iphone|ipad/.test(ua),
67         isTouch =  (function() {
68             try {
69                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
70                     window.addEventListener('touchstart', function __set_has_touch__ () {
71                         Roo.isTouch = true;
72                         window.removeEventListener('touchstart', __set_has_touch__);
73                     });
74                     return false; // no touch on chrome!?
75                 }
76                 document.createEvent("TouchEvent");  
77                 return true;  
78             } catch (e) {  
79                 return false;  
80             } 
81             
82         })();
83     // remove css image flicker
84         if(isIE && !isIE7){
85         try{
86             document.execCommand("BackgroundImageCache", false, true);
87         }catch(e){}
88     }
89     
90     Roo.apply(Roo, {
91         /**
92          * True if the browser is in strict mode
93          * @type Boolean
94          */
95         isStrict : isStrict,
96         /**
97          * True if the page is running over SSL
98          * @type Boolean
99          */
100         isSecure : isSecure,
101         /**
102          * True when the document is fully initialized and ready for action
103          * @type Boolean
104          */
105         isReady : false,
106         /**
107          * Turn on debugging output (currently only the factory uses this)
108          * @type Boolean
109          */
110         
111         debug: false,
112
113         /**
114          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
115          * @type Boolean
116          */
117         enableGarbageCollector : true,
118
119         /**
120          * True to automatically purge event listeners after uncaching an element (defaults to false).
121          * Note: this only happens if enableGarbageCollector is true.
122          * @type Boolean
123          */
124         enableListenerCollection:false,
125
126         /**
127          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
128          * the IE insecure content warning (defaults to javascript:false).
129          * @type String
130          */
131         SSL_SECURE_URL : "javascript:false",
132
133         /**
134          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
135          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
136          * @type String
137          */
138         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
139
140         emptyFn : function(){},
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         isFirefox : isFirefox,
624         /** @type Boolean */
625         isIE : isIE,
626         /** @type Boolean */
627         isIE7 : isIE7,
628         /** @type Boolean */
629         isIE11 : isIE11,
630         /** @type Boolean */
631         isGecko : isGecko,
632         /** @type Boolean */
633         isBorderBox : isBorderBox,
634         /** @type Boolean */
635         isWindows : isWindows,
636         /** @type Boolean */
637         isLinux : isLinux,
638         /** @type Boolean */
639         isMac : isMac,
640         /** @type Boolean */
641         isIOS : isIOS,
642         /** @type Boolean */
643         isTouch : isTouch,
644
645         /**
646          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
647          * you may want to set this to true.
648          * @type Boolean
649          */
650         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
651         
652         
653                 
654         /**
655          * Selects a single element as a Roo Element
656          * This is about as close as you can get to jQuery's $('do crazy stuff')
657          * @param {String} selector The selector/xpath query
658          * @param {Node} root (optional) The start of the query (defaults to document).
659          * @return {Roo.Element}
660          */
661         selectNode : function(selector, root) 
662         {
663             var node = Roo.DomQuery.selectNode(selector,root);
664             return node ? Roo.get(node) : new Roo.Element(false);
665         }
666         
667     });
668
669
670 })();
671
672 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
673                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
674                 "Roo.app", "Roo.ux",
675                 "Roo.bootstrap",
676                 "Roo.bootstrap.dash");
677 /*
678  * Based on:
679  * Ext JS Library 1.1.1
680  * Copyright(c) 2006-2007, Ext JS, LLC.
681  *
682  * Originally Released Under LGPL - original licence link has changed is not relivant.
683  *
684  * Fork - LGPL
685  * <script type="text/javascript">
686  */
687
688 (function() {    
689     // wrappedn so fnCleanup is not in global scope...
690     if(Roo.isIE) {
691         function fnCleanUp() {
692             var p = Function.prototype;
693             delete p.createSequence;
694             delete p.defer;
695             delete p.createDelegate;
696             delete p.createCallback;
697             delete p.createInterceptor;
698
699             window.detachEvent("onunload", fnCleanUp);
700         }
701         window.attachEvent("onunload", fnCleanUp);
702     }
703 })();
704
705
706 /**
707  * @class Function
708  * These functions are available on every Function object (any JavaScript function).
709  */
710 Roo.apply(Function.prototype, {
711      /**
712      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
713      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
714      * Will create a function that is bound to those 2 args.
715      * @return {Function} The new function
716     */
717     createCallback : function(/*args...*/){
718         // make args available, in function below
719         var args = arguments;
720         var method = this;
721         return function() {
722             return method.apply(window, args);
723         };
724     },
725
726     /**
727      * Creates a delegate (callback) that sets the scope to obj.
728      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
729      * Will create a function that is automatically scoped to this.
730      * @param {Object} obj (optional) The object for which the scope is set
731      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
732      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
733      *                                             if a number the args are inserted at the specified position
734      * @return {Function} The new function
735      */
736     createDelegate : function(obj, args, appendArgs){
737         var method = this;
738         return function() {
739             var callArgs = args || arguments;
740             if(appendArgs === true){
741                 callArgs = Array.prototype.slice.call(arguments, 0);
742                 callArgs = callArgs.concat(args);
743             }else if(typeof appendArgs == "number"){
744                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
745                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
746                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
747             }
748             return method.apply(obj || window, callArgs);
749         };
750     },
751
752     /**
753      * Calls this function after the number of millseconds specified.
754      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
755      * @param {Object} obj (optional) The object for which the scope is set
756      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
757      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
758      *                                             if a number the args are inserted at the specified position
759      * @return {Number} The timeout id that can be used with clearTimeout
760      */
761     defer : function(millis, obj, args, appendArgs){
762         var fn = this.createDelegate(obj, args, appendArgs);
763         if(millis){
764             return setTimeout(fn, millis);
765         }
766         fn();
767         return 0;
768     },
769     /**
770      * Create a combined function call sequence of the original function + the passed function.
771      * The resulting function returns the results of the original function.
772      * The passed fcn is called with the parameters of the original function
773      * @param {Function} fcn The function to sequence
774      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
775      * @return {Function} The new function
776      */
777     createSequence : function(fcn, scope){
778         if(typeof fcn != "function"){
779             return this;
780         }
781         var method = this;
782         return function() {
783             var retval = method.apply(this || window, arguments);
784             fcn.apply(scope || this || window, arguments);
785             return retval;
786         };
787     },
788
789     /**
790      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
791      * The resulting function returns the results of the original function.
792      * The passed fcn is called with the parameters of the original function.
793      * @addon
794      * @param {Function} fcn The function to call before the original
795      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
796      * @return {Function} The new function
797      */
798     createInterceptor : function(fcn, scope){
799         if(typeof fcn != "function"){
800             return this;
801         }
802         var method = this;
803         return function() {
804             fcn.target = this;
805             fcn.method = method;
806             if(fcn.apply(scope || this || window, arguments) === false){
807                 return;
808             }
809             return method.apply(this || window, arguments);
810         };
811     }
812 });
813 /*
814  * Based on:
815  * Ext JS Library 1.1.1
816  * Copyright(c) 2006-2007, Ext JS, LLC.
817  *
818  * Originally Released Under LGPL - original licence link has changed is not relivant.
819  *
820  * Fork - LGPL
821  * <script type="text/javascript">
822  */
823
824 Roo.applyIf(String, {
825     
826     /** @scope String */
827     
828     /**
829      * Escapes the passed string for ' and \
830      * @param {String} string The string to escape
831      * @return {String} The escaped string
832      * @static
833      */
834     escape : function(string) {
835         return string.replace(/('|\\)/g, "\\$1");
836     },
837
838     /**
839      * Pads the left side of a string with a specified character.  This is especially useful
840      * for normalizing number and date strings.  Example usage:
841      * <pre><code>
842 var s = String.leftPad('123', 5, '0');
843 // s now contains the string: '00123'
844 </code></pre>
845      * @param {String} string The original string
846      * @param {Number} size The total length of the output string
847      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
848      * @return {String} The padded string
849      * @static
850      */
851     leftPad : function (val, size, ch) {
852         var result = new String(val);
853         if(ch === null || ch === undefined || ch === '') {
854             ch = " ";
855         }
856         while (result.length < size) {
857             result = ch + result;
858         }
859         return result;
860     },
861
862     /**
863      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
864      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
865      * <pre><code>
866 var cls = 'my-class', text = 'Some text';
867 var s = String.format('<div class="{0}">{1}</div>', cls, text);
868 // s now contains the string: '<div class="my-class">Some text</div>'
869 </code></pre>
870      * @param {String} string The tokenized string to be formatted
871      * @param {String} value1 The value to replace token {0}
872      * @param {String} value2 Etc...
873      * @return {String} The formatted string
874      * @static
875      */
876     format : function(format){
877         var args = Array.prototype.slice.call(arguments, 1);
878         return format.replace(/\{(\d+)\}/g, function(m, i){
879             return Roo.util.Format.htmlEncode(args[i]);
880         });
881     }
882 });
883
884 /**
885  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
886  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
887  * they are already different, the first value passed in is returned.  Note that this method returns the new value
888  * but does not change the current string.
889  * <pre><code>
890 // alternate sort directions
891 sort = sort.toggle('ASC', 'DESC');
892
893 // instead of conditional logic:
894 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
895 </code></pre>
896  * @param {String} value The value to compare to the current string
897  * @param {String} other The new value to use if the string already equals the first value passed in
898  * @return {String} The new value
899  */
900  
901 String.prototype.toggle = function(value, other){
902     return this == value ? other : value;
903 };/*
904  * Based on:
905  * Ext JS Library 1.1.1
906  * Copyright(c) 2006-2007, Ext JS, LLC.
907  *
908  * Originally Released Under LGPL - original licence link has changed is not relivant.
909  *
910  * Fork - LGPL
911  * <script type="text/javascript">
912  */
913
914  /**
915  * @class Number
916  */
917 Roo.applyIf(Number.prototype, {
918     /**
919      * Checks whether or not the current number is within a desired range.  If the number is already within the
920      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
921      * exceeded.  Note that this method returns the constrained value but does not change the current number.
922      * @param {Number} min The minimum number in the range
923      * @param {Number} max The maximum number in the range
924      * @return {Number} The constrained value if outside the range, otherwise the current value
925      */
926     constrain : function(min, max){
927         return Math.min(Math.max(this, min), max);
928     }
929 });/*
930  * Based on:
931  * Ext JS Library 1.1.1
932  * Copyright(c) 2006-2007, Ext JS, LLC.
933  *
934  * Originally Released Under LGPL - original licence link has changed is not relivant.
935  *
936  * Fork - LGPL
937  * <script type="text/javascript">
938  */
939  /**
940  * @class Array
941  */
942 Roo.applyIf(Array.prototype, {
943     /**
944      * 
945      * Checks whether or not the specified object exists in the array.
946      * @param {Object} o The object to check for
947      * @return {Number} The index of o in the array (or -1 if it is not found)
948      */
949     indexOf : function(o){
950        for (var i = 0, len = this.length; i < len; i++){
951               if(this[i] == o) { return i; }
952        }
953            return -1;
954     },
955
956     /**
957      * Removes the specified object from the array.  If the object is not found nothing happens.
958      * @param {Object} o The object to remove
959      */
960     remove : function(o){
961        var index = this.indexOf(o);
962        if(index != -1){
963            this.splice(index, 1);
964        }
965     },
966     /**
967      * Map (JS 1.6 compatibility)
968      * @param {Function} function  to call
969      */
970     map : function(fun )
971     {
972         var len = this.length >>> 0;
973         if (typeof fun != "function") {
974             throw new TypeError();
975         }
976         var res = new Array(len);
977         var thisp = arguments[1];
978         for (var i = 0; i < len; i++)
979         {
980             if (i in this) {
981                 res[i] = fun.call(thisp, this[i], i, this);
982             }
983         }
984
985         return res;
986     }
987     
988 });
989
990
991  
992 /*
993  * Based on:
994  * Ext JS Library 1.1.1
995  * Copyright(c) 2006-2007, Ext JS, LLC.
996  *
997  * Originally Released Under LGPL - original licence link has changed is not relivant.
998  *
999  * Fork - LGPL
1000  * <script type="text/javascript">
1001  */
1002
1003 /**
1004  * @class Date
1005  *
1006  * The date parsing and format syntax is a subset of
1007  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1008  * supported will provide results equivalent to their PHP versions.
1009  *
1010  * Following is the list of all currently supported formats:
1011  *<pre>
1012 Sample date:
1013 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1014
1015 Format  Output      Description
1016 ------  ----------  --------------------------------------------------------------
1017   d      10         Day of the month, 2 digits with leading zeros
1018   D      Wed        A textual representation of a day, three letters
1019   j      10         Day of the month without leading zeros
1020   l      Wednesday  A full textual representation of the day of the week
1021   S      th         English ordinal day of month suffix, 2 chars (use with j)
1022   w      3          Numeric representation of the day of the week
1023   z      9          The julian date, or day of the year (0-365)
1024   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1025   F      January    A full textual representation of the month
1026   m      01         Numeric representation of a month, with leading zeros
1027   M      Jan        Month name abbreviation, three letters
1028   n      1          Numeric representation of a month, without leading zeros
1029   t      31         Number of days in the given month
1030   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1031   Y      2007       A full numeric representation of a year, 4 digits
1032   y      07         A two digit representation of a year
1033   a      pm         Lowercase Ante meridiem and Post meridiem
1034   A      PM         Uppercase Ante meridiem and Post meridiem
1035   g      3          12-hour format of an hour without leading zeros
1036   G      15         24-hour format of an hour without leading zeros
1037   h      03         12-hour format of an hour with leading zeros
1038   H      15         24-hour format of an hour with leading zeros
1039   i      05         Minutes with leading zeros
1040   s      01         Seconds, with leading zeros
1041   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1042   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1043   T      CST        Timezone setting of the machine running the code
1044   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1045 </pre>
1046  *
1047  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1048  * <pre><code>
1049 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1050 document.write(dt.format('Y-m-d'));                         //2007-01-10
1051 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1052 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
1053  </code></pre>
1054  *
1055  * Here are some standard date/time patterns that you might find helpful.  They
1056  * are not part of the source of Date.js, but to use them you can simply copy this
1057  * block of code into any script that is included after Date.js and they will also become
1058  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1059  * <pre><code>
1060 Date.patterns = {
1061     ISO8601Long:"Y-m-d H:i:s",
1062     ISO8601Short:"Y-m-d",
1063     ShortDate: "n/j/Y",
1064     LongDate: "l, F d, Y",
1065     FullDateTime: "l, F d, Y g:i:s A",
1066     MonthDay: "F d",
1067     ShortTime: "g:i A",
1068     LongTime: "g:i:s A",
1069     SortableDateTime: "Y-m-d\\TH:i:s",
1070     UniversalSortableDateTime: "Y-m-d H:i:sO",
1071     YearMonth: "F, Y"
1072 };
1073 </code></pre>
1074  *
1075  * Example usage:
1076  * <pre><code>
1077 var dt = new Date();
1078 document.write(dt.format(Date.patterns.ShortDate));
1079  </code></pre>
1080  */
1081
1082 /*
1083  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1084  * They generate precompiled functions from date formats instead of parsing and
1085  * processing the pattern every time you format a date.  These functions are available
1086  * on every Date object (any javascript function).
1087  *
1088  * The original article and download are here:
1089  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1090  *
1091  */
1092  
1093  
1094  // was in core
1095 /**
1096  Returns the number of milliseconds between this date and date
1097  @param {Date} date (optional) Defaults to now
1098  @return {Number} The diff in milliseconds
1099  @member Date getElapsed
1100  */
1101 Date.prototype.getElapsed = function(date) {
1102         return Math.abs((date || new Date()).getTime()-this.getTime());
1103 };
1104 // was in date file..
1105
1106
1107 // private
1108 Date.parseFunctions = {count:0};
1109 // private
1110 Date.parseRegexes = [];
1111 // private
1112 Date.formatFunctions = {count:0};
1113
1114 // private
1115 Date.prototype.dateFormat = function(format) {
1116     if (Date.formatFunctions[format] == null) {
1117         Date.createNewFormat(format);
1118     }
1119     var func = Date.formatFunctions[format];
1120     return this[func]();
1121 };
1122
1123
1124 /**
1125  * Formats a date given the supplied format string
1126  * @param {String} format The format string
1127  * @return {String} The formatted date
1128  * @method
1129  */
1130 Date.prototype.format = Date.prototype.dateFormat;
1131
1132 // private
1133 Date.createNewFormat = function(format) {
1134     var funcName = "format" + Date.formatFunctions.count++;
1135     Date.formatFunctions[format] = funcName;
1136     var code = "Date.prototype." + funcName + " = function(){return ";
1137     var special = false;
1138     var ch = '';
1139     for (var i = 0; i < format.length; ++i) {
1140         ch = format.charAt(i);
1141         if (!special && ch == "\\") {
1142             special = true;
1143         }
1144         else if (special) {
1145             special = false;
1146             code += "'" + String.escape(ch) + "' + ";
1147         }
1148         else {
1149             code += Date.getFormatCode(ch);
1150         }
1151     }
1152     /** eval:var:zzzzzzzzzzzzz */
1153     eval(code.substring(0, code.length - 3) + ";}");
1154 };
1155
1156 // private
1157 Date.getFormatCode = function(character) {
1158     switch (character) {
1159     case "d":
1160         return "String.leftPad(this.getDate(), 2, '0') + ";
1161     case "D":
1162         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1163     case "j":
1164         return "this.getDate() + ";
1165     case "l":
1166         return "Date.dayNames[this.getDay()] + ";
1167     case "S":
1168         return "this.getSuffix() + ";
1169     case "w":
1170         return "this.getDay() + ";
1171     case "z":
1172         return "this.getDayOfYear() + ";
1173     case "W":
1174         return "this.getWeekOfYear() + ";
1175     case "F":
1176         return "Date.monthNames[this.getMonth()] + ";
1177     case "m":
1178         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1179     case "M":
1180         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1181     case "n":
1182         return "(this.getMonth() + 1) + ";
1183     case "t":
1184         return "this.getDaysInMonth() + ";
1185     case "L":
1186         return "(this.isLeapYear() ? 1 : 0) + ";
1187     case "Y":
1188         return "this.getFullYear() + ";
1189     case "y":
1190         return "('' + this.getFullYear()).substring(2, 4) + ";
1191     case "a":
1192         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1193     case "A":
1194         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1195     case "g":
1196         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1197     case "G":
1198         return "this.getHours() + ";
1199     case "h":
1200         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1201     case "H":
1202         return "String.leftPad(this.getHours(), 2, '0') + ";
1203     case "i":
1204         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1205     case "s":
1206         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1207     case "O":
1208         return "this.getGMTOffset() + ";
1209     case "P":
1210         return "this.getGMTColonOffset() + ";
1211     case "T":
1212         return "this.getTimezone() + ";
1213     case "Z":
1214         return "(this.getTimezoneOffset() * -60) + ";
1215     default:
1216         return "'" + String.escape(character) + "' + ";
1217     }
1218 };
1219
1220 /**
1221  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1222  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1223  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1224  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1225  * string or the parse operation will fail.
1226  * Example Usage:
1227 <pre><code>
1228 //dt = Fri May 25 2007 (current date)
1229 var dt = new Date();
1230
1231 //dt = Thu May 25 2006 (today's month/day in 2006)
1232 dt = Date.parseDate("2006", "Y");
1233
1234 //dt = Sun Jan 15 2006 (all date parts specified)
1235 dt = Date.parseDate("2006-1-15", "Y-m-d");
1236
1237 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1238 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1239 </code></pre>
1240  * @param {String} input The unparsed date as a string
1241  * @param {String} format The format the date is in
1242  * @return {Date} The parsed date
1243  * @static
1244  */
1245 Date.parseDate = function(input, format) {
1246     if (Date.parseFunctions[format] == null) {
1247         Date.createParser(format);
1248     }
1249     var func = Date.parseFunctions[format];
1250     return Date[func](input);
1251 };
1252 /**
1253  * @private
1254  */
1255
1256 Date.createParser = function(format) {
1257     var funcName = "parse" + Date.parseFunctions.count++;
1258     var regexNum = Date.parseRegexes.length;
1259     var currentGroup = 1;
1260     Date.parseFunctions[format] = funcName;
1261
1262     var code = "Date." + funcName + " = function(input){\n"
1263         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1264         + "var d = new Date();\n"
1265         + "y = d.getFullYear();\n"
1266         + "m = d.getMonth();\n"
1267         + "d = d.getDate();\n"
1268         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1269         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1270         + "if (results && results.length > 0) {";
1271     var regex = "";
1272
1273     var special = false;
1274     var ch = '';
1275     for (var i = 0; i < format.length; ++i) {
1276         ch = format.charAt(i);
1277         if (!special && ch == "\\") {
1278             special = true;
1279         }
1280         else if (special) {
1281             special = false;
1282             regex += String.escape(ch);
1283         }
1284         else {
1285             var obj = Date.formatCodeToRegex(ch, currentGroup);
1286             currentGroup += obj.g;
1287             regex += obj.s;
1288             if (obj.g && obj.c) {
1289                 code += obj.c;
1290             }
1291         }
1292     }
1293
1294     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1295         + "{v = new Date(y, m, d, h, i, s);}\n"
1296         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1297         + "{v = new Date(y, m, d, h, i);}\n"
1298         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1299         + "{v = new Date(y, m, d, h);}\n"
1300         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1301         + "{v = new Date(y, m, d);}\n"
1302         + "else if (y >= 0 && m >= 0)\n"
1303         + "{v = new Date(y, m);}\n"
1304         + "else if (y >= 0)\n"
1305         + "{v = new Date(y);}\n"
1306         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1307         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1308         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1309         + ";}";
1310
1311     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1312     /** eval:var:zzzzzzzzzzzzz */
1313     eval(code);
1314 };
1315
1316 // private
1317 Date.formatCodeToRegex = function(character, currentGroup) {
1318     switch (character) {
1319     case "D":
1320         return {g:0,
1321         c:null,
1322         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1323     case "j":
1324         return {g:1,
1325             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1326             s:"(\\d{1,2})"}; // day of month without leading zeroes
1327     case "d":
1328         return {g:1,
1329             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1330             s:"(\\d{2})"}; // day of month with leading zeroes
1331     case "l":
1332         return {g:0,
1333             c:null,
1334             s:"(?:" + Date.dayNames.join("|") + ")"};
1335     case "S":
1336         return {g:0,
1337             c:null,
1338             s:"(?:st|nd|rd|th)"};
1339     case "w":
1340         return {g:0,
1341             c:null,
1342             s:"\\d"};
1343     case "z":
1344         return {g:0,
1345             c:null,
1346             s:"(?:\\d{1,3})"};
1347     case "W":
1348         return {g:0,
1349             c:null,
1350             s:"(?:\\d{2})"};
1351     case "F":
1352         return {g:1,
1353             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1354             s:"(" + Date.monthNames.join("|") + ")"};
1355     case "M":
1356         return {g:1,
1357             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1358             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1359     case "n":
1360         return {g:1,
1361             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1362             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1363     case "m":
1364         return {g:1,
1365             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1366             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1367     case "t":
1368         return {g:0,
1369             c:null,
1370             s:"\\d{1,2}"};
1371     case "L":
1372         return {g:0,
1373             c:null,
1374             s:"(?:1|0)"};
1375     case "Y":
1376         return {g:1,
1377             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1378             s:"(\\d{4})"};
1379     case "y":
1380         return {g:1,
1381             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1382                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1383             s:"(\\d{1,2})"};
1384     case "a":
1385         return {g:1,
1386             c:"if (results[" + currentGroup + "] == 'am') {\n"
1387                 + "if (h == 12) { h = 0; }\n"
1388                 + "} else { if (h < 12) { h += 12; }}",
1389             s:"(am|pm)"};
1390     case "A":
1391         return {g:1,
1392             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1393                 + "if (h == 12) { h = 0; }\n"
1394                 + "} else { if (h < 12) { h += 12; }}",
1395             s:"(AM|PM)"};
1396     case "g":
1397     case "G":
1398         return {g:1,
1399             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1400             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1401     case "h":
1402     case "H":
1403         return {g:1,
1404             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1405             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1406     case "i":
1407         return {g:1,
1408             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1409             s:"(\\d{2})"};
1410     case "s":
1411         return {g:1,
1412             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1413             s:"(\\d{2})"};
1414     case "O":
1415         return {g:1,
1416             c:[
1417                 "o = results[", currentGroup, "];\n",
1418                 "var sn = o.substring(0,1);\n", // get + / - sign
1419                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1420                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1421                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1422                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1423             ].join(""),
1424             s:"([+\-]\\d{2,4})"};
1425     
1426     
1427     case "P":
1428         return {g:1,
1429                 c:[
1430                    "o = results[", currentGroup, "];\n",
1431                    "var sn = o.substring(0,1);\n",
1432                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1433                    "var mn = o.substring(4,6) % 60;\n",
1434                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1435                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1436             ].join(""),
1437             s:"([+\-]\\d{4})"};
1438     case "T":
1439         return {g:0,
1440             c:null,
1441             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1442     case "Z":
1443         return {g:1,
1444             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1445                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1446             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1447     default:
1448         return {g:0,
1449             c:null,
1450             s:String.escape(character)};
1451     }
1452 };
1453
1454 /**
1455  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1456  * @return {String} The abbreviated timezone name (e.g. 'CST')
1457  */
1458 Date.prototype.getTimezone = function() {
1459     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1460 };
1461
1462 /**
1463  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1464  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1465  */
1466 Date.prototype.getGMTOffset = function() {
1467     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1468         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1469         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1470 };
1471
1472 /**
1473  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1474  * @return {String} 2-characters representing hours and 2-characters representing minutes
1475  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1476  */
1477 Date.prototype.getGMTColonOffset = function() {
1478         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1479                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1480                 + ":"
1481                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1482 }
1483
1484 /**
1485  * Get the numeric day number of the year, adjusted for leap year.
1486  * @return {Number} 0 through 364 (365 in leap years)
1487  */
1488 Date.prototype.getDayOfYear = function() {
1489     var num = 0;
1490     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1491     for (var i = 0; i < this.getMonth(); ++i) {
1492         num += Date.daysInMonth[i];
1493     }
1494     return num + this.getDate() - 1;
1495 };
1496
1497 /**
1498  * Get the string representation of the numeric week number of the year
1499  * (equivalent to the format specifier 'W').
1500  * @return {String} '00' through '52'
1501  */
1502 Date.prototype.getWeekOfYear = function() {
1503     // Skip to Thursday of this week
1504     var now = this.getDayOfYear() + (4 - this.getDay());
1505     // Find the first Thursday of the year
1506     var jan1 = new Date(this.getFullYear(), 0, 1);
1507     var then = (7 - jan1.getDay() + 4);
1508     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1509 };
1510
1511 /**
1512  * Whether or not the current date is in a leap year.
1513  * @return {Boolean} True if the current date is in a leap year, else false
1514  */
1515 Date.prototype.isLeapYear = function() {
1516     var year = this.getFullYear();
1517     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1518 };
1519
1520 /**
1521  * Get the first 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.getFirstDayOfMonth()]); //output: 'Monday'
1528 </code></pre>
1529  * @return {Number} The day number (0-6)
1530  */
1531 Date.prototype.getFirstDayOfMonth = function() {
1532     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1533     return (day < 0) ? (day + 7) : day;
1534 };
1535
1536 /**
1537  * Get the last day of the current month, adjusted for leap year.  The returned value
1538  * is the numeric day index within the week (0-6) which can be used in conjunction with
1539  * the {@link #monthNames} array to retrieve the textual day name.
1540  * Example:
1541  *<pre><code>
1542 var dt = new Date('1/10/2007');
1543 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1544 </code></pre>
1545  * @return {Number} The day number (0-6)
1546  */
1547 Date.prototype.getLastDayOfMonth = function() {
1548     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1549     return (day < 0) ? (day + 7) : day;
1550 };
1551
1552
1553 /**
1554  * Get the first date of this date's month
1555  * @return {Date}
1556  */
1557 Date.prototype.getFirstDateOfMonth = function() {
1558     return new Date(this.getFullYear(), this.getMonth(), 1);
1559 };
1560
1561 /**
1562  * Get the last date of this date's month
1563  * @return {Date}
1564  */
1565 Date.prototype.getLastDateOfMonth = function() {
1566     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1567 };
1568 /**
1569  * Get the number of days in the current month, adjusted for leap year.
1570  * @return {Number} The number of days in the month
1571  */
1572 Date.prototype.getDaysInMonth = function() {
1573     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1574     return Date.daysInMonth[this.getMonth()];
1575 };
1576
1577 /**
1578  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1579  * @return {String} 'st, 'nd', 'rd' or 'th'
1580  */
1581 Date.prototype.getSuffix = function() {
1582     switch (this.getDate()) {
1583         case 1:
1584         case 21:
1585         case 31:
1586             return "st";
1587         case 2:
1588         case 22:
1589             return "nd";
1590         case 3:
1591         case 23:
1592             return "rd";
1593         default:
1594             return "th";
1595     }
1596 };
1597
1598 // private
1599 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1600
1601 /**
1602  * An array of textual month names.
1603  * Override these values for international dates, for example...
1604  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1605  * @type Array
1606  * @static
1607  */
1608 Date.monthNames =
1609    ["January",
1610     "February",
1611     "March",
1612     "April",
1613     "May",
1614     "June",
1615     "July",
1616     "August",
1617     "September",
1618     "October",
1619     "November",
1620     "December"];
1621
1622 /**
1623  * An array of textual day names.
1624  * Override these values for international dates, for example...
1625  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1626  * @type Array
1627  * @static
1628  */
1629 Date.dayNames =
1630    ["Sunday",
1631     "Monday",
1632     "Tuesday",
1633     "Wednesday",
1634     "Thursday",
1635     "Friday",
1636     "Saturday"];
1637
1638 // private
1639 Date.y2kYear = 50;
1640 // private
1641 Date.monthNumbers = {
1642     Jan:0,
1643     Feb:1,
1644     Mar:2,
1645     Apr:3,
1646     May:4,
1647     Jun:5,
1648     Jul:6,
1649     Aug:7,
1650     Sep:8,
1651     Oct:9,
1652     Nov:10,
1653     Dec:11};
1654
1655 /**
1656  * Creates and returns a new Date instance with the exact same date value as the called instance.
1657  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1658  * variable will also be changed.  When the intention is to create a new variable that will not
1659  * modify the original instance, you should create a clone.
1660  *
1661  * Example of correctly cloning a date:
1662  * <pre><code>
1663 //wrong way:
1664 var orig = new Date('10/1/2006');
1665 var copy = orig;
1666 copy.setDate(5);
1667 document.write(orig);  //returns 'Thu Oct 05 2006'!
1668
1669 //correct way:
1670 var orig = new Date('10/1/2006');
1671 var copy = orig.clone();
1672 copy.setDate(5);
1673 document.write(orig);  //returns 'Thu Oct 01 2006'
1674 </code></pre>
1675  * @return {Date} The new Date instance
1676  */
1677 Date.prototype.clone = function() {
1678         return new Date(this.getTime());
1679 };
1680
1681 /**
1682  * Clears any time information from this date
1683  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1684  @return {Date} this or the clone
1685  */
1686 Date.prototype.clearTime = function(clone){
1687     if(clone){
1688         return this.clone().clearTime();
1689     }
1690     this.setHours(0);
1691     this.setMinutes(0);
1692     this.setSeconds(0);
1693     this.setMilliseconds(0);
1694     return this;
1695 };
1696
1697 // private
1698 // safari setMonth is broken -- check that this is only donw once...
1699 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1700     Date.brokenSetMonth = Date.prototype.setMonth;
1701         Date.prototype.setMonth = function(num){
1702                 if(num <= -1){
1703                         var n = Math.ceil(-num);
1704                         var back_year = Math.ceil(n/12);
1705                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1706                         this.setFullYear(this.getFullYear() - back_year);
1707                         return Date.brokenSetMonth.call(this, month);
1708                 } else {
1709                         return Date.brokenSetMonth.apply(this, arguments);
1710                 }
1711         };
1712 }
1713
1714 /** Date interval constant 
1715 * @static 
1716 * @type String */
1717 Date.MILLI = "ms";
1718 /** Date interval constant 
1719 * @static 
1720 * @type String */
1721 Date.SECOND = "s";
1722 /** Date interval constant 
1723 * @static 
1724 * @type String */
1725 Date.MINUTE = "mi";
1726 /** Date interval constant 
1727 * @static 
1728 * @type String */
1729 Date.HOUR = "h";
1730 /** Date interval constant 
1731 * @static 
1732 * @type String */
1733 Date.DAY = "d";
1734 /** Date interval constant 
1735 * @static 
1736 * @type String */
1737 Date.MONTH = "mo";
1738 /** Date interval constant 
1739 * @static 
1740 * @type String */
1741 Date.YEAR = "y";
1742
1743 /**
1744  * Provides a convenient method of performing basic date arithmetic.  This method
1745  * does not modify the Date instance being called - it creates and returns
1746  * a new Date instance containing the resulting date value.
1747  *
1748  * Examples:
1749  * <pre><code>
1750 //Basic usage:
1751 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1752 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1753
1754 //Negative values will subtract correctly:
1755 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1756 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1757
1758 //You can even chain several calls together in one line!
1759 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1760 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1761  </code></pre>
1762  *
1763  * @param {String} interval   A valid date interval enum value
1764  * @param {Number} value      The amount to add to the current date
1765  * @return {Date} The new Date instance
1766  */
1767 Date.prototype.add = function(interval, value){
1768   var d = this.clone();
1769   if (!interval || value === 0) { return d; }
1770   switch(interval.toLowerCase()){
1771     case Date.MILLI:
1772       d.setMilliseconds(this.getMilliseconds() + value);
1773       break;
1774     case Date.SECOND:
1775       d.setSeconds(this.getSeconds() + value);
1776       break;
1777     case Date.MINUTE:
1778       d.setMinutes(this.getMinutes() + value);
1779       break;
1780     case Date.HOUR:
1781       d.setHours(this.getHours() + value);
1782       break;
1783     case Date.DAY:
1784       d.setDate(this.getDate() + value);
1785       break;
1786     case Date.MONTH:
1787       var day = this.getDate();
1788       if(day > 28){
1789           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1790       }
1791       d.setDate(day);
1792       d.setMonth(this.getMonth() + value);
1793       break;
1794     case Date.YEAR:
1795       d.setFullYear(this.getFullYear() + value);
1796       break;
1797   }
1798   return d;
1799 };
1800 /*
1801  * Based on:
1802  * Ext JS Library 1.1.1
1803  * Copyright(c) 2006-2007, Ext JS, LLC.
1804  *
1805  * Originally Released Under LGPL - original licence link has changed is not relivant.
1806  *
1807  * Fork - LGPL
1808  * <script type="text/javascript">
1809  */
1810
1811 /**
1812  * @class Roo.lib.Dom
1813  * @static
1814  * 
1815  * Dom utils (from YIU afaik)
1816  * 
1817  **/
1818 Roo.lib.Dom = {
1819     /**
1820      * Get the view width
1821      * @param {Boolean} full True will get the full document, otherwise it's the view width
1822      * @return {Number} The width
1823      */
1824      
1825     getViewWidth : function(full) {
1826         return full ? this.getDocumentWidth() : this.getViewportWidth();
1827     },
1828     /**
1829      * Get the view height
1830      * @param {Boolean} full True will get the full document, otherwise it's the view height
1831      * @return {Number} The height
1832      */
1833     getViewHeight : function(full) {
1834         return full ? this.getDocumentHeight() : this.getViewportHeight();
1835     },
1836
1837     getDocumentHeight: function() {
1838         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1839         return Math.max(scrollHeight, this.getViewportHeight());
1840     },
1841
1842     getDocumentWidth: function() {
1843         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1844         return Math.max(scrollWidth, this.getViewportWidth());
1845     },
1846
1847     getViewportHeight: function() {
1848         var height = self.innerHeight;
1849         var mode = document.compatMode;
1850
1851         if ((mode || Roo.isIE) && !Roo.isOpera) {
1852             height = (mode == "CSS1Compat") ?
1853                      document.documentElement.clientHeight :
1854                      document.body.clientHeight;
1855         }
1856
1857         return height;
1858     },
1859
1860     getViewportWidth: function() {
1861         var width = self.innerWidth;
1862         var mode = document.compatMode;
1863
1864         if (mode || Roo.isIE) {
1865             width = (mode == "CSS1Compat") ?
1866                     document.documentElement.clientWidth :
1867                     document.body.clientWidth;
1868         }
1869         return width;
1870     },
1871
1872     isAncestor : function(p, c) {
1873         p = Roo.getDom(p);
1874         c = Roo.getDom(c);
1875         if (!p || !c) {
1876             return false;
1877         }
1878
1879         if (p.contains && !Roo.isSafari) {
1880             return p.contains(c);
1881         } else if (p.compareDocumentPosition) {
1882             return !!(p.compareDocumentPosition(c) & 16);
1883         } else {
1884             var parent = c.parentNode;
1885             while (parent) {
1886                 if (parent == p) {
1887                     return true;
1888                 }
1889                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1890                     return false;
1891                 }
1892                 parent = parent.parentNode;
1893             }
1894             return false;
1895         }
1896     },
1897
1898     getRegion : function(el) {
1899         return Roo.lib.Region.getRegion(el);
1900     },
1901
1902     getY : function(el) {
1903         return this.getXY(el)[1];
1904     },
1905
1906     getX : function(el) {
1907         return this.getXY(el)[0];
1908     },
1909
1910     getXY : function(el) {
1911         var p, pe, b, scroll, bd = document.body;
1912         el = Roo.getDom(el);
1913         var fly = Roo.lib.AnimBase.fly;
1914         if (el.getBoundingClientRect) {
1915             b = el.getBoundingClientRect();
1916             scroll = fly(document).getScroll();
1917             return [b.left + scroll.left, b.top + scroll.top];
1918         }
1919         var x = 0, y = 0;
1920
1921         p = el;
1922
1923         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1924
1925         while (p) {
1926
1927             x += p.offsetLeft;
1928             y += p.offsetTop;
1929
1930             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1931                 hasAbsolute = true;
1932             }
1933
1934             if (Roo.isGecko) {
1935                 pe = fly(p);
1936
1937                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1938                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1939
1940
1941                 x += bl;
1942                 y += bt;
1943
1944
1945                 if (p != el && pe.getStyle('overflow') != 'visible') {
1946                     x += bl;
1947                     y += bt;
1948                 }
1949             }
1950             p = p.offsetParent;
1951         }
1952
1953         if (Roo.isSafari && hasAbsolute) {
1954             x -= bd.offsetLeft;
1955             y -= bd.offsetTop;
1956         }
1957
1958         if (Roo.isGecko && !hasAbsolute) {
1959             var dbd = fly(bd);
1960             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1961             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1962         }
1963
1964         p = el.parentNode;
1965         while (p && p != bd) {
1966             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1967                 x -= p.scrollLeft;
1968                 y -= p.scrollTop;
1969             }
1970             p = p.parentNode;
1971         }
1972         return [x, y];
1973     },
1974  
1975   
1976
1977
1978     setXY : function(el, xy) {
1979         el = Roo.fly(el, '_setXY');
1980         el.position();
1981         var pts = el.translatePoints(xy);
1982         if (xy[0] !== false) {
1983             el.dom.style.left = pts.left + "px";
1984         }
1985         if (xy[1] !== false) {
1986             el.dom.style.top = pts.top + "px";
1987         }
1988     },
1989
1990     setX : function(el, x) {
1991         this.setXY(el, [x, false]);
1992     },
1993
1994     setY : function(el, y) {
1995         this.setXY(el, [false, y]);
1996     }
1997 };
1998 /*
1999  * Portions of this file are based on pieces of Yahoo User Interface Library
2000  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2001  * YUI licensed under the BSD License:
2002  * http://developer.yahoo.net/yui/license.txt
2003  * <script type="text/javascript">
2004  *
2005  */
2006
2007 Roo.lib.Event = function() {
2008     var loadComplete = false;
2009     var listeners = [];
2010     var unloadListeners = [];
2011     var retryCount = 0;
2012     var onAvailStack = [];
2013     var counter = 0;
2014     var lastError = null;
2015
2016     return {
2017         POLL_RETRYS: 200,
2018         POLL_INTERVAL: 20,
2019         EL: 0,
2020         TYPE: 1,
2021         FN: 2,
2022         WFN: 3,
2023         OBJ: 3,
2024         ADJ_SCOPE: 4,
2025         _interval: null,
2026
2027         startInterval: function() {
2028             if (!this._interval) {
2029                 var self = this;
2030                 var callback = function() {
2031                     self._tryPreloadAttach();
2032                 };
2033                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2034
2035             }
2036         },
2037
2038         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2039             onAvailStack.push({ id:         p_id,
2040                 fn:         p_fn,
2041                 obj:        p_obj,
2042                 override:   p_override,
2043                 checkReady: false    });
2044
2045             retryCount = this.POLL_RETRYS;
2046             this.startInterval();
2047         },
2048
2049
2050         addListener: function(el, eventName, fn) {
2051             el = Roo.getDom(el);
2052             if (!el || !fn) {
2053                 return false;
2054             }
2055
2056             if ("unload" == eventName) {
2057                 unloadListeners[unloadListeners.length] =
2058                 [el, eventName, fn];
2059                 return true;
2060             }
2061
2062             var wrappedFn = function(e) {
2063                 return fn(Roo.lib.Event.getEvent(e));
2064             };
2065
2066             var li = [el, eventName, fn, wrappedFn];
2067
2068             var index = listeners.length;
2069             listeners[index] = li;
2070
2071             this.doAdd(el, eventName, wrappedFn, false);
2072             return true;
2073
2074         },
2075
2076
2077         removeListener: function(el, eventName, fn) {
2078             var i, len;
2079
2080             el = Roo.getDom(el);
2081
2082             if(!fn) {
2083                 return this.purgeElement(el, false, eventName);
2084             }
2085
2086
2087             if ("unload" == eventName) {
2088
2089                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2090                     var li = unloadListeners[i];
2091                     if (li &&
2092                         li[0] == el &&
2093                         li[1] == eventName &&
2094                         li[2] == fn) {
2095                         unloadListeners.splice(i, 1);
2096                         return true;
2097                     }
2098                 }
2099
2100                 return false;
2101             }
2102
2103             var cacheItem = null;
2104
2105
2106             var index = arguments[3];
2107
2108             if ("undefined" == typeof index) {
2109                 index = this._getCacheIndex(el, eventName, fn);
2110             }
2111
2112             if (index >= 0) {
2113                 cacheItem = listeners[index];
2114             }
2115
2116             if (!el || !cacheItem) {
2117                 return false;
2118             }
2119
2120             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2121
2122             delete listeners[index][this.WFN];
2123             delete listeners[index][this.FN];
2124             listeners.splice(index, 1);
2125
2126             return true;
2127
2128         },
2129
2130
2131         getTarget: function(ev, resolveTextNode) {
2132             ev = ev.browserEvent || ev;
2133             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2134             var t = ev.target || ev.srcElement;
2135             return this.resolveTextNode(t);
2136         },
2137
2138
2139         resolveTextNode: function(node) {
2140             if (Roo.isSafari && node && 3 == node.nodeType) {
2141                 return node.parentNode;
2142             } else {
2143                 return node;
2144             }
2145         },
2146
2147
2148         getPageX: function(ev) {
2149             ev = ev.browserEvent || ev;
2150             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2151             var x = ev.pageX;
2152             if (!x && 0 !== x) {
2153                 x = ev.clientX || 0;
2154
2155                 if (Roo.isIE) {
2156                     x += this.getScroll()[1];
2157                 }
2158             }
2159
2160             return x;
2161         },
2162
2163
2164         getPageY: function(ev) {
2165             ev = ev.browserEvent || ev;
2166             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2167             var y = ev.pageY;
2168             if (!y && 0 !== y) {
2169                 y = ev.clientY || 0;
2170
2171                 if (Roo.isIE) {
2172                     y += this.getScroll()[0];
2173                 }
2174             }
2175
2176
2177             return y;
2178         },
2179
2180
2181         getXY: function(ev) {
2182             ev = ev.browserEvent || ev;
2183             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2184             return [this.getPageX(ev), this.getPageY(ev)];
2185         },
2186
2187
2188         getRelatedTarget: function(ev) {
2189             ev = ev.browserEvent || ev;
2190             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2191             var t = ev.relatedTarget;
2192             if (!t) {
2193                 if (ev.type == "mouseout") {
2194                     t = ev.toElement;
2195                 } else if (ev.type == "mouseover") {
2196                     t = ev.fromElement;
2197                 }
2198             }
2199
2200             return this.resolveTextNode(t);
2201         },
2202
2203
2204         getTime: function(ev) {
2205             ev = ev.browserEvent || ev;
2206             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2207             if (!ev.time) {
2208                 var t = new Date().getTime();
2209                 try {
2210                     ev.time = t;
2211                 } catch(ex) {
2212                     this.lastError = ex;
2213                     return t;
2214                 }
2215             }
2216
2217             return ev.time;
2218         },
2219
2220
2221         stopEvent: function(ev) {
2222             this.stopPropagation(ev);
2223             this.preventDefault(ev);
2224         },
2225
2226
2227         stopPropagation: function(ev) {
2228             ev = ev.browserEvent || ev;
2229             if (ev.stopPropagation) {
2230                 ev.stopPropagation();
2231             } else {
2232                 ev.cancelBubble = true;
2233             }
2234         },
2235
2236
2237         preventDefault: function(ev) {
2238             ev = ev.browserEvent || ev;
2239             if(ev.preventDefault) {
2240                 ev.preventDefault();
2241             } else {
2242                 ev.returnValue = false;
2243             }
2244         },
2245
2246
2247         getEvent: function(e) {
2248             var ev = e || window.event;
2249             if (!ev) {
2250                 var c = this.getEvent.caller;
2251                 while (c) {
2252                     ev = c.arguments[0];
2253                     if (ev && Event == ev.constructor) {
2254                         break;
2255                     }
2256                     c = c.caller;
2257                 }
2258             }
2259             return ev;
2260         },
2261
2262
2263         getCharCode: function(ev) {
2264             ev = ev.browserEvent || ev;
2265             return ev.charCode || ev.keyCode || 0;
2266         },
2267
2268
2269         _getCacheIndex: function(el, eventName, fn) {
2270             for (var i = 0,len = listeners.length; i < len; ++i) {
2271                 var li = listeners[i];
2272                 if (li &&
2273                     li[this.FN] == fn &&
2274                     li[this.EL] == el &&
2275                     li[this.TYPE] == eventName) {
2276                     return i;
2277                 }
2278             }
2279
2280             return -1;
2281         },
2282
2283
2284         elCache: {},
2285
2286
2287         getEl: function(id) {
2288             return document.getElementById(id);
2289         },
2290
2291
2292         clearCache: function() {
2293         },
2294
2295
2296         _load: function(e) {
2297             loadComplete = true;
2298             var EU = Roo.lib.Event;
2299
2300
2301             if (Roo.isIE) {
2302                 EU.doRemove(window, "load", EU._load);
2303             }
2304         },
2305
2306
2307         _tryPreloadAttach: function() {
2308
2309             if (this.locked) {
2310                 return false;
2311             }
2312
2313             this.locked = true;
2314
2315
2316             var tryAgain = !loadComplete;
2317             if (!tryAgain) {
2318                 tryAgain = (retryCount > 0);
2319             }
2320
2321
2322             var notAvail = [];
2323             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2324                 var item = onAvailStack[i];
2325                 if (item) {
2326                     var el = this.getEl(item.id);
2327
2328                     if (el) {
2329                         if (!item.checkReady ||
2330                             loadComplete ||
2331                             el.nextSibling ||
2332                             (document && document.body)) {
2333
2334                             var scope = el;
2335                             if (item.override) {
2336                                 if (item.override === true) {
2337                                     scope = item.obj;
2338                                 } else {
2339                                     scope = item.override;
2340                                 }
2341                             }
2342                             item.fn.call(scope, item.obj);
2343                             onAvailStack[i] = null;
2344                         }
2345                     } else {
2346                         notAvail.push(item);
2347                     }
2348                 }
2349             }
2350
2351             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2352
2353             if (tryAgain) {
2354
2355                 this.startInterval();
2356             } else {
2357                 clearInterval(this._interval);
2358                 this._interval = null;
2359             }
2360
2361             this.locked = false;
2362
2363             return true;
2364
2365         },
2366
2367
2368         purgeElement: function(el, recurse, eventName) {
2369             var elListeners = this.getListeners(el, eventName);
2370             if (elListeners) {
2371                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2372                     var l = elListeners[i];
2373                     this.removeListener(el, l.type, l.fn);
2374                 }
2375             }
2376
2377             if (recurse && el && el.childNodes) {
2378                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2379                     this.purgeElement(el.childNodes[i], recurse, eventName);
2380                 }
2381             }
2382         },
2383
2384
2385         getListeners: function(el, eventName) {
2386             var results = [], searchLists;
2387             if (!eventName) {
2388                 searchLists = [listeners, unloadListeners];
2389             } else if (eventName == "unload") {
2390                 searchLists = [unloadListeners];
2391             } else {
2392                 searchLists = [listeners];
2393             }
2394
2395             for (var j = 0; j < searchLists.length; ++j) {
2396                 var searchList = searchLists[j];
2397                 if (searchList && searchList.length > 0) {
2398                     for (var i = 0,len = searchList.length; i < len; ++i) {
2399                         var l = searchList[i];
2400                         if (l && l[this.EL] === el &&
2401                             (!eventName || eventName === l[this.TYPE])) {
2402                             results.push({
2403                                 type:   l[this.TYPE],
2404                                 fn:     l[this.FN],
2405                                 obj:    l[this.OBJ],
2406                                 adjust: l[this.ADJ_SCOPE],
2407                                 index:  i
2408                             });
2409                         }
2410                     }
2411                 }
2412             }
2413
2414             return (results.length) ? results : null;
2415         },
2416
2417
2418         _unload: function(e) {
2419
2420             var EU = Roo.lib.Event, i, j, l, len, index;
2421
2422             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2423                 l = unloadListeners[i];
2424                 if (l) {
2425                     var scope = window;
2426                     if (l[EU.ADJ_SCOPE]) {
2427                         if (l[EU.ADJ_SCOPE] === true) {
2428                             scope = l[EU.OBJ];
2429                         } else {
2430                             scope = l[EU.ADJ_SCOPE];
2431                         }
2432                     }
2433                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2434                     unloadListeners[i] = null;
2435                     l = null;
2436                     scope = null;
2437                 }
2438             }
2439
2440             unloadListeners = null;
2441
2442             if (listeners && listeners.length > 0) {
2443                 j = listeners.length;
2444                 while (j) {
2445                     index = j - 1;
2446                     l = listeners[index];
2447                     if (l) {
2448                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2449                                 l[EU.FN], index);
2450                     }
2451                     j = j - 1;
2452                 }
2453                 l = null;
2454
2455                 EU.clearCache();
2456             }
2457
2458             EU.doRemove(window, "unload", EU._unload);
2459
2460         },
2461
2462
2463         getScroll: function() {
2464             var dd = document.documentElement, db = document.body;
2465             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2466                 return [dd.scrollTop, dd.scrollLeft];
2467             } else if (db) {
2468                 return [db.scrollTop, db.scrollLeft];
2469             } else {
2470                 return [0, 0];
2471             }
2472         },
2473
2474
2475         doAdd: function () {
2476             if (window.addEventListener) {
2477                 return function(el, eventName, fn, capture) {
2478                     el.addEventListener(eventName, fn, (capture));
2479                 };
2480             } else if (window.attachEvent) {
2481                 return function(el, eventName, fn, capture) {
2482                     el.attachEvent("on" + eventName, fn);
2483                 };
2484             } else {
2485                 return function() {
2486                 };
2487             }
2488         }(),
2489
2490
2491         doRemove: function() {
2492             if (window.removeEventListener) {
2493                 return function (el, eventName, fn, capture) {
2494                     el.removeEventListener(eventName, fn, (capture));
2495                 };
2496             } else if (window.detachEvent) {
2497                 return function (el, eventName, fn) {
2498                     el.detachEvent("on" + eventName, fn);
2499                 };
2500             } else {
2501                 return function() {
2502                 };
2503             }
2504         }()
2505     };
2506     
2507 }();
2508 (function() {     
2509    
2510     var E = Roo.lib.Event;
2511     E.on = E.addListener;
2512     E.un = E.removeListener;
2513
2514     if (document && document.body) {
2515         E._load();
2516     } else {
2517         E.doAdd(window, "load", E._load);
2518     }
2519     E.doAdd(window, "unload", E._unload);
2520     E._tryPreloadAttach();
2521 })();
2522
2523 /*
2524  * Portions of this file are based on pieces of Yahoo User Interface Library
2525  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2526  * YUI licensed under the BSD License:
2527  * http://developer.yahoo.net/yui/license.txt
2528  * <script type="text/javascript">
2529  *
2530  */
2531
2532 (function() {
2533     /**
2534      * @class Roo.lib.Ajax
2535      *
2536      */
2537     Roo.lib.Ajax = {
2538         /**
2539          * @static 
2540          */
2541         request : function(method, uri, cb, data, options) {
2542             if(options){
2543                 var hs = options.headers;
2544                 if(hs){
2545                     for(var h in hs){
2546                         if(hs.hasOwnProperty(h)){
2547                             this.initHeader(h, hs[h], false);
2548                         }
2549                     }
2550                 }
2551                 if(options.xmlData){
2552                     this.initHeader('Content-Type', 'text/xml', false);
2553                     method = 'POST';
2554                     data = options.xmlData;
2555                 }
2556             }
2557
2558             return this.asyncRequest(method, uri, cb, data);
2559         },
2560
2561         serializeForm : function(form) {
2562             if(typeof form == 'string') {
2563                 form = (document.getElementById(form) || document.forms[form]);
2564             }
2565
2566             var el, name, val, disabled, data = '', hasSubmit = false;
2567             for (var i = 0; i < form.elements.length; i++) {
2568                 el = form.elements[i];
2569                 disabled = form.elements[i].disabled;
2570                 name = form.elements[i].name;
2571                 val = form.elements[i].value;
2572
2573                 if (!disabled && name){
2574                     switch (el.type)
2575                             {
2576                         case 'select-one':
2577                         case 'select-multiple':
2578                             for (var j = 0; j < el.options.length; j++) {
2579                                 if (el.options[j].selected) {
2580                                     if (Roo.isIE) {
2581                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2582                                     }
2583                                     else {
2584                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2585                                     }
2586                                 }
2587                             }
2588                             break;
2589                         case 'radio':
2590                         case 'checkbox':
2591                             if (el.checked) {
2592                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2593                             }
2594                             break;
2595                         case 'file':
2596
2597                         case undefined:
2598
2599                         case 'reset':
2600
2601                         case 'button':
2602
2603                             break;
2604                         case 'submit':
2605                             if(hasSubmit == false) {
2606                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2607                                 hasSubmit = true;
2608                             }
2609                             break;
2610                         default:
2611                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2612                             break;
2613                     }
2614                 }
2615             }
2616             data = data.substr(0, data.length - 1);
2617             return data;
2618         },
2619
2620         headers:{},
2621
2622         hasHeaders:false,
2623
2624         useDefaultHeader:true,
2625
2626         defaultPostHeader:'application/x-www-form-urlencoded',
2627
2628         useDefaultXhrHeader:true,
2629
2630         defaultXhrHeader:'XMLHttpRequest',
2631
2632         hasDefaultHeaders:true,
2633
2634         defaultHeaders:{},
2635
2636         poll:{},
2637
2638         timeout:{},
2639
2640         pollInterval:50,
2641
2642         transactionId:0,
2643
2644         setProgId:function(id)
2645         {
2646             this.activeX.unshift(id);
2647         },
2648
2649         setDefaultPostHeader:function(b)
2650         {
2651             this.useDefaultHeader = b;
2652         },
2653
2654         setDefaultXhrHeader:function(b)
2655         {
2656             this.useDefaultXhrHeader = b;
2657         },
2658
2659         setPollingInterval:function(i)
2660         {
2661             if (typeof i == 'number' && isFinite(i)) {
2662                 this.pollInterval = i;
2663             }
2664         },
2665
2666         createXhrObject:function(transactionId)
2667         {
2668             var obj,http;
2669             try
2670             {
2671
2672                 http = new XMLHttpRequest();
2673
2674                 obj = { conn:http, tId:transactionId };
2675             }
2676             catch(e)
2677             {
2678                 for (var i = 0; i < this.activeX.length; ++i) {
2679                     try
2680                     {
2681
2682                         http = new ActiveXObject(this.activeX[i]);
2683
2684                         obj = { conn:http, tId:transactionId };
2685                         break;
2686                     }
2687                     catch(e) {
2688                     }
2689                 }
2690             }
2691             finally
2692             {
2693                 return obj;
2694             }
2695         },
2696
2697         getConnectionObject:function()
2698         {
2699             var o;
2700             var tId = this.transactionId;
2701
2702             try
2703             {
2704                 o = this.createXhrObject(tId);
2705                 if (o) {
2706                     this.transactionId++;
2707                 }
2708             }
2709             catch(e) {
2710             }
2711             finally
2712             {
2713                 return o;
2714             }
2715         },
2716
2717         asyncRequest:function(method, uri, callback, postData)
2718         {
2719             var o = this.getConnectionObject();
2720
2721             if (!o) {
2722                 return null;
2723             }
2724             else {
2725                 o.conn.open(method, uri, true);
2726
2727                 if (this.useDefaultXhrHeader) {
2728                     if (!this.defaultHeaders['X-Requested-With']) {
2729                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2730                     }
2731                 }
2732
2733                 if(postData && this.useDefaultHeader){
2734                     this.initHeader('Content-Type', this.defaultPostHeader);
2735                 }
2736
2737                  if (this.hasDefaultHeaders || this.hasHeaders) {
2738                     this.setHeader(o);
2739                 }
2740
2741                 this.handleReadyState(o, callback);
2742                 o.conn.send(postData || null);
2743
2744                 return o;
2745             }
2746         },
2747
2748         handleReadyState:function(o, callback)
2749         {
2750             var oConn = this;
2751
2752             if (callback && callback.timeout) {
2753                 
2754                 this.timeout[o.tId] = window.setTimeout(function() {
2755                     oConn.abort(o, callback, true);
2756                 }, callback.timeout);
2757             }
2758
2759             this.poll[o.tId] = window.setInterval(
2760                     function() {
2761                         if (o.conn && o.conn.readyState == 4) {
2762                             window.clearInterval(oConn.poll[o.tId]);
2763                             delete oConn.poll[o.tId];
2764
2765                             if(callback && callback.timeout) {
2766                                 window.clearTimeout(oConn.timeout[o.tId]);
2767                                 delete oConn.timeout[o.tId];
2768                             }
2769
2770                             oConn.handleTransactionResponse(o, callback);
2771                         }
2772                     }
2773                     , this.pollInterval);
2774         },
2775
2776         handleTransactionResponse:function(o, callback, isAbort)
2777         {
2778
2779             if (!callback) {
2780                 this.releaseObject(o);
2781                 return;
2782             }
2783
2784             var httpStatus, responseObject;
2785
2786             try
2787             {
2788                 if (o.conn.status !== undefined && o.conn.status != 0) {
2789                     httpStatus = o.conn.status;
2790                 }
2791                 else {
2792                     httpStatus = 13030;
2793                 }
2794             }
2795             catch(e) {
2796
2797
2798                 httpStatus = 13030;
2799             }
2800
2801             if (httpStatus >= 200 && httpStatus < 300) {
2802                 responseObject = this.createResponseObject(o, callback.argument);
2803                 if (callback.success) {
2804                     if (!callback.scope) {
2805                         callback.success(responseObject);
2806                     }
2807                     else {
2808
2809
2810                         callback.success.apply(callback.scope, [responseObject]);
2811                     }
2812                 }
2813             }
2814             else {
2815                 switch (httpStatus) {
2816
2817                     case 12002:
2818                     case 12029:
2819                     case 12030:
2820                     case 12031:
2821                     case 12152:
2822                     case 13030:
2823                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2824                         if (callback.failure) {
2825                             if (!callback.scope) {
2826                                 callback.failure(responseObject);
2827                             }
2828                             else {
2829                                 callback.failure.apply(callback.scope, [responseObject]);
2830                             }
2831                         }
2832                         break;
2833                     default:
2834                         responseObject = this.createResponseObject(o, callback.argument);
2835                         if (callback.failure) {
2836                             if (!callback.scope) {
2837                                 callback.failure(responseObject);
2838                             }
2839                             else {
2840                                 callback.failure.apply(callback.scope, [responseObject]);
2841                             }
2842                         }
2843                 }
2844             }
2845
2846             this.releaseObject(o);
2847             responseObject = null;
2848         },
2849
2850         createResponseObject:function(o, callbackArg)
2851         {
2852             var obj = {};
2853             var headerObj = {};
2854
2855             try
2856             {
2857                 var headerStr = o.conn.getAllResponseHeaders();
2858                 var header = headerStr.split('\n');
2859                 for (var i = 0; i < header.length; i++) {
2860                     var delimitPos = header[i].indexOf(':');
2861                     if (delimitPos != -1) {
2862                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2863                     }
2864                 }
2865             }
2866             catch(e) {
2867             }
2868
2869             obj.tId = o.tId;
2870             obj.status = o.conn.status;
2871             obj.statusText = o.conn.statusText;
2872             obj.getResponseHeader = headerObj;
2873             obj.getAllResponseHeaders = headerStr;
2874             obj.responseText = o.conn.responseText;
2875             obj.responseXML = o.conn.responseXML;
2876
2877             if (typeof callbackArg !== undefined) {
2878                 obj.argument = callbackArg;
2879             }
2880
2881             return obj;
2882         },
2883
2884         createExceptionObject:function(tId, callbackArg, isAbort)
2885         {
2886             var COMM_CODE = 0;
2887             var COMM_ERROR = 'communication failure';
2888             var ABORT_CODE = -1;
2889             var ABORT_ERROR = 'transaction aborted';
2890
2891             var obj = {};
2892
2893             obj.tId = tId;
2894             if (isAbort) {
2895                 obj.status = ABORT_CODE;
2896                 obj.statusText = ABORT_ERROR;
2897             }
2898             else {
2899                 obj.status = COMM_CODE;
2900                 obj.statusText = COMM_ERROR;
2901             }
2902
2903             if (callbackArg) {
2904                 obj.argument = callbackArg;
2905             }
2906
2907             return obj;
2908         },
2909
2910         initHeader:function(label, value, isDefault)
2911         {
2912             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2913
2914             if (headerObj[label] === undefined) {
2915                 headerObj[label] = value;
2916             }
2917             else {
2918
2919
2920                 headerObj[label] = value + "," + headerObj[label];
2921             }
2922
2923             if (isDefault) {
2924                 this.hasDefaultHeaders = true;
2925             }
2926             else {
2927                 this.hasHeaders = true;
2928             }
2929         },
2930
2931
2932         setHeader:function(o)
2933         {
2934             if (this.hasDefaultHeaders) {
2935                 for (var prop in this.defaultHeaders) {
2936                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2937                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2938                     }
2939                 }
2940             }
2941
2942             if (this.hasHeaders) {
2943                 for (var prop in this.headers) {
2944                     if (this.headers.hasOwnProperty(prop)) {
2945                         o.conn.setRequestHeader(prop, this.headers[prop]);
2946                     }
2947                 }
2948                 this.headers = {};
2949                 this.hasHeaders = false;
2950             }
2951         },
2952
2953         resetDefaultHeaders:function() {
2954             delete this.defaultHeaders;
2955             this.defaultHeaders = {};
2956             this.hasDefaultHeaders = false;
2957         },
2958
2959         abort:function(o, callback, isTimeout)
2960         {
2961             if(this.isCallInProgress(o)) {
2962                 o.conn.abort();
2963                 window.clearInterval(this.poll[o.tId]);
2964                 delete this.poll[o.tId];
2965                 if (isTimeout) {
2966                     delete this.timeout[o.tId];
2967                 }
2968
2969                 this.handleTransactionResponse(o, callback, true);
2970
2971                 return true;
2972             }
2973             else {
2974                 return false;
2975             }
2976         },
2977
2978
2979         isCallInProgress:function(o)
2980         {
2981             if (o && o.conn) {
2982                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2983             }
2984             else {
2985
2986                 return false;
2987             }
2988         },
2989
2990
2991         releaseObject:function(o)
2992         {
2993
2994             o.conn = null;
2995
2996             o = null;
2997         },
2998
2999         activeX:[
3000         'MSXML2.XMLHTTP.3.0',
3001         'MSXML2.XMLHTTP',
3002         'Microsoft.XMLHTTP'
3003         ]
3004
3005
3006     };
3007 })();/*
3008  * Portions of this file are based on pieces of Yahoo User Interface Library
3009  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3010  * YUI licensed under the BSD License:
3011  * http://developer.yahoo.net/yui/license.txt
3012  * <script type="text/javascript">
3013  *
3014  */
3015
3016 Roo.lib.Region = function(t, r, b, l) {
3017     this.top = t;
3018     this[1] = t;
3019     this.right = r;
3020     this.bottom = b;
3021     this.left = l;
3022     this[0] = l;
3023 };
3024
3025
3026 Roo.lib.Region.prototype = {
3027     contains : function(region) {
3028         return ( region.left >= this.left &&
3029                  region.right <= this.right &&
3030                  region.top >= this.top &&
3031                  region.bottom <= this.bottom    );
3032
3033     },
3034
3035     getArea : function() {
3036         return ( (this.bottom - this.top) * (this.right - this.left) );
3037     },
3038
3039     intersect : function(region) {
3040         var t = Math.max(this.top, region.top);
3041         var r = Math.min(this.right, region.right);
3042         var b = Math.min(this.bottom, region.bottom);
3043         var l = Math.max(this.left, region.left);
3044
3045         if (b >= t && r >= l) {
3046             return new Roo.lib.Region(t, r, b, l);
3047         } else {
3048             return null;
3049         }
3050     },
3051     union : function(region) {
3052         var t = Math.min(this.top, region.top);
3053         var r = Math.max(this.right, region.right);
3054         var b = Math.max(this.bottom, region.bottom);
3055         var l = Math.min(this.left, region.left);
3056
3057         return new Roo.lib.Region(t, r, b, l);
3058     },
3059
3060     adjust : function(t, l, b, r) {
3061         this.top += t;
3062         this.left += l;
3063         this.right += r;
3064         this.bottom += b;
3065         return this;
3066     }
3067 };
3068
3069 Roo.lib.Region.getRegion = function(el) {
3070     var p = Roo.lib.Dom.getXY(el);
3071
3072     var t = p[1];
3073     var r = p[0] + el.offsetWidth;
3074     var b = p[1] + el.offsetHeight;
3075     var l = p[0];
3076
3077     return new Roo.lib.Region(t, r, b, l);
3078 };
3079 /*
3080  * Portions of this file are based on pieces of Yahoo User Interface Library
3081  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3082  * YUI licensed under the BSD License:
3083  * http://developer.yahoo.net/yui/license.txt
3084  * <script type="text/javascript">
3085  *
3086  */
3087 //@@dep Roo.lib.Region
3088
3089
3090 Roo.lib.Point = function(x, y) {
3091     if (x instanceof Array) {
3092         y = x[1];
3093         x = x[0];
3094     }
3095     this.x = this.right = this.left = this[0] = x;
3096     this.y = this.top = this.bottom = this[1] = y;
3097 };
3098
3099 Roo.lib.Point.prototype = new Roo.lib.Region();
3100 /*
3101  * Portions of this file are based on pieces of Yahoo User Interface Library
3102  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3103  * YUI licensed under the BSD License:
3104  * http://developer.yahoo.net/yui/license.txt
3105  * <script type="text/javascript">
3106  *
3107  */
3108  
3109 (function() {   
3110
3111     Roo.lib.Anim = {
3112         scroll : function(el, args, duration, easing, cb, scope) {
3113             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3114         },
3115
3116         motion : function(el, args, duration, easing, cb, scope) {
3117             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3118         },
3119
3120         color : function(el, args, duration, easing, cb, scope) {
3121             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3122         },
3123
3124         run : function(el, args, duration, easing, cb, scope, type) {
3125             type = type || Roo.lib.AnimBase;
3126             if (typeof easing == "string") {
3127                 easing = Roo.lib.Easing[easing];
3128             }
3129             var anim = new type(el, args, duration, easing);
3130             anim.animateX(function() {
3131                 Roo.callback(cb, scope);
3132             });
3133             return anim;
3134         }
3135     };
3136 })();/*
3137  * Portions of this file are based on pieces of Yahoo User Interface Library
3138  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3139  * YUI licensed under the BSD License:
3140  * http://developer.yahoo.net/yui/license.txt
3141  * <script type="text/javascript">
3142  *
3143  */
3144
3145 (function() {    
3146     var libFlyweight;
3147     
3148     function fly(el) {
3149         if (!libFlyweight) {
3150             libFlyweight = new Roo.Element.Flyweight();
3151         }
3152         libFlyweight.dom = el;
3153         return libFlyweight;
3154     }
3155
3156     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3157     
3158    
3159     
3160     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3161         if (el) {
3162             this.init(el, attributes, duration, method);
3163         }
3164     };
3165
3166     Roo.lib.AnimBase.fly = fly;
3167     
3168     
3169     
3170     Roo.lib.AnimBase.prototype = {
3171
3172         toString: function() {
3173             var el = this.getEl();
3174             var id = el.id || el.tagName;
3175             return ("Anim " + id);
3176         },
3177
3178         patterns: {
3179             noNegatives:        /width|height|opacity|padding/i,
3180             offsetAttribute:  /^((width|height)|(top|left))$/,
3181             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3182             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3183         },
3184
3185
3186         doMethod: function(attr, start, end) {
3187             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3188         },
3189
3190
3191         setAttribute: function(attr, val, unit) {
3192             if (this.patterns.noNegatives.test(attr)) {
3193                 val = (val > 0) ? val : 0;
3194             }
3195
3196             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3197         },
3198
3199
3200         getAttribute: function(attr) {
3201             var el = this.getEl();
3202             var val = fly(el).getStyle(attr);
3203
3204             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3205                 return parseFloat(val);
3206             }
3207
3208             var a = this.patterns.offsetAttribute.exec(attr) || [];
3209             var pos = !!( a[3] );
3210             var box = !!( a[2] );
3211
3212
3213             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3214                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3215             } else {
3216                 val = 0;
3217             }
3218
3219             return val;
3220         },
3221
3222
3223         getDefaultUnit: function(attr) {
3224             if (this.patterns.defaultUnit.test(attr)) {
3225                 return 'px';
3226             }
3227
3228             return '';
3229         },
3230
3231         animateX : function(callback, scope) {
3232             var f = function() {
3233                 this.onComplete.removeListener(f);
3234                 if (typeof callback == "function") {
3235                     callback.call(scope || this, this);
3236                 }
3237             };
3238             this.onComplete.addListener(f, this);
3239             this.animate();
3240         },
3241
3242
3243         setRuntimeAttribute: function(attr) {
3244             var start;
3245             var end;
3246             var attributes = this.attributes;
3247
3248             this.runtimeAttributes[attr] = {};
3249
3250             var isset = function(prop) {
3251                 return (typeof prop !== 'undefined');
3252             };
3253
3254             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3255                 return false;
3256             }
3257
3258             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3259
3260
3261             if (isset(attributes[attr]['to'])) {
3262                 end = attributes[attr]['to'];
3263             } else if (isset(attributes[attr]['by'])) {
3264                 if (start.constructor == Array) {
3265                     end = [];
3266                     for (var i = 0, len = start.length; i < len; ++i) {
3267                         end[i] = start[i] + attributes[attr]['by'][i];
3268                     }
3269                 } else {
3270                     end = start + attributes[attr]['by'];
3271                 }
3272             }
3273
3274             this.runtimeAttributes[attr].start = start;
3275             this.runtimeAttributes[attr].end = end;
3276
3277
3278             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3279         },
3280
3281
3282         init: function(el, attributes, duration, method) {
3283
3284             var isAnimated = false;
3285
3286
3287             var startTime = null;
3288
3289
3290             var actualFrames = 0;
3291
3292
3293             el = Roo.getDom(el);
3294
3295
3296             this.attributes = attributes || {};
3297
3298
3299             this.duration = duration || 1;
3300
3301
3302             this.method = method || Roo.lib.Easing.easeNone;
3303
3304
3305             this.useSeconds = true;
3306
3307
3308             this.currentFrame = 0;
3309
3310
3311             this.totalFrames = Roo.lib.AnimMgr.fps;
3312
3313
3314             this.getEl = function() {
3315                 return el;
3316             };
3317
3318
3319             this.isAnimated = function() {
3320                 return isAnimated;
3321             };
3322
3323
3324             this.getStartTime = function() {
3325                 return startTime;
3326             };
3327
3328             this.runtimeAttributes = {};
3329
3330
3331             this.animate = function() {
3332                 if (this.isAnimated()) {
3333                     return false;
3334                 }
3335
3336                 this.currentFrame = 0;
3337
3338                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3339
3340                 Roo.lib.AnimMgr.registerElement(this);
3341             };
3342
3343
3344             this.stop = function(finish) {
3345                 if (finish) {
3346                     this.currentFrame = this.totalFrames;
3347                     this._onTween.fire();
3348                 }
3349                 Roo.lib.AnimMgr.stop(this);
3350             };
3351
3352             var onStart = function() {
3353                 this.onStart.fire();
3354
3355                 this.runtimeAttributes = {};
3356                 for (var attr in this.attributes) {
3357                     this.setRuntimeAttribute(attr);
3358                 }
3359
3360                 isAnimated = true;
3361                 actualFrames = 0;
3362                 startTime = new Date();
3363             };
3364
3365
3366             var onTween = function() {
3367                 var data = {
3368                     duration: new Date() - this.getStartTime(),
3369                     currentFrame: this.currentFrame
3370                 };
3371
3372                 data.toString = function() {
3373                     return (
3374                             'duration: ' + data.duration +
3375                             ', currentFrame: ' + data.currentFrame
3376                             );
3377                 };
3378
3379                 this.onTween.fire(data);
3380
3381                 var runtimeAttributes = this.runtimeAttributes;
3382
3383                 for (var attr in runtimeAttributes) {
3384                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3385                 }
3386
3387                 actualFrames += 1;
3388             };
3389
3390             var onComplete = function() {
3391                 var actual_duration = (new Date() - startTime) / 1000 ;
3392
3393                 var data = {
3394                     duration: actual_duration,
3395                     frames: actualFrames,
3396                     fps: actualFrames / actual_duration
3397                 };
3398
3399                 data.toString = function() {
3400                     return (
3401                             'duration: ' + data.duration +
3402                             ', frames: ' + data.frames +
3403                             ', fps: ' + data.fps
3404                             );
3405                 };
3406
3407                 isAnimated = false;
3408                 actualFrames = 0;
3409                 this.onComplete.fire(data);
3410             };
3411
3412
3413             this._onStart = new Roo.util.Event(this);
3414             this.onStart = new Roo.util.Event(this);
3415             this.onTween = new Roo.util.Event(this);
3416             this._onTween = new Roo.util.Event(this);
3417             this.onComplete = new Roo.util.Event(this);
3418             this._onComplete = new Roo.util.Event(this);
3419             this._onStart.addListener(onStart);
3420             this._onTween.addListener(onTween);
3421             this._onComplete.addListener(onComplete);
3422         }
3423     };
3424 })();
3425 /*
3426  * Portions of this file are based on pieces of Yahoo User Interface Library
3427  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3428  * YUI licensed under the BSD License:
3429  * http://developer.yahoo.net/yui/license.txt
3430  * <script type="text/javascript">
3431  *
3432  */
3433
3434 Roo.lib.AnimMgr = new function() {
3435
3436     var thread = null;
3437
3438
3439     var queue = [];
3440
3441
3442     var tweenCount = 0;
3443
3444
3445     this.fps = 1000;
3446
3447
3448     this.delay = 1;
3449
3450
3451     this.registerElement = function(tween) {
3452         queue[queue.length] = tween;
3453         tweenCount += 1;
3454         tween._onStart.fire();
3455         this.start();
3456     };
3457
3458
3459     this.unRegister = function(tween, index) {
3460         tween._onComplete.fire();
3461         index = index || getIndex(tween);
3462         if (index != -1) {
3463             queue.splice(index, 1);
3464         }
3465
3466         tweenCount -= 1;
3467         if (tweenCount <= 0) {
3468             this.stop();
3469         }
3470     };
3471
3472
3473     this.start = function() {
3474         if (thread === null) {
3475             thread = setInterval(this.run, this.delay);
3476         }
3477     };
3478
3479
3480     this.stop = function(tween) {
3481         if (!tween) {
3482             clearInterval(thread);
3483
3484             for (var i = 0, len = queue.length; i < len; ++i) {
3485                 if (queue[0].isAnimated()) {
3486                     this.unRegister(queue[0], 0);
3487                 }
3488             }
3489
3490             queue = [];
3491             thread = null;
3492             tweenCount = 0;
3493         }
3494         else {
3495             this.unRegister(tween);
3496         }
3497     };
3498
3499
3500     this.run = function() {
3501         for (var i = 0, len = queue.length; i < len; ++i) {
3502             var tween = queue[i];
3503             if (!tween || !tween.isAnimated()) {
3504                 continue;
3505             }
3506
3507             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3508             {
3509                 tween.currentFrame += 1;
3510
3511                 if (tween.useSeconds) {
3512                     correctFrame(tween);
3513                 }
3514                 tween._onTween.fire();
3515             }
3516             else {
3517                 Roo.lib.AnimMgr.stop(tween, i);
3518             }
3519         }
3520     };
3521
3522     var getIndex = function(anim) {
3523         for (var i = 0, len = queue.length; i < len; ++i) {
3524             if (queue[i] == anim) {
3525                 return i;
3526             }
3527         }
3528         return -1;
3529     };
3530
3531
3532     var correctFrame = function(tween) {
3533         var frames = tween.totalFrames;
3534         var frame = tween.currentFrame;
3535         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3536         var elapsed = (new Date() - tween.getStartTime());
3537         var tweak = 0;
3538
3539         if (elapsed < tween.duration * 1000) {
3540             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3541         } else {
3542             tweak = frames - (frame + 1);
3543         }
3544         if (tweak > 0 && isFinite(tweak)) {
3545             if (tween.currentFrame + tweak >= frames) {
3546                 tweak = frames - (frame + 1);
3547             }
3548
3549             tween.currentFrame += tweak;
3550         }
3551     };
3552 };
3553
3554     /*
3555  * Portions of this file are based on pieces of Yahoo User Interface Library
3556  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3557  * YUI licensed under the BSD License:
3558  * http://developer.yahoo.net/yui/license.txt
3559  * <script type="text/javascript">
3560  *
3561  */
3562 Roo.lib.Bezier = new function() {
3563
3564         this.getPosition = function(points, t) {
3565             var n = points.length;
3566             var tmp = [];
3567
3568             for (var i = 0; i < n; ++i) {
3569                 tmp[i] = [points[i][0], points[i][1]];
3570             }
3571
3572             for (var j = 1; j < n; ++j) {
3573                 for (i = 0; i < n - j; ++i) {
3574                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3575                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3576                 }
3577             }
3578
3579             return [ tmp[0][0], tmp[0][1] ];
3580
3581         };
3582     };/*
3583  * Portions of this file are based on pieces of Yahoo User Interface Library
3584  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3585  * YUI licensed under the BSD License:
3586  * http://developer.yahoo.net/yui/license.txt
3587  * <script type="text/javascript">
3588  *
3589  */
3590 (function() {
3591
3592     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3593         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3594     };
3595
3596     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3597
3598     var fly = Roo.lib.AnimBase.fly;
3599     var Y = Roo.lib;
3600     var superclass = Y.ColorAnim.superclass;
3601     var proto = Y.ColorAnim.prototype;
3602
3603     proto.toString = function() {
3604         var el = this.getEl();
3605         var id = el.id || el.tagName;
3606         return ("ColorAnim " + id);
3607     };
3608
3609     proto.patterns.color = /color$/i;
3610     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3611     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3612     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3613     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3614
3615
3616     proto.parseColor = function(s) {
3617         if (s.length == 3) {
3618             return s;
3619         }
3620
3621         var c = this.patterns.hex.exec(s);
3622         if (c && c.length == 4) {
3623             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3624         }
3625
3626         c = this.patterns.rgb.exec(s);
3627         if (c && c.length == 4) {
3628             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3629         }
3630
3631         c = this.patterns.hex3.exec(s);
3632         if (c && c.length == 4) {
3633             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3634         }
3635
3636         return null;
3637     };
3638     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3639     proto.getAttribute = function(attr) {
3640         var el = this.getEl();
3641         if (this.patterns.color.test(attr)) {
3642             var val = fly(el).getStyle(attr);
3643
3644             if (this.patterns.transparent.test(val)) {
3645                 var parent = el.parentNode;
3646                 val = fly(parent).getStyle(attr);
3647
3648                 while (parent && this.patterns.transparent.test(val)) {
3649                     parent = parent.parentNode;
3650                     val = fly(parent).getStyle(attr);
3651                     if (parent.tagName.toUpperCase() == 'HTML') {
3652                         val = '#fff';
3653                     }
3654                 }
3655             }
3656         } else {
3657             val = superclass.getAttribute.call(this, attr);
3658         }
3659
3660         return val;
3661     };
3662     proto.getAttribute = function(attr) {
3663         var el = this.getEl();
3664         if (this.patterns.color.test(attr)) {
3665             var val = fly(el).getStyle(attr);
3666
3667             if (this.patterns.transparent.test(val)) {
3668                 var parent = el.parentNode;
3669                 val = fly(parent).getStyle(attr);
3670
3671                 while (parent && this.patterns.transparent.test(val)) {
3672                     parent = parent.parentNode;
3673                     val = fly(parent).getStyle(attr);
3674                     if (parent.tagName.toUpperCase() == 'HTML') {
3675                         val = '#fff';
3676                     }
3677                 }
3678             }
3679         } else {
3680             val = superclass.getAttribute.call(this, attr);
3681         }
3682
3683         return val;
3684     };
3685
3686     proto.doMethod = function(attr, start, end) {
3687         var val;
3688
3689         if (this.patterns.color.test(attr)) {
3690             val = [];
3691             for (var i = 0, len = start.length; i < len; ++i) {
3692                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3693             }
3694
3695             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3696         }
3697         else {
3698             val = superclass.doMethod.call(this, attr, start, end);
3699         }
3700
3701         return val;
3702     };
3703
3704     proto.setRuntimeAttribute = function(attr) {
3705         superclass.setRuntimeAttribute.call(this, attr);
3706
3707         if (this.patterns.color.test(attr)) {
3708             var attributes = this.attributes;
3709             var start = this.parseColor(this.runtimeAttributes[attr].start);
3710             var end = this.parseColor(this.runtimeAttributes[attr].end);
3711
3712             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3713                 end = this.parseColor(attributes[attr].by);
3714
3715                 for (var i = 0, len = start.length; i < len; ++i) {
3716                     end[i] = start[i] + end[i];
3717                 }
3718             }
3719
3720             this.runtimeAttributes[attr].start = start;
3721             this.runtimeAttributes[attr].end = end;
3722         }
3723     };
3724 })();
3725
3726 /*
3727  * Portions of this file are based on pieces of Yahoo User Interface Library
3728  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3729  * YUI licensed under the BSD License:
3730  * http://developer.yahoo.net/yui/license.txt
3731  * <script type="text/javascript">
3732  *
3733  */
3734 Roo.lib.Easing = {
3735
3736
3737     easeNone: function (t, b, c, d) {
3738         return c * t / d + b;
3739     },
3740
3741
3742     easeIn: function (t, b, c, d) {
3743         return c * (t /= d) * t + b;
3744     },
3745
3746
3747     easeOut: function (t, b, c, d) {
3748         return -c * (t /= d) * (t - 2) + b;
3749     },
3750
3751
3752     easeBoth: function (t, b, c, d) {
3753         if ((t /= d / 2) < 1) {
3754             return c / 2 * t * t + b;
3755         }
3756
3757         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3758     },
3759
3760
3761     easeInStrong: function (t, b, c, d) {
3762         return c * (t /= d) * t * t * t + b;
3763     },
3764
3765
3766     easeOutStrong: function (t, b, c, d) {
3767         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3768     },
3769
3770
3771     easeBothStrong: function (t, b, c, d) {
3772         if ((t /= d / 2) < 1) {
3773             return c / 2 * t * t * t * t + b;
3774         }
3775
3776         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3777     },
3778
3779
3780
3781     elasticIn: function (t, b, c, d, a, p) {
3782         if (t == 0) {
3783             return b;
3784         }
3785         if ((t /= d) == 1) {
3786             return b + c;
3787         }
3788         if (!p) {
3789             p = d * .3;
3790         }
3791
3792         if (!a || a < Math.abs(c)) {
3793             a = c;
3794             var s = p / 4;
3795         }
3796         else {
3797             var s = p / (2 * Math.PI) * Math.asin(c / a);
3798         }
3799
3800         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3801     },
3802
3803
3804     elasticOut: function (t, b, c, d, a, p) {
3805         if (t == 0) {
3806             return b;
3807         }
3808         if ((t /= d) == 1) {
3809             return b + c;
3810         }
3811         if (!p) {
3812             p = d * .3;
3813         }
3814
3815         if (!a || a < Math.abs(c)) {
3816             a = c;
3817             var s = p / 4;
3818         }
3819         else {
3820             var s = p / (2 * Math.PI) * Math.asin(c / a);
3821         }
3822
3823         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3824     },
3825
3826
3827     elasticBoth: function (t, b, c, d, a, p) {
3828         if (t == 0) {
3829             return b;
3830         }
3831
3832         if ((t /= d / 2) == 2) {
3833             return b + c;
3834         }
3835
3836         if (!p) {
3837             p = d * (.3 * 1.5);
3838         }
3839
3840         if (!a || a < Math.abs(c)) {
3841             a = c;
3842             var s = p / 4;
3843         }
3844         else {
3845             var s = p / (2 * Math.PI) * Math.asin(c / a);
3846         }
3847
3848         if (t < 1) {
3849             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3850                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3851         }
3852         return a * Math.pow(2, -10 * (t -= 1)) *
3853                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3854     },
3855
3856
3857
3858     backIn: function (t, b, c, d, s) {
3859         if (typeof s == 'undefined') {
3860             s = 1.70158;
3861         }
3862         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3863     },
3864
3865
3866     backOut: function (t, b, c, d, s) {
3867         if (typeof s == 'undefined') {
3868             s = 1.70158;
3869         }
3870         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3871     },
3872
3873
3874     backBoth: function (t, b, c, d, s) {
3875         if (typeof s == 'undefined') {
3876             s = 1.70158;
3877         }
3878
3879         if ((t /= d / 2 ) < 1) {
3880             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3881         }
3882         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3883     },
3884
3885
3886     bounceIn: function (t, b, c, d) {
3887         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3888     },
3889
3890
3891     bounceOut: function (t, b, c, d) {
3892         if ((t /= d) < (1 / 2.75)) {
3893             return c * (7.5625 * t * t) + b;
3894         } else if (t < (2 / 2.75)) {
3895             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3896         } else if (t < (2.5 / 2.75)) {
3897             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3898         }
3899         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3900     },
3901
3902
3903     bounceBoth: function (t, b, c, d) {
3904         if (t < d / 2) {
3905             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3906         }
3907         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3908     }
3909 };/*
3910  * Portions of this file are based on pieces of Yahoo User Interface Library
3911  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3912  * YUI licensed under the BSD License:
3913  * http://developer.yahoo.net/yui/license.txt
3914  * <script type="text/javascript">
3915  *
3916  */
3917     (function() {
3918         Roo.lib.Motion = function(el, attributes, duration, method) {
3919             if (el) {
3920                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3921             }
3922         };
3923
3924         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3925
3926
3927         var Y = Roo.lib;
3928         var superclass = Y.Motion.superclass;
3929         var proto = Y.Motion.prototype;
3930
3931         proto.toString = function() {
3932             var el = this.getEl();
3933             var id = el.id || el.tagName;
3934             return ("Motion " + id);
3935         };
3936
3937         proto.patterns.points = /^points$/i;
3938
3939         proto.setAttribute = function(attr, val, unit) {
3940             if (this.patterns.points.test(attr)) {
3941                 unit = unit || 'px';
3942                 superclass.setAttribute.call(this, 'left', val[0], unit);
3943                 superclass.setAttribute.call(this, 'top', val[1], unit);
3944             } else {
3945                 superclass.setAttribute.call(this, attr, val, unit);
3946             }
3947         };
3948
3949         proto.getAttribute = function(attr) {
3950             if (this.patterns.points.test(attr)) {
3951                 var val = [
3952                         superclass.getAttribute.call(this, 'left'),
3953                         superclass.getAttribute.call(this, 'top')
3954                         ];
3955             } else {
3956                 val = superclass.getAttribute.call(this, attr);
3957             }
3958
3959             return val;
3960         };
3961
3962         proto.doMethod = function(attr, start, end) {
3963             var val = null;
3964
3965             if (this.patterns.points.test(attr)) {
3966                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3967                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3968             } else {
3969                 val = superclass.doMethod.call(this, attr, start, end);
3970             }
3971             return val;
3972         };
3973
3974         proto.setRuntimeAttribute = function(attr) {
3975             if (this.patterns.points.test(attr)) {
3976                 var el = this.getEl();
3977                 var attributes = this.attributes;
3978                 var start;
3979                 var control = attributes['points']['control'] || [];
3980                 var end;
3981                 var i, len;
3982
3983                 if (control.length > 0 && !(control[0] instanceof Array)) {
3984                     control = [control];
3985                 } else {
3986                     var tmp = [];
3987                     for (i = 0,len = control.length; i < len; ++i) {
3988                         tmp[i] = control[i];
3989                     }
3990                     control = tmp;
3991                 }
3992
3993                 Roo.fly(el).position();
3994
3995                 if (isset(attributes['points']['from'])) {
3996                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3997                 }
3998                 else {
3999                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4000                 }
4001
4002                 start = this.getAttribute('points');
4003
4004
4005                 if (isset(attributes['points']['to'])) {
4006                     end = translateValues.call(this, attributes['points']['to'], start);
4007
4008                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4009                     for (i = 0,len = control.length; i < len; ++i) {
4010                         control[i] = translateValues.call(this, control[i], start);
4011                     }
4012
4013
4014                 } else if (isset(attributes['points']['by'])) {
4015                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4016
4017                     for (i = 0,len = control.length; i < len; ++i) {
4018                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4019                     }
4020                 }
4021
4022                 this.runtimeAttributes[attr] = [start];
4023
4024                 if (control.length > 0) {
4025                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4026                 }
4027
4028                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4029             }
4030             else {
4031                 superclass.setRuntimeAttribute.call(this, attr);
4032             }
4033         };
4034
4035         var translateValues = function(val, start) {
4036             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4037             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4038
4039             return val;
4040         };
4041
4042         var isset = function(prop) {
4043             return (typeof prop !== 'undefined');
4044         };
4045     })();
4046 /*
4047  * Portions of this file are based on pieces of Yahoo User Interface Library
4048  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4049  * YUI licensed under the BSD License:
4050  * http://developer.yahoo.net/yui/license.txt
4051  * <script type="text/javascript">
4052  *
4053  */
4054     (function() {
4055         Roo.lib.Scroll = function(el, attributes, duration, method) {
4056             if (el) {
4057                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4058             }
4059         };
4060
4061         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4062
4063
4064         var Y = Roo.lib;
4065         var superclass = Y.Scroll.superclass;
4066         var proto = Y.Scroll.prototype;
4067
4068         proto.toString = function() {
4069             var el = this.getEl();
4070             var id = el.id || el.tagName;
4071             return ("Scroll " + id);
4072         };
4073
4074         proto.doMethod = function(attr, start, end) {
4075             var val = null;
4076
4077             if (attr == 'scroll') {
4078                 val = [
4079                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4080                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4081                         ];
4082
4083             } else {
4084                 val = superclass.doMethod.call(this, attr, start, end);
4085             }
4086             return val;
4087         };
4088
4089         proto.getAttribute = function(attr) {
4090             var val = null;
4091             var el = this.getEl();
4092
4093             if (attr == 'scroll') {
4094                 val = [ el.scrollLeft, el.scrollTop ];
4095             } else {
4096                 val = superclass.getAttribute.call(this, attr);
4097             }
4098
4099             return val;
4100         };
4101
4102         proto.setAttribute = function(attr, val, unit) {
4103             var el = this.getEl();
4104
4105             if (attr == 'scroll') {
4106                 el.scrollLeft = val[0];
4107                 el.scrollTop = val[1];
4108             } else {
4109                 superclass.setAttribute.call(this, attr, val, unit);
4110             }
4111         };
4112     })();
4113 /*
4114  * Based on:
4115  * Ext JS Library 1.1.1
4116  * Copyright(c) 2006-2007, Ext JS, LLC.
4117  *
4118  * Originally Released Under LGPL - original licence link has changed is not relivant.
4119  *
4120  * Fork - LGPL
4121  * <script type="text/javascript">
4122  */
4123
4124
4125 // nasty IE9 hack - what a pile of crap that is..
4126
4127  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4128     Range.prototype.createContextualFragment = function (html) {
4129         var doc = window.document;
4130         var container = doc.createElement("div");
4131         container.innerHTML = html;
4132         var frag = doc.createDocumentFragment(), n;
4133         while ((n = container.firstChild)) {
4134             frag.appendChild(n);
4135         }
4136         return frag;
4137     };
4138 }
4139
4140 /**
4141  * @class Roo.DomHelper
4142  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4143  * 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>.
4144  * @singleton
4145  */
4146 Roo.DomHelper = function(){
4147     var tempTableEl = null;
4148     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4149     var tableRe = /^table|tbody|tr|td$/i;
4150     var xmlns = {};
4151     // build as innerHTML where available
4152     /** @ignore */
4153     var createHtml = function(o){
4154         if(typeof o == 'string'){
4155             return o;
4156         }
4157         var b = "";
4158         if(!o.tag){
4159             o.tag = "div";
4160         }
4161         b += "<" + o.tag;
4162         for(var attr in o){
4163             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4164             if(attr == "style"){
4165                 var s = o["style"];
4166                 if(typeof s == "function"){
4167                     s = s.call();
4168                 }
4169                 if(typeof s == "string"){
4170                     b += ' style="' + s + '"';
4171                 }else if(typeof s == "object"){
4172                     b += ' style="';
4173                     for(var key in s){
4174                         if(typeof s[key] != "function"){
4175                             b += key + ":" + s[key] + ";";
4176                         }
4177                     }
4178                     b += '"';
4179                 }
4180             }else{
4181                 if(attr == "cls"){
4182                     b += ' class="' + o["cls"] + '"';
4183                 }else if(attr == "htmlFor"){
4184                     b += ' for="' + o["htmlFor"] + '"';
4185                 }else{
4186                     b += " " + attr + '="' + o[attr] + '"';
4187                 }
4188             }
4189         }
4190         if(emptyTags.test(o.tag)){
4191             b += "/>";
4192         }else{
4193             b += ">";
4194             var cn = o.children || o.cn;
4195             if(cn){
4196                 //http://bugs.kde.org/show_bug.cgi?id=71506
4197                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198                     for(var i = 0, len = cn.length; i < len; i++) {
4199                         b += createHtml(cn[i], b);
4200                     }
4201                 }else{
4202                     b += createHtml(cn, b);
4203                 }
4204             }
4205             if(o.html){
4206                 b += o.html;
4207             }
4208             b += "</" + o.tag + ">";
4209         }
4210         return b;
4211     };
4212
4213     // build as dom
4214     /** @ignore */
4215     var createDom = function(o, parentNode){
4216          
4217         // defininition craeted..
4218         var ns = false;
4219         if (o.ns && o.ns != 'html') {
4220                
4221             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4222                 xmlns[o.ns] = o.xmlns;
4223                 ns = o.xmlns;
4224             }
4225             if (typeof(xmlns[o.ns]) == 'undefined') {
4226                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4227             }
4228             ns = xmlns[o.ns];
4229         }
4230         
4231         
4232         if (typeof(o) == 'string') {
4233             return parentNode.appendChild(document.createTextNode(o));
4234         }
4235         o.tag = o.tag || div;
4236         if (o.ns && Roo.isIE) {
4237             ns = false;
4238             o.tag = o.ns + ':' + o.tag;
4239             
4240         }
4241         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4242         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4243         for(var attr in o){
4244             
4245             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4246                     attr == "style" || typeof o[attr] == "function") { continue; }
4247                     
4248             if(attr=="cls" && Roo.isIE){
4249                 el.className = o["cls"];
4250             }else{
4251                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4252                 else { 
4253                     el[attr] = o[attr];
4254                 }
4255             }
4256         }
4257         Roo.DomHelper.applyStyles(el, o.style);
4258         var cn = o.children || o.cn;
4259         if(cn){
4260             //http://bugs.kde.org/show_bug.cgi?id=71506
4261              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4262                 for(var i = 0, len = cn.length; i < len; i++) {
4263                     createDom(cn[i], el);
4264                 }
4265             }else{
4266                 createDom(cn, el);
4267             }
4268         }
4269         if(o.html){
4270             el.innerHTML = o.html;
4271         }
4272         if(parentNode){
4273            parentNode.appendChild(el);
4274         }
4275         return el;
4276     };
4277
4278     var ieTable = function(depth, s, h, e){
4279         tempTableEl.innerHTML = [s, h, e].join('');
4280         var i = -1, el = tempTableEl;
4281         while(++i < depth){
4282             el = el.firstChild;
4283         }
4284         return el;
4285     };
4286
4287     // kill repeat to save bytes
4288     var ts = '<table>',
4289         te = '</table>',
4290         tbs = ts+'<tbody>',
4291         tbe = '</tbody>'+te,
4292         trs = tbs + '<tr>',
4293         tre = '</tr>'+tbe;
4294
4295     /**
4296      * @ignore
4297      * Nasty code for IE's broken table implementation
4298      */
4299     var insertIntoTable = function(tag, where, el, html){
4300         if(!tempTableEl){
4301             tempTableEl = document.createElement('div');
4302         }
4303         var node;
4304         var before = null;
4305         if(tag == 'td'){
4306             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4307                 return;
4308             }
4309             if(where == 'beforebegin'){
4310                 before = el;
4311                 el = el.parentNode;
4312             } else{
4313                 before = el.nextSibling;
4314                 el = el.parentNode;
4315             }
4316             node = ieTable(4, trs, html, tre);
4317         }
4318         else if(tag == 'tr'){
4319             if(where == 'beforebegin'){
4320                 before = el;
4321                 el = el.parentNode;
4322                 node = ieTable(3, tbs, html, tbe);
4323             } else if(where == 'afterend'){
4324                 before = el.nextSibling;
4325                 el = el.parentNode;
4326                 node = ieTable(3, tbs, html, tbe);
4327             } else{ // INTO a TR
4328                 if(where == 'afterbegin'){
4329                     before = el.firstChild;
4330                 }
4331                 node = ieTable(4, trs, html, tre);
4332             }
4333         } else if(tag == 'tbody'){
4334             if(where == 'beforebegin'){
4335                 before = el;
4336                 el = el.parentNode;
4337                 node = ieTable(2, ts, html, te);
4338             } else if(where == 'afterend'){
4339                 before = el.nextSibling;
4340                 el = el.parentNode;
4341                 node = ieTable(2, ts, html, te);
4342             } else{
4343                 if(where == 'afterbegin'){
4344                     before = el.firstChild;
4345                 }
4346                 node = ieTable(3, tbs, html, tbe);
4347             }
4348         } else{ // TABLE
4349             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4350                 return;
4351             }
4352             if(where == 'afterbegin'){
4353                 before = el.firstChild;
4354             }
4355             node = ieTable(2, ts, html, te);
4356         }
4357         el.insertBefore(node, before);
4358         return node;
4359     };
4360
4361     return {
4362     /** True to force the use of DOM instead of html fragments @type Boolean */
4363     useDom : false,
4364
4365     /**
4366      * Returns the markup for the passed Element(s) config
4367      * @param {Object} o The Dom object spec (and children)
4368      * @return {String}
4369      */
4370     markup : function(o){
4371         return createHtml(o);
4372     },
4373
4374     /**
4375      * Applies a style specification to an element
4376      * @param {String/HTMLElement} el The element to apply styles to
4377      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4378      * a function which returns such a specification.
4379      */
4380     applyStyles : function(el, styles){
4381         if(styles){
4382            el = Roo.fly(el);
4383            if(typeof styles == "string"){
4384                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4385                var matches;
4386                while ((matches = re.exec(styles)) != null){
4387                    el.setStyle(matches[1], matches[2]);
4388                }
4389            }else if (typeof styles == "object"){
4390                for (var style in styles){
4391                   el.setStyle(style, styles[style]);
4392                }
4393            }else if (typeof styles == "function"){
4394                 Roo.DomHelper.applyStyles(el, styles.call());
4395            }
4396         }
4397     },
4398
4399     /**
4400      * Inserts an HTML fragment into the Dom
4401      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4402      * @param {HTMLElement} el The context element
4403      * @param {String} html The HTML fragmenet
4404      * @return {HTMLElement} The new node
4405      */
4406     insertHtml : function(where, el, html){
4407         where = where.toLowerCase();
4408         if(el.insertAdjacentHTML){
4409             if(tableRe.test(el.tagName)){
4410                 var rs;
4411                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4412                     return rs;
4413                 }
4414             }
4415             switch(where){
4416                 case "beforebegin":
4417                     el.insertAdjacentHTML('BeforeBegin', html);
4418                     return el.previousSibling;
4419                 case "afterbegin":
4420                     el.insertAdjacentHTML('AfterBegin', html);
4421                     return el.firstChild;
4422                 case "beforeend":
4423                     el.insertAdjacentHTML('BeforeEnd', html);
4424                     return el.lastChild;
4425                 case "afterend":
4426                     el.insertAdjacentHTML('AfterEnd', html);
4427                     return el.nextSibling;
4428             }
4429             throw 'Illegal insertion point -> "' + where + '"';
4430         }
4431         var range = el.ownerDocument.createRange();
4432         var frag;
4433         switch(where){
4434              case "beforebegin":
4435                 range.setStartBefore(el);
4436                 frag = range.createContextualFragment(html);
4437                 el.parentNode.insertBefore(frag, el);
4438                 return el.previousSibling;
4439              case "afterbegin":
4440                 if(el.firstChild){
4441                     range.setStartBefore(el.firstChild);
4442                     frag = range.createContextualFragment(html);
4443                     el.insertBefore(frag, el.firstChild);
4444                     return el.firstChild;
4445                 }else{
4446                     el.innerHTML = html;
4447                     return el.firstChild;
4448                 }
4449             case "beforeend":
4450                 if(el.lastChild){
4451                     range.setStartAfter(el.lastChild);
4452                     frag = range.createContextualFragment(html);
4453                     el.appendChild(frag);
4454                     return el.lastChild;
4455                 }else{
4456                     el.innerHTML = html;
4457                     return el.lastChild;
4458                 }
4459             case "afterend":
4460                 range.setStartAfter(el);
4461                 frag = range.createContextualFragment(html);
4462                 el.parentNode.insertBefore(frag, el.nextSibling);
4463                 return el.nextSibling;
4464             }
4465             throw 'Illegal insertion point -> "' + where + '"';
4466     },
4467
4468     /**
4469      * Creates new Dom element(s) and inserts them before el
4470      * @param {String/HTMLElement/Element} el The context element
4471      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4472      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4473      * @return {HTMLElement/Roo.Element} The new node
4474      */
4475     insertBefore : function(el, o, returnElement){
4476         return this.doInsert(el, o, returnElement, "beforeBegin");
4477     },
4478
4479     /**
4480      * Creates new Dom element(s) and inserts them after el
4481      * @param {String/HTMLElement/Element} el The context element
4482      * @param {Object} o The Dom object spec (and children)
4483      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4484      * @return {HTMLElement/Roo.Element} The new node
4485      */
4486     insertAfter : function(el, o, returnElement){
4487         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4488     },
4489
4490     /**
4491      * Creates new Dom element(s) and inserts them as the first child of el
4492      * @param {String/HTMLElement/Element} el The context element
4493      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4494      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4495      * @return {HTMLElement/Roo.Element} The new node
4496      */
4497     insertFirst : function(el, o, returnElement){
4498         return this.doInsert(el, o, returnElement, "afterBegin");
4499     },
4500
4501     // private
4502     doInsert : function(el, o, returnElement, pos, sibling){
4503         el = Roo.getDom(el);
4504         var newNode;
4505         if(this.useDom || o.ns){
4506             newNode = createDom(o, null);
4507             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4508         }else{
4509             var html = createHtml(o);
4510             newNode = this.insertHtml(pos, el, html);
4511         }
4512         return returnElement ? Roo.get(newNode, true) : newNode;
4513     },
4514
4515     /**
4516      * Creates new Dom element(s) and appends them to el
4517      * @param {String/HTMLElement/Element} el The context element
4518      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4519      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4520      * @return {HTMLElement/Roo.Element} The new node
4521      */
4522     append : function(el, o, returnElement){
4523         el = Roo.getDom(el);
4524         var newNode;
4525         if(this.useDom || o.ns){
4526             newNode = createDom(o, null);
4527             el.appendChild(newNode);
4528         }else{
4529             var html = createHtml(o);
4530             newNode = this.insertHtml("beforeEnd", el, html);
4531         }
4532         return returnElement ? Roo.get(newNode, true) : newNode;
4533     },
4534
4535     /**
4536      * Creates new Dom element(s) and overwrites the contents of el with them
4537      * @param {String/HTMLElement/Element} el The context element
4538      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4539      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4540      * @return {HTMLElement/Roo.Element} The new node
4541      */
4542     overwrite : function(el, o, returnElement){
4543         el = Roo.getDom(el);
4544         if (o.ns) {
4545           
4546             while (el.childNodes.length) {
4547                 el.removeChild(el.firstChild);
4548             }
4549             createDom(o, el);
4550         } else {
4551             el.innerHTML = createHtml(o);   
4552         }
4553         
4554         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4555     },
4556
4557     /**
4558      * Creates a new Roo.DomHelper.Template from the Dom object spec
4559      * @param {Object} o The Dom object spec (and children)
4560      * @return {Roo.DomHelper.Template} The new template
4561      */
4562     createTemplate : function(o){
4563         var html = createHtml(o);
4564         return new Roo.Template(html);
4565     }
4566     };
4567 }();
4568 /*
4569  * Based on:
4570  * Ext JS Library 1.1.1
4571  * Copyright(c) 2006-2007, Ext JS, LLC.
4572  *
4573  * Originally Released Under LGPL - original licence link has changed is not relivant.
4574  *
4575  * Fork - LGPL
4576  * <script type="text/javascript">
4577  */
4578  
4579 /**
4580 * @class Roo.Template
4581 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4582 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4583 * Usage:
4584 <pre><code>
4585 var t = new Roo.Template({
4586     html :  '&lt;div name="{id}"&gt;' + 
4587         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4588         '&lt;/div&gt;',
4589     myformat: function (value, allValues) {
4590         return 'XX' + value;
4591     }
4592 });
4593 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4594 </code></pre>
4595 * For more information see this blog post with examples:
4596 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4597      - Create Elements using DOM, HTML fragments and Templates</a>. 
4598 * @constructor
4599 * @param {Object} cfg - Configuration object.
4600 */
4601 Roo.Template = function(cfg){
4602     // BC!
4603     if(cfg instanceof Array){
4604         cfg = cfg.join("");
4605     }else if(arguments.length > 1){
4606         cfg = Array.prototype.join.call(arguments, "");
4607     }
4608     
4609     
4610     if (typeof(cfg) == 'object') {
4611         Roo.apply(this,cfg)
4612     } else {
4613         // bc
4614         this.html = cfg;
4615     }
4616     if (this.url) {
4617         this.load();
4618     }
4619     
4620 };
4621 Roo.Template.prototype = {
4622     
4623     /**
4624      * @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..
4625      *                    it should be fixed so that template is observable...
4626      */
4627     url : false,
4628     /**
4629      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4630      */
4631     html : '',
4632     /**
4633      * Returns an HTML fragment of this template with the specified values applied.
4634      * @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'})
4635      * @return {String} The HTML fragment
4636      */
4637     applyTemplate : function(values){
4638         try {
4639            
4640             if(this.compiled){
4641                 return this.compiled(values);
4642             }
4643             var useF = this.disableFormats !== true;
4644             var fm = Roo.util.Format, tpl = this;
4645             var fn = function(m, name, format, args){
4646                 if(format && useF){
4647                     if(format.substr(0, 5) == "this."){
4648                         return tpl.call(format.substr(5), values[name], values);
4649                     }else{
4650                         if(args){
4651                             // quoted values are required for strings in compiled templates, 
4652                             // but for non compiled we need to strip them
4653                             // quoted reversed for jsmin
4654                             var re = /^\s*['"](.*)["']\s*$/;
4655                             args = args.split(',');
4656                             for(var i = 0, len = args.length; i < len; i++){
4657                                 args[i] = args[i].replace(re, "$1");
4658                             }
4659                             args = [values[name]].concat(args);
4660                         }else{
4661                             args = [values[name]];
4662                         }
4663                         return fm[format].apply(fm, args);
4664                     }
4665                 }else{
4666                     return values[name] !== undefined ? values[name] : "";
4667                 }
4668             };
4669             return this.html.replace(this.re, fn);
4670         } catch (e) {
4671             Roo.log(e);
4672             throw e;
4673         }
4674          
4675     },
4676     
4677     loading : false,
4678       
4679     load : function ()
4680     {
4681          
4682         if (this.loading) {
4683             return;
4684         }
4685         var _t = this;
4686         
4687         this.loading = true;
4688         this.compiled = false;
4689         
4690         var cx = new Roo.data.Connection();
4691         cx.request({
4692             url : this.url,
4693             method : 'GET',
4694             success : function (response) {
4695                 _t.loading = false;
4696                 _t.html = response.responseText;
4697                 _t.url = false;
4698                 _t.compile();
4699              },
4700             failure : function(response) {
4701                 Roo.log("Template failed to load from " + _t.url);
4702                 _t.loading = false;
4703             }
4704         });
4705     },
4706
4707     /**
4708      * Sets the HTML used as the template and optionally compiles it.
4709      * @param {String} html
4710      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4711      * @return {Roo.Template} this
4712      */
4713     set : function(html, compile){
4714         this.html = html;
4715         this.compiled = null;
4716         if(compile){
4717             this.compile();
4718         }
4719         return this;
4720     },
4721     
4722     /**
4723      * True to disable format functions (defaults to false)
4724      * @type Boolean
4725      */
4726     disableFormats : false,
4727     
4728     /**
4729     * The regular expression used to match template variables 
4730     * @type RegExp
4731     * @property 
4732     */
4733     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4734     
4735     /**
4736      * Compiles the template into an internal function, eliminating the RegEx overhead.
4737      * @return {Roo.Template} this
4738      */
4739     compile : function(){
4740         var fm = Roo.util.Format;
4741         var useF = this.disableFormats !== true;
4742         var sep = Roo.isGecko ? "+" : ",";
4743         var fn = function(m, name, format, args){
4744             if(format && useF){
4745                 args = args ? ',' + args : "";
4746                 if(format.substr(0, 5) != "this."){
4747                     format = "fm." + format + '(';
4748                 }else{
4749                     format = 'this.call("'+ format.substr(5) + '", ';
4750                     args = ", values";
4751                 }
4752             }else{
4753                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4754             }
4755             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4756         };
4757         var body;
4758         // branched to use + in gecko and [].join() in others
4759         if(Roo.isGecko){
4760             body = "this.compiled = function(values){ return '" +
4761                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4762                     "';};";
4763         }else{
4764             body = ["this.compiled = function(values){ return ['"];
4765             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4766             body.push("'].join('');};");
4767             body = body.join('');
4768         }
4769         /**
4770          * eval:var:values
4771          * eval:var:fm
4772          */
4773         eval(body);
4774         return this;
4775     },
4776     
4777     // private function used to call members
4778     call : function(fnName, value, allValues){
4779         return this[fnName](value, allValues);
4780     },
4781     
4782     /**
4783      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4784      * @param {String/HTMLElement/Roo.Element} el The context element
4785      * @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'})
4786      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4787      * @return {HTMLElement/Roo.Element} The new node or Element
4788      */
4789     insertFirst: function(el, values, returnElement){
4790         return this.doInsert('afterBegin', el, values, returnElement);
4791     },
4792
4793     /**
4794      * Applies the supplied values to the template and inserts the new node(s) before el.
4795      * @param {String/HTMLElement/Roo.Element} el The context element
4796      * @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'})
4797      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4798      * @return {HTMLElement/Roo.Element} The new node or Element
4799      */
4800     insertBefore: function(el, values, returnElement){
4801         return this.doInsert('beforeBegin', el, values, returnElement);
4802     },
4803
4804     /**
4805      * Applies the supplied values to the template and inserts the new node(s) after el.
4806      * @param {String/HTMLElement/Roo.Element} el The context element
4807      * @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'})
4808      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4809      * @return {HTMLElement/Roo.Element} The new node or Element
4810      */
4811     insertAfter : function(el, values, returnElement){
4812         return this.doInsert('afterEnd', el, values, returnElement);
4813     },
4814     
4815     /**
4816      * Applies the supplied values to the template and appends the new node(s) to el.
4817      * @param {String/HTMLElement/Roo.Element} el The context element
4818      * @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'})
4819      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4820      * @return {HTMLElement/Roo.Element} The new node or Element
4821      */
4822     append : function(el, values, returnElement){
4823         return this.doInsert('beforeEnd', el, values, returnElement);
4824     },
4825
4826     doInsert : function(where, el, values, returnEl){
4827         el = Roo.getDom(el);
4828         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4829         return returnEl ? Roo.get(newNode, true) : newNode;
4830     },
4831
4832     /**
4833      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4834      * @param {String/HTMLElement/Roo.Element} el The context element
4835      * @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'})
4836      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4837      * @return {HTMLElement/Roo.Element} The new node or Element
4838      */
4839     overwrite : function(el, values, returnElement){
4840         el = Roo.getDom(el);
4841         el.innerHTML = this.applyTemplate(values);
4842         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4843     }
4844 };
4845 /**
4846  * Alias for {@link #applyTemplate}
4847  * @method
4848  */
4849 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4850
4851 // backwards compat
4852 Roo.DomHelper.Template = Roo.Template;
4853
4854 /**
4855  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4856  * @param {String/HTMLElement} el A DOM element or its id
4857  * @returns {Roo.Template} The created template
4858  * @static
4859  */
4860 Roo.Template.from = function(el){
4861     el = Roo.getDom(el);
4862     return new Roo.Template(el.value || el.innerHTML);
4863 };/*
4864  * Based on:
4865  * Ext JS Library 1.1.1
4866  * Copyright(c) 2006-2007, Ext JS, LLC.
4867  *
4868  * Originally Released Under LGPL - original licence link has changed is not relivant.
4869  *
4870  * Fork - LGPL
4871  * <script type="text/javascript">
4872  */
4873  
4874
4875 /*
4876  * This is code is also distributed under MIT license for use
4877  * with jQuery and prototype JavaScript libraries.
4878  */
4879 /**
4880  * @class Roo.DomQuery
4881 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).
4882 <p>
4883 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>
4884
4885 <p>
4886 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.
4887 </p>
4888 <h4>Element Selectors:</h4>
4889 <ul class="list">
4890     <li> <b>*</b> any element</li>
4891     <li> <b>E</b> an element with the tag E</li>
4892     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4893     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4894     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4895     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4896 </ul>
4897 <h4>Attribute Selectors:</h4>
4898 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4899 <ul class="list">
4900     <li> <b>E[foo]</b> has an attribute "foo"</li>
4901     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4902     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4903     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4904     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4905     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4906     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4907 </ul>
4908 <h4>Pseudo Classes:</h4>
4909 <ul class="list">
4910     <li> <b>E:first-child</b> E is the first child of its parent</li>
4911     <li> <b>E:last-child</b> E is the last child of its parent</li>
4912     <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>
4913     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4914     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4915     <li> <b>E:only-child</b> E is the only child of its parent</li>
4916     <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>
4917     <li> <b>E:first</b> the first E in the resultset</li>
4918     <li> <b>E:last</b> the last E in the resultset</li>
4919     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4920     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4921     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4922     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4923     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4924     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4925     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4926     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4927     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4928 </ul>
4929 <h4>CSS Value Selectors:</h4>
4930 <ul class="list">
4931     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4932     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4933     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4934     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4935     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4936     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4937 </ul>
4938  * @singleton
4939  */
4940 Roo.DomQuery = function(){
4941     var cache = {}, simpleCache = {}, valueCache = {};
4942     var nonSpace = /\S/;
4943     var trimRe = /^\s+|\s+$/g;
4944     var tplRe = /\{(\d+)\}/g;
4945     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4946     var tagTokenRe = /^(#)?([\w-\*]+)/;
4947     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4948
4949     function child(p, index){
4950         var i = 0;
4951         var n = p.firstChild;
4952         while(n){
4953             if(n.nodeType == 1){
4954                if(++i == index){
4955                    return n;
4956                }
4957             }
4958             n = n.nextSibling;
4959         }
4960         return null;
4961     };
4962
4963     function next(n){
4964         while((n = n.nextSibling) && n.nodeType != 1);
4965         return n;
4966     };
4967
4968     function prev(n){
4969         while((n = n.previousSibling) && n.nodeType != 1);
4970         return n;
4971     };
4972
4973     function children(d){
4974         var n = d.firstChild, ni = -1;
4975             while(n){
4976                 var nx = n.nextSibling;
4977                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4978                     d.removeChild(n);
4979                 }else{
4980                     n.nodeIndex = ++ni;
4981                 }
4982                 n = nx;
4983             }
4984             return this;
4985         };
4986
4987     function byClassName(c, a, v){
4988         if(!v){
4989             return c;
4990         }
4991         var r = [], ri = -1, cn;
4992         for(var i = 0, ci; ci = c[i]; i++){
4993             if((' '+ci.className+' ').indexOf(v) != -1){
4994                 r[++ri] = ci;
4995             }
4996         }
4997         return r;
4998     };
4999
5000     function attrValue(n, attr){
5001         if(!n.tagName && typeof n.length != "undefined"){
5002             n = n[0];
5003         }
5004         if(!n){
5005             return null;
5006         }
5007         if(attr == "for"){
5008             return n.htmlFor;
5009         }
5010         if(attr == "class" || attr == "className"){
5011             return n.className;
5012         }
5013         return n.getAttribute(attr) || n[attr];
5014
5015     };
5016
5017     function getNodes(ns, mode, tagName){
5018         var result = [], ri = -1, cs;
5019         if(!ns){
5020             return result;
5021         }
5022         tagName = tagName || "*";
5023         if(typeof ns.getElementsByTagName != "undefined"){
5024             ns = [ns];
5025         }
5026         if(!mode){
5027             for(var i = 0, ni; ni = ns[i]; i++){
5028                 cs = ni.getElementsByTagName(tagName);
5029                 for(var j = 0, ci; ci = cs[j]; j++){
5030                     result[++ri] = ci;
5031                 }
5032             }
5033         }else if(mode == "/" || mode == ">"){
5034             var utag = tagName.toUpperCase();
5035             for(var i = 0, ni, cn; ni = ns[i]; i++){
5036                 cn = ni.children || ni.childNodes;
5037                 for(var j = 0, cj; cj = cn[j]; j++){
5038                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5039                         result[++ri] = cj;
5040                     }
5041                 }
5042             }
5043         }else if(mode == "+"){
5044             var utag = tagName.toUpperCase();
5045             for(var i = 0, n; n = ns[i]; i++){
5046                 while((n = n.nextSibling) && n.nodeType != 1);
5047                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5048                     result[++ri] = n;
5049                 }
5050             }
5051         }else if(mode == "~"){
5052             for(var i = 0, n; n = ns[i]; i++){
5053                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5054                 if(n){
5055                     result[++ri] = n;
5056                 }
5057             }
5058         }
5059         return result;
5060     };
5061
5062     function concat(a, b){
5063         if(b.slice){
5064             return a.concat(b);
5065         }
5066         for(var i = 0, l = b.length; i < l; i++){
5067             a[a.length] = b[i];
5068         }
5069         return a;
5070     }
5071
5072     function byTag(cs, tagName){
5073         if(cs.tagName || cs == document){
5074             cs = [cs];
5075         }
5076         if(!tagName){
5077             return cs;
5078         }
5079         var r = [], ri = -1;
5080         tagName = tagName.toLowerCase();
5081         for(var i = 0, ci; ci = cs[i]; i++){
5082             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5083                 r[++ri] = ci;
5084             }
5085         }
5086         return r;
5087     };
5088
5089     function byId(cs, attr, id){
5090         if(cs.tagName || cs == document){
5091             cs = [cs];
5092         }
5093         if(!id){
5094             return cs;
5095         }
5096         var r = [], ri = -1;
5097         for(var i = 0,ci; ci = cs[i]; i++){
5098             if(ci && ci.id == id){
5099                 r[++ri] = ci;
5100                 return r;
5101             }
5102         }
5103         return r;
5104     };
5105
5106     function byAttribute(cs, attr, value, op, custom){
5107         var r = [], ri = -1, st = custom=="{";
5108         var f = Roo.DomQuery.operators[op];
5109         for(var i = 0, ci; ci = cs[i]; i++){
5110             var a;
5111             if(st){
5112                 a = Roo.DomQuery.getStyle(ci, attr);
5113             }
5114             else if(attr == "class" || attr == "className"){
5115                 a = ci.className;
5116             }else if(attr == "for"){
5117                 a = ci.htmlFor;
5118             }else if(attr == "href"){
5119                 a = ci.getAttribute("href", 2);
5120             }else{
5121                 a = ci.getAttribute(attr);
5122             }
5123             if((f && f(a, value)) || (!f && a)){
5124                 r[++ri] = ci;
5125             }
5126         }
5127         return r;
5128     };
5129
5130     function byPseudo(cs, name, value){
5131         return Roo.DomQuery.pseudos[name](cs, value);
5132     };
5133
5134     // This is for IE MSXML which does not support expandos.
5135     // IE runs the same speed using setAttribute, however FF slows way down
5136     // and Safari completely fails so they need to continue to use expandos.
5137     var isIE = window.ActiveXObject ? true : false;
5138
5139     // this eval is stop the compressor from
5140     // renaming the variable to something shorter
5141     
5142     /** eval:var:batch */
5143     var batch = 30803; 
5144
5145     var key = 30803;
5146
5147     function nodupIEXml(cs){
5148         var d = ++key;
5149         cs[0].setAttribute("_nodup", d);
5150         var r = [cs[0]];
5151         for(var i = 1, len = cs.length; i < len; i++){
5152             var c = cs[i];
5153             if(!c.getAttribute("_nodup") != d){
5154                 c.setAttribute("_nodup", d);
5155                 r[r.length] = c;
5156             }
5157         }
5158         for(var i = 0, len = cs.length; i < len; i++){
5159             cs[i].removeAttribute("_nodup");
5160         }
5161         return r;
5162     }
5163
5164     function nodup(cs){
5165         if(!cs){
5166             return [];
5167         }
5168         var len = cs.length, c, i, r = cs, cj, ri = -1;
5169         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5170             return cs;
5171         }
5172         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5173             return nodupIEXml(cs);
5174         }
5175         var d = ++key;
5176         cs[0]._nodup = d;
5177         for(i = 1; c = cs[i]; i++){
5178             if(c._nodup != d){
5179                 c._nodup = d;
5180             }else{
5181                 r = [];
5182                 for(var j = 0; j < i; j++){
5183                     r[++ri] = cs[j];
5184                 }
5185                 for(j = i+1; cj = cs[j]; j++){
5186                     if(cj._nodup != d){
5187                         cj._nodup = d;
5188                         r[++ri] = cj;
5189                     }
5190                 }
5191                 return r;
5192             }
5193         }
5194         return r;
5195     }
5196
5197     function quickDiffIEXml(c1, c2){
5198         var d = ++key;
5199         for(var i = 0, len = c1.length; i < len; i++){
5200             c1[i].setAttribute("_qdiff", d);
5201         }
5202         var r = [];
5203         for(var i = 0, len = c2.length; i < len; i++){
5204             if(c2[i].getAttribute("_qdiff") != d){
5205                 r[r.length] = c2[i];
5206             }
5207         }
5208         for(var i = 0, len = c1.length; i < len; i++){
5209            c1[i].removeAttribute("_qdiff");
5210         }
5211         return r;
5212     }
5213
5214     function quickDiff(c1, c2){
5215         var len1 = c1.length;
5216         if(!len1){
5217             return c2;
5218         }
5219         if(isIE && c1[0].selectSingleNode){
5220             return quickDiffIEXml(c1, c2);
5221         }
5222         var d = ++key;
5223         for(var i = 0; i < len1; i++){
5224             c1[i]._qdiff = d;
5225         }
5226         var r = [];
5227         for(var i = 0, len = c2.length; i < len; i++){
5228             if(c2[i]._qdiff != d){
5229                 r[r.length] = c2[i];
5230             }
5231         }
5232         return r;
5233     }
5234
5235     function quickId(ns, mode, root, id){
5236         if(ns == root){
5237            var d = root.ownerDocument || root;
5238            return d.getElementById(id);
5239         }
5240         ns = getNodes(ns, mode, "*");
5241         return byId(ns, null, id);
5242     }
5243
5244     return {
5245         getStyle : function(el, name){
5246             return Roo.fly(el).getStyle(name);
5247         },
5248         /**
5249          * Compiles a selector/xpath query into a reusable function. The returned function
5250          * takes one parameter "root" (optional), which is the context node from where the query should start.
5251          * @param {String} selector The selector/xpath query
5252          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5253          * @return {Function}
5254          */
5255         compile : function(path, type){
5256             type = type || "select";
5257             
5258             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5259             var q = path, mode, lq;
5260             var tk = Roo.DomQuery.matchers;
5261             var tklen = tk.length;
5262             var mm;
5263
5264             // accept leading mode switch
5265             var lmode = q.match(modeRe);
5266             if(lmode && lmode[1]){
5267                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5268                 q = q.replace(lmode[1], "");
5269             }
5270             // strip leading slashes
5271             while(path.substr(0, 1)=="/"){
5272                 path = path.substr(1);
5273             }
5274
5275             while(q && lq != q){
5276                 lq = q;
5277                 var tm = q.match(tagTokenRe);
5278                 if(type == "select"){
5279                     if(tm){
5280                         if(tm[1] == "#"){
5281                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5282                         }else{
5283                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5284                         }
5285                         q = q.replace(tm[0], "");
5286                     }else if(q.substr(0, 1) != '@'){
5287                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5288                     }
5289                 }else{
5290                     if(tm){
5291                         if(tm[1] == "#"){
5292                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5293                         }else{
5294                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5295                         }
5296                         q = q.replace(tm[0], "");
5297                     }
5298                 }
5299                 while(!(mm = q.match(modeRe))){
5300                     var matched = false;
5301                     for(var j = 0; j < tklen; j++){
5302                         var t = tk[j];
5303                         var m = q.match(t.re);
5304                         if(m){
5305                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5306                                                     return m[i];
5307                                                 });
5308                             q = q.replace(m[0], "");
5309                             matched = true;
5310                             break;
5311                         }
5312                     }
5313                     // prevent infinite loop on bad selector
5314                     if(!matched){
5315                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5316                     }
5317                 }
5318                 if(mm[1]){
5319                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5320                     q = q.replace(mm[1], "");
5321                 }
5322             }
5323             fn[fn.length] = "return nodup(n);\n}";
5324             
5325              /** 
5326               * list of variables that need from compression as they are used by eval.
5327              *  eval:var:batch 
5328              *  eval:var:nodup
5329              *  eval:var:byTag
5330              *  eval:var:ById
5331              *  eval:var:getNodes
5332              *  eval:var:quickId
5333              *  eval:var:mode
5334              *  eval:var:root
5335              *  eval:var:n
5336              *  eval:var:byClassName
5337              *  eval:var:byPseudo
5338              *  eval:var:byAttribute
5339              *  eval:var:attrValue
5340              * 
5341              **/ 
5342             eval(fn.join(""));
5343             return f;
5344         },
5345
5346         /**
5347          * Selects a group of elements.
5348          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5349          * @param {Node} root (optional) The start of the query (defaults to document).
5350          * @return {Array}
5351          */
5352         select : function(path, root, type){
5353             if(!root || root == document){
5354                 root = document;
5355             }
5356             if(typeof root == "string"){
5357                 root = document.getElementById(root);
5358             }
5359             var paths = path.split(",");
5360             var results = [];
5361             for(var i = 0, len = paths.length; i < len; i++){
5362                 var p = paths[i].replace(trimRe, "");
5363                 if(!cache[p]){
5364                     cache[p] = Roo.DomQuery.compile(p);
5365                     if(!cache[p]){
5366                         throw p + " is not a valid selector";
5367                     }
5368                 }
5369                 var result = cache[p](root);
5370                 if(result && result != document){
5371                     results = results.concat(result);
5372                 }
5373             }
5374             if(paths.length > 1){
5375                 return nodup(results);
5376             }
5377             return results;
5378         },
5379
5380         /**
5381          * Selects a single element.
5382          * @param {String} selector The selector/xpath query
5383          * @param {Node} root (optional) The start of the query (defaults to document).
5384          * @return {Element}
5385          */
5386         selectNode : function(path, root){
5387             return Roo.DomQuery.select(path, root)[0];
5388         },
5389
5390         /**
5391          * Selects the value of a node, optionally replacing null with the defaultValue.
5392          * @param {String} selector The selector/xpath query
5393          * @param {Node} root (optional) The start of the query (defaults to document).
5394          * @param {String} defaultValue
5395          */
5396         selectValue : function(path, root, defaultValue){
5397             path = path.replace(trimRe, "");
5398             if(!valueCache[path]){
5399                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5400             }
5401             var n = valueCache[path](root);
5402             n = n[0] ? n[0] : n;
5403             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5404             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5405         },
5406
5407         /**
5408          * Selects the value of a node, parsing integers and floats.
5409          * @param {String} selector The selector/xpath query
5410          * @param {Node} root (optional) The start of the query (defaults to document).
5411          * @param {Number} defaultValue
5412          * @return {Number}
5413          */
5414         selectNumber : function(path, root, defaultValue){
5415             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5416             return parseFloat(v);
5417         },
5418
5419         /**
5420          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5421          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5422          * @param {String} selector The simple selector to test
5423          * @return {Boolean}
5424          */
5425         is : function(el, ss){
5426             if(typeof el == "string"){
5427                 el = document.getElementById(el);
5428             }
5429             var isArray = (el instanceof Array);
5430             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5431             return isArray ? (result.length == el.length) : (result.length > 0);
5432         },
5433
5434         /**
5435          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5436          * @param {Array} el An array of elements to filter
5437          * @param {String} selector The simple selector to test
5438          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5439          * the selector instead of the ones that match
5440          * @return {Array}
5441          */
5442         filter : function(els, ss, nonMatches){
5443             ss = ss.replace(trimRe, "");
5444             if(!simpleCache[ss]){
5445                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5446             }
5447             var result = simpleCache[ss](els);
5448             return nonMatches ? quickDiff(result, els) : result;
5449         },
5450
5451         /**
5452          * Collection of matching regular expressions and code snippets.
5453          */
5454         matchers : [{
5455                 re: /^\.([\w-]+)/,
5456                 select: 'n = byClassName(n, null, " {1} ");'
5457             }, {
5458                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5459                 select: 'n = byPseudo(n, "{1}", "{2}");'
5460             },{
5461                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5462                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5463             }, {
5464                 re: /^#([\w-]+)/,
5465                 select: 'n = byId(n, null, "{1}");'
5466             },{
5467                 re: /^@([\w-]+)/,
5468                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5469             }
5470         ],
5471
5472         /**
5473          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5474          * 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;.
5475          */
5476         operators : {
5477             "=" : function(a, v){
5478                 return a == v;
5479             },
5480             "!=" : function(a, v){
5481                 return a != v;
5482             },
5483             "^=" : function(a, v){
5484                 return a && a.substr(0, v.length) == v;
5485             },
5486             "$=" : function(a, v){
5487                 return a && a.substr(a.length-v.length) == v;
5488             },
5489             "*=" : function(a, v){
5490                 return a && a.indexOf(v) !== -1;
5491             },
5492             "%=" : function(a, v){
5493                 return (a % v) == 0;
5494             },
5495             "|=" : function(a, v){
5496                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5497             },
5498             "~=" : function(a, v){
5499                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5500             }
5501         },
5502
5503         /**
5504          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5505          * and the argument (if any) supplied in the selector.
5506          */
5507         pseudos : {
5508             "first-child" : function(c){
5509                 var r = [], ri = -1, n;
5510                 for(var i = 0, ci; ci = n = c[i]; i++){
5511                     while((n = n.previousSibling) && n.nodeType != 1);
5512                     if(!n){
5513                         r[++ri] = ci;
5514                     }
5515                 }
5516                 return r;
5517             },
5518
5519             "last-child" : function(c){
5520                 var r = [], ri = -1, n;
5521                 for(var i = 0, ci; ci = n = c[i]; i++){
5522                     while((n = n.nextSibling) && n.nodeType != 1);
5523                     if(!n){
5524                         r[++ri] = ci;
5525                     }
5526                 }
5527                 return r;
5528             },
5529
5530             "nth-child" : function(c, a) {
5531                 var r = [], ri = -1;
5532                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5533                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5534                 for(var i = 0, n; n = c[i]; i++){
5535                     var pn = n.parentNode;
5536                     if (batch != pn._batch) {
5537                         var j = 0;
5538                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5539                             if(cn.nodeType == 1){
5540                                cn.nodeIndex = ++j;
5541                             }
5542                         }
5543                         pn._batch = batch;
5544                     }
5545                     if (f == 1) {
5546                         if (l == 0 || n.nodeIndex == l){
5547                             r[++ri] = n;
5548                         }
5549                     } else if ((n.nodeIndex + l) % f == 0){
5550                         r[++ri] = n;
5551                     }
5552                 }
5553
5554                 return r;
5555             },
5556
5557             "only-child" : function(c){
5558                 var r = [], ri = -1;;
5559                 for(var i = 0, ci; ci = c[i]; i++){
5560                     if(!prev(ci) && !next(ci)){
5561                         r[++ri] = ci;
5562                     }
5563                 }
5564                 return r;
5565             },
5566
5567             "empty" : function(c){
5568                 var r = [], ri = -1;
5569                 for(var i = 0, ci; ci = c[i]; i++){
5570                     var cns = ci.childNodes, j = 0, cn, empty = true;
5571                     while(cn = cns[j]){
5572                         ++j;
5573                         if(cn.nodeType == 1 || cn.nodeType == 3){
5574                             empty = false;
5575                             break;
5576                         }
5577                     }
5578                     if(empty){
5579                         r[++ri] = ci;
5580                     }
5581                 }
5582                 return r;
5583             },
5584
5585             "contains" : function(c, v){
5586                 var r = [], ri = -1;
5587                 for(var i = 0, ci; ci = c[i]; i++){
5588                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5589                         r[++ri] = ci;
5590                     }
5591                 }
5592                 return r;
5593             },
5594
5595             "nodeValue" : function(c, v){
5596                 var r = [], ri = -1;
5597                 for(var i = 0, ci; ci = c[i]; i++){
5598                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5599                         r[++ri] = ci;
5600                     }
5601                 }
5602                 return r;
5603             },
5604
5605             "checked" : function(c){
5606                 var r = [], ri = -1;
5607                 for(var i = 0, ci; ci = c[i]; i++){
5608                     if(ci.checked == true){
5609                         r[++ri] = ci;
5610                     }
5611                 }
5612                 return r;
5613             },
5614
5615             "not" : function(c, ss){
5616                 return Roo.DomQuery.filter(c, ss, true);
5617             },
5618
5619             "odd" : function(c){
5620                 return this["nth-child"](c, "odd");
5621             },
5622
5623             "even" : function(c){
5624                 return this["nth-child"](c, "even");
5625             },
5626
5627             "nth" : function(c, a){
5628                 return c[a-1] || [];
5629             },
5630
5631             "first" : function(c){
5632                 return c[0] || [];
5633             },
5634
5635             "last" : function(c){
5636                 return c[c.length-1] || [];
5637             },
5638
5639             "has" : function(c, ss){
5640                 var s = Roo.DomQuery.select;
5641                 var r = [], ri = -1;
5642                 for(var i = 0, ci; ci = c[i]; i++){
5643                     if(s(ss, ci).length > 0){
5644                         r[++ri] = ci;
5645                     }
5646                 }
5647                 return r;
5648             },
5649
5650             "next" : function(c, ss){
5651                 var is = Roo.DomQuery.is;
5652                 var r = [], ri = -1;
5653                 for(var i = 0, ci; ci = c[i]; i++){
5654                     var n = next(ci);
5655                     if(n && is(n, ss)){
5656                         r[++ri] = ci;
5657                     }
5658                 }
5659                 return r;
5660             },
5661
5662             "prev" : function(c, ss){
5663                 var is = Roo.DomQuery.is;
5664                 var r = [], ri = -1;
5665                 for(var i = 0, ci; ci = c[i]; i++){
5666                     var n = prev(ci);
5667                     if(n && is(n, ss)){
5668                         r[++ri] = ci;
5669                     }
5670                 }
5671                 return r;
5672             }
5673         }
5674     };
5675 }();
5676
5677 /**
5678  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5679  * @param {String} path The selector/xpath query
5680  * @param {Node} root (optional) The start of the query (defaults to document).
5681  * @return {Array}
5682  * @member Roo
5683  * @method query
5684  */
5685 Roo.query = Roo.DomQuery.select;
5686 /*
5687  * Based on:
5688  * Ext JS Library 1.1.1
5689  * Copyright(c) 2006-2007, Ext JS, LLC.
5690  *
5691  * Originally Released Under LGPL - original licence link has changed is not relivant.
5692  *
5693  * Fork - LGPL
5694  * <script type="text/javascript">
5695  */
5696
5697 /**
5698  * @class Roo.util.Observable
5699  * Base class that provides a common interface for publishing events. Subclasses are expected to
5700  * to have a property "events" with all the events defined.<br>
5701  * For example:
5702  * <pre><code>
5703  Employee = function(name){
5704     this.name = name;
5705     this.addEvents({
5706         "fired" : true,
5707         "quit" : true
5708     });
5709  }
5710  Roo.extend(Employee, Roo.util.Observable);
5711 </code></pre>
5712  * @param {Object} config properties to use (incuding events / listeners)
5713  */
5714
5715 Roo.util.Observable = function(cfg){
5716     
5717     cfg = cfg|| {};
5718     this.addEvents(cfg.events || {});
5719     if (cfg.events) {
5720         delete cfg.events; // make sure
5721     }
5722      
5723     Roo.apply(this, cfg);
5724     
5725     if(this.listeners){
5726         this.on(this.listeners);
5727         delete this.listeners;
5728     }
5729 };
5730 Roo.util.Observable.prototype = {
5731     /** 
5732  * @cfg {Object} listeners  list of events and functions to call for this object, 
5733  * For example :
5734  * <pre><code>
5735     listeners :  { 
5736        'click' : function(e) {
5737            ..... 
5738         } ,
5739         .... 
5740     } 
5741   </code></pre>
5742  */
5743     
5744     
5745     /**
5746      * Fires the specified event with the passed parameters (minus the event name).
5747      * @param {String} eventName
5748      * @param {Object...} args Variable number of parameters are passed to handlers
5749      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5750      */
5751     fireEvent : function(){
5752         var ce = this.events[arguments[0].toLowerCase()];
5753         if(typeof ce == "object"){
5754             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5755         }else{
5756             return true;
5757         }
5758     },
5759
5760     // private
5761     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5762
5763     /**
5764      * Appends an event handler to this component
5765      * @param {String}   eventName The type of event to listen for
5766      * @param {Function} handler The method the event invokes
5767      * @param {Object}   scope (optional) The scope in which to execute the handler
5768      * function. The handler function's "this" context.
5769      * @param {Object}   options (optional) An object containing handler configuration
5770      * properties. This may contain any of the following properties:<ul>
5771      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5772      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5773      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5774      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5775      * by the specified number of milliseconds. If the event fires again within that time, the original
5776      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5777      * </ul><br>
5778      * <p>
5779      * <b>Combining Options</b><br>
5780      * Using the options argument, it is possible to combine different types of listeners:<br>
5781      * <br>
5782      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5783                 <pre><code>
5784                 el.on('click', this.onClick, this, {
5785                         single: true,
5786                 delay: 100,
5787                 forumId: 4
5788                 });
5789                 </code></pre>
5790      * <p>
5791      * <b>Attaching multiple handlers in 1 call</b><br>
5792      * The method also allows for a single argument to be passed which is a config object containing properties
5793      * which specify multiple handlers.
5794      * <pre><code>
5795                 el.on({
5796                         'click': {
5797                         fn: this.onClick,
5798                         scope: this,
5799                         delay: 100
5800                 }, 
5801                 'mouseover': {
5802                         fn: this.onMouseOver,
5803                         scope: this
5804                 },
5805                 'mouseout': {
5806                         fn: this.onMouseOut,
5807                         scope: this
5808                 }
5809                 });
5810                 </code></pre>
5811      * <p>
5812      * Or a shorthand syntax which passes the same scope object to all handlers:
5813         <pre><code>
5814                 el.on({
5815                         'click': this.onClick,
5816                 'mouseover': this.onMouseOver,
5817                 'mouseout': this.onMouseOut,
5818                 scope: this
5819                 });
5820                 </code></pre>
5821      */
5822     addListener : function(eventName, fn, scope, o){
5823         if(typeof eventName == "object"){
5824             o = eventName;
5825             for(var e in o){
5826                 if(this.filterOptRe.test(e)){
5827                     continue;
5828                 }
5829                 if(typeof o[e] == "function"){
5830                     // shared options
5831                     this.addListener(e, o[e], o.scope,  o);
5832                 }else{
5833                     // individual options
5834                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5835                 }
5836             }
5837             return;
5838         }
5839         o = (!o || typeof o == "boolean") ? {} : o;
5840         eventName = eventName.toLowerCase();
5841         var ce = this.events[eventName] || true;
5842         if(typeof ce == "boolean"){
5843             ce = new Roo.util.Event(this, eventName);
5844             this.events[eventName] = ce;
5845         }
5846         ce.addListener(fn, scope, o);
5847     },
5848
5849     /**
5850      * Removes a listener
5851      * @param {String}   eventName     The type of event to listen for
5852      * @param {Function} handler        The handler to remove
5853      * @param {Object}   scope  (optional) The scope (this object) for the handler
5854      */
5855     removeListener : function(eventName, fn, scope){
5856         var ce = this.events[eventName.toLowerCase()];
5857         if(typeof ce == "object"){
5858             ce.removeListener(fn, scope);
5859         }
5860     },
5861
5862     /**
5863      * Removes all listeners for this object
5864      */
5865     purgeListeners : function(){
5866         for(var evt in this.events){
5867             if(typeof this.events[evt] == "object"){
5868                  this.events[evt].clearListeners();
5869             }
5870         }
5871     },
5872
5873     relayEvents : function(o, events){
5874         var createHandler = function(ename){
5875             return function(){
5876                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5877             };
5878         };
5879         for(var i = 0, len = events.length; i < len; i++){
5880             var ename = events[i];
5881             if(!this.events[ename]){ this.events[ename] = true; };
5882             o.on(ename, createHandler(ename), this);
5883         }
5884     },
5885
5886     /**
5887      * Used to define events on this Observable
5888      * @param {Object} object The object with the events defined
5889      */
5890     addEvents : function(o){
5891         if(!this.events){
5892             this.events = {};
5893         }
5894         Roo.applyIf(this.events, o);
5895     },
5896
5897     /**
5898      * Checks to see if this object has any listeners for a specified event
5899      * @param {String} eventName The name of the event to check for
5900      * @return {Boolean} True if the event is being listened for, else false
5901      */
5902     hasListener : function(eventName){
5903         var e = this.events[eventName];
5904         return typeof e == "object" && e.listeners.length > 0;
5905     }
5906 };
5907 /**
5908  * Appends an event handler to this element (shorthand for addListener)
5909  * @param {String}   eventName     The type of event to listen for
5910  * @param {Function} handler        The method the event invokes
5911  * @param {Object}   scope (optional) The scope in which to execute the handler
5912  * function. The handler function's "this" context.
5913  * @param {Object}   options  (optional)
5914  * @method
5915  */
5916 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5917 /**
5918  * Removes a listener (shorthand for removeListener)
5919  * @param {String}   eventName     The type of event to listen for
5920  * @param {Function} handler        The handler to remove
5921  * @param {Object}   scope  (optional) The scope (this object) for the handler
5922  * @method
5923  */
5924 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5925
5926 /**
5927  * Starts capture on the specified Observable. All events will be passed
5928  * to the supplied function with the event name + standard signature of the event
5929  * <b>before</b> the event is fired. If the supplied function returns false,
5930  * the event will not fire.
5931  * @param {Observable} o The Observable to capture
5932  * @param {Function} fn The function to call
5933  * @param {Object} scope (optional) The scope (this object) for the fn
5934  * @static
5935  */
5936 Roo.util.Observable.capture = function(o, fn, scope){
5937     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5938 };
5939
5940 /**
5941  * Removes <b>all</b> added captures from the Observable.
5942  * @param {Observable} o The Observable to release
5943  * @static
5944  */
5945 Roo.util.Observable.releaseCapture = function(o){
5946     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5947 };
5948
5949 (function(){
5950
5951     var createBuffered = function(h, o, scope){
5952         var task = new Roo.util.DelayedTask();
5953         return function(){
5954             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5955         };
5956     };
5957
5958     var createSingle = function(h, e, fn, scope){
5959         return function(){
5960             e.removeListener(fn, scope);
5961             return h.apply(scope, arguments);
5962         };
5963     };
5964
5965     var createDelayed = function(h, o, scope){
5966         return function(){
5967             var args = Array.prototype.slice.call(arguments, 0);
5968             setTimeout(function(){
5969                 h.apply(scope, args);
5970             }, o.delay || 10);
5971         };
5972     };
5973
5974     Roo.util.Event = function(obj, name){
5975         this.name = name;
5976         this.obj = obj;
5977         this.listeners = [];
5978     };
5979
5980     Roo.util.Event.prototype = {
5981         addListener : function(fn, scope, options){
5982             var o = options || {};
5983             scope = scope || this.obj;
5984             if(!this.isListening(fn, scope)){
5985                 var l = {fn: fn, scope: scope, options: o};
5986                 var h = fn;
5987                 if(o.delay){
5988                     h = createDelayed(h, o, scope);
5989                 }
5990                 if(o.single){
5991                     h = createSingle(h, this, fn, scope);
5992                 }
5993                 if(o.buffer){
5994                     h = createBuffered(h, o, scope);
5995                 }
5996                 l.fireFn = h;
5997                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5998                     this.listeners.push(l);
5999                 }else{
6000                     this.listeners = this.listeners.slice(0);
6001                     this.listeners.push(l);
6002                 }
6003             }
6004         },
6005
6006         findListener : function(fn, scope){
6007             scope = scope || this.obj;
6008             var ls = this.listeners;
6009             for(var i = 0, len = ls.length; i < len; i++){
6010                 var l = ls[i];
6011                 if(l.fn == fn && l.scope == scope){
6012                     return i;
6013                 }
6014             }
6015             return -1;
6016         },
6017
6018         isListening : function(fn, scope){
6019             return this.findListener(fn, scope) != -1;
6020         },
6021
6022         removeListener : function(fn, scope){
6023             var index;
6024             if((index = this.findListener(fn, scope)) != -1){
6025                 if(!this.firing){
6026                     this.listeners.splice(index, 1);
6027                 }else{
6028                     this.listeners = this.listeners.slice(0);
6029                     this.listeners.splice(index, 1);
6030                 }
6031                 return true;
6032             }
6033             return false;
6034         },
6035
6036         clearListeners : function(){
6037             this.listeners = [];
6038         },
6039
6040         fire : function(){
6041             var ls = this.listeners, scope, len = ls.length;
6042             if(len > 0){
6043                 this.firing = true;
6044                 var args = Array.prototype.slice.call(arguments, 0);
6045                 for(var i = 0; i < len; i++){
6046                     var l = ls[i];
6047                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6048                         this.firing = false;
6049                         return false;
6050                     }
6051                 }
6052                 this.firing = false;
6053             }
6054             return true;
6055         }
6056     };
6057 })();/*
6058  * Based on:
6059  * Ext JS Library 1.1.1
6060  * Copyright(c) 2006-2007, Ext JS, LLC.
6061  *
6062  * Originally Released Under LGPL - original licence link has changed is not relivant.
6063  *
6064  * Fork - LGPL
6065  * <script type="text/javascript">
6066  */
6067
6068 /**
6069  * @class Roo.EventManager
6070  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6071  * several useful events directly.
6072  * See {@link Roo.EventObject} for more details on normalized event objects.
6073  * @singleton
6074  */
6075 Roo.EventManager = function(){
6076     var docReadyEvent, docReadyProcId, docReadyState = false;
6077     var resizeEvent, resizeTask, textEvent, textSize;
6078     var E = Roo.lib.Event;
6079     var D = Roo.lib.Dom;
6080
6081     
6082     
6083
6084     var fireDocReady = function(){
6085         if(!docReadyState){
6086             docReadyState = true;
6087             Roo.isReady = true;
6088             if(docReadyProcId){
6089                 clearInterval(docReadyProcId);
6090             }
6091             if(Roo.isGecko || Roo.isOpera) {
6092                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6093             }
6094             if(Roo.isIE){
6095                 var defer = document.getElementById("ie-deferred-loader");
6096                 if(defer){
6097                     defer.onreadystatechange = null;
6098                     defer.parentNode.removeChild(defer);
6099                 }
6100             }
6101             if(docReadyEvent){
6102                 docReadyEvent.fire();
6103                 docReadyEvent.clearListeners();
6104             }
6105         }
6106     };
6107     
6108     var initDocReady = function(){
6109         docReadyEvent = new Roo.util.Event();
6110         if(Roo.isGecko || Roo.isOpera) {
6111             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6112         }else if(Roo.isIE){
6113             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6114             var defer = document.getElementById("ie-deferred-loader");
6115             defer.onreadystatechange = function(){
6116                 if(this.readyState == "complete"){
6117                     fireDocReady();
6118                 }
6119             };
6120         }else if(Roo.isSafari){ 
6121             docReadyProcId = setInterval(function(){
6122                 var rs = document.readyState;
6123                 if(rs == "complete") {
6124                     fireDocReady();     
6125                  }
6126             }, 10);
6127         }
6128         // no matter what, make sure it fires on load
6129         E.on(window, "load", fireDocReady);
6130     };
6131
6132     var createBuffered = function(h, o){
6133         var task = new Roo.util.DelayedTask(h);
6134         return function(e){
6135             // create new event object impl so new events don't wipe out properties
6136             e = new Roo.EventObjectImpl(e);
6137             task.delay(o.buffer, h, null, [e]);
6138         };
6139     };
6140
6141     var createSingle = function(h, el, ename, fn){
6142         return function(e){
6143             Roo.EventManager.removeListener(el, ename, fn);
6144             h(e);
6145         };
6146     };
6147
6148     var createDelayed = function(h, o){
6149         return function(e){
6150             // create new event object impl so new events don't wipe out properties
6151             e = new Roo.EventObjectImpl(e);
6152             setTimeout(function(){
6153                 h(e);
6154             }, o.delay || 10);
6155         };
6156     };
6157     var transitionEndVal = false;
6158     
6159     var transitionEnd = function()
6160     {
6161         if (transitionEndVal) {
6162             return transitionEndVal;
6163         }
6164         var el = document.createElement('div');
6165
6166         var transEndEventNames = {
6167             WebkitTransition : 'webkitTransitionEnd',
6168             MozTransition    : 'transitionend',
6169             OTransition      : 'oTransitionEnd otransitionend',
6170             transition       : 'transitionend'
6171         };
6172     
6173         for (var name in transEndEventNames) {
6174             if (el.style[name] !== undefined) {
6175                 transitionEndVal = transEndEventNames[name];
6176                 return  transitionEndVal ;
6177             }
6178         }
6179     }
6180     
6181
6182     var listen = function(element, ename, opt, fn, scope){
6183         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6184         fn = fn || o.fn; scope = scope || o.scope;
6185         var el = Roo.getDom(element);
6186         
6187         
6188         if(!el){
6189             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6190         }
6191         
6192         if (ename == 'transitionend') {
6193             ename = transitionEnd();
6194         }
6195         var h = function(e){
6196             e = Roo.EventObject.setEvent(e);
6197             var t;
6198             if(o.delegate){
6199                 t = e.getTarget(o.delegate, el);
6200                 if(!t){
6201                     return;
6202                 }
6203             }else{
6204                 t = e.target;
6205             }
6206             if(o.stopEvent === true){
6207                 e.stopEvent();
6208             }
6209             if(o.preventDefault === true){
6210                e.preventDefault();
6211             }
6212             if(o.stopPropagation === true){
6213                 e.stopPropagation();
6214             }
6215
6216             if(o.normalized === false){
6217                 e = e.browserEvent;
6218             }
6219
6220             fn.call(scope || el, e, t, o);
6221         };
6222         if(o.delay){
6223             h = createDelayed(h, o);
6224         }
6225         if(o.single){
6226             h = createSingle(h, el, ename, fn);
6227         }
6228         if(o.buffer){
6229             h = createBuffered(h, o);
6230         }
6231         fn._handlers = fn._handlers || [];
6232         
6233         
6234         fn._handlers.push([Roo.id(el), ename, h]);
6235         
6236         
6237          
6238         E.on(el, ename, h);
6239         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6240             el.addEventListener("DOMMouseScroll", h, false);
6241             E.on(window, 'unload', function(){
6242                 el.removeEventListener("DOMMouseScroll", h, false);
6243             });
6244         }
6245         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6246             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6247         }
6248         return h;
6249     };
6250
6251     var stopListening = function(el, ename, fn){
6252         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6253         if(hds){
6254             for(var i = 0, len = hds.length; i < len; i++){
6255                 var h = hds[i];
6256                 if(h[0] == id && h[1] == ename){
6257                     hd = h[2];
6258                     hds.splice(i, 1);
6259                     break;
6260                 }
6261             }
6262         }
6263         E.un(el, ename, hd);
6264         el = Roo.getDom(el);
6265         if(ename == "mousewheel" && el.addEventListener){
6266             el.removeEventListener("DOMMouseScroll", hd, false);
6267         }
6268         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6269             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6270         }
6271     };
6272
6273     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6274     
6275     var pub = {
6276         
6277         
6278         /** 
6279          * Fix for doc tools
6280          * @scope Roo.EventManager
6281          */
6282         
6283         
6284         /** 
6285          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6286          * object with a Roo.EventObject
6287          * @param {Function} fn        The method the event invokes
6288          * @param {Object}   scope    An object that becomes the scope of the handler
6289          * @param {boolean}  override If true, the obj passed in becomes
6290          *                             the execution scope of the listener
6291          * @return {Function} The wrapped function
6292          * @deprecated
6293          */
6294         wrap : function(fn, scope, override){
6295             return function(e){
6296                 Roo.EventObject.setEvent(e);
6297                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6298             };
6299         },
6300         
6301         /**
6302      * Appends an event handler to an element (shorthand for addListener)
6303      * @param {String/HTMLElement}   element        The html element or id to assign the
6304      * @param {String}   eventName The type of event to listen for
6305      * @param {Function} handler The method the event invokes
6306      * @param {Object}   scope (optional) The scope in which to execute the handler
6307      * function. The handler function's "this" context.
6308      * @param {Object}   options (optional) An object containing handler configuration
6309      * properties. This may contain any of the following properties:<ul>
6310      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6311      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6312      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6313      * <li>preventDefault {Boolean} True to prevent the default action</li>
6314      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6315      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6316      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6317      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6318      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6319      * by the specified number of milliseconds. If the event fires again within that time, the original
6320      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6321      * </ul><br>
6322      * <p>
6323      * <b>Combining Options</b><br>
6324      * Using the options argument, it is possible to combine different types of listeners:<br>
6325      * <br>
6326      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6327      * Code:<pre><code>
6328 el.on('click', this.onClick, this, {
6329     single: true,
6330     delay: 100,
6331     stopEvent : true,
6332     forumId: 4
6333 });</code></pre>
6334      * <p>
6335      * <b>Attaching multiple handlers in 1 call</b><br>
6336       * The method also allows for a single argument to be passed which is a config object containing properties
6337      * which specify multiple handlers.
6338      * <p>
6339      * Code:<pre><code>
6340 el.on({
6341     'click' : {
6342         fn: this.onClick
6343         scope: this,
6344         delay: 100
6345     },
6346     'mouseover' : {
6347         fn: this.onMouseOver
6348         scope: this
6349     },
6350     'mouseout' : {
6351         fn: this.onMouseOut
6352         scope: this
6353     }
6354 });</code></pre>
6355      * <p>
6356      * Or a shorthand syntax:<br>
6357      * Code:<pre><code>
6358 el.on({
6359     'click' : this.onClick,
6360     'mouseover' : this.onMouseOver,
6361     'mouseout' : this.onMouseOut
6362     scope: this
6363 });</code></pre>
6364      */
6365         addListener : function(element, eventName, fn, scope, options){
6366             if(typeof eventName == "object"){
6367                 var o = eventName;
6368                 for(var e in o){
6369                     if(propRe.test(e)){
6370                         continue;
6371                     }
6372                     if(typeof o[e] == "function"){
6373                         // shared options
6374                         listen(element, e, o, o[e], o.scope);
6375                     }else{
6376                         // individual options
6377                         listen(element, e, o[e]);
6378                     }
6379                 }
6380                 return;
6381             }
6382             return listen(element, eventName, options, fn, scope);
6383         },
6384         
6385         /**
6386          * Removes an event handler
6387          *
6388          * @param {String/HTMLElement}   element        The id or html element to remove the 
6389          *                             event from
6390          * @param {String}   eventName     The type of event
6391          * @param {Function} fn
6392          * @return {Boolean} True if a listener was actually removed
6393          */
6394         removeListener : function(element, eventName, fn){
6395             return stopListening(element, eventName, fn);
6396         },
6397         
6398         /**
6399          * Fires when the document is ready (before onload and before images are loaded). Can be 
6400          * accessed shorthanded Roo.onReady().
6401          * @param {Function} fn        The method the event invokes
6402          * @param {Object}   scope    An  object that becomes the scope of the handler
6403          * @param {boolean}  options
6404          */
6405         onDocumentReady : function(fn, scope, options){
6406             if(docReadyState){ // if it already fired
6407                 docReadyEvent.addListener(fn, scope, options);
6408                 docReadyEvent.fire();
6409                 docReadyEvent.clearListeners();
6410                 return;
6411             }
6412             if(!docReadyEvent){
6413                 initDocReady();
6414             }
6415             docReadyEvent.addListener(fn, scope, options);
6416         },
6417         
6418         /**
6419          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6420          * @param {Function} fn        The method the event invokes
6421          * @param {Object}   scope    An object that becomes the scope of the handler
6422          * @param {boolean}  options
6423          */
6424         onWindowResize : function(fn, scope, options){
6425             if(!resizeEvent){
6426                 resizeEvent = new Roo.util.Event();
6427                 resizeTask = new Roo.util.DelayedTask(function(){
6428                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6429                 });
6430                 E.on(window, "resize", function(){
6431                     if(Roo.isIE){
6432                         resizeTask.delay(50);
6433                     }else{
6434                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6435                     }
6436                 });
6437             }
6438             resizeEvent.addListener(fn, scope, options);
6439         },
6440
6441         /**
6442          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6443          * @param {Function} fn        The method the event invokes
6444          * @param {Object}   scope    An object that becomes the scope of the handler
6445          * @param {boolean}  options
6446          */
6447         onTextResize : function(fn, scope, options){
6448             if(!textEvent){
6449                 textEvent = new Roo.util.Event();
6450                 var textEl = new Roo.Element(document.createElement('div'));
6451                 textEl.dom.className = 'x-text-resize';
6452                 textEl.dom.innerHTML = 'X';
6453                 textEl.appendTo(document.body);
6454                 textSize = textEl.dom.offsetHeight;
6455                 setInterval(function(){
6456                     if(textEl.dom.offsetHeight != textSize){
6457                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6458                     }
6459                 }, this.textResizeInterval);
6460             }
6461             textEvent.addListener(fn, scope, options);
6462         },
6463
6464         /**
6465          * Removes the passed window resize listener.
6466          * @param {Function} fn        The method the event invokes
6467          * @param {Object}   scope    The scope of handler
6468          */
6469         removeResizeListener : function(fn, scope){
6470             if(resizeEvent){
6471                 resizeEvent.removeListener(fn, scope);
6472             }
6473         },
6474
6475         // private
6476         fireResize : function(){
6477             if(resizeEvent){
6478                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6479             }   
6480         },
6481         /**
6482          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6483          */
6484         ieDeferSrc : false,
6485         /**
6486          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6487          */
6488         textResizeInterval : 50
6489     };
6490     
6491     /**
6492      * Fix for doc tools
6493      * @scopeAlias pub=Roo.EventManager
6494      */
6495     
6496      /**
6497      * Appends an event handler to an element (shorthand for addListener)
6498      * @param {String/HTMLElement}   element        The html element or id to assign the
6499      * @param {String}   eventName The type of event to listen for
6500      * @param {Function} handler The method the event invokes
6501      * @param {Object}   scope (optional) The scope in which to execute the handler
6502      * function. The handler function's "this" context.
6503      * @param {Object}   options (optional) An object containing handler configuration
6504      * properties. This may contain any of the following properties:<ul>
6505      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6506      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6507      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6508      * <li>preventDefault {Boolean} True to prevent the default action</li>
6509      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6510      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6511      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6512      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6513      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6514      * by the specified number of milliseconds. If the event fires again within that time, the original
6515      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6516      * </ul><br>
6517      * <p>
6518      * <b>Combining Options</b><br>
6519      * Using the options argument, it is possible to combine different types of listeners:<br>
6520      * <br>
6521      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6522      * Code:<pre><code>
6523 el.on('click', this.onClick, this, {
6524     single: true,
6525     delay: 100,
6526     stopEvent : true,
6527     forumId: 4
6528 });</code></pre>
6529      * <p>
6530      * <b>Attaching multiple handlers in 1 call</b><br>
6531       * The method also allows for a single argument to be passed which is a config object containing properties
6532      * which specify multiple handlers.
6533      * <p>
6534      * Code:<pre><code>
6535 el.on({
6536     'click' : {
6537         fn: this.onClick
6538         scope: this,
6539         delay: 100
6540     },
6541     'mouseover' : {
6542         fn: this.onMouseOver
6543         scope: this
6544     },
6545     'mouseout' : {
6546         fn: this.onMouseOut
6547         scope: this
6548     }
6549 });</code></pre>
6550      * <p>
6551      * Or a shorthand syntax:<br>
6552      * Code:<pre><code>
6553 el.on({
6554     'click' : this.onClick,
6555     'mouseover' : this.onMouseOver,
6556     'mouseout' : this.onMouseOut
6557     scope: this
6558 });</code></pre>
6559      */
6560     pub.on = pub.addListener;
6561     pub.un = pub.removeListener;
6562
6563     pub.stoppedMouseDownEvent = new Roo.util.Event();
6564     return pub;
6565 }();
6566 /**
6567   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6568   * @param {Function} fn        The method the event invokes
6569   * @param {Object}   scope    An  object that becomes the scope of the handler
6570   * @param {boolean}  override If true, the obj passed in becomes
6571   *                             the execution scope of the listener
6572   * @member Roo
6573   * @method onReady
6574  */
6575 Roo.onReady = Roo.EventManager.onDocumentReady;
6576
6577 Roo.onReady(function(){
6578     var bd = Roo.get(document.body);
6579     if(!bd){ return; }
6580
6581     var cls = [
6582             Roo.isIE ? "roo-ie"
6583             : Roo.isGecko ? "roo-gecko"
6584             : Roo.isOpera ? "roo-opera"
6585             : Roo.isSafari ? "roo-safari" : ""];
6586
6587     if(Roo.isMac){
6588         cls.push("roo-mac");
6589     }
6590     if(Roo.isLinux){
6591         cls.push("roo-linux");
6592     }
6593     if(Roo.isIOS){
6594         cls.push("roo-ios");
6595     }
6596     if(Roo.isTouch){
6597         cls.push("roo-touch");
6598     }
6599     if(Roo.isBorderBox){
6600         cls.push('roo-border-box');
6601     }
6602     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6603         var p = bd.dom.parentNode;
6604         if(p){
6605             p.className += ' roo-strict';
6606         }
6607     }
6608     bd.addClass(cls.join(' '));
6609 });
6610
6611 /**
6612  * @class Roo.EventObject
6613  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6614  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6615  * Example:
6616  * <pre><code>
6617  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6618     e.preventDefault();
6619     var target = e.getTarget();
6620     ...
6621  }
6622  var myDiv = Roo.get("myDiv");
6623  myDiv.on("click", handleClick);
6624  //or
6625  Roo.EventManager.on("myDiv", 'click', handleClick);
6626  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6627  </code></pre>
6628  * @singleton
6629  */
6630 Roo.EventObject = function(){
6631     
6632     var E = Roo.lib.Event;
6633     
6634     // safari keypress events for special keys return bad keycodes
6635     var safariKeys = {
6636         63234 : 37, // left
6637         63235 : 39, // right
6638         63232 : 38, // up
6639         63233 : 40, // down
6640         63276 : 33, // page up
6641         63277 : 34, // page down
6642         63272 : 46, // delete
6643         63273 : 36, // home
6644         63275 : 35  // end
6645     };
6646
6647     // normalize button clicks
6648     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6649                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6650
6651     Roo.EventObjectImpl = function(e){
6652         if(e){
6653             this.setEvent(e.browserEvent || e);
6654         }
6655     };
6656     Roo.EventObjectImpl.prototype = {
6657         /**
6658          * Used to fix doc tools.
6659          * @scope Roo.EventObject.prototype
6660          */
6661             
6662
6663         
6664         
6665         /** The normal browser event */
6666         browserEvent : null,
6667         /** The button pressed in a mouse event */
6668         button : -1,
6669         /** True if the shift key was down during the event */
6670         shiftKey : false,
6671         /** True if the control key was down during the event */
6672         ctrlKey : false,
6673         /** True if the alt key was down during the event */
6674         altKey : false,
6675
6676         /** Key constant 
6677         * @type Number */
6678         BACKSPACE : 8,
6679         /** Key constant 
6680         * @type Number */
6681         TAB : 9,
6682         /** Key constant 
6683         * @type Number */
6684         RETURN : 13,
6685         /** Key constant 
6686         * @type Number */
6687         ENTER : 13,
6688         /** Key constant 
6689         * @type Number */
6690         SHIFT : 16,
6691         /** Key constant 
6692         * @type Number */
6693         CONTROL : 17,
6694         /** Key constant 
6695         * @type Number */
6696         ESC : 27,
6697         /** Key constant 
6698         * @type Number */
6699         SPACE : 32,
6700         /** Key constant 
6701         * @type Number */
6702         PAGEUP : 33,
6703         /** Key constant 
6704         * @type Number */
6705         PAGEDOWN : 34,
6706         /** Key constant 
6707         * @type Number */
6708         END : 35,
6709         /** Key constant 
6710         * @type Number */
6711         HOME : 36,
6712         /** Key constant 
6713         * @type Number */
6714         LEFT : 37,
6715         /** Key constant 
6716         * @type Number */
6717         UP : 38,
6718         /** Key constant 
6719         * @type Number */
6720         RIGHT : 39,
6721         /** Key constant 
6722         * @type Number */
6723         DOWN : 40,
6724         /** Key constant 
6725         * @type Number */
6726         DELETE : 46,
6727         /** Key constant 
6728         * @type Number */
6729         F5 : 116,
6730
6731            /** @private */
6732         setEvent : function(e){
6733             if(e == this || (e && e.browserEvent)){ // already wrapped
6734                 return e;
6735             }
6736             this.browserEvent = e;
6737             if(e){
6738                 // normalize buttons
6739                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6740                 if(e.type == 'click' && this.button == -1){
6741                     this.button = 0;
6742                 }
6743                 this.type = e.type;
6744                 this.shiftKey = e.shiftKey;
6745                 // mac metaKey behaves like ctrlKey
6746                 this.ctrlKey = e.ctrlKey || e.metaKey;
6747                 this.altKey = e.altKey;
6748                 // in getKey these will be normalized for the mac
6749                 this.keyCode = e.keyCode;
6750                 // keyup warnings on firefox.
6751                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6752                 // cache the target for the delayed and or buffered events
6753                 this.target = E.getTarget(e);
6754                 // same for XY
6755                 this.xy = E.getXY(e);
6756             }else{
6757                 this.button = -1;
6758                 this.shiftKey = false;
6759                 this.ctrlKey = false;
6760                 this.altKey = false;
6761                 this.keyCode = 0;
6762                 this.charCode =0;
6763                 this.target = null;
6764                 this.xy = [0, 0];
6765             }
6766             return this;
6767         },
6768
6769         /**
6770          * Stop the event (preventDefault and stopPropagation)
6771          */
6772         stopEvent : function(){
6773             if(this.browserEvent){
6774                 if(this.browserEvent.type == 'mousedown'){
6775                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6776                 }
6777                 E.stopEvent(this.browserEvent);
6778             }
6779         },
6780
6781         /**
6782          * Prevents the browsers default handling of the event.
6783          */
6784         preventDefault : function(){
6785             if(this.browserEvent){
6786                 E.preventDefault(this.browserEvent);
6787             }
6788         },
6789
6790         /** @private */
6791         isNavKeyPress : function(){
6792             var k = this.keyCode;
6793             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6794             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6795         },
6796
6797         isSpecialKey : function(){
6798             var k = this.keyCode;
6799             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6800             (k == 16) || (k == 17) ||
6801             (k >= 18 && k <= 20) ||
6802             (k >= 33 && k <= 35) ||
6803             (k >= 36 && k <= 39) ||
6804             (k >= 44 && k <= 45);
6805         },
6806         /**
6807          * Cancels bubbling of the event.
6808          */
6809         stopPropagation : function(){
6810             if(this.browserEvent){
6811                 if(this.type == 'mousedown'){
6812                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6813                 }
6814                 E.stopPropagation(this.browserEvent);
6815             }
6816         },
6817
6818         /**
6819          * Gets the key code for the event.
6820          * @return {Number}
6821          */
6822         getCharCode : function(){
6823             return this.charCode || this.keyCode;
6824         },
6825
6826         /**
6827          * Returns a normalized keyCode for the event.
6828          * @return {Number} The key code
6829          */
6830         getKey : function(){
6831             var k = this.keyCode || this.charCode;
6832             return Roo.isSafari ? (safariKeys[k] || k) : k;
6833         },
6834
6835         /**
6836          * Gets the x coordinate of the event.
6837          * @return {Number}
6838          */
6839         getPageX : function(){
6840             return this.xy[0];
6841         },
6842
6843         /**
6844          * Gets the y coordinate of the event.
6845          * @return {Number}
6846          */
6847         getPageY : function(){
6848             return this.xy[1];
6849         },
6850
6851         /**
6852          * Gets the time of the event.
6853          * @return {Number}
6854          */
6855         getTime : function(){
6856             if(this.browserEvent){
6857                 return E.getTime(this.browserEvent);
6858             }
6859             return null;
6860         },
6861
6862         /**
6863          * Gets the page coordinates of the event.
6864          * @return {Array} The xy values like [x, y]
6865          */
6866         getXY : function(){
6867             return this.xy;
6868         },
6869
6870         /**
6871          * Gets the target for the event.
6872          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6873          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6874                 search as a number or element (defaults to 10 || document.body)
6875          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6876          * @return {HTMLelement}
6877          */
6878         getTarget : function(selector, maxDepth, returnEl){
6879             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6880         },
6881         /**
6882          * Gets the related target.
6883          * @return {HTMLElement}
6884          */
6885         getRelatedTarget : function(){
6886             if(this.browserEvent){
6887                 return E.getRelatedTarget(this.browserEvent);
6888             }
6889             return null;
6890         },
6891
6892         /**
6893          * Normalizes mouse wheel delta across browsers
6894          * @return {Number} The delta
6895          */
6896         getWheelDelta : function(){
6897             var e = this.browserEvent;
6898             var delta = 0;
6899             if(e.wheelDelta){ /* IE/Opera. */
6900                 delta = e.wheelDelta/120;
6901             }else if(e.detail){ /* Mozilla case. */
6902                 delta = -e.detail/3;
6903             }
6904             return delta;
6905         },
6906
6907         /**
6908          * Returns true if the control, meta, shift or alt key was pressed during this event.
6909          * @return {Boolean}
6910          */
6911         hasModifier : function(){
6912             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6913         },
6914
6915         /**
6916          * Returns true if the target of this event equals el or is a child of el
6917          * @param {String/HTMLElement/Element} el
6918          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6919          * @return {Boolean}
6920          */
6921         within : function(el, related){
6922             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6923             return t && Roo.fly(el).contains(t);
6924         },
6925
6926         getPoint : function(){
6927             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6928         }
6929     };
6930
6931     return new Roo.EventObjectImpl();
6932 }();
6933             
6934     /*
6935  * Based on:
6936  * Ext JS Library 1.1.1
6937  * Copyright(c) 2006-2007, Ext JS, LLC.
6938  *
6939  * Originally Released Under LGPL - original licence link has changed is not relivant.
6940  *
6941  * Fork - LGPL
6942  * <script type="text/javascript">
6943  */
6944
6945  
6946 // was in Composite Element!??!?!
6947  
6948 (function(){
6949     var D = Roo.lib.Dom;
6950     var E = Roo.lib.Event;
6951     var A = Roo.lib.Anim;
6952
6953     // local style camelizing for speed
6954     var propCache = {};
6955     var camelRe = /(-[a-z])/gi;
6956     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6957     var view = document.defaultView;
6958
6959 /**
6960  * @class Roo.Element
6961  * Represents an Element in the DOM.<br><br>
6962  * Usage:<br>
6963 <pre><code>
6964 var el = Roo.get("my-div");
6965
6966 // or with getEl
6967 var el = getEl("my-div");
6968
6969 // or with a DOM element
6970 var el = Roo.get(myDivElement);
6971 </code></pre>
6972  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6973  * each call instead of constructing a new one.<br><br>
6974  * <b>Animations</b><br />
6975  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6976  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6977 <pre>
6978 Option    Default   Description
6979 --------- --------  ---------------------------------------------
6980 duration  .35       The duration of the animation in seconds
6981 easing    easeOut   The YUI easing method
6982 callback  none      A function to execute when the anim completes
6983 scope     this      The scope (this) of the callback function
6984 </pre>
6985 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6986 * manipulate the animation. Here's an example:
6987 <pre><code>
6988 var el = Roo.get("my-div");
6989
6990 // no animation
6991 el.setWidth(100);
6992
6993 // default animation
6994 el.setWidth(100, true);
6995
6996 // animation with some options set
6997 el.setWidth(100, {
6998     duration: 1,
6999     callback: this.foo,
7000     scope: this
7001 });
7002
7003 // using the "anim" property to get the Anim object
7004 var opt = {
7005     duration: 1,
7006     callback: this.foo,
7007     scope: this
7008 };
7009 el.setWidth(100, opt);
7010 ...
7011 if(opt.anim.isAnimated()){
7012     opt.anim.stop();
7013 }
7014 </code></pre>
7015 * <b> Composite (Collections of) Elements</b><br />
7016  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7017  * @constructor Create a new Element directly.
7018  * @param {String/HTMLElement} element
7019  * @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).
7020  */
7021     Roo.Element = function(element, forceNew){
7022         var dom = typeof element == "string" ?
7023                 document.getElementById(element) : element;
7024         if(!dom){ // invalid id/element
7025             return null;
7026         }
7027         var id = dom.id;
7028         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7029             return Roo.Element.cache[id];
7030         }
7031
7032         /**
7033          * The DOM element
7034          * @type HTMLElement
7035          */
7036         this.dom = dom;
7037
7038         /**
7039          * The DOM element ID
7040          * @type String
7041          */
7042         this.id = id || Roo.id(dom);
7043     };
7044
7045     var El = Roo.Element;
7046
7047     El.prototype = {
7048         /**
7049          * The element's default display mode  (defaults to "")
7050          * @type String
7051          */
7052         originalDisplay : "",
7053
7054         visibilityMode : 1,
7055         /**
7056          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7057          * @type String
7058          */
7059         defaultUnit : "px",
7060         
7061         /**
7062          * Sets the element's visibility mode. When setVisible() is called it
7063          * will use this to determine whether to set the visibility or the display property.
7064          * @param visMode Element.VISIBILITY or Element.DISPLAY
7065          * @return {Roo.Element} this
7066          */
7067         setVisibilityMode : function(visMode){
7068             this.visibilityMode = visMode;
7069             return this;
7070         },
7071         /**
7072          * Convenience method for setVisibilityMode(Element.DISPLAY)
7073          * @param {String} display (optional) What to set display to when visible
7074          * @return {Roo.Element} this
7075          */
7076         enableDisplayMode : function(display){
7077             this.setVisibilityMode(El.DISPLAY);
7078             if(typeof display != "undefined") { this.originalDisplay = display; }
7079             return this;
7080         },
7081
7082         /**
7083          * 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)
7084          * @param {String} selector The simple selector to test
7085          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7086                 search as a number or element (defaults to 10 || document.body)
7087          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7088          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7089          */
7090         findParent : function(simpleSelector, maxDepth, returnEl){
7091             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7092             maxDepth = maxDepth || 50;
7093             if(typeof maxDepth != "number"){
7094                 stopEl = Roo.getDom(maxDepth);
7095                 maxDepth = 10;
7096             }
7097             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7098                 if(dq.is(p, simpleSelector)){
7099                     return returnEl ? Roo.get(p) : p;
7100                 }
7101                 depth++;
7102                 p = p.parentNode;
7103             }
7104             return null;
7105         },
7106
7107
7108         /**
7109          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7110          * @param {String} selector The simple selector to test
7111          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7112                 search as a number or element (defaults to 10 || document.body)
7113          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7114          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7115          */
7116         findParentNode : function(simpleSelector, maxDepth, returnEl){
7117             var p = Roo.fly(this.dom.parentNode, '_internal');
7118             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7119         },
7120
7121         /**
7122          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7123          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7124          * @param {String} selector The simple selector to test
7125          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7126                 search as a number or element (defaults to 10 || document.body)
7127          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7128          */
7129         up : function(simpleSelector, maxDepth){
7130             return this.findParentNode(simpleSelector, maxDepth, true);
7131         },
7132
7133
7134
7135         /**
7136          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7137          * @param {String} selector The simple selector to test
7138          * @return {Boolean} True if this element matches the selector, else false
7139          */
7140         is : function(simpleSelector){
7141             return Roo.DomQuery.is(this.dom, simpleSelector);
7142         },
7143
7144         /**
7145          * Perform animation on this element.
7146          * @param {Object} args The YUI animation control args
7147          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7148          * @param {Function} onComplete (optional) Function to call when animation completes
7149          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7150          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7151          * @return {Roo.Element} this
7152          */
7153         animate : function(args, duration, onComplete, easing, animType){
7154             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7155             return this;
7156         },
7157
7158         /*
7159          * @private Internal animation call
7160          */
7161         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7162             animType = animType || 'run';
7163             opt = opt || {};
7164             var anim = Roo.lib.Anim[animType](
7165                 this.dom, args,
7166                 (opt.duration || defaultDur) || .35,
7167                 (opt.easing || defaultEase) || 'easeOut',
7168                 function(){
7169                     Roo.callback(cb, this);
7170                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7171                 },
7172                 this
7173             );
7174             opt.anim = anim;
7175             return anim;
7176         },
7177
7178         // private legacy anim prep
7179         preanim : function(a, i){
7180             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7181         },
7182
7183         /**
7184          * Removes worthless text nodes
7185          * @param {Boolean} forceReclean (optional) By default the element
7186          * keeps track if it has been cleaned already so
7187          * you can call this over and over. However, if you update the element and
7188          * need to force a reclean, you can pass true.
7189          */
7190         clean : function(forceReclean){
7191             if(this.isCleaned && forceReclean !== true){
7192                 return this;
7193             }
7194             var ns = /\S/;
7195             var d = this.dom, n = d.firstChild, ni = -1;
7196             while(n){
7197                 var nx = n.nextSibling;
7198                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7199                     d.removeChild(n);
7200                 }else{
7201                     n.nodeIndex = ++ni;
7202                 }
7203                 n = nx;
7204             }
7205             this.isCleaned = true;
7206             return this;
7207         },
7208
7209         // private
7210         calcOffsetsTo : function(el){
7211             el = Roo.get(el);
7212             var d = el.dom;
7213             var restorePos = false;
7214             if(el.getStyle('position') == 'static'){
7215                 el.position('relative');
7216                 restorePos = true;
7217             }
7218             var x = 0, y =0;
7219             var op = this.dom;
7220             while(op && op != d && op.tagName != 'HTML'){
7221                 x+= op.offsetLeft;
7222                 y+= op.offsetTop;
7223                 op = op.offsetParent;
7224             }
7225             if(restorePos){
7226                 el.position('static');
7227             }
7228             return [x, y];
7229         },
7230
7231         /**
7232          * Scrolls this element into view within the passed container.
7233          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7234          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7235          * @return {Roo.Element} this
7236          */
7237         scrollIntoView : function(container, hscroll){
7238             var c = Roo.getDom(container) || document.body;
7239             var el = this.dom;
7240
7241             var o = this.calcOffsetsTo(c),
7242                 l = o[0],
7243                 t = o[1],
7244                 b = t+el.offsetHeight,
7245                 r = l+el.offsetWidth;
7246
7247             var ch = c.clientHeight;
7248             var ct = parseInt(c.scrollTop, 10);
7249             var cl = parseInt(c.scrollLeft, 10);
7250             var cb = ct + ch;
7251             var cr = cl + c.clientWidth;
7252
7253             if(t < ct){
7254                 c.scrollTop = t;
7255             }else if(b > cb){
7256                 c.scrollTop = b-ch;
7257             }
7258
7259             if(hscroll !== false){
7260                 if(l < cl){
7261                     c.scrollLeft = l;
7262                 }else if(r > cr){
7263                     c.scrollLeft = r-c.clientWidth;
7264                 }
7265             }
7266             return this;
7267         },
7268
7269         // private
7270         scrollChildIntoView : function(child, hscroll){
7271             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7272         },
7273
7274         /**
7275          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7276          * the new height may not be available immediately.
7277          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7278          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7279          * @param {Function} onComplete (optional) Function to call when animation completes
7280          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7281          * @return {Roo.Element} this
7282          */
7283         autoHeight : function(animate, duration, onComplete, easing){
7284             var oldHeight = this.getHeight();
7285             this.clip();
7286             this.setHeight(1); // force clipping
7287             setTimeout(function(){
7288                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7289                 if(!animate){
7290                     this.setHeight(height);
7291                     this.unclip();
7292                     if(typeof onComplete == "function"){
7293                         onComplete();
7294                     }
7295                 }else{
7296                     this.setHeight(oldHeight); // restore original height
7297                     this.setHeight(height, animate, duration, function(){
7298                         this.unclip();
7299                         if(typeof onComplete == "function") { onComplete(); }
7300                     }.createDelegate(this), easing);
7301                 }
7302             }.createDelegate(this), 0);
7303             return this;
7304         },
7305
7306         /**
7307          * Returns true if this element is an ancestor of the passed element
7308          * @param {HTMLElement/String} el The element to check
7309          * @return {Boolean} True if this element is an ancestor of el, else false
7310          */
7311         contains : function(el){
7312             if(!el){return false;}
7313             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7314         },
7315
7316         /**
7317          * Checks whether the element is currently visible using both visibility and display properties.
7318          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7319          * @return {Boolean} True if the element is currently visible, else false
7320          */
7321         isVisible : function(deep) {
7322             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7323             if(deep !== true || !vis){
7324                 return vis;
7325             }
7326             var p = this.dom.parentNode;
7327             while(p && p.tagName.toLowerCase() != "body"){
7328                 if(!Roo.fly(p, '_isVisible').isVisible()){
7329                     return false;
7330                 }
7331                 p = p.parentNode;
7332             }
7333             return true;
7334         },
7335
7336         /**
7337          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7338          * @param {String} selector The CSS selector
7339          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7340          * @return {CompositeElement/CompositeElementLite} The composite element
7341          */
7342         select : function(selector, unique){
7343             return El.select(selector, unique, this.dom);
7344         },
7345
7346         /**
7347          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7348          * @param {String} selector The CSS selector
7349          * @return {Array} An array of the matched nodes
7350          */
7351         query : function(selector, unique){
7352             return Roo.DomQuery.select(selector, this.dom);
7353         },
7354
7355         /**
7356          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7357          * @param {String} selector The CSS selector
7358          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7359          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7360          */
7361         child : function(selector, returnDom){
7362             var n = Roo.DomQuery.selectNode(selector, this.dom);
7363             return returnDom ? n : Roo.get(n);
7364         },
7365
7366         /**
7367          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7368          * @param {String} selector The CSS selector
7369          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7370          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7371          */
7372         down : function(selector, returnDom){
7373             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7374             return returnDom ? n : Roo.get(n);
7375         },
7376
7377         /**
7378          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7379          * @param {String} group The group the DD object is member of
7380          * @param {Object} config The DD config object
7381          * @param {Object} overrides An object containing methods to override/implement on the DD object
7382          * @return {Roo.dd.DD} The DD object
7383          */
7384         initDD : function(group, config, overrides){
7385             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7386             return Roo.apply(dd, overrides);
7387         },
7388
7389         /**
7390          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7391          * @param {String} group The group the DDProxy object is member of
7392          * @param {Object} config The DDProxy config object
7393          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7394          * @return {Roo.dd.DDProxy} The DDProxy object
7395          */
7396         initDDProxy : function(group, config, overrides){
7397             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7398             return Roo.apply(dd, overrides);
7399         },
7400
7401         /**
7402          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7403          * @param {String} group The group the DDTarget object is member of
7404          * @param {Object} config The DDTarget config object
7405          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7406          * @return {Roo.dd.DDTarget} The DDTarget object
7407          */
7408         initDDTarget : function(group, config, overrides){
7409             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7410             return Roo.apply(dd, overrides);
7411         },
7412
7413         /**
7414          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7415          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7416          * @param {Boolean} visible Whether the element is visible
7417          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7418          * @return {Roo.Element} this
7419          */
7420          setVisible : function(visible, animate){
7421             if(!animate || !A){
7422                 if(this.visibilityMode == El.DISPLAY){
7423                     this.setDisplayed(visible);
7424                 }else{
7425                     this.fixDisplay();
7426                     this.dom.style.visibility = visible ? "visible" : "hidden";
7427                 }
7428             }else{
7429                 // closure for composites
7430                 var dom = this.dom;
7431                 var visMode = this.visibilityMode;
7432                 if(visible){
7433                     this.setOpacity(.01);
7434                     this.setVisible(true);
7435                 }
7436                 this.anim({opacity: { to: (visible?1:0) }},
7437                       this.preanim(arguments, 1),
7438                       null, .35, 'easeIn', function(){
7439                          if(!visible){
7440                              if(visMode == El.DISPLAY){
7441                                  dom.style.display = "none";
7442                              }else{
7443                                  dom.style.visibility = "hidden";
7444                              }
7445                              Roo.get(dom).setOpacity(1);
7446                          }
7447                      });
7448             }
7449             return this;
7450         },
7451
7452         /**
7453          * Returns true if display is not "none"
7454          * @return {Boolean}
7455          */
7456         isDisplayed : function() {
7457             return this.getStyle("display") != "none";
7458         },
7459
7460         /**
7461          * Toggles the element's visibility or display, depending on visibility mode.
7462          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7463          * @return {Roo.Element} this
7464          */
7465         toggle : function(animate){
7466             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7467             return this;
7468         },
7469
7470         /**
7471          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7472          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7473          * @return {Roo.Element} this
7474          */
7475         setDisplayed : function(value) {
7476             if(typeof value == "boolean"){
7477                value = value ? this.originalDisplay : "none";
7478             }
7479             this.setStyle("display", value);
7480             return this;
7481         },
7482
7483         /**
7484          * Tries to focus the element. Any exceptions are caught and ignored.
7485          * @return {Roo.Element} this
7486          */
7487         focus : function() {
7488             try{
7489                 this.dom.focus();
7490             }catch(e){}
7491             return this;
7492         },
7493
7494         /**
7495          * Tries to blur the element. Any exceptions are caught and ignored.
7496          * @return {Roo.Element} this
7497          */
7498         blur : function() {
7499             try{
7500                 this.dom.blur();
7501             }catch(e){}
7502             return this;
7503         },
7504
7505         /**
7506          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7507          * @param {String/Array} className The CSS class to add, or an array of classes
7508          * @return {Roo.Element} this
7509          */
7510         addClass : function(className){
7511             if(className instanceof Array){
7512                 for(var i = 0, len = className.length; i < len; i++) {
7513                     this.addClass(className[i]);
7514                 }
7515             }else{
7516                 if(className && !this.hasClass(className)){
7517                     this.dom.className = this.dom.className + " " + className;
7518                 }
7519             }
7520             return this;
7521         },
7522
7523         /**
7524          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7525          * @param {String/Array} className The CSS class to add, or an array of classes
7526          * @return {Roo.Element} this
7527          */
7528         radioClass : function(className){
7529             var siblings = this.dom.parentNode.childNodes;
7530             for(var i = 0; i < siblings.length; i++) {
7531                 var s = siblings[i];
7532                 if(s.nodeType == 1){
7533                     Roo.get(s).removeClass(className);
7534                 }
7535             }
7536             this.addClass(className);
7537             return this;
7538         },
7539
7540         /**
7541          * Removes one or more CSS classes from the element.
7542          * @param {String/Array} className The CSS class to remove, or an array of classes
7543          * @return {Roo.Element} this
7544          */
7545         removeClass : function(className){
7546             if(!className || !this.dom.className){
7547                 return this;
7548             }
7549             if(className instanceof Array){
7550                 for(var i = 0, len = className.length; i < len; i++) {
7551                     this.removeClass(className[i]);
7552                 }
7553             }else{
7554                 if(this.hasClass(className)){
7555                     var re = this.classReCache[className];
7556                     if (!re) {
7557                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7558                        this.classReCache[className] = re;
7559                     }
7560                     this.dom.className =
7561                         this.dom.className.replace(re, " ");
7562                 }
7563             }
7564             return this;
7565         },
7566
7567         // private
7568         classReCache: {},
7569
7570         /**
7571          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7572          * @param {String} className The CSS class to toggle
7573          * @return {Roo.Element} this
7574          */
7575         toggleClass : function(className){
7576             if(this.hasClass(className)){
7577                 this.removeClass(className);
7578             }else{
7579                 this.addClass(className);
7580             }
7581             return this;
7582         },
7583
7584         /**
7585          * Checks if the specified CSS class exists on this element's DOM node.
7586          * @param {String} className The CSS class to check for
7587          * @return {Boolean} True if the class exists, else false
7588          */
7589         hasClass : function(className){
7590             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7591         },
7592
7593         /**
7594          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7595          * @param {String} oldClassName The CSS class to replace
7596          * @param {String} newClassName The replacement CSS class
7597          * @return {Roo.Element} this
7598          */
7599         replaceClass : function(oldClassName, newClassName){
7600             this.removeClass(oldClassName);
7601             this.addClass(newClassName);
7602             return this;
7603         },
7604
7605         /**
7606          * Returns an object with properties matching the styles requested.
7607          * For example, el.getStyles('color', 'font-size', 'width') might return
7608          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7609          * @param {String} style1 A style name
7610          * @param {String} style2 A style name
7611          * @param {String} etc.
7612          * @return {Object} The style object
7613          */
7614         getStyles : function(){
7615             var a = arguments, len = a.length, r = {};
7616             for(var i = 0; i < len; i++){
7617                 r[a[i]] = this.getStyle(a[i]);
7618             }
7619             return r;
7620         },
7621
7622         /**
7623          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7624          * @param {String} property The style property whose value is returned.
7625          * @return {String} The current value of the style property for this element.
7626          */
7627         getStyle : function(){
7628             return view && view.getComputedStyle ?
7629                 function(prop){
7630                     var el = this.dom, v, cs, camel;
7631                     if(prop == 'float'){
7632                         prop = "cssFloat";
7633                     }
7634                     if(el.style && (v = el.style[prop])){
7635                         return v;
7636                     }
7637                     if(cs = view.getComputedStyle(el, "")){
7638                         if(!(camel = propCache[prop])){
7639                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7640                         }
7641                         return cs[camel];
7642                     }
7643                     return null;
7644                 } :
7645                 function(prop){
7646                     var el = this.dom, v, cs, camel;
7647                     if(prop == 'opacity'){
7648                         if(typeof el.style.filter == 'string'){
7649                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7650                             if(m){
7651                                 var fv = parseFloat(m[1]);
7652                                 if(!isNaN(fv)){
7653                                     return fv ? fv / 100 : 0;
7654                                 }
7655                             }
7656                         }
7657                         return 1;
7658                     }else if(prop == 'float'){
7659                         prop = "styleFloat";
7660                     }
7661                     if(!(camel = propCache[prop])){
7662                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7663                     }
7664                     if(v = el.style[camel]){
7665                         return v;
7666                     }
7667                     if(cs = el.currentStyle){
7668                         return cs[camel];
7669                     }
7670                     return null;
7671                 };
7672         }(),
7673
7674         /**
7675          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7676          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7677          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7678          * @return {Roo.Element} this
7679          */
7680         setStyle : function(prop, value){
7681             if(typeof prop == "string"){
7682                 
7683                 if (prop == 'float') {
7684                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7685                     return this;
7686                 }
7687                 
7688                 var camel;
7689                 if(!(camel = propCache[prop])){
7690                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7691                 }
7692                 
7693                 if(camel == 'opacity') {
7694                     this.setOpacity(value);
7695                 }else{
7696                     this.dom.style[camel] = value;
7697                 }
7698             }else{
7699                 for(var style in prop){
7700                     if(typeof prop[style] != "function"){
7701                        this.setStyle(style, prop[style]);
7702                     }
7703                 }
7704             }
7705             return this;
7706         },
7707
7708         /**
7709          * More flexible version of {@link #setStyle} for setting style properties.
7710          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7711          * a function which returns such a specification.
7712          * @return {Roo.Element} this
7713          */
7714         applyStyles : function(style){
7715             Roo.DomHelper.applyStyles(this.dom, style);
7716             return this;
7717         },
7718
7719         /**
7720           * 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).
7721           * @return {Number} The X position of the element
7722           */
7723         getX : function(){
7724             return D.getX(this.dom);
7725         },
7726
7727         /**
7728           * 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).
7729           * @return {Number} The Y position of the element
7730           */
7731         getY : function(){
7732             return D.getY(this.dom);
7733         },
7734
7735         /**
7736           * 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).
7737           * @return {Array} The XY position of the element
7738           */
7739         getXY : function(){
7740             return D.getXY(this.dom);
7741         },
7742
7743         /**
7744          * 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).
7745          * @param {Number} The X position of the element
7746          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7747          * @return {Roo.Element} this
7748          */
7749         setX : function(x, animate){
7750             if(!animate || !A){
7751                 D.setX(this.dom, x);
7752             }else{
7753                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7754             }
7755             return this;
7756         },
7757
7758         /**
7759          * 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).
7760          * @param {Number} The Y position of the element
7761          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7762          * @return {Roo.Element} this
7763          */
7764         setY : function(y, animate){
7765             if(!animate || !A){
7766                 D.setY(this.dom, y);
7767             }else{
7768                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7769             }
7770             return this;
7771         },
7772
7773         /**
7774          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7775          * @param {String} left The left CSS property value
7776          * @return {Roo.Element} this
7777          */
7778         setLeft : function(left){
7779             this.setStyle("left", this.addUnits(left));
7780             return this;
7781         },
7782
7783         /**
7784          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7785          * @param {String} top The top CSS property value
7786          * @return {Roo.Element} this
7787          */
7788         setTop : function(top){
7789             this.setStyle("top", this.addUnits(top));
7790             return this;
7791         },
7792
7793         /**
7794          * Sets the element's CSS right style.
7795          * @param {String} right The right CSS property value
7796          * @return {Roo.Element} this
7797          */
7798         setRight : function(right){
7799             this.setStyle("right", this.addUnits(right));
7800             return this;
7801         },
7802
7803         /**
7804          * Sets the element's CSS bottom style.
7805          * @param {String} bottom The bottom CSS property value
7806          * @return {Roo.Element} this
7807          */
7808         setBottom : function(bottom){
7809             this.setStyle("bottom", this.addUnits(bottom));
7810             return this;
7811         },
7812
7813         /**
7814          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7815          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7816          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7817          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7818          * @return {Roo.Element} this
7819          */
7820         setXY : function(pos, animate){
7821             if(!animate || !A){
7822                 D.setXY(this.dom, pos);
7823             }else{
7824                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7825             }
7826             return this;
7827         },
7828
7829         /**
7830          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7831          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7832          * @param {Number} x X value for new position (coordinates are page-based)
7833          * @param {Number} y Y value for new position (coordinates are page-based)
7834          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7835          * @return {Roo.Element} this
7836          */
7837         setLocation : function(x, y, animate){
7838             this.setXY([x, y], this.preanim(arguments, 2));
7839             return this;
7840         },
7841
7842         /**
7843          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7844          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7845          * @param {Number} x X value for new position (coordinates are page-based)
7846          * @param {Number} y Y value for new position (coordinates are page-based)
7847          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7848          * @return {Roo.Element} this
7849          */
7850         moveTo : function(x, y, animate){
7851             this.setXY([x, y], this.preanim(arguments, 2));
7852             return this;
7853         },
7854
7855         /**
7856          * Returns the region of the given element.
7857          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7858          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7859          */
7860         getRegion : function(){
7861             return D.getRegion(this.dom);
7862         },
7863
7864         /**
7865          * Returns the offset height of the element
7866          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7867          * @return {Number} The element's height
7868          */
7869         getHeight : function(contentHeight){
7870             var h = this.dom.offsetHeight || 0;
7871             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7872         },
7873
7874         /**
7875          * Returns the offset width of the element
7876          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7877          * @return {Number} The element's width
7878          */
7879         getWidth : function(contentWidth){
7880             var w = this.dom.offsetWidth || 0;
7881             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7882         },
7883
7884         /**
7885          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7886          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7887          * if a height has not been set using CSS.
7888          * @return {Number}
7889          */
7890         getComputedHeight : function(){
7891             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7892             if(!h){
7893                 h = parseInt(this.getStyle('height'), 10) || 0;
7894                 if(!this.isBorderBox()){
7895                     h += this.getFrameWidth('tb');
7896                 }
7897             }
7898             return h;
7899         },
7900
7901         /**
7902          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7903          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7904          * if a width has not been set using CSS.
7905          * @return {Number}
7906          */
7907         getComputedWidth : function(){
7908             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7909             if(!w){
7910                 w = parseInt(this.getStyle('width'), 10) || 0;
7911                 if(!this.isBorderBox()){
7912                     w += this.getFrameWidth('lr');
7913                 }
7914             }
7915             return w;
7916         },
7917
7918         /**
7919          * Returns the size of the element.
7920          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7921          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7922          */
7923         getSize : function(contentSize){
7924             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7925         },
7926
7927         /**
7928          * Returns the width and height of the viewport.
7929          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7930          */
7931         getViewSize : function(){
7932             var d = this.dom, doc = document, aw = 0, ah = 0;
7933             if(d == doc || d == doc.body){
7934                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7935             }else{
7936                 return {
7937                     width : d.clientWidth,
7938                     height: d.clientHeight
7939                 };
7940             }
7941         },
7942
7943         /**
7944          * Returns the value of the "value" attribute
7945          * @param {Boolean} asNumber true to parse the value as a number
7946          * @return {String/Number}
7947          */
7948         getValue : function(asNumber){
7949             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7950         },
7951
7952         // private
7953         adjustWidth : function(width){
7954             if(typeof width == "number"){
7955                 if(this.autoBoxAdjust && !this.isBorderBox()){
7956                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7957                 }
7958                 if(width < 0){
7959                     width = 0;
7960                 }
7961             }
7962             return width;
7963         },
7964
7965         // private
7966         adjustHeight : function(height){
7967             if(typeof height == "number"){
7968                if(this.autoBoxAdjust && !this.isBorderBox()){
7969                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7970                }
7971                if(height < 0){
7972                    height = 0;
7973                }
7974             }
7975             return height;
7976         },
7977
7978         /**
7979          * Set the width of the element
7980          * @param {Number} width The new width
7981          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7982          * @return {Roo.Element} this
7983          */
7984         setWidth : function(width, animate){
7985             width = this.adjustWidth(width);
7986             if(!animate || !A){
7987                 this.dom.style.width = this.addUnits(width);
7988             }else{
7989                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7990             }
7991             return this;
7992         },
7993
7994         /**
7995          * Set the height of the element
7996          * @param {Number} height The new height
7997          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7998          * @return {Roo.Element} this
7999          */
8000          setHeight : function(height, animate){
8001             height = this.adjustHeight(height);
8002             if(!animate || !A){
8003                 this.dom.style.height = this.addUnits(height);
8004             }else{
8005                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8006             }
8007             return this;
8008         },
8009
8010         /**
8011          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8012          * @param {Number} width The new width
8013          * @param {Number} height The new height
8014          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8015          * @return {Roo.Element} this
8016          */
8017          setSize : function(width, height, animate){
8018             if(typeof width == "object"){ // in case of object from getSize()
8019                 height = width.height; width = width.width;
8020             }
8021             width = this.adjustWidth(width); height = this.adjustHeight(height);
8022             if(!animate || !A){
8023                 this.dom.style.width = this.addUnits(width);
8024                 this.dom.style.height = this.addUnits(height);
8025             }else{
8026                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8027             }
8028             return this;
8029         },
8030
8031         /**
8032          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8033          * @param {Number} x X value for new position (coordinates are page-based)
8034          * @param {Number} y Y value for new position (coordinates are page-based)
8035          * @param {Number} width The new width
8036          * @param {Number} height The new height
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         setBounds : function(x, y, width, height, animate){
8041             if(!animate || !A){
8042                 this.setSize(width, height);
8043                 this.setLocation(x, y);
8044             }else{
8045                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8046                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8047                               this.preanim(arguments, 4), 'motion');
8048             }
8049             return this;
8050         },
8051
8052         /**
8053          * 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.
8054          * @param {Roo.lib.Region} region The region to fill
8055          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8056          * @return {Roo.Element} this
8057          */
8058         setRegion : function(region, animate){
8059             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8060             return this;
8061         },
8062
8063         /**
8064          * Appends an event handler
8065          *
8066          * @param {String}   eventName     The type of event to append
8067          * @param {Function} fn        The method the event invokes
8068          * @param {Object} scope       (optional) The scope (this object) of the fn
8069          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8070          */
8071         addListener : function(eventName, fn, scope, options){
8072             if (this.dom) {
8073                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8074             }
8075         },
8076
8077         /**
8078          * Removes an event handler from this element
8079          * @param {String} eventName the type of event to remove
8080          * @param {Function} fn the method the event invokes
8081          * @return {Roo.Element} this
8082          */
8083         removeListener : function(eventName, fn){
8084             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8085             return this;
8086         },
8087
8088         /**
8089          * Removes all previous added listeners from this element
8090          * @return {Roo.Element} this
8091          */
8092         removeAllListeners : function(){
8093             E.purgeElement(this.dom);
8094             return this;
8095         },
8096
8097         relayEvent : function(eventName, observable){
8098             this.on(eventName, function(e){
8099                 observable.fireEvent(eventName, e);
8100             });
8101         },
8102
8103         /**
8104          * Set the opacity of the element
8105          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8106          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8107          * @return {Roo.Element} this
8108          */
8109          setOpacity : function(opacity, animate){
8110             if(!animate || !A){
8111                 var s = this.dom.style;
8112                 if(Roo.isIE){
8113                     s.zoom = 1;
8114                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8115                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8116                 }else{
8117                     s.opacity = opacity;
8118                 }
8119             }else{
8120                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8121             }
8122             return this;
8123         },
8124
8125         /**
8126          * Gets the left X coordinate
8127          * @param {Boolean} local True to get the local css position instead of page coordinate
8128          * @return {Number}
8129          */
8130         getLeft : function(local){
8131             if(!local){
8132                 return this.getX();
8133             }else{
8134                 return parseInt(this.getStyle("left"), 10) || 0;
8135             }
8136         },
8137
8138         /**
8139          * Gets the right X coordinate of the element (element X position + element width)
8140          * @param {Boolean} local True to get the local css position instead of page coordinate
8141          * @return {Number}
8142          */
8143         getRight : function(local){
8144             if(!local){
8145                 return this.getX() + this.getWidth();
8146             }else{
8147                 return (this.getLeft(true) + this.getWidth()) || 0;
8148             }
8149         },
8150
8151         /**
8152          * Gets the top Y coordinate
8153          * @param {Boolean} local True to get the local css position instead of page coordinate
8154          * @return {Number}
8155          */
8156         getTop : function(local) {
8157             if(!local){
8158                 return this.getY();
8159             }else{
8160                 return parseInt(this.getStyle("top"), 10) || 0;
8161             }
8162         },
8163
8164         /**
8165          * Gets the bottom Y coordinate of the element (element Y position + element height)
8166          * @param {Boolean} local True to get the local css position instead of page coordinate
8167          * @return {Number}
8168          */
8169         getBottom : function(local){
8170             if(!local){
8171                 return this.getY() + this.getHeight();
8172             }else{
8173                 return (this.getTop(true) + this.getHeight()) || 0;
8174             }
8175         },
8176
8177         /**
8178         * Initializes positioning on this element. If a desired position is not passed, it will make the
8179         * the element positioned relative IF it is not already positioned.
8180         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8181         * @param {Number} zIndex (optional) The zIndex to apply
8182         * @param {Number} x (optional) Set the page X position
8183         * @param {Number} y (optional) Set the page Y position
8184         */
8185         position : function(pos, zIndex, x, y){
8186             if(!pos){
8187                if(this.getStyle('position') == 'static'){
8188                    this.setStyle('position', 'relative');
8189                }
8190             }else{
8191                 this.setStyle("position", pos);
8192             }
8193             if(zIndex){
8194                 this.setStyle("z-index", zIndex);
8195             }
8196             if(x !== undefined && y !== undefined){
8197                 this.setXY([x, y]);
8198             }else if(x !== undefined){
8199                 this.setX(x);
8200             }else if(y !== undefined){
8201                 this.setY(y);
8202             }
8203         },
8204
8205         /**
8206         * Clear positioning back to the default when the document was loaded
8207         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8208         * @return {Roo.Element} this
8209          */
8210         clearPositioning : function(value){
8211             value = value ||'';
8212             this.setStyle({
8213                 "left": value,
8214                 "right": value,
8215                 "top": value,
8216                 "bottom": value,
8217                 "z-index": "",
8218                 "position" : "static"
8219             });
8220             return this;
8221         },
8222
8223         /**
8224         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8225         * snapshot before performing an update and then restoring the element.
8226         * @return {Object}
8227         */
8228         getPositioning : function(){
8229             var l = this.getStyle("left");
8230             var t = this.getStyle("top");
8231             return {
8232                 "position" : this.getStyle("position"),
8233                 "left" : l,
8234                 "right" : l ? "" : this.getStyle("right"),
8235                 "top" : t,
8236                 "bottom" : t ? "" : this.getStyle("bottom"),
8237                 "z-index" : this.getStyle("z-index")
8238             };
8239         },
8240
8241         /**
8242          * Gets the width of the border(s) for the specified side(s)
8243          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8244          * passing lr would get the border (l)eft width + the border (r)ight width.
8245          * @return {Number} The width of the sides passed added together
8246          */
8247         getBorderWidth : function(side){
8248             return this.addStyles(side, El.borders);
8249         },
8250
8251         /**
8252          * Gets the width of the padding(s) for the specified side(s)
8253          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8254          * passing lr would get the padding (l)eft + the padding (r)ight.
8255          * @return {Number} The padding of the sides passed added together
8256          */
8257         getPadding : function(side){
8258             return this.addStyles(side, El.paddings);
8259         },
8260
8261         /**
8262         * Set positioning with an object returned by getPositioning().
8263         * @param {Object} posCfg
8264         * @return {Roo.Element} this
8265          */
8266         setPositioning : function(pc){
8267             this.applyStyles(pc);
8268             if(pc.right == "auto"){
8269                 this.dom.style.right = "";
8270             }
8271             if(pc.bottom == "auto"){
8272                 this.dom.style.bottom = "";
8273             }
8274             return this;
8275         },
8276
8277         // private
8278         fixDisplay : function(){
8279             if(this.getStyle("display") == "none"){
8280                 this.setStyle("visibility", "hidden");
8281                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8282                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8283                     this.setStyle("display", "block");
8284                 }
8285             }
8286         },
8287
8288         /**
8289          * Quick set left and top adding default units
8290          * @param {String} left The left CSS property value
8291          * @param {String} top The top CSS property value
8292          * @return {Roo.Element} this
8293          */
8294          setLeftTop : function(left, top){
8295             this.dom.style.left = this.addUnits(left);
8296             this.dom.style.top = this.addUnits(top);
8297             return this;
8298         },
8299
8300         /**
8301          * Move this element relative to its current position.
8302          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8303          * @param {Number} distance How far to move the element in pixels
8304          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8305          * @return {Roo.Element} this
8306          */
8307          move : function(direction, distance, animate){
8308             var xy = this.getXY();
8309             direction = direction.toLowerCase();
8310             switch(direction){
8311                 case "l":
8312                 case "left":
8313                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8314                     break;
8315                case "r":
8316                case "right":
8317                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8318                     break;
8319                case "t":
8320                case "top":
8321                case "up":
8322                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8323                     break;
8324                case "b":
8325                case "bottom":
8326                case "down":
8327                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8328                     break;
8329             }
8330             return this;
8331         },
8332
8333         /**
8334          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8335          * @return {Roo.Element} this
8336          */
8337         clip : function(){
8338             if(!this.isClipped){
8339                this.isClipped = true;
8340                this.originalClip = {
8341                    "o": this.getStyle("overflow"),
8342                    "x": this.getStyle("overflow-x"),
8343                    "y": this.getStyle("overflow-y")
8344                };
8345                this.setStyle("overflow", "hidden");
8346                this.setStyle("overflow-x", "hidden");
8347                this.setStyle("overflow-y", "hidden");
8348             }
8349             return this;
8350         },
8351
8352         /**
8353          *  Return clipping (overflow) to original clipping before clip() was called
8354          * @return {Roo.Element} this
8355          */
8356         unclip : function(){
8357             if(this.isClipped){
8358                 this.isClipped = false;
8359                 var o = this.originalClip;
8360                 if(o.o){this.setStyle("overflow", o.o);}
8361                 if(o.x){this.setStyle("overflow-x", o.x);}
8362                 if(o.y){this.setStyle("overflow-y", o.y);}
8363             }
8364             return this;
8365         },
8366
8367
8368         /**
8369          * Gets the x,y coordinates specified by the anchor position on the element.
8370          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8371          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8372          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8373          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8374          * @return {Array} [x, y] An array containing the element's x and y coordinates
8375          */
8376         getAnchorXY : function(anchor, local, s){
8377             //Passing a different size is useful for pre-calculating anchors,
8378             //especially for anchored animations that change the el size.
8379
8380             var w, h, vp = false;
8381             if(!s){
8382                 var d = this.dom;
8383                 if(d == document.body || d == document){
8384                     vp = true;
8385                     w = D.getViewWidth(); h = D.getViewHeight();
8386                 }else{
8387                     w = this.getWidth(); h = this.getHeight();
8388                 }
8389             }else{
8390                 w = s.width;  h = s.height;
8391             }
8392             var x = 0, y = 0, r = Math.round;
8393             switch((anchor || "tl").toLowerCase()){
8394                 case "c":
8395                     x = r(w*.5);
8396                     y = r(h*.5);
8397                 break;
8398                 case "t":
8399                     x = r(w*.5);
8400                     y = 0;
8401                 break;
8402                 case "l":
8403                     x = 0;
8404                     y = r(h*.5);
8405                 break;
8406                 case "r":
8407                     x = w;
8408                     y = r(h*.5);
8409                 break;
8410                 case "b":
8411                     x = r(w*.5);
8412                     y = h;
8413                 break;
8414                 case "tl":
8415                     x = 0;
8416                     y = 0;
8417                 break;
8418                 case "bl":
8419                     x = 0;
8420                     y = h;
8421                 break;
8422                 case "br":
8423                     x = w;
8424                     y = h;
8425                 break;
8426                 case "tr":
8427                     x = w;
8428                     y = 0;
8429                 break;
8430             }
8431             if(local === true){
8432                 return [x, y];
8433             }
8434             if(vp){
8435                 var sc = this.getScroll();
8436                 return [x + sc.left, y + sc.top];
8437             }
8438             //Add the element's offset xy
8439             var o = this.getXY();
8440             return [x+o[0], y+o[1]];
8441         },
8442
8443         /**
8444          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8445          * supported position values.
8446          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8447          * @param {String} position The position to align to.
8448          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8449          * @return {Array} [x, y]
8450          */
8451         getAlignToXY : function(el, p, o){
8452             el = Roo.get(el);
8453             var d = this.dom;
8454             if(!el.dom){
8455                 throw "Element.alignTo with an element that doesn't exist";
8456             }
8457             var c = false; //constrain to viewport
8458             var p1 = "", p2 = "";
8459             o = o || [0,0];
8460
8461             if(!p){
8462                 p = "tl-bl";
8463             }else if(p == "?"){
8464                 p = "tl-bl?";
8465             }else if(p.indexOf("-") == -1){
8466                 p = "tl-" + p;
8467             }
8468             p = p.toLowerCase();
8469             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8470             if(!m){
8471                throw "Element.alignTo with an invalid alignment " + p;
8472             }
8473             p1 = m[1]; p2 = m[2]; c = !!m[3];
8474
8475             //Subtract the aligned el's internal xy from the target's offset xy
8476             //plus custom offset to get the aligned el's new offset xy
8477             var a1 = this.getAnchorXY(p1, true);
8478             var a2 = el.getAnchorXY(p2, false);
8479             var x = a2[0] - a1[0] + o[0];
8480             var y = a2[1] - a1[1] + o[1];
8481             if(c){
8482                 //constrain the aligned el to viewport if necessary
8483                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8484                 // 5px of margin for ie
8485                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8486
8487                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8488                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8489                 //otherwise swap the aligned el to the opposite border of the target.
8490                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8491                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8492                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8493                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8494
8495                var doc = document;
8496                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8497                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8498
8499                if((x+w) > dw + scrollX){
8500                     x = swapX ? r.left-w : dw+scrollX-w;
8501                 }
8502                if(x < scrollX){
8503                    x = swapX ? r.right : scrollX;
8504                }
8505                if((y+h) > dh + scrollY){
8506                     y = swapY ? r.top-h : dh+scrollY-h;
8507                 }
8508                if (y < scrollY){
8509                    y = swapY ? r.bottom : scrollY;
8510                }
8511             }
8512             return [x,y];
8513         },
8514
8515         // private
8516         getConstrainToXY : function(){
8517             var os = {top:0, left:0, bottom:0, right: 0};
8518
8519             return function(el, local, offsets, proposedXY){
8520                 el = Roo.get(el);
8521                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8522
8523                 var vw, vh, vx = 0, vy = 0;
8524                 if(el.dom == document.body || el.dom == document){
8525                     vw = Roo.lib.Dom.getViewWidth();
8526                     vh = Roo.lib.Dom.getViewHeight();
8527                 }else{
8528                     vw = el.dom.clientWidth;
8529                     vh = el.dom.clientHeight;
8530                     if(!local){
8531                         var vxy = el.getXY();
8532                         vx = vxy[0];
8533                         vy = vxy[1];
8534                     }
8535                 }
8536
8537                 var s = el.getScroll();
8538
8539                 vx += offsets.left + s.left;
8540                 vy += offsets.top + s.top;
8541
8542                 vw -= offsets.right;
8543                 vh -= offsets.bottom;
8544
8545                 var vr = vx+vw;
8546                 var vb = vy+vh;
8547
8548                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8549                 var x = xy[0], y = xy[1];
8550                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8551
8552                 // only move it if it needs it
8553                 var moved = false;
8554
8555                 // first validate right/bottom
8556                 if((x + w) > vr){
8557                     x = vr - w;
8558                     moved = true;
8559                 }
8560                 if((y + h) > vb){
8561                     y = vb - h;
8562                     moved = true;
8563                 }
8564                 // then make sure top/left isn't negative
8565                 if(x < vx){
8566                     x = vx;
8567                     moved = true;
8568                 }
8569                 if(y < vy){
8570                     y = vy;
8571                     moved = true;
8572                 }
8573                 return moved ? [x, y] : false;
8574             };
8575         }(),
8576
8577         // private
8578         adjustForConstraints : function(xy, parent, offsets){
8579             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8580         },
8581
8582         /**
8583          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8584          * document it aligns it to the viewport.
8585          * The position parameter is optional, and can be specified in any one of the following formats:
8586          * <ul>
8587          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8588          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8589          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8590          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8591          *   <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
8592          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8593          * </ul>
8594          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8595          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8596          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8597          * that specified in order to enforce the viewport constraints.
8598          * Following are all of the supported anchor positions:
8599     <pre>
8600     Value  Description
8601     -----  -----------------------------
8602     tl     The top left corner (default)
8603     t      The center of the top edge
8604     tr     The top right corner
8605     l      The center of the left edge
8606     c      In the center of the element
8607     r      The center of the right edge
8608     bl     The bottom left corner
8609     b      The center of the bottom edge
8610     br     The bottom right corner
8611     </pre>
8612     Example Usage:
8613     <pre><code>
8614     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8615     el.alignTo("other-el");
8616
8617     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8618     el.alignTo("other-el", "tr?");
8619
8620     // align the bottom right corner of el with the center left edge of other-el
8621     el.alignTo("other-el", "br-l?");
8622
8623     // align the center of el with the bottom left corner of other-el and
8624     // adjust the x position by -6 pixels (and the y position by 0)
8625     el.alignTo("other-el", "c-bl", [-6, 0]);
8626     </code></pre>
8627          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8628          * @param {String} position The position to align to.
8629          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8630          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8631          * @return {Roo.Element} this
8632          */
8633         alignTo : function(element, position, offsets, animate){
8634             var xy = this.getAlignToXY(element, position, offsets);
8635             this.setXY(xy, this.preanim(arguments, 3));
8636             return this;
8637         },
8638
8639         /**
8640          * Anchors an element to another element and realigns it when the window is resized.
8641          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8642          * @param {String} position The position to align to.
8643          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8644          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8645          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8646          * is a number, it is used as the buffer delay (defaults to 50ms).
8647          * @param {Function} callback The function to call after the animation finishes
8648          * @return {Roo.Element} this
8649          */
8650         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8651             var action = function(){
8652                 this.alignTo(el, alignment, offsets, animate);
8653                 Roo.callback(callback, this);
8654             };
8655             Roo.EventManager.onWindowResize(action, this);
8656             var tm = typeof monitorScroll;
8657             if(tm != 'undefined'){
8658                 Roo.EventManager.on(window, 'scroll', action, this,
8659                     {buffer: tm == 'number' ? monitorScroll : 50});
8660             }
8661             action.call(this); // align immediately
8662             return this;
8663         },
8664         /**
8665          * Clears any opacity settings from this element. Required in some cases for IE.
8666          * @return {Roo.Element} this
8667          */
8668         clearOpacity : function(){
8669             if (window.ActiveXObject) {
8670                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8671                     this.dom.style.filter = "";
8672                 }
8673             } else {
8674                 this.dom.style.opacity = "";
8675                 this.dom.style["-moz-opacity"] = "";
8676                 this.dom.style["-khtml-opacity"] = "";
8677             }
8678             return this;
8679         },
8680
8681         /**
8682          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8683          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8684          * @return {Roo.Element} this
8685          */
8686         hide : function(animate){
8687             this.setVisible(false, this.preanim(arguments, 0));
8688             return this;
8689         },
8690
8691         /**
8692         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8693         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8694          * @return {Roo.Element} this
8695          */
8696         show : function(animate){
8697             this.setVisible(true, this.preanim(arguments, 0));
8698             return this;
8699         },
8700
8701         /**
8702          * @private Test if size has a unit, otherwise appends the default
8703          */
8704         addUnits : function(size){
8705             return Roo.Element.addUnits(size, this.defaultUnit);
8706         },
8707
8708         /**
8709          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8710          * @return {Roo.Element} this
8711          */
8712         beginMeasure : function(){
8713             var el = this.dom;
8714             if(el.offsetWidth || el.offsetHeight){
8715                 return this; // offsets work already
8716             }
8717             var changed = [];
8718             var p = this.dom, b = document.body; // start with this element
8719             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8720                 var pe = Roo.get(p);
8721                 if(pe.getStyle('display') == 'none'){
8722                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8723                     p.style.visibility = "hidden";
8724                     p.style.display = "block";
8725                 }
8726                 p = p.parentNode;
8727             }
8728             this._measureChanged = changed;
8729             return this;
8730
8731         },
8732
8733         /**
8734          * Restores displays to before beginMeasure was called
8735          * @return {Roo.Element} this
8736          */
8737         endMeasure : function(){
8738             var changed = this._measureChanged;
8739             if(changed){
8740                 for(var i = 0, len = changed.length; i < len; i++) {
8741                     var r = changed[i];
8742                     r.el.style.visibility = r.visibility;
8743                     r.el.style.display = "none";
8744                 }
8745                 this._measureChanged = null;
8746             }
8747             return this;
8748         },
8749
8750         /**
8751         * Update the innerHTML of this element, optionally searching for and processing scripts
8752         * @param {String} html The new HTML
8753         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8754         * @param {Function} callback For async script loading you can be noticed when the update completes
8755         * @return {Roo.Element} this
8756          */
8757         update : function(html, loadScripts, callback){
8758             if(typeof html == "undefined"){
8759                 html = "";
8760             }
8761             if(loadScripts !== true){
8762                 this.dom.innerHTML = html;
8763                 if(typeof callback == "function"){
8764                     callback();
8765                 }
8766                 return this;
8767             }
8768             var id = Roo.id();
8769             var dom = this.dom;
8770
8771             html += '<span id="' + id + '"></span>';
8772
8773             E.onAvailable(id, function(){
8774                 var hd = document.getElementsByTagName("head")[0];
8775                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8776                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8777                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8778
8779                 var match;
8780                 while(match = re.exec(html)){
8781                     var attrs = match[1];
8782                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8783                     if(srcMatch && srcMatch[2]){
8784                        var s = document.createElement("script");
8785                        s.src = srcMatch[2];
8786                        var typeMatch = attrs.match(typeRe);
8787                        if(typeMatch && typeMatch[2]){
8788                            s.type = typeMatch[2];
8789                        }
8790                        hd.appendChild(s);
8791                     }else if(match[2] && match[2].length > 0){
8792                         if(window.execScript) {
8793                            window.execScript(match[2]);
8794                         } else {
8795                             /**
8796                              * eval:var:id
8797                              * eval:var:dom
8798                              * eval:var:html
8799                              * 
8800                              */
8801                            window.eval(match[2]);
8802                         }
8803                     }
8804                 }
8805                 var el = document.getElementById(id);
8806                 if(el){el.parentNode.removeChild(el);}
8807                 if(typeof callback == "function"){
8808                     callback();
8809                 }
8810             });
8811             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8812             return this;
8813         },
8814
8815         /**
8816          * Direct access to the UpdateManager update() method (takes the same parameters).
8817          * @param {String/Function} url The url for this request or a function to call to get the url
8818          * @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}
8819          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8820          * @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.
8821          * @return {Roo.Element} this
8822          */
8823         load : function(){
8824             var um = this.getUpdateManager();
8825             um.update.apply(um, arguments);
8826             return this;
8827         },
8828
8829         /**
8830         * Gets this element's UpdateManager
8831         * @return {Roo.UpdateManager} The UpdateManager
8832         */
8833         getUpdateManager : function(){
8834             if(!this.updateManager){
8835                 this.updateManager = new Roo.UpdateManager(this);
8836             }
8837             return this.updateManager;
8838         },
8839
8840         /**
8841          * Disables text selection for this element (normalized across browsers)
8842          * @return {Roo.Element} this
8843          */
8844         unselectable : function(){
8845             this.dom.unselectable = "on";
8846             this.swallowEvent("selectstart", true);
8847             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8848             this.addClass("x-unselectable");
8849             return this;
8850         },
8851
8852         /**
8853         * Calculates the x, y to center this element on the screen
8854         * @return {Array} The x, y values [x, y]
8855         */
8856         getCenterXY : function(){
8857             return this.getAlignToXY(document, 'c-c');
8858         },
8859
8860         /**
8861         * Centers the Element in either the viewport, or another Element.
8862         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8863         */
8864         center : function(centerIn){
8865             this.alignTo(centerIn || document, 'c-c');
8866             return this;
8867         },
8868
8869         /**
8870          * Tests various css rules/browsers to determine if this element uses a border box
8871          * @return {Boolean}
8872          */
8873         isBorderBox : function(){
8874             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8875         },
8876
8877         /**
8878          * Return a box {x, y, width, height} that can be used to set another elements
8879          * size/location to match this element.
8880          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8881          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8882          * @return {Object} box An object in the format {x, y, width, height}
8883          */
8884         getBox : function(contentBox, local){
8885             var xy;
8886             if(!local){
8887                 xy = this.getXY();
8888             }else{
8889                 var left = parseInt(this.getStyle("left"), 10) || 0;
8890                 var top = parseInt(this.getStyle("top"), 10) || 0;
8891                 xy = [left, top];
8892             }
8893             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8894             if(!contentBox){
8895                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8896             }else{
8897                 var l = this.getBorderWidth("l")+this.getPadding("l");
8898                 var r = this.getBorderWidth("r")+this.getPadding("r");
8899                 var t = this.getBorderWidth("t")+this.getPadding("t");
8900                 var b = this.getBorderWidth("b")+this.getPadding("b");
8901                 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)};
8902             }
8903             bx.right = bx.x + bx.width;
8904             bx.bottom = bx.y + bx.height;
8905             return bx;
8906         },
8907
8908         /**
8909          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8910          for more information about the sides.
8911          * @param {String} sides
8912          * @return {Number}
8913          */
8914         getFrameWidth : function(sides, onlyContentBox){
8915             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8916         },
8917
8918         /**
8919          * 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.
8920          * @param {Object} box The box to fill {x, y, width, height}
8921          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8922          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8923          * @return {Roo.Element} this
8924          */
8925         setBox : function(box, adjust, animate){
8926             var w = box.width, h = box.height;
8927             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8928                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8929                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8930             }
8931             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8932             return this;
8933         },
8934
8935         /**
8936          * Forces the browser to repaint this element
8937          * @return {Roo.Element} this
8938          */
8939          repaint : function(){
8940             var dom = this.dom;
8941             this.addClass("x-repaint");
8942             setTimeout(function(){
8943                 Roo.get(dom).removeClass("x-repaint");
8944             }, 1);
8945             return this;
8946         },
8947
8948         /**
8949          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8950          * then it returns the calculated width of the sides (see getPadding)
8951          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8952          * @return {Object/Number}
8953          */
8954         getMargins : function(side){
8955             if(!side){
8956                 return {
8957                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8958                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8959                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8960                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8961                 };
8962             }else{
8963                 return this.addStyles(side, El.margins);
8964              }
8965         },
8966
8967         // private
8968         addStyles : function(sides, styles){
8969             var val = 0, v, w;
8970             for(var i = 0, len = sides.length; i < len; i++){
8971                 v = this.getStyle(styles[sides.charAt(i)]);
8972                 if(v){
8973                      w = parseInt(v, 10);
8974                      if(w){ val += w; }
8975                 }
8976             }
8977             return val;
8978         },
8979
8980         /**
8981          * Creates a proxy element of this element
8982          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8983          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8984          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8985          * @return {Roo.Element} The new proxy element
8986          */
8987         createProxy : function(config, renderTo, matchBox){
8988             if(renderTo){
8989                 renderTo = Roo.getDom(renderTo);
8990             }else{
8991                 renderTo = document.body;
8992             }
8993             config = typeof config == "object" ?
8994                 config : {tag : "div", cls: config};
8995             var proxy = Roo.DomHelper.append(renderTo, config, true);
8996             if(matchBox){
8997                proxy.setBox(this.getBox());
8998             }
8999             return proxy;
9000         },
9001
9002         /**
9003          * Puts a mask over this element to disable user interaction. Requires core.css.
9004          * This method can only be applied to elements which accept child nodes.
9005          * @param {String} msg (optional) A message to display in the mask
9006          * @param {String} msgCls (optional) A css class to apply to the msg element
9007          * @return {Element} The mask  element
9008          */
9009         mask : function(msg, msgCls)
9010         {
9011             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9012                 this.setStyle("position", "relative");
9013             }
9014             if(!this._mask){
9015                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9016             }
9017             this.addClass("x-masked");
9018             this._mask.setDisplayed(true);
9019             
9020             // we wander
9021             var z = 0;
9022             var dom = this.dom;
9023             while (dom && dom.style) {
9024                 if (!isNaN(parseInt(dom.style.zIndex))) {
9025                     z = Math.max(z, parseInt(dom.style.zIndex));
9026                 }
9027                 dom = dom.parentNode;
9028             }
9029             // if we are masking the body - then it hides everything..
9030             if (this.dom == document.body) {
9031                 z = 1000000;
9032                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9033                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9034             }
9035            
9036             if(typeof msg == 'string'){
9037                 if(!this._maskMsg){
9038                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9039                 }
9040                 var mm = this._maskMsg;
9041                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9042                 if (mm.dom.firstChild) { // weird IE issue?
9043                     mm.dom.firstChild.innerHTML = msg;
9044                 }
9045                 mm.setDisplayed(true);
9046                 mm.center(this);
9047                 mm.setStyle('z-index', z + 102);
9048             }
9049             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9050                 this._mask.setHeight(this.getHeight());
9051             }
9052             this._mask.setStyle('z-index', z + 100);
9053             
9054             return this._mask;
9055         },
9056
9057         /**
9058          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9059          * it is cached for reuse.
9060          */
9061         unmask : function(removeEl){
9062             if(this._mask){
9063                 if(removeEl === true){
9064                     this._mask.remove();
9065                     delete this._mask;
9066                     if(this._maskMsg){
9067                         this._maskMsg.remove();
9068                         delete this._maskMsg;
9069                     }
9070                 }else{
9071                     this._mask.setDisplayed(false);
9072                     if(this._maskMsg){
9073                         this._maskMsg.setDisplayed(false);
9074                     }
9075                 }
9076             }
9077             this.removeClass("x-masked");
9078         },
9079
9080         /**
9081          * Returns true if this element is masked
9082          * @return {Boolean}
9083          */
9084         isMasked : function(){
9085             return this._mask && this._mask.isVisible();
9086         },
9087
9088         /**
9089          * Creates an iframe shim for this element to keep selects and other windowed objects from
9090          * showing through.
9091          * @return {Roo.Element} The new shim element
9092          */
9093         createShim : function(){
9094             var el = document.createElement('iframe');
9095             el.frameBorder = 'no';
9096             el.className = 'roo-shim';
9097             if(Roo.isIE && Roo.isSecure){
9098                 el.src = Roo.SSL_SECURE_URL;
9099             }
9100             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9101             shim.autoBoxAdjust = false;
9102             return shim;
9103         },
9104
9105         /**
9106          * Removes this element from the DOM and deletes it from the cache
9107          */
9108         remove : function(){
9109             if(this.dom.parentNode){
9110                 this.dom.parentNode.removeChild(this.dom);
9111             }
9112             delete El.cache[this.dom.id];
9113         },
9114
9115         /**
9116          * Sets up event handlers to add and remove a css class when the mouse is over this element
9117          * @param {String} className
9118          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9119          * mouseout events for children elements
9120          * @return {Roo.Element} this
9121          */
9122         addClassOnOver : function(className, preventFlicker){
9123             this.on("mouseover", function(){
9124                 Roo.fly(this, '_internal').addClass(className);
9125             }, this.dom);
9126             var removeFn = function(e){
9127                 if(preventFlicker !== true || !e.within(this, true)){
9128                     Roo.fly(this, '_internal').removeClass(className);
9129                 }
9130             };
9131             this.on("mouseout", removeFn, this.dom);
9132             return this;
9133         },
9134
9135         /**
9136          * Sets up event handlers to add and remove a css class when this element has the focus
9137          * @param {String} className
9138          * @return {Roo.Element} this
9139          */
9140         addClassOnFocus : function(className){
9141             this.on("focus", function(){
9142                 Roo.fly(this, '_internal').addClass(className);
9143             }, this.dom);
9144             this.on("blur", function(){
9145                 Roo.fly(this, '_internal').removeClass(className);
9146             }, this.dom);
9147             return this;
9148         },
9149         /**
9150          * 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)
9151          * @param {String} className
9152          * @return {Roo.Element} this
9153          */
9154         addClassOnClick : function(className){
9155             var dom = this.dom;
9156             this.on("mousedown", function(){
9157                 Roo.fly(dom, '_internal').addClass(className);
9158                 var d = Roo.get(document);
9159                 var fn = function(){
9160                     Roo.fly(dom, '_internal').removeClass(className);
9161                     d.removeListener("mouseup", fn);
9162                 };
9163                 d.on("mouseup", fn);
9164             });
9165             return this;
9166         },
9167
9168         /**
9169          * Stops the specified event from bubbling and optionally prevents the default action
9170          * @param {String} eventName
9171          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9172          * @return {Roo.Element} this
9173          */
9174         swallowEvent : function(eventName, preventDefault){
9175             var fn = function(e){
9176                 e.stopPropagation();
9177                 if(preventDefault){
9178                     e.preventDefault();
9179                 }
9180             };
9181             if(eventName instanceof Array){
9182                 for(var i = 0, len = eventName.length; i < len; i++){
9183                      this.on(eventName[i], fn);
9184                 }
9185                 return this;
9186             }
9187             this.on(eventName, fn);
9188             return this;
9189         },
9190
9191         /**
9192          * @private
9193          */
9194       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9195
9196         /**
9197          * Sizes this element to its parent element's dimensions performing
9198          * neccessary box adjustments.
9199          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9200          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9201          * @return {Roo.Element} this
9202          */
9203         fitToParent : function(monitorResize, targetParent) {
9204           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9205           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9206           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9207             return;
9208           }
9209           var p = Roo.get(targetParent || this.dom.parentNode);
9210           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9211           if (monitorResize === true) {
9212             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9213             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9214           }
9215           return this;
9216         },
9217
9218         /**
9219          * Gets the next sibling, skipping text nodes
9220          * @return {HTMLElement} The next sibling or null
9221          */
9222         getNextSibling : function(){
9223             var n = this.dom.nextSibling;
9224             while(n && n.nodeType != 1){
9225                 n = n.nextSibling;
9226             }
9227             return n;
9228         },
9229
9230         /**
9231          * Gets the previous sibling, skipping text nodes
9232          * @return {HTMLElement} The previous sibling or null
9233          */
9234         getPrevSibling : function(){
9235             var n = this.dom.previousSibling;
9236             while(n && n.nodeType != 1){
9237                 n = n.previousSibling;
9238             }
9239             return n;
9240         },
9241
9242
9243         /**
9244          * Appends the passed element(s) to this element
9245          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9246          * @return {Roo.Element} this
9247          */
9248         appendChild: function(el){
9249             el = Roo.get(el);
9250             el.appendTo(this);
9251             return this;
9252         },
9253
9254         /**
9255          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9256          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9257          * automatically generated with the specified attributes.
9258          * @param {HTMLElement} insertBefore (optional) a child element of this element
9259          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9260          * @return {Roo.Element} The new child element
9261          */
9262         createChild: function(config, insertBefore, returnDom){
9263             config = config || {tag:'div'};
9264             if(insertBefore){
9265                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9266             }
9267             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9268         },
9269
9270         /**
9271          * Appends this element to the passed element
9272          * @param {String/HTMLElement/Element} el The new parent element
9273          * @return {Roo.Element} this
9274          */
9275         appendTo: function(el){
9276             el = Roo.getDom(el);
9277             el.appendChild(this.dom);
9278             return this;
9279         },
9280
9281         /**
9282          * Inserts this element before the passed element in the DOM
9283          * @param {String/HTMLElement/Element} el The element to insert before
9284          * @return {Roo.Element} this
9285          */
9286         insertBefore: function(el){
9287             el = Roo.getDom(el);
9288             el.parentNode.insertBefore(this.dom, el);
9289             return this;
9290         },
9291
9292         /**
9293          * Inserts this element after the passed element in the DOM
9294          * @param {String/HTMLElement/Element} el The element to insert after
9295          * @return {Roo.Element} this
9296          */
9297         insertAfter: function(el){
9298             el = Roo.getDom(el);
9299             el.parentNode.insertBefore(this.dom, el.nextSibling);
9300             return this;
9301         },
9302
9303         /**
9304          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9305          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9306          * @return {Roo.Element} The new child
9307          */
9308         insertFirst: function(el, returnDom){
9309             el = el || {};
9310             if(typeof el == 'object' && !el.nodeType){ // dh config
9311                 return this.createChild(el, this.dom.firstChild, returnDom);
9312             }else{
9313                 el = Roo.getDom(el);
9314                 this.dom.insertBefore(el, this.dom.firstChild);
9315                 return !returnDom ? Roo.get(el) : el;
9316             }
9317         },
9318
9319         /**
9320          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9321          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9322          * @param {String} where (optional) 'before' or 'after' defaults to before
9323          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9324          * @return {Roo.Element} the inserted Element
9325          */
9326         insertSibling: function(el, where, returnDom){
9327             where = where ? where.toLowerCase() : 'before';
9328             el = el || {};
9329             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9330
9331             if(typeof el == 'object' && !el.nodeType){ // dh config
9332                 if(where == 'after' && !this.dom.nextSibling){
9333                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9334                 }else{
9335                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9336                 }
9337
9338             }else{
9339                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9340                             where == 'before' ? this.dom : this.dom.nextSibling);
9341                 if(!returnDom){
9342                     rt = Roo.get(rt);
9343                 }
9344             }
9345             return rt;
9346         },
9347
9348         /**
9349          * Creates and wraps this element with another element
9350          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9351          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9352          * @return {HTMLElement/Element} The newly created wrapper element
9353          */
9354         wrap: function(config, returnDom){
9355             if(!config){
9356                 config = {tag: "div"};
9357             }
9358             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9359             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9360             return newEl;
9361         },
9362
9363         /**
9364          * Replaces the passed element with this element
9365          * @param {String/HTMLElement/Element} el The element to replace
9366          * @return {Roo.Element} this
9367          */
9368         replace: function(el){
9369             el = Roo.get(el);
9370             this.insertBefore(el);
9371             el.remove();
9372             return this;
9373         },
9374
9375         /**
9376          * Inserts an html fragment into this element
9377          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9378          * @param {String} html The HTML fragment
9379          * @param {Boolean} returnEl True to return an Roo.Element
9380          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9381          */
9382         insertHtml : function(where, html, returnEl){
9383             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9384             return returnEl ? Roo.get(el) : el;
9385         },
9386
9387         /**
9388          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9389          * @param {Object} o The object with the attributes
9390          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9391          * @return {Roo.Element} this
9392          */
9393         set : function(o, useSet){
9394             var el = this.dom;
9395             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9396             for(var attr in o){
9397                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9398                 if(attr=="cls"){
9399                     el.className = o["cls"];
9400                 }else{
9401                     if(useSet) {
9402                         el.setAttribute(attr, o[attr]);
9403                     } else {
9404                         el[attr] = o[attr];
9405                     }
9406                 }
9407             }
9408             if(o.style){
9409                 Roo.DomHelper.applyStyles(el, o.style);
9410             }
9411             return this;
9412         },
9413
9414         /**
9415          * Convenience method for constructing a KeyMap
9416          * @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:
9417          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9418          * @param {Function} fn The function to call
9419          * @param {Object} scope (optional) The scope of the function
9420          * @return {Roo.KeyMap} The KeyMap created
9421          */
9422         addKeyListener : function(key, fn, scope){
9423             var config;
9424             if(typeof key != "object" || key instanceof Array){
9425                 config = {
9426                     key: key,
9427                     fn: fn,
9428                     scope: scope
9429                 };
9430             }else{
9431                 config = {
9432                     key : key.key,
9433                     shift : key.shift,
9434                     ctrl : key.ctrl,
9435                     alt : key.alt,
9436                     fn: fn,
9437                     scope: scope
9438                 };
9439             }
9440             return new Roo.KeyMap(this, config);
9441         },
9442
9443         /**
9444          * Creates a KeyMap for this element
9445          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9446          * @return {Roo.KeyMap} The KeyMap created
9447          */
9448         addKeyMap : function(config){
9449             return new Roo.KeyMap(this, config);
9450         },
9451
9452         /**
9453          * Returns true if this element is scrollable.
9454          * @return {Boolean}
9455          */
9456          isScrollable : function(){
9457             var dom = this.dom;
9458             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9459         },
9460
9461         /**
9462          * 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().
9463          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9464          * @param {Number} value The new scroll value
9465          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9466          * @return {Element} this
9467          */
9468
9469         scrollTo : function(side, value, animate){
9470             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9471             if(!animate || !A){
9472                 this.dom[prop] = value;
9473             }else{
9474                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9475                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9476             }
9477             return this;
9478         },
9479
9480         /**
9481          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9482          * within this element's scrollable range.
9483          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9484          * @param {Number} distance How far to scroll the element in pixels
9485          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9486          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9487          * was scrolled as far as it could go.
9488          */
9489          scroll : function(direction, distance, animate){
9490              if(!this.isScrollable()){
9491                  return;
9492              }
9493              var el = this.dom;
9494              var l = el.scrollLeft, t = el.scrollTop;
9495              var w = el.scrollWidth, h = el.scrollHeight;
9496              var cw = el.clientWidth, ch = el.clientHeight;
9497              direction = direction.toLowerCase();
9498              var scrolled = false;
9499              var a = this.preanim(arguments, 2);
9500              switch(direction){
9501                  case "l":
9502                  case "left":
9503                      if(w - l > cw){
9504                          var v = Math.min(l + distance, w-cw);
9505                          this.scrollTo("left", v, a);
9506                          scrolled = true;
9507                      }
9508                      break;
9509                 case "r":
9510                 case "right":
9511                      if(l > 0){
9512                          var v = Math.max(l - distance, 0);
9513                          this.scrollTo("left", v, a);
9514                          scrolled = true;
9515                      }
9516                      break;
9517                 case "t":
9518                 case "top":
9519                 case "up":
9520                      if(t > 0){
9521                          var v = Math.max(t - distance, 0);
9522                          this.scrollTo("top", v, a);
9523                          scrolled = true;
9524                      }
9525                      break;
9526                 case "b":
9527                 case "bottom":
9528                 case "down":
9529                      if(h - t > ch){
9530                          var v = Math.min(t + distance, h-ch);
9531                          this.scrollTo("top", v, a);
9532                          scrolled = true;
9533                      }
9534                      break;
9535              }
9536              return scrolled;
9537         },
9538
9539         /**
9540          * Translates the passed page coordinates into left/top css values for this element
9541          * @param {Number/Array} x The page x or an array containing [x, y]
9542          * @param {Number} y The page y
9543          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9544          */
9545         translatePoints : function(x, y){
9546             if(typeof x == 'object' || x instanceof Array){
9547                 y = x[1]; x = x[0];
9548             }
9549             var p = this.getStyle('position');
9550             var o = this.getXY();
9551
9552             var l = parseInt(this.getStyle('left'), 10);
9553             var t = parseInt(this.getStyle('top'), 10);
9554
9555             if(isNaN(l)){
9556                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9557             }
9558             if(isNaN(t)){
9559                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9560             }
9561
9562             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9563         },
9564
9565         /**
9566          * Returns the current scroll position of the element.
9567          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9568          */
9569         getScroll : function(){
9570             var d = this.dom, doc = document;
9571             if(d == doc || d == doc.body){
9572                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9573                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9574                 return {left: l, top: t};
9575             }else{
9576                 return {left: d.scrollLeft, top: d.scrollTop};
9577             }
9578         },
9579
9580         /**
9581          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9582          * are convert to standard 6 digit hex color.
9583          * @param {String} attr The css attribute
9584          * @param {String} defaultValue The default value to use when a valid color isn't found
9585          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9586          * YUI color anims.
9587          */
9588         getColor : function(attr, defaultValue, prefix){
9589             var v = this.getStyle(attr);
9590             if(!v || v == "transparent" || v == "inherit") {
9591                 return defaultValue;
9592             }
9593             var color = typeof prefix == "undefined" ? "#" : prefix;
9594             if(v.substr(0, 4) == "rgb("){
9595                 var rvs = v.slice(4, v.length -1).split(",");
9596                 for(var i = 0; i < 3; i++){
9597                     var h = parseInt(rvs[i]).toString(16);
9598                     if(h < 16){
9599                         h = "0" + h;
9600                     }
9601                     color += h;
9602                 }
9603             } else {
9604                 if(v.substr(0, 1) == "#"){
9605                     if(v.length == 4) {
9606                         for(var i = 1; i < 4; i++){
9607                             var c = v.charAt(i);
9608                             color +=  c + c;
9609                         }
9610                     }else if(v.length == 7){
9611                         color += v.substr(1);
9612                     }
9613                 }
9614             }
9615             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9616         },
9617
9618         /**
9619          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9620          * gradient background, rounded corners and a 4-way shadow.
9621          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9622          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9623          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9624          * @return {Roo.Element} this
9625          */
9626         boxWrap : function(cls){
9627             cls = cls || 'x-box';
9628             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9629             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9630             return el;
9631         },
9632
9633         /**
9634          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9635          * @param {String} namespace The namespace in which to look for the attribute
9636          * @param {String} name The attribute name
9637          * @return {String} The attribute value
9638          */
9639         getAttributeNS : Roo.isIE ? function(ns, name){
9640             var d = this.dom;
9641             var type = typeof d[ns+":"+name];
9642             if(type != 'undefined' && type != 'unknown'){
9643                 return d[ns+":"+name];
9644             }
9645             return d[name];
9646         } : function(ns, name){
9647             var d = this.dom;
9648             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9649         },
9650         
9651         
9652         /**
9653          * Sets or Returns the value the dom attribute value
9654          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9655          * @param {String} value (optional) The value to set the attribute to
9656          * @return {String} The attribute value
9657          */
9658         attr : function(name){
9659             if (arguments.length > 1) {
9660                 this.dom.setAttribute(name, arguments[1]);
9661                 return arguments[1];
9662             }
9663             if (typeof(name) == 'object') {
9664                 for(var i in name) {
9665                     this.attr(i, name[i]);
9666                 }
9667                 return name;
9668             }
9669             
9670             
9671             if (!this.dom.hasAttribute(name)) {
9672                 return undefined;
9673             }
9674             return this.dom.getAttribute(name);
9675         }
9676         
9677         
9678         
9679     };
9680
9681     var ep = El.prototype;
9682
9683     /**
9684      * Appends an event handler (Shorthand for addListener)
9685      * @param {String}   eventName     The type of event to append
9686      * @param {Function} fn        The method the event invokes
9687      * @param {Object} scope       (optional) The scope (this object) of the fn
9688      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9689      * @method
9690      */
9691     ep.on = ep.addListener;
9692         // backwards compat
9693     ep.mon = ep.addListener;
9694
9695     /**
9696      * Removes an event handler from this element (shorthand for removeListener)
9697      * @param {String} eventName the type of event to remove
9698      * @param {Function} fn the method the event invokes
9699      * @return {Roo.Element} this
9700      * @method
9701      */
9702     ep.un = ep.removeListener;
9703
9704     /**
9705      * true to automatically adjust width and height settings for box-model issues (default to true)
9706      */
9707     ep.autoBoxAdjust = true;
9708
9709     // private
9710     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9711
9712     // private
9713     El.addUnits = function(v, defaultUnit){
9714         if(v === "" || v == "auto"){
9715             return v;
9716         }
9717         if(v === undefined){
9718             return '';
9719         }
9720         if(typeof v == "number" || !El.unitPattern.test(v)){
9721             return v + (defaultUnit || 'px');
9722         }
9723         return v;
9724     };
9725
9726     // special markup used throughout Roo when box wrapping elements
9727     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>';
9728     /**
9729      * Visibility mode constant - Use visibility to hide element
9730      * @static
9731      * @type Number
9732      */
9733     El.VISIBILITY = 1;
9734     /**
9735      * Visibility mode constant - Use display to hide element
9736      * @static
9737      * @type Number
9738      */
9739     El.DISPLAY = 2;
9740
9741     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9742     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9743     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9744
9745
9746
9747     /**
9748      * @private
9749      */
9750     El.cache = {};
9751
9752     var docEl;
9753
9754     /**
9755      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9756      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9757      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9758      * @return {Element} The Element object
9759      * @static
9760      */
9761     El.get = function(el){
9762         var ex, elm, id;
9763         if(!el){ return null; }
9764         if(typeof el == "string"){ // element id
9765             if(!(elm = document.getElementById(el))){
9766                 return null;
9767             }
9768             if(ex = El.cache[el]){
9769                 ex.dom = elm;
9770             }else{
9771                 ex = El.cache[el] = new El(elm);
9772             }
9773             return ex;
9774         }else if(el.tagName){ // dom element
9775             if(!(id = el.id)){
9776                 id = Roo.id(el);
9777             }
9778             if(ex = El.cache[id]){
9779                 ex.dom = el;
9780             }else{
9781                 ex = El.cache[id] = new El(el);
9782             }
9783             return ex;
9784         }else if(el instanceof El){
9785             if(el != docEl){
9786                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9787                                                               // catch case where it hasn't been appended
9788                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9789             }
9790             return el;
9791         }else if(el.isComposite){
9792             return el;
9793         }else if(el instanceof Array){
9794             return El.select(el);
9795         }else if(el == document){
9796             // create a bogus element object representing the document object
9797             if(!docEl){
9798                 var f = function(){};
9799                 f.prototype = El.prototype;
9800                 docEl = new f();
9801                 docEl.dom = document;
9802             }
9803             return docEl;
9804         }
9805         return null;
9806     };
9807
9808     // private
9809     El.uncache = function(el){
9810         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9811             if(a[i]){
9812                 delete El.cache[a[i].id || a[i]];
9813             }
9814         }
9815     };
9816
9817     // private
9818     // Garbage collection - uncache elements/purge listeners on orphaned elements
9819     // so we don't hold a reference and cause the browser to retain them
9820     El.garbageCollect = function(){
9821         if(!Roo.enableGarbageCollector){
9822             clearInterval(El.collectorThread);
9823             return;
9824         }
9825         for(var eid in El.cache){
9826             var el = El.cache[eid], d = el.dom;
9827             // -------------------------------------------------------
9828             // Determining what is garbage:
9829             // -------------------------------------------------------
9830             // !d
9831             // dom node is null, definitely garbage
9832             // -------------------------------------------------------
9833             // !d.parentNode
9834             // no parentNode == direct orphan, definitely garbage
9835             // -------------------------------------------------------
9836             // !d.offsetParent && !document.getElementById(eid)
9837             // display none elements have no offsetParent so we will
9838             // also try to look it up by it's id. However, check
9839             // offsetParent first so we don't do unneeded lookups.
9840             // This enables collection of elements that are not orphans
9841             // directly, but somewhere up the line they have an orphan
9842             // parent.
9843             // -------------------------------------------------------
9844             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9845                 delete El.cache[eid];
9846                 if(d && Roo.enableListenerCollection){
9847                     E.purgeElement(d);
9848                 }
9849             }
9850         }
9851     }
9852     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9853
9854
9855     // dom is optional
9856     El.Flyweight = function(dom){
9857         this.dom = dom;
9858     };
9859     El.Flyweight.prototype = El.prototype;
9860
9861     El._flyweights = {};
9862     /**
9863      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9864      * the dom node can be overwritten by other code.
9865      * @param {String/HTMLElement} el The dom node or id
9866      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9867      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9868      * @static
9869      * @return {Element} The shared Element object
9870      */
9871     El.fly = function(el, named){
9872         named = named || '_global';
9873         el = Roo.getDom(el);
9874         if(!el){
9875             return null;
9876         }
9877         if(!El._flyweights[named]){
9878             El._flyweights[named] = new El.Flyweight();
9879         }
9880         El._flyweights[named].dom = el;
9881         return El._flyweights[named];
9882     };
9883
9884     /**
9885      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9886      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9887      * Shorthand of {@link Roo.Element#get}
9888      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9889      * @return {Element} The Element object
9890      * @member Roo
9891      * @method get
9892      */
9893     Roo.get = El.get;
9894     /**
9895      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9896      * the dom node can be overwritten by other code.
9897      * Shorthand of {@link Roo.Element#fly}
9898      * @param {String/HTMLElement} el The dom node or id
9899      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9900      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9901      * @static
9902      * @return {Element} The shared Element object
9903      * @member Roo
9904      * @method fly
9905      */
9906     Roo.fly = El.fly;
9907
9908     // speedy lookup for elements never to box adjust
9909     var noBoxAdjust = Roo.isStrict ? {
9910         select:1
9911     } : {
9912         input:1, select:1, textarea:1
9913     };
9914     if(Roo.isIE || Roo.isGecko){
9915         noBoxAdjust['button'] = 1;
9916     }
9917
9918
9919     Roo.EventManager.on(window, 'unload', function(){
9920         delete El.cache;
9921         delete El._flyweights;
9922     });
9923 })();
9924
9925
9926
9927
9928 if(Roo.DomQuery){
9929     Roo.Element.selectorFunction = Roo.DomQuery.select;
9930 }
9931
9932 Roo.Element.select = function(selector, unique, root){
9933     var els;
9934     if(typeof selector == "string"){
9935         els = Roo.Element.selectorFunction(selector, root);
9936     }else if(selector.length !== undefined){
9937         els = selector;
9938     }else{
9939         throw "Invalid selector";
9940     }
9941     if(unique === true){
9942         return new Roo.CompositeElement(els);
9943     }else{
9944         return new Roo.CompositeElementLite(els);
9945     }
9946 };
9947 /**
9948  * Selects elements based on the passed CSS selector to enable working on them as 1.
9949  * @param {String/Array} selector The CSS selector or an array of elements
9950  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9951  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9952  * @return {CompositeElementLite/CompositeElement}
9953  * @member Roo
9954  * @method select
9955  */
9956 Roo.select = Roo.Element.select;
9957
9958
9959
9960
9961
9962
9963
9964
9965
9966
9967
9968
9969
9970
9971 /*
9972  * Based on:
9973  * Ext JS Library 1.1.1
9974  * Copyright(c) 2006-2007, Ext JS, LLC.
9975  *
9976  * Originally Released Under LGPL - original licence link has changed is not relivant.
9977  *
9978  * Fork - LGPL
9979  * <script type="text/javascript">
9980  */
9981
9982
9983
9984 //Notifies Element that fx methods are available
9985 Roo.enableFx = true;
9986
9987 /**
9988  * @class Roo.Fx
9989  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9990  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9991  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9992  * Element effects to work.</p><br/>
9993  *
9994  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9995  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9996  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9997  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9998  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9999  * expected results and should be done with care.</p><br/>
10000  *
10001  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10002  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10003 <pre>
10004 Value  Description
10005 -----  -----------------------------
10006 tl     The top left corner
10007 t      The center of the top edge
10008 tr     The top right corner
10009 l      The center of the left edge
10010 r      The center of the right edge
10011 bl     The bottom left corner
10012 b      The center of the bottom edge
10013 br     The bottom right corner
10014 </pre>
10015  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10016  * below are common options that can be passed to any Fx method.</b>
10017  * @cfg {Function} callback A function called when the effect is finished
10018  * @cfg {Object} scope The scope of the effect function
10019  * @cfg {String} easing A valid Easing value for the effect
10020  * @cfg {String} afterCls A css class to apply after the effect
10021  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10022  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10023  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10024  * effects that end with the element being visually hidden, ignored otherwise)
10025  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10026  * a function which returns such a specification that will be applied to the Element after the effect finishes
10027  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10028  * @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
10029  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10030  */
10031 Roo.Fx = {
10032         /**
10033          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10034          * origin for the slide effect.  This function automatically handles wrapping the element with
10035          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10036          * Usage:
10037          *<pre><code>
10038 // default: slide the element in from the top
10039 el.slideIn();
10040
10041 // custom: slide the element in from the right with a 2-second duration
10042 el.slideIn('r', { duration: 2 });
10043
10044 // common config options shown with default values
10045 el.slideIn('t', {
10046     easing: 'easeOut',
10047     duration: .5
10048 });
10049 </code></pre>
10050          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10051          * @param {Object} options (optional) Object literal with any of the Fx config options
10052          * @return {Roo.Element} The Element
10053          */
10054     slideIn : function(anchor, o){
10055         var el = this.getFxEl();
10056         o = o || {};
10057
10058         el.queueFx(o, function(){
10059
10060             anchor = anchor || "t";
10061
10062             // fix display to visibility
10063             this.fixDisplay();
10064
10065             // restore values after effect
10066             var r = this.getFxRestore();
10067             var b = this.getBox();
10068             // fixed size for slide
10069             this.setSize(b);
10070
10071             // wrap if needed
10072             var wrap = this.fxWrap(r.pos, o, "hidden");
10073
10074             var st = this.dom.style;
10075             st.visibility = "visible";
10076             st.position = "absolute";
10077
10078             // clear out temp styles after slide and unwrap
10079             var after = function(){
10080                 el.fxUnwrap(wrap, r.pos, o);
10081                 st.width = r.width;
10082                 st.height = r.height;
10083                 el.afterFx(o);
10084             };
10085             // time to calc the positions
10086             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10087
10088             switch(anchor.toLowerCase()){
10089                 case "t":
10090                     wrap.setSize(b.width, 0);
10091                     st.left = st.bottom = "0";
10092                     a = {height: bh};
10093                 break;
10094                 case "l":
10095                     wrap.setSize(0, b.height);
10096                     st.right = st.top = "0";
10097                     a = {width: bw};
10098                 break;
10099                 case "r":
10100                     wrap.setSize(0, b.height);
10101                     wrap.setX(b.right);
10102                     st.left = st.top = "0";
10103                     a = {width: bw, points: pt};
10104                 break;
10105                 case "b":
10106                     wrap.setSize(b.width, 0);
10107                     wrap.setY(b.bottom);
10108                     st.left = st.top = "0";
10109                     a = {height: bh, points: pt};
10110                 break;
10111                 case "tl":
10112                     wrap.setSize(0, 0);
10113                     st.right = st.bottom = "0";
10114                     a = {width: bw, height: bh};
10115                 break;
10116                 case "bl":
10117                     wrap.setSize(0, 0);
10118                     wrap.setY(b.y+b.height);
10119                     st.right = st.top = "0";
10120                     a = {width: bw, height: bh, points: pt};
10121                 break;
10122                 case "br":
10123                     wrap.setSize(0, 0);
10124                     wrap.setXY([b.right, b.bottom]);
10125                     st.left = st.top = "0";
10126                     a = {width: bw, height: bh, points: pt};
10127                 break;
10128                 case "tr":
10129                     wrap.setSize(0, 0);
10130                     wrap.setX(b.x+b.width);
10131                     st.left = st.bottom = "0";
10132                     a = {width: bw, height: bh, points: pt};
10133                 break;
10134             }
10135             this.dom.style.visibility = "visible";
10136             wrap.show();
10137
10138             arguments.callee.anim = wrap.fxanim(a,
10139                 o,
10140                 'motion',
10141                 .5,
10142                 'easeOut', after);
10143         });
10144         return this;
10145     },
10146     
10147         /**
10148          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10149          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10150          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10151          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10152          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10153          * Usage:
10154          *<pre><code>
10155 // default: slide the element out to the top
10156 el.slideOut();
10157
10158 // custom: slide the element out to the right with a 2-second duration
10159 el.slideOut('r', { duration: 2 });
10160
10161 // common config options shown with default values
10162 el.slideOut('t', {
10163     easing: 'easeOut',
10164     duration: .5,
10165     remove: false,
10166     useDisplay: false
10167 });
10168 </code></pre>
10169          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10170          * @param {Object} options (optional) Object literal with any of the Fx config options
10171          * @return {Roo.Element} The Element
10172          */
10173     slideOut : function(anchor, o){
10174         var el = this.getFxEl();
10175         o = o || {};
10176
10177         el.queueFx(o, function(){
10178
10179             anchor = anchor || "t";
10180
10181             // restore values after effect
10182             var r = this.getFxRestore();
10183             
10184             var b = this.getBox();
10185             // fixed size for slide
10186             this.setSize(b);
10187
10188             // wrap if needed
10189             var wrap = this.fxWrap(r.pos, o, "visible");
10190
10191             var st = this.dom.style;
10192             st.visibility = "visible";
10193             st.position = "absolute";
10194
10195             wrap.setSize(b);
10196
10197             var after = function(){
10198                 if(o.useDisplay){
10199                     el.setDisplayed(false);
10200                 }else{
10201                     el.hide();
10202                 }
10203
10204                 el.fxUnwrap(wrap, r.pos, o);
10205
10206                 st.width = r.width;
10207                 st.height = r.height;
10208
10209                 el.afterFx(o);
10210             };
10211
10212             var a, zero = {to: 0};
10213             switch(anchor.toLowerCase()){
10214                 case "t":
10215                     st.left = st.bottom = "0";
10216                     a = {height: zero};
10217                 break;
10218                 case "l":
10219                     st.right = st.top = "0";
10220                     a = {width: zero};
10221                 break;
10222                 case "r":
10223                     st.left = st.top = "0";
10224                     a = {width: zero, points: {to:[b.right, b.y]}};
10225                 break;
10226                 case "b":
10227                     st.left = st.top = "0";
10228                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10229                 break;
10230                 case "tl":
10231                     st.right = st.bottom = "0";
10232                     a = {width: zero, height: zero};
10233                 break;
10234                 case "bl":
10235                     st.right = st.top = "0";
10236                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10237                 break;
10238                 case "br":
10239                     st.left = st.top = "0";
10240                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10241                 break;
10242                 case "tr":
10243                     st.left = st.bottom = "0";
10244                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10245                 break;
10246             }
10247
10248             arguments.callee.anim = wrap.fxanim(a,
10249                 o,
10250                 'motion',
10251                 .5,
10252                 "easeOut", after);
10253         });
10254         return this;
10255     },
10256
10257         /**
10258          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10259          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10260          * The element must be removed from the DOM using the 'remove' config option if desired.
10261          * Usage:
10262          *<pre><code>
10263 // default
10264 el.puff();
10265
10266 // common config options shown with default values
10267 el.puff({
10268     easing: 'easeOut',
10269     duration: .5,
10270     remove: false,
10271     useDisplay: false
10272 });
10273 </code></pre>
10274          * @param {Object} options (optional) Object literal with any of the Fx config options
10275          * @return {Roo.Element} The Element
10276          */
10277     puff : function(o){
10278         var el = this.getFxEl();
10279         o = o || {};
10280
10281         el.queueFx(o, function(){
10282             this.clearOpacity();
10283             this.show();
10284
10285             // restore values after effect
10286             var r = this.getFxRestore();
10287             var st = this.dom.style;
10288
10289             var after = function(){
10290                 if(o.useDisplay){
10291                     el.setDisplayed(false);
10292                 }else{
10293                     el.hide();
10294                 }
10295
10296                 el.clearOpacity();
10297
10298                 el.setPositioning(r.pos);
10299                 st.width = r.width;
10300                 st.height = r.height;
10301                 st.fontSize = '';
10302                 el.afterFx(o);
10303             };
10304
10305             var width = this.getWidth();
10306             var height = this.getHeight();
10307
10308             arguments.callee.anim = this.fxanim({
10309                     width : {to: this.adjustWidth(width * 2)},
10310                     height : {to: this.adjustHeight(height * 2)},
10311                     points : {by: [-(width * .5), -(height * .5)]},
10312                     opacity : {to: 0},
10313                     fontSize: {to:200, unit: "%"}
10314                 },
10315                 o,
10316                 'motion',
10317                 .5,
10318                 "easeOut", after);
10319         });
10320         return this;
10321     },
10322
10323         /**
10324          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10325          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10326          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10327          * Usage:
10328          *<pre><code>
10329 // default
10330 el.switchOff();
10331
10332 // all config options shown with default values
10333 el.switchOff({
10334     easing: 'easeIn',
10335     duration: .3,
10336     remove: false,
10337     useDisplay: false
10338 });
10339 </code></pre>
10340          * @param {Object} options (optional) Object literal with any of the Fx config options
10341          * @return {Roo.Element} The Element
10342          */
10343     switchOff : function(o){
10344         var el = this.getFxEl();
10345         o = o || {};
10346
10347         el.queueFx(o, function(){
10348             this.clearOpacity();
10349             this.clip();
10350
10351             // restore values after effect
10352             var r = this.getFxRestore();
10353             var st = this.dom.style;
10354
10355             var after = function(){
10356                 if(o.useDisplay){
10357                     el.setDisplayed(false);
10358                 }else{
10359                     el.hide();
10360                 }
10361
10362                 el.clearOpacity();
10363                 el.setPositioning(r.pos);
10364                 st.width = r.width;
10365                 st.height = r.height;
10366
10367                 el.afterFx(o);
10368             };
10369
10370             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10371                 this.clearOpacity();
10372                 (function(){
10373                     this.fxanim({
10374                         height:{to:1},
10375                         points:{by:[0, this.getHeight() * .5]}
10376                     }, o, 'motion', 0.3, 'easeIn', after);
10377                 }).defer(100, this);
10378             });
10379         });
10380         return this;
10381     },
10382
10383     /**
10384      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10385      * changed using the "attr" config option) and then fading back to the original color. If no original
10386      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10387      * Usage:
10388 <pre><code>
10389 // default: highlight background to yellow
10390 el.highlight();
10391
10392 // custom: highlight foreground text to blue for 2 seconds
10393 el.highlight("0000ff", { attr: 'color', duration: 2 });
10394
10395 // common config options shown with default values
10396 el.highlight("ffff9c", {
10397     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10398     endColor: (current color) or "ffffff",
10399     easing: 'easeIn',
10400     duration: 1
10401 });
10402 </code></pre>
10403      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10404      * @param {Object} options (optional) Object literal with any of the Fx config options
10405      * @return {Roo.Element} The Element
10406      */ 
10407     highlight : function(color, o){
10408         var el = this.getFxEl();
10409         o = o || {};
10410
10411         el.queueFx(o, function(){
10412             color = color || "ffff9c";
10413             attr = o.attr || "backgroundColor";
10414
10415             this.clearOpacity();
10416             this.show();
10417
10418             var origColor = this.getColor(attr);
10419             var restoreColor = this.dom.style[attr];
10420             endColor = (o.endColor || origColor) || "ffffff";
10421
10422             var after = function(){
10423                 el.dom.style[attr] = restoreColor;
10424                 el.afterFx(o);
10425             };
10426
10427             var a = {};
10428             a[attr] = {from: color, to: endColor};
10429             arguments.callee.anim = this.fxanim(a,
10430                 o,
10431                 'color',
10432                 1,
10433                 'easeIn', after);
10434         });
10435         return this;
10436     },
10437
10438    /**
10439     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10440     * Usage:
10441 <pre><code>
10442 // default: a single light blue ripple
10443 el.frame();
10444
10445 // custom: 3 red ripples lasting 3 seconds total
10446 el.frame("ff0000", 3, { duration: 3 });
10447
10448 // common config options shown with default values
10449 el.frame("C3DAF9", 1, {
10450     duration: 1 //duration of entire animation (not each individual ripple)
10451     // Note: Easing is not configurable and will be ignored if included
10452 });
10453 </code></pre>
10454     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10455     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10456     * @param {Object} options (optional) Object literal with any of the Fx config options
10457     * @return {Roo.Element} The Element
10458     */
10459     frame : function(color, count, o){
10460         var el = this.getFxEl();
10461         o = o || {};
10462
10463         el.queueFx(o, function(){
10464             color = color || "#C3DAF9";
10465             if(color.length == 6){
10466                 color = "#" + color;
10467             }
10468             count = count || 1;
10469             duration = o.duration || 1;
10470             this.show();
10471
10472             var b = this.getBox();
10473             var animFn = function(){
10474                 var proxy = this.createProxy({
10475
10476                      style:{
10477                         visbility:"hidden",
10478                         position:"absolute",
10479                         "z-index":"35000", // yee haw
10480                         border:"0px solid " + color
10481                      }
10482                   });
10483                 var scale = Roo.isBorderBox ? 2 : 1;
10484                 proxy.animate({
10485                     top:{from:b.y, to:b.y - 20},
10486                     left:{from:b.x, to:b.x - 20},
10487                     borderWidth:{from:0, to:10},
10488                     opacity:{from:1, to:0},
10489                     height:{from:b.height, to:(b.height + (20*scale))},
10490                     width:{from:b.width, to:(b.width + (20*scale))}
10491                 }, duration, function(){
10492                     proxy.remove();
10493                 });
10494                 if(--count > 0){
10495                      animFn.defer((duration/2)*1000, this);
10496                 }else{
10497                     el.afterFx(o);
10498                 }
10499             };
10500             animFn.call(this);
10501         });
10502         return this;
10503     },
10504
10505    /**
10506     * Creates a pause before any subsequent queued effects begin.  If there are
10507     * no effects queued after the pause it will have no effect.
10508     * Usage:
10509 <pre><code>
10510 el.pause(1);
10511 </code></pre>
10512     * @param {Number} seconds The length of time to pause (in seconds)
10513     * @return {Roo.Element} The Element
10514     */
10515     pause : function(seconds){
10516         var el = this.getFxEl();
10517         var o = {};
10518
10519         el.queueFx(o, function(){
10520             setTimeout(function(){
10521                 el.afterFx(o);
10522             }, seconds * 1000);
10523         });
10524         return this;
10525     },
10526
10527    /**
10528     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10529     * using the "endOpacity" config option.
10530     * Usage:
10531 <pre><code>
10532 // default: fade in from opacity 0 to 100%
10533 el.fadeIn();
10534
10535 // custom: fade in from opacity 0 to 75% over 2 seconds
10536 el.fadeIn({ endOpacity: .75, duration: 2});
10537
10538 // common config options shown with default values
10539 el.fadeIn({
10540     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10541     easing: 'easeOut',
10542     duration: .5
10543 });
10544 </code></pre>
10545     * @param {Object} options (optional) Object literal with any of the Fx config options
10546     * @return {Roo.Element} The Element
10547     */
10548     fadeIn : function(o){
10549         var el = this.getFxEl();
10550         o = o || {};
10551         el.queueFx(o, function(){
10552             this.setOpacity(0);
10553             this.fixDisplay();
10554             this.dom.style.visibility = 'visible';
10555             var to = o.endOpacity || 1;
10556             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10557                 o, null, .5, "easeOut", function(){
10558                 if(to == 1){
10559                     this.clearOpacity();
10560                 }
10561                 el.afterFx(o);
10562             });
10563         });
10564         return this;
10565     },
10566
10567    /**
10568     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10569     * using the "endOpacity" config option.
10570     * Usage:
10571 <pre><code>
10572 // default: fade out from the element's current opacity to 0
10573 el.fadeOut();
10574
10575 // custom: fade out from the element's current opacity to 25% over 2 seconds
10576 el.fadeOut({ endOpacity: .25, duration: 2});
10577
10578 // common config options shown with default values
10579 el.fadeOut({
10580     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10581     easing: 'easeOut',
10582     duration: .5
10583     remove: false,
10584     useDisplay: false
10585 });
10586 </code></pre>
10587     * @param {Object} options (optional) Object literal with any of the Fx config options
10588     * @return {Roo.Element} The Element
10589     */
10590     fadeOut : function(o){
10591         var el = this.getFxEl();
10592         o = o || {};
10593         el.queueFx(o, function(){
10594             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10595                 o, null, .5, "easeOut", function(){
10596                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10597                      this.dom.style.display = "none";
10598                 }else{
10599                      this.dom.style.visibility = "hidden";
10600                 }
10601                 this.clearOpacity();
10602                 el.afterFx(o);
10603             });
10604         });
10605         return this;
10606     },
10607
10608    /**
10609     * Animates the transition of an element's dimensions from a starting height/width
10610     * to an ending height/width.
10611     * Usage:
10612 <pre><code>
10613 // change height and width to 100x100 pixels
10614 el.scale(100, 100);
10615
10616 // common config options shown with default values.  The height and width will default to
10617 // the element's existing values if passed as null.
10618 el.scale(
10619     [element's width],
10620     [element's height], {
10621     easing: 'easeOut',
10622     duration: .35
10623 });
10624 </code></pre>
10625     * @param {Number} width  The new width (pass undefined to keep the original width)
10626     * @param {Number} height  The new height (pass undefined to keep the original height)
10627     * @param {Object} options (optional) Object literal with any of the Fx config options
10628     * @return {Roo.Element} The Element
10629     */
10630     scale : function(w, h, o){
10631         this.shift(Roo.apply({}, o, {
10632             width: w,
10633             height: h
10634         }));
10635         return this;
10636     },
10637
10638    /**
10639     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10640     * Any of these properties not specified in the config object will not be changed.  This effect 
10641     * requires that at least one new dimension, position or opacity setting must be passed in on
10642     * the config object in order for the function to have any effect.
10643     * Usage:
10644 <pre><code>
10645 // slide the element horizontally to x position 200 while changing the height and opacity
10646 el.shift({ x: 200, height: 50, opacity: .8 });
10647
10648 // common config options shown with default values.
10649 el.shift({
10650     width: [element's width],
10651     height: [element's height],
10652     x: [element's x position],
10653     y: [element's y position],
10654     opacity: [element's opacity],
10655     easing: 'easeOut',
10656     duration: .35
10657 });
10658 </code></pre>
10659     * @param {Object} options  Object literal with any of the Fx config options
10660     * @return {Roo.Element} The Element
10661     */
10662     shift : function(o){
10663         var el = this.getFxEl();
10664         o = o || {};
10665         el.queueFx(o, function(){
10666             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10667             if(w !== undefined){
10668                 a.width = {to: this.adjustWidth(w)};
10669             }
10670             if(h !== undefined){
10671                 a.height = {to: this.adjustHeight(h)};
10672             }
10673             if(x !== undefined || y !== undefined){
10674                 a.points = {to: [
10675                     x !== undefined ? x : this.getX(),
10676                     y !== undefined ? y : this.getY()
10677                 ]};
10678             }
10679             if(op !== undefined){
10680                 a.opacity = {to: op};
10681             }
10682             if(o.xy !== undefined){
10683                 a.points = {to: o.xy};
10684             }
10685             arguments.callee.anim = this.fxanim(a,
10686                 o, 'motion', .35, "easeOut", function(){
10687                 el.afterFx(o);
10688             });
10689         });
10690         return this;
10691     },
10692
10693         /**
10694          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10695          * ending point of the effect.
10696          * Usage:
10697          *<pre><code>
10698 // default: slide the element downward while fading out
10699 el.ghost();
10700
10701 // custom: slide the element out to the right with a 2-second duration
10702 el.ghost('r', { duration: 2 });
10703
10704 // common config options shown with default values
10705 el.ghost('b', {
10706     easing: 'easeOut',
10707     duration: .5
10708     remove: false,
10709     useDisplay: false
10710 });
10711 </code></pre>
10712          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10713          * @param {Object} options (optional) Object literal with any of the Fx config options
10714          * @return {Roo.Element} The Element
10715          */
10716     ghost : function(anchor, o){
10717         var el = this.getFxEl();
10718         o = o || {};
10719
10720         el.queueFx(o, function(){
10721             anchor = anchor || "b";
10722
10723             // restore values after effect
10724             var r = this.getFxRestore();
10725             var w = this.getWidth(),
10726                 h = this.getHeight();
10727
10728             var st = this.dom.style;
10729
10730             var after = function(){
10731                 if(o.useDisplay){
10732                     el.setDisplayed(false);
10733                 }else{
10734                     el.hide();
10735                 }
10736
10737                 el.clearOpacity();
10738                 el.setPositioning(r.pos);
10739                 st.width = r.width;
10740                 st.height = r.height;
10741
10742                 el.afterFx(o);
10743             };
10744
10745             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10746             switch(anchor.toLowerCase()){
10747                 case "t":
10748                     pt.by = [0, -h];
10749                 break;
10750                 case "l":
10751                     pt.by = [-w, 0];
10752                 break;
10753                 case "r":
10754                     pt.by = [w, 0];
10755                 break;
10756                 case "b":
10757                     pt.by = [0, h];
10758                 break;
10759                 case "tl":
10760                     pt.by = [-w, -h];
10761                 break;
10762                 case "bl":
10763                     pt.by = [-w, h];
10764                 break;
10765                 case "br":
10766                     pt.by = [w, h];
10767                 break;
10768                 case "tr":
10769                     pt.by = [w, -h];
10770                 break;
10771             }
10772
10773             arguments.callee.anim = this.fxanim(a,
10774                 o,
10775                 'motion',
10776                 .5,
10777                 "easeOut", after);
10778         });
10779         return this;
10780     },
10781
10782         /**
10783          * Ensures that all effects queued after syncFx is called on the element are
10784          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10785          * @return {Roo.Element} The Element
10786          */
10787     syncFx : function(){
10788         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10789             block : false,
10790             concurrent : true,
10791             stopFx : false
10792         });
10793         return this;
10794     },
10795
10796         /**
10797          * Ensures that all effects queued after sequenceFx is called on the element are
10798          * run in sequence.  This is the opposite of {@link #syncFx}.
10799          * @return {Roo.Element} The Element
10800          */
10801     sequenceFx : function(){
10802         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10803             block : false,
10804             concurrent : false,
10805             stopFx : false
10806         });
10807         return this;
10808     },
10809
10810         /* @private */
10811     nextFx : function(){
10812         var ef = this.fxQueue[0];
10813         if(ef){
10814             ef.call(this);
10815         }
10816     },
10817
10818         /**
10819          * Returns true if the element has any effects actively running or queued, else returns false.
10820          * @return {Boolean} True if element has active effects, else false
10821          */
10822     hasActiveFx : function(){
10823         return this.fxQueue && this.fxQueue[0];
10824     },
10825
10826         /**
10827          * Stops any running effects and clears the element's internal effects queue if it contains
10828          * any additional effects that haven't started yet.
10829          * @return {Roo.Element} The Element
10830          */
10831     stopFx : function(){
10832         if(this.hasActiveFx()){
10833             var cur = this.fxQueue[0];
10834             if(cur && cur.anim && cur.anim.isAnimated()){
10835                 this.fxQueue = [cur]; // clear out others
10836                 cur.anim.stop(true);
10837             }
10838         }
10839         return this;
10840     },
10841
10842         /* @private */
10843     beforeFx : function(o){
10844         if(this.hasActiveFx() && !o.concurrent){
10845            if(o.stopFx){
10846                this.stopFx();
10847                return true;
10848            }
10849            return false;
10850         }
10851         return true;
10852     },
10853
10854         /**
10855          * Returns true if the element is currently blocking so that no other effect can be queued
10856          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10857          * used to ensure that an effect initiated by a user action runs to completion prior to the
10858          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10859          * @return {Boolean} True if blocking, else false
10860          */
10861     hasFxBlock : function(){
10862         var q = this.fxQueue;
10863         return q && q[0] && q[0].block;
10864     },
10865
10866         /* @private */
10867     queueFx : function(o, fn){
10868         if(!this.fxQueue){
10869             this.fxQueue = [];
10870         }
10871         if(!this.hasFxBlock()){
10872             Roo.applyIf(o, this.fxDefaults);
10873             if(!o.concurrent){
10874                 var run = this.beforeFx(o);
10875                 fn.block = o.block;
10876                 this.fxQueue.push(fn);
10877                 if(run){
10878                     this.nextFx();
10879                 }
10880             }else{
10881                 fn.call(this);
10882             }
10883         }
10884         return this;
10885     },
10886
10887         /* @private */
10888     fxWrap : function(pos, o, vis){
10889         var wrap;
10890         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10891             var wrapXY;
10892             if(o.fixPosition){
10893                 wrapXY = this.getXY();
10894             }
10895             var div = document.createElement("div");
10896             div.style.visibility = vis;
10897             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10898             wrap.setPositioning(pos);
10899             if(wrap.getStyle("position") == "static"){
10900                 wrap.position("relative");
10901             }
10902             this.clearPositioning('auto');
10903             wrap.clip();
10904             wrap.dom.appendChild(this.dom);
10905             if(wrapXY){
10906                 wrap.setXY(wrapXY);
10907             }
10908         }
10909         return wrap;
10910     },
10911
10912         /* @private */
10913     fxUnwrap : function(wrap, pos, o){
10914         this.clearPositioning();
10915         this.setPositioning(pos);
10916         if(!o.wrap){
10917             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10918             wrap.remove();
10919         }
10920     },
10921
10922         /* @private */
10923     getFxRestore : function(){
10924         var st = this.dom.style;
10925         return {pos: this.getPositioning(), width: st.width, height : st.height};
10926     },
10927
10928         /* @private */
10929     afterFx : function(o){
10930         if(o.afterStyle){
10931             this.applyStyles(o.afterStyle);
10932         }
10933         if(o.afterCls){
10934             this.addClass(o.afterCls);
10935         }
10936         if(o.remove === true){
10937             this.remove();
10938         }
10939         Roo.callback(o.callback, o.scope, [this]);
10940         if(!o.concurrent){
10941             this.fxQueue.shift();
10942             this.nextFx();
10943         }
10944     },
10945
10946         /* @private */
10947     getFxEl : function(){ // support for composite element fx
10948         return Roo.get(this.dom);
10949     },
10950
10951         /* @private */
10952     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10953         animType = animType || 'run';
10954         opt = opt || {};
10955         var anim = Roo.lib.Anim[animType](
10956             this.dom, args,
10957             (opt.duration || defaultDur) || .35,
10958             (opt.easing || defaultEase) || 'easeOut',
10959             function(){
10960                 Roo.callback(cb, this);
10961             },
10962             this
10963         );
10964         opt.anim = anim;
10965         return anim;
10966     }
10967 };
10968
10969 // backwords compat
10970 Roo.Fx.resize = Roo.Fx.scale;
10971
10972 //When included, Roo.Fx is automatically applied to Element so that all basic
10973 //effects are available directly via the Element API
10974 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10975  * Based on:
10976  * Ext JS Library 1.1.1
10977  * Copyright(c) 2006-2007, Ext JS, LLC.
10978  *
10979  * Originally Released Under LGPL - original licence link has changed is not relivant.
10980  *
10981  * Fork - LGPL
10982  * <script type="text/javascript">
10983  */
10984
10985
10986 /**
10987  * @class Roo.CompositeElement
10988  * Standard composite class. Creates a Roo.Element for every element in the collection.
10989  * <br><br>
10990  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10991  * actions will be performed on all the elements in this collection.</b>
10992  * <br><br>
10993  * All methods return <i>this</i> and can be chained.
10994  <pre><code>
10995  var els = Roo.select("#some-el div.some-class", true);
10996  // or select directly from an existing element
10997  var el = Roo.get('some-el');
10998  el.select('div.some-class', true);
10999
11000  els.setWidth(100); // all elements become 100 width
11001  els.hide(true); // all elements fade out and hide
11002  // or
11003  els.setWidth(100).hide(true);
11004  </code></pre>
11005  */
11006 Roo.CompositeElement = function(els){
11007     this.elements = [];
11008     this.addElements(els);
11009 };
11010 Roo.CompositeElement.prototype = {
11011     isComposite: true,
11012     addElements : function(els){
11013         if(!els) {
11014             return this;
11015         }
11016         if(typeof els == "string"){
11017             els = Roo.Element.selectorFunction(els);
11018         }
11019         var yels = this.elements;
11020         var index = yels.length-1;
11021         for(var i = 0, len = els.length; i < len; i++) {
11022                 yels[++index] = Roo.get(els[i]);
11023         }
11024         return this;
11025     },
11026
11027     /**
11028     * Clears this composite and adds the elements returned by the passed selector.
11029     * @param {String/Array} els A string CSS selector, an array of elements or an element
11030     * @return {CompositeElement} this
11031     */
11032     fill : function(els){
11033         this.elements = [];
11034         this.add(els);
11035         return this;
11036     },
11037
11038     /**
11039     * Filters this composite to only elements that match the passed selector.
11040     * @param {String} selector A string CSS selector
11041     * @param {Boolean} inverse return inverse filter (not matches)
11042     * @return {CompositeElement} this
11043     */
11044     filter : function(selector, inverse){
11045         var els = [];
11046         inverse = inverse || false;
11047         this.each(function(el){
11048             var match = inverse ? !el.is(selector) : el.is(selector);
11049             if(match){
11050                 els[els.length] = el.dom;
11051             }
11052         });
11053         this.fill(els);
11054         return this;
11055     },
11056
11057     invoke : function(fn, args){
11058         var els = this.elements;
11059         for(var i = 0, len = els.length; i < len; i++) {
11060                 Roo.Element.prototype[fn].apply(els[i], args);
11061         }
11062         return this;
11063     },
11064     /**
11065     * Adds elements to this composite.
11066     * @param {String/Array} els A string CSS selector, an array of elements or an element
11067     * @return {CompositeElement} this
11068     */
11069     add : function(els){
11070         if(typeof els == "string"){
11071             this.addElements(Roo.Element.selectorFunction(els));
11072         }else if(els.length !== undefined){
11073             this.addElements(els);
11074         }else{
11075             this.addElements([els]);
11076         }
11077         return this;
11078     },
11079     /**
11080     * Calls the passed function passing (el, this, index) for each element in this composite.
11081     * @param {Function} fn The function to call
11082     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11083     * @return {CompositeElement} this
11084     */
11085     each : function(fn, scope){
11086         var els = this.elements;
11087         for(var i = 0, len = els.length; i < len; i++){
11088             if(fn.call(scope || els[i], els[i], this, i) === false) {
11089                 break;
11090             }
11091         }
11092         return this;
11093     },
11094
11095     /**
11096      * Returns the Element object at the specified index
11097      * @param {Number} index
11098      * @return {Roo.Element}
11099      */
11100     item : function(index){
11101         return this.elements[index] || null;
11102     },
11103
11104     /**
11105      * Returns the first Element
11106      * @return {Roo.Element}
11107      */
11108     first : function(){
11109         return this.item(0);
11110     },
11111
11112     /**
11113      * Returns the last Element
11114      * @return {Roo.Element}
11115      */
11116     last : function(){
11117         return this.item(this.elements.length-1);
11118     },
11119
11120     /**
11121      * Returns the number of elements in this composite
11122      * @return Number
11123      */
11124     getCount : function(){
11125         return this.elements.length;
11126     },
11127
11128     /**
11129      * Returns true if this composite contains the passed element
11130      * @return Boolean
11131      */
11132     contains : function(el){
11133         return this.indexOf(el) !== -1;
11134     },
11135
11136     /**
11137      * Returns true if this composite contains the passed element
11138      * @return Boolean
11139      */
11140     indexOf : function(el){
11141         return this.elements.indexOf(Roo.get(el));
11142     },
11143
11144
11145     /**
11146     * Removes the specified element(s).
11147     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11148     * or an array of any of those.
11149     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11150     * @return {CompositeElement} this
11151     */
11152     removeElement : function(el, removeDom){
11153         if(el instanceof Array){
11154             for(var i = 0, len = el.length; i < len; i++){
11155                 this.removeElement(el[i]);
11156             }
11157             return this;
11158         }
11159         var index = typeof el == 'number' ? el : this.indexOf(el);
11160         if(index !== -1){
11161             if(removeDom){
11162                 var d = this.elements[index];
11163                 if(d.dom){
11164                     d.remove();
11165                 }else{
11166                     d.parentNode.removeChild(d);
11167                 }
11168             }
11169             this.elements.splice(index, 1);
11170         }
11171         return this;
11172     },
11173
11174     /**
11175     * Replaces the specified element with the passed element.
11176     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11177     * to replace.
11178     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11179     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11180     * @return {CompositeElement} this
11181     */
11182     replaceElement : function(el, replacement, domReplace){
11183         var index = typeof el == 'number' ? el : this.indexOf(el);
11184         if(index !== -1){
11185             if(domReplace){
11186                 this.elements[index].replaceWith(replacement);
11187             }else{
11188                 this.elements.splice(index, 1, Roo.get(replacement))
11189             }
11190         }
11191         return this;
11192     },
11193
11194     /**
11195      * Removes all elements.
11196      */
11197     clear : function(){
11198         this.elements = [];
11199     }
11200 };
11201 (function(){
11202     Roo.CompositeElement.createCall = function(proto, fnName){
11203         if(!proto[fnName]){
11204             proto[fnName] = function(){
11205                 return this.invoke(fnName, arguments);
11206             };
11207         }
11208     };
11209     for(var fnName in Roo.Element.prototype){
11210         if(typeof Roo.Element.prototype[fnName] == "function"){
11211             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11212         }
11213     };
11214 })();
11215 /*
11216  * Based on:
11217  * Ext JS Library 1.1.1
11218  * Copyright(c) 2006-2007, Ext JS, LLC.
11219  *
11220  * Originally Released Under LGPL - original licence link has changed is not relivant.
11221  *
11222  * Fork - LGPL
11223  * <script type="text/javascript">
11224  */
11225
11226 /**
11227  * @class Roo.CompositeElementLite
11228  * @extends Roo.CompositeElement
11229  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11230  <pre><code>
11231  var els = Roo.select("#some-el div.some-class");
11232  // or select directly from an existing element
11233  var el = Roo.get('some-el');
11234  el.select('div.some-class');
11235
11236  els.setWidth(100); // all elements become 100 width
11237  els.hide(true); // all elements fade out and hide
11238  // or
11239  els.setWidth(100).hide(true);
11240  </code></pre><br><br>
11241  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11242  * actions will be performed on all the elements in this collection.</b>
11243  */
11244 Roo.CompositeElementLite = function(els){
11245     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11246     this.el = new Roo.Element.Flyweight();
11247 };
11248 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11249     addElements : function(els){
11250         if(els){
11251             if(els instanceof Array){
11252                 this.elements = this.elements.concat(els);
11253             }else{
11254                 var yels = this.elements;
11255                 var index = yels.length-1;
11256                 for(var i = 0, len = els.length; i < len; i++) {
11257                     yels[++index] = els[i];
11258                 }
11259             }
11260         }
11261         return this;
11262     },
11263     invoke : function(fn, args){
11264         var els = this.elements;
11265         var el = this.el;
11266         for(var i = 0, len = els.length; i < len; i++) {
11267             el.dom = els[i];
11268                 Roo.Element.prototype[fn].apply(el, args);
11269         }
11270         return this;
11271     },
11272     /**
11273      * Returns a flyweight Element of the dom element object at the specified index
11274      * @param {Number} index
11275      * @return {Roo.Element}
11276      */
11277     item : function(index){
11278         if(!this.elements[index]){
11279             return null;
11280         }
11281         this.el.dom = this.elements[index];
11282         return this.el;
11283     },
11284
11285     // fixes scope with flyweight
11286     addListener : function(eventName, handler, scope, opt){
11287         var els = this.elements;
11288         for(var i = 0, len = els.length; i < len; i++) {
11289             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11290         }
11291         return this;
11292     },
11293
11294     /**
11295     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11296     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11297     * a reference to the dom node, use el.dom.</b>
11298     * @param {Function} fn The function to call
11299     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11300     * @return {CompositeElement} this
11301     */
11302     each : function(fn, scope){
11303         var els = this.elements;
11304         var el = this.el;
11305         for(var i = 0, len = els.length; i < len; i++){
11306             el.dom = els[i];
11307                 if(fn.call(scope || el, el, this, i) === false){
11308                 break;
11309             }
11310         }
11311         return this;
11312     },
11313
11314     indexOf : function(el){
11315         return this.elements.indexOf(Roo.getDom(el));
11316     },
11317
11318     replaceElement : function(el, replacement, domReplace){
11319         var index = typeof el == 'number' ? el : this.indexOf(el);
11320         if(index !== -1){
11321             replacement = Roo.getDom(replacement);
11322             if(domReplace){
11323                 var d = this.elements[index];
11324                 d.parentNode.insertBefore(replacement, d);
11325                 d.parentNode.removeChild(d);
11326             }
11327             this.elements.splice(index, 1, replacement);
11328         }
11329         return this;
11330     }
11331 });
11332 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11333
11334 /*
11335  * Based on:
11336  * Ext JS Library 1.1.1
11337  * Copyright(c) 2006-2007, Ext JS, LLC.
11338  *
11339  * Originally Released Under LGPL - original licence link has changed is not relivant.
11340  *
11341  * Fork - LGPL
11342  * <script type="text/javascript">
11343  */
11344
11345  
11346
11347 /**
11348  * @class Roo.data.Connection
11349  * @extends Roo.util.Observable
11350  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11351  * either to a configured URL, or to a URL specified at request time.<br><br>
11352  * <p>
11353  * Requests made by this class are asynchronous, and will return immediately. No data from
11354  * the server will be available to the statement immediately following the {@link #request} call.
11355  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11356  * <p>
11357  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11358  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11359  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11360  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11361  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11362  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11363  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11364  * standard DOM methods.
11365  * @constructor
11366  * @param {Object} config a configuration object.
11367  */
11368 Roo.data.Connection = function(config){
11369     Roo.apply(this, config);
11370     this.addEvents({
11371         /**
11372          * @event beforerequest
11373          * Fires before a network request is made to retrieve a data object.
11374          * @param {Connection} conn This Connection object.
11375          * @param {Object} options The options config object passed to the {@link #request} method.
11376          */
11377         "beforerequest" : true,
11378         /**
11379          * @event requestcomplete
11380          * Fires if the request was successfully completed.
11381          * @param {Connection} conn This Connection object.
11382          * @param {Object} response The XHR object containing the response data.
11383          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11384          * @param {Object} options The options config object passed to the {@link #request} method.
11385          */
11386         "requestcomplete" : true,
11387         /**
11388          * @event requestexception
11389          * Fires if an error HTTP status was returned from the server.
11390          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11391          * @param {Connection} conn This Connection object.
11392          * @param {Object} response The XHR object containing the response data.
11393          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11394          * @param {Object} options The options config object passed to the {@link #request} method.
11395          */
11396         "requestexception" : true
11397     });
11398     Roo.data.Connection.superclass.constructor.call(this);
11399 };
11400
11401 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11402     /**
11403      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11404      */
11405     /**
11406      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11407      * extra parameters to each request made by this object. (defaults to undefined)
11408      */
11409     /**
11410      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11411      *  to each request made by this object. (defaults to undefined)
11412      */
11413     /**
11414      * @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)
11415      */
11416     /**
11417      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11418      */
11419     timeout : 30000,
11420     /**
11421      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11422      * @type Boolean
11423      */
11424     autoAbort:false,
11425
11426     /**
11427      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11428      * @type Boolean
11429      */
11430     disableCaching: true,
11431
11432     /**
11433      * Sends an HTTP request to a remote server.
11434      * @param {Object} options An object which may contain the following properties:<ul>
11435      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11436      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11437      * request, a url encoded string or a function to call to get either.</li>
11438      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11439      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11440      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11441      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11442      * <li>options {Object} The parameter to the request call.</li>
11443      * <li>success {Boolean} True if the request succeeded.</li>
11444      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11445      * </ul></li>
11446      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11447      * The callback is passed the following parameters:<ul>
11448      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11449      * <li>options {Object} The parameter to the request call.</li>
11450      * </ul></li>
11451      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11452      * The callback is passed the following parameters:<ul>
11453      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11454      * <li>options {Object} The parameter to the request call.</li>
11455      * </ul></li>
11456      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11457      * for the callback function. Defaults to the browser window.</li>
11458      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11459      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11460      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11461      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11462      * params for the post data. Any params will be appended to the URL.</li>
11463      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11464      * </ul>
11465      * @return {Number} transactionId
11466      */
11467     request : function(o){
11468         if(this.fireEvent("beforerequest", this, o) !== false){
11469             var p = o.params;
11470
11471             if(typeof p == "function"){
11472                 p = p.call(o.scope||window, o);
11473             }
11474             if(typeof p == "object"){
11475                 p = Roo.urlEncode(o.params);
11476             }
11477             if(this.extraParams){
11478                 var extras = Roo.urlEncode(this.extraParams);
11479                 p = p ? (p + '&' + extras) : extras;
11480             }
11481
11482             var url = o.url || this.url;
11483             if(typeof url == 'function'){
11484                 url = url.call(o.scope||window, o);
11485             }
11486
11487             if(o.form){
11488                 var form = Roo.getDom(o.form);
11489                 url = url || form.action;
11490
11491                 var enctype = form.getAttribute("enctype");
11492                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11493                     return this.doFormUpload(o, p, url);
11494                 }
11495                 var f = Roo.lib.Ajax.serializeForm(form);
11496                 p = p ? (p + '&' + f) : f;
11497             }
11498
11499             var hs = o.headers;
11500             if(this.defaultHeaders){
11501                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11502                 if(!o.headers){
11503                     o.headers = hs;
11504                 }
11505             }
11506
11507             var cb = {
11508                 success: this.handleResponse,
11509                 failure: this.handleFailure,
11510                 scope: this,
11511                 argument: {options: o},
11512                 timeout : o.timeout || this.timeout
11513             };
11514
11515             var method = o.method||this.method||(p ? "POST" : "GET");
11516
11517             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11518                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11519             }
11520
11521             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11522                 if(o.autoAbort){
11523                     this.abort();
11524                 }
11525             }else if(this.autoAbort !== false){
11526                 this.abort();
11527             }
11528
11529             if((method == 'GET' && p) || o.xmlData){
11530                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11531                 p = '';
11532             }
11533             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11534             return this.transId;
11535         }else{
11536             Roo.callback(o.callback, o.scope, [o, null, null]);
11537             return null;
11538         }
11539     },
11540
11541     /**
11542      * Determine whether this object has a request outstanding.
11543      * @param {Number} transactionId (Optional) defaults to the last transaction
11544      * @return {Boolean} True if there is an outstanding request.
11545      */
11546     isLoading : function(transId){
11547         if(transId){
11548             return Roo.lib.Ajax.isCallInProgress(transId);
11549         }else{
11550             return this.transId ? true : false;
11551         }
11552     },
11553
11554     /**
11555      * Aborts any outstanding request.
11556      * @param {Number} transactionId (Optional) defaults to the last transaction
11557      */
11558     abort : function(transId){
11559         if(transId || this.isLoading()){
11560             Roo.lib.Ajax.abort(transId || this.transId);
11561         }
11562     },
11563
11564     // private
11565     handleResponse : function(response){
11566         this.transId = false;
11567         var options = response.argument.options;
11568         response.argument = options ? options.argument : null;
11569         this.fireEvent("requestcomplete", this, response, options);
11570         Roo.callback(options.success, options.scope, [response, options]);
11571         Roo.callback(options.callback, options.scope, [options, true, response]);
11572     },
11573
11574     // private
11575     handleFailure : function(response, e){
11576         this.transId = false;
11577         var options = response.argument.options;
11578         response.argument = options ? options.argument : null;
11579         this.fireEvent("requestexception", this, response, options, e);
11580         Roo.callback(options.failure, options.scope, [response, options]);
11581         Roo.callback(options.callback, options.scope, [options, false, response]);
11582     },
11583
11584     // private
11585     doFormUpload : function(o, ps, url){
11586         var id = Roo.id();
11587         var frame = document.createElement('iframe');
11588         frame.id = id;
11589         frame.name = id;
11590         frame.className = 'x-hidden';
11591         if(Roo.isIE){
11592             frame.src = Roo.SSL_SECURE_URL;
11593         }
11594         document.body.appendChild(frame);
11595
11596         if(Roo.isIE){
11597            document.frames[id].name = id;
11598         }
11599
11600         var form = Roo.getDom(o.form);
11601         form.target = id;
11602         form.method = 'POST';
11603         form.enctype = form.encoding = 'multipart/form-data';
11604         if(url){
11605             form.action = url;
11606         }
11607
11608         var hiddens, hd;
11609         if(ps){ // add dynamic params
11610             hiddens = [];
11611             ps = Roo.urlDecode(ps, false);
11612             for(var k in ps){
11613                 if(ps.hasOwnProperty(k)){
11614                     hd = document.createElement('input');
11615                     hd.type = 'hidden';
11616                     hd.name = k;
11617                     hd.value = ps[k];
11618                     form.appendChild(hd);
11619                     hiddens.push(hd);
11620                 }
11621             }
11622         }
11623
11624         function cb(){
11625             var r = {  // bogus response object
11626                 responseText : '',
11627                 responseXML : null
11628             };
11629
11630             r.argument = o ? o.argument : null;
11631
11632             try { //
11633                 var doc;
11634                 if(Roo.isIE){
11635                     doc = frame.contentWindow.document;
11636                 }else {
11637                     doc = (frame.contentDocument || window.frames[id].document);
11638                 }
11639                 if(doc && doc.body){
11640                     r.responseText = doc.body.innerHTML;
11641                 }
11642                 if(doc && doc.XMLDocument){
11643                     r.responseXML = doc.XMLDocument;
11644                 }else {
11645                     r.responseXML = doc;
11646                 }
11647             }
11648             catch(e) {
11649                 // ignore
11650             }
11651
11652             Roo.EventManager.removeListener(frame, 'load', cb, this);
11653
11654             this.fireEvent("requestcomplete", this, r, o);
11655             Roo.callback(o.success, o.scope, [r, o]);
11656             Roo.callback(o.callback, o.scope, [o, true, r]);
11657
11658             setTimeout(function(){document.body.removeChild(frame);}, 100);
11659         }
11660
11661         Roo.EventManager.on(frame, 'load', cb, this);
11662         form.submit();
11663
11664         if(hiddens){ // remove dynamic params
11665             for(var i = 0, len = hiddens.length; i < len; i++){
11666                 form.removeChild(hiddens[i]);
11667             }
11668         }
11669     }
11670 });
11671 /*
11672  * Based on:
11673  * Ext JS Library 1.1.1
11674  * Copyright(c) 2006-2007, Ext JS, LLC.
11675  *
11676  * Originally Released Under LGPL - original licence link has changed is not relivant.
11677  *
11678  * Fork - LGPL
11679  * <script type="text/javascript">
11680  */
11681  
11682 /**
11683  * Global Ajax request class.
11684  * 
11685  * @class Roo.Ajax
11686  * @extends Roo.data.Connection
11687  * @static
11688  * 
11689  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11690  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11691  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11692  * @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)
11693  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11694  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11695  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11696  */
11697 Roo.Ajax = new Roo.data.Connection({
11698     // fix up the docs
11699     /**
11700      * @scope Roo.Ajax
11701      * @type {Boolear} 
11702      */
11703     autoAbort : false,
11704
11705     /**
11706      * Serialize the passed form into a url encoded string
11707      * @scope Roo.Ajax
11708      * @param {String/HTMLElement} form
11709      * @return {String}
11710      */
11711     serializeForm : function(form){
11712         return Roo.lib.Ajax.serializeForm(form);
11713     }
11714 });/*
11715  * Based on:
11716  * Ext JS Library 1.1.1
11717  * Copyright(c) 2006-2007, Ext JS, LLC.
11718  *
11719  * Originally Released Under LGPL - original licence link has changed is not relivant.
11720  *
11721  * Fork - LGPL
11722  * <script type="text/javascript">
11723  */
11724
11725  
11726 /**
11727  * @class Roo.UpdateManager
11728  * @extends Roo.util.Observable
11729  * Provides AJAX-style update for Element object.<br><br>
11730  * Usage:<br>
11731  * <pre><code>
11732  * // Get it from a Roo.Element object
11733  * var el = Roo.get("foo");
11734  * var mgr = el.getUpdateManager();
11735  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11736  * ...
11737  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11738  * <br>
11739  * // or directly (returns the same UpdateManager instance)
11740  * var mgr = new Roo.UpdateManager("myElementId");
11741  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11742  * mgr.on("update", myFcnNeedsToKnow);
11743  * <br>
11744    // short handed call directly from the element object
11745    Roo.get("foo").load({
11746         url: "bar.php",
11747         scripts:true,
11748         params: "for=bar",
11749         text: "Loading Foo..."
11750    });
11751  * </code></pre>
11752  * @constructor
11753  * Create new UpdateManager directly.
11754  * @param {String/HTMLElement/Roo.Element} el The element to update
11755  * @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).
11756  */
11757 Roo.UpdateManager = function(el, forceNew){
11758     el = Roo.get(el);
11759     if(!forceNew && el.updateManager){
11760         return el.updateManager;
11761     }
11762     /**
11763      * The Element object
11764      * @type Roo.Element
11765      */
11766     this.el = el;
11767     /**
11768      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11769      * @type String
11770      */
11771     this.defaultUrl = null;
11772
11773     this.addEvents({
11774         /**
11775          * @event beforeupdate
11776          * Fired before an update is made, return false from your handler and the update is cancelled.
11777          * @param {Roo.Element} el
11778          * @param {String/Object/Function} url
11779          * @param {String/Object} params
11780          */
11781         "beforeupdate": true,
11782         /**
11783          * @event update
11784          * Fired after successful update is made.
11785          * @param {Roo.Element} el
11786          * @param {Object} oResponseObject The response Object
11787          */
11788         "update": true,
11789         /**
11790          * @event failure
11791          * Fired on update failure.
11792          * @param {Roo.Element} el
11793          * @param {Object} oResponseObject The response Object
11794          */
11795         "failure": true
11796     });
11797     var d = Roo.UpdateManager.defaults;
11798     /**
11799      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11800      * @type String
11801      */
11802     this.sslBlankUrl = d.sslBlankUrl;
11803     /**
11804      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11805      * @type Boolean
11806      */
11807     this.disableCaching = d.disableCaching;
11808     /**
11809      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11810      * @type String
11811      */
11812     this.indicatorText = d.indicatorText;
11813     /**
11814      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11815      * @type String
11816      */
11817     this.showLoadIndicator = d.showLoadIndicator;
11818     /**
11819      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11820      * @type Number
11821      */
11822     this.timeout = d.timeout;
11823
11824     /**
11825      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11826      * @type Boolean
11827      */
11828     this.loadScripts = d.loadScripts;
11829
11830     /**
11831      * Transaction object of current executing transaction
11832      */
11833     this.transaction = null;
11834
11835     /**
11836      * @private
11837      */
11838     this.autoRefreshProcId = null;
11839     /**
11840      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11841      * @type Function
11842      */
11843     this.refreshDelegate = this.refresh.createDelegate(this);
11844     /**
11845      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11846      * @type Function
11847      */
11848     this.updateDelegate = this.update.createDelegate(this);
11849     /**
11850      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11851      * @type Function
11852      */
11853     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11854     /**
11855      * @private
11856      */
11857     this.successDelegate = this.processSuccess.createDelegate(this);
11858     /**
11859      * @private
11860      */
11861     this.failureDelegate = this.processFailure.createDelegate(this);
11862
11863     if(!this.renderer){
11864      /**
11865       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11866       */
11867     this.renderer = new Roo.UpdateManager.BasicRenderer();
11868     }
11869     
11870     Roo.UpdateManager.superclass.constructor.call(this);
11871 };
11872
11873 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11874     /**
11875      * Get the Element this UpdateManager is bound to
11876      * @return {Roo.Element} The element
11877      */
11878     getEl : function(){
11879         return this.el;
11880     },
11881     /**
11882      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11883      * @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:
11884 <pre><code>
11885 um.update({<br/>
11886     url: "your-url.php",<br/>
11887     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11888     callback: yourFunction,<br/>
11889     scope: yourObject, //(optional scope)  <br/>
11890     discardUrl: false, <br/>
11891     nocache: false,<br/>
11892     text: "Loading...",<br/>
11893     timeout: 30,<br/>
11894     scripts: false<br/>
11895 });
11896 </code></pre>
11897      * The only required property is url. The optional properties nocache, text and scripts
11898      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11899      * @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}
11900      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11901      * @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.
11902      */
11903     update : function(url, params, callback, discardUrl){
11904         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11905             var method = this.method,
11906                 cfg;
11907             if(typeof url == "object"){ // must be config object
11908                 cfg = url;
11909                 url = cfg.url;
11910                 params = params || cfg.params;
11911                 callback = callback || cfg.callback;
11912                 discardUrl = discardUrl || cfg.discardUrl;
11913                 if(callback && cfg.scope){
11914                     callback = callback.createDelegate(cfg.scope);
11915                 }
11916                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11917                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11918                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11919                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11920                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11921             }
11922             this.showLoading();
11923             if(!discardUrl){
11924                 this.defaultUrl = url;
11925             }
11926             if(typeof url == "function"){
11927                 url = url.call(this);
11928             }
11929
11930             method = method || (params ? "POST" : "GET");
11931             if(method == "GET"){
11932                 url = this.prepareUrl(url);
11933             }
11934
11935             var o = Roo.apply(cfg ||{}, {
11936                 url : url,
11937                 params: params,
11938                 success: this.successDelegate,
11939                 failure: this.failureDelegate,
11940                 callback: undefined,
11941                 timeout: (this.timeout*1000),
11942                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11943             });
11944             Roo.log("updated manager called with timeout of " + o.timeout);
11945             this.transaction = Roo.Ajax.request(o);
11946         }
11947     },
11948
11949     /**
11950      * 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.
11951      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11952      * @param {String/HTMLElement} form The form Id or form element
11953      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11954      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11955      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11956      */
11957     formUpdate : function(form, url, reset, callback){
11958         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11959             if(typeof url == "function"){
11960                 url = url.call(this);
11961             }
11962             form = Roo.getDom(form);
11963             this.transaction = Roo.Ajax.request({
11964                 form: form,
11965                 url:url,
11966                 success: this.successDelegate,
11967                 failure: this.failureDelegate,
11968                 timeout: (this.timeout*1000),
11969                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11970             });
11971             this.showLoading.defer(1, this);
11972         }
11973     },
11974
11975     /**
11976      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11977      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11978      */
11979     refresh : function(callback){
11980         if(this.defaultUrl == null){
11981             return;
11982         }
11983         this.update(this.defaultUrl, null, callback, true);
11984     },
11985
11986     /**
11987      * Set this element to auto refresh.
11988      * @param {Number} interval How often to update (in seconds).
11989      * @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)
11990      * @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}
11991      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11992      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11993      */
11994     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11995         if(refreshNow){
11996             this.update(url || this.defaultUrl, params, callback, true);
11997         }
11998         if(this.autoRefreshProcId){
11999             clearInterval(this.autoRefreshProcId);
12000         }
12001         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12002     },
12003
12004     /**
12005      * Stop auto refresh on this element.
12006      */
12007      stopAutoRefresh : function(){
12008         if(this.autoRefreshProcId){
12009             clearInterval(this.autoRefreshProcId);
12010             delete this.autoRefreshProcId;
12011         }
12012     },
12013
12014     isAutoRefreshing : function(){
12015        return this.autoRefreshProcId ? true : false;
12016     },
12017     /**
12018      * Called to update the element to "Loading" state. Override to perform custom action.
12019      */
12020     showLoading : function(){
12021         if(this.showLoadIndicator){
12022             this.el.update(this.indicatorText);
12023         }
12024     },
12025
12026     /**
12027      * Adds unique parameter to query string if disableCaching = true
12028      * @private
12029      */
12030     prepareUrl : function(url){
12031         if(this.disableCaching){
12032             var append = "_dc=" + (new Date().getTime());
12033             if(url.indexOf("?") !== -1){
12034                 url += "&" + append;
12035             }else{
12036                 url += "?" + append;
12037             }
12038         }
12039         return url;
12040     },
12041
12042     /**
12043      * @private
12044      */
12045     processSuccess : function(response){
12046         this.transaction = null;
12047         if(response.argument.form && response.argument.reset){
12048             try{ // put in try/catch since some older FF releases had problems with this
12049                 response.argument.form.reset();
12050             }catch(e){}
12051         }
12052         if(this.loadScripts){
12053             this.renderer.render(this.el, response, this,
12054                 this.updateComplete.createDelegate(this, [response]));
12055         }else{
12056             this.renderer.render(this.el, response, this);
12057             this.updateComplete(response);
12058         }
12059     },
12060
12061     updateComplete : function(response){
12062         this.fireEvent("update", this.el, response);
12063         if(typeof response.argument.callback == "function"){
12064             response.argument.callback(this.el, true, response);
12065         }
12066     },
12067
12068     /**
12069      * @private
12070      */
12071     processFailure : function(response){
12072         this.transaction = null;
12073         this.fireEvent("failure", this.el, response);
12074         if(typeof response.argument.callback == "function"){
12075             response.argument.callback(this.el, false, response);
12076         }
12077     },
12078
12079     /**
12080      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12081      * @param {Object} renderer The object implementing the render() method
12082      */
12083     setRenderer : function(renderer){
12084         this.renderer = renderer;
12085     },
12086
12087     getRenderer : function(){
12088        return this.renderer;
12089     },
12090
12091     /**
12092      * Set the defaultUrl used for updates
12093      * @param {String/Function} defaultUrl The url or a function to call to get the url
12094      */
12095     setDefaultUrl : function(defaultUrl){
12096         this.defaultUrl = defaultUrl;
12097     },
12098
12099     /**
12100      * Aborts the executing transaction
12101      */
12102     abort : function(){
12103         if(this.transaction){
12104             Roo.Ajax.abort(this.transaction);
12105         }
12106     },
12107
12108     /**
12109      * Returns true if an update is in progress
12110      * @return {Boolean}
12111      */
12112     isUpdating : function(){
12113         if(this.transaction){
12114             return Roo.Ajax.isLoading(this.transaction);
12115         }
12116         return false;
12117     }
12118 });
12119
12120 /**
12121  * @class Roo.UpdateManager.defaults
12122  * @static (not really - but it helps the doc tool)
12123  * The defaults collection enables customizing the default properties of UpdateManager
12124  */
12125    Roo.UpdateManager.defaults = {
12126        /**
12127          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12128          * @type Number
12129          */
12130          timeout : 30,
12131
12132          /**
12133          * True to process scripts by default (Defaults to false).
12134          * @type Boolean
12135          */
12136         loadScripts : false,
12137
12138         /**
12139         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12140         * @type String
12141         */
12142         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12143         /**
12144          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12145          * @type Boolean
12146          */
12147         disableCaching : false,
12148         /**
12149          * Whether to show indicatorText when loading (Defaults to true).
12150          * @type Boolean
12151          */
12152         showLoadIndicator : true,
12153         /**
12154          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12155          * @type String
12156          */
12157         indicatorText : '<div class="loading-indicator">Loading...</div>'
12158    };
12159
12160 /**
12161  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12162  *Usage:
12163  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12164  * @param {String/HTMLElement/Roo.Element} el The element to update
12165  * @param {String} url The url
12166  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12167  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12168  * @static
12169  * @deprecated
12170  * @member Roo.UpdateManager
12171  */
12172 Roo.UpdateManager.updateElement = function(el, url, params, options){
12173     var um = Roo.get(el, true).getUpdateManager();
12174     Roo.apply(um, options);
12175     um.update(url, params, options ? options.callback : null);
12176 };
12177 // alias for backwards compat
12178 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12179 /**
12180  * @class Roo.UpdateManager.BasicRenderer
12181  * Default Content renderer. Updates the elements innerHTML with the responseText.
12182  */
12183 Roo.UpdateManager.BasicRenderer = function(){};
12184
12185 Roo.UpdateManager.BasicRenderer.prototype = {
12186     /**
12187      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12188      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12189      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12190      * @param {Roo.Element} el The element being rendered
12191      * @param {Object} response The YUI Connect response object
12192      * @param {UpdateManager} updateManager The calling update manager
12193      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12194      */
12195      render : function(el, response, updateManager, callback){
12196         el.update(response.responseText, updateManager.loadScripts, callback);
12197     }
12198 };
12199 /*
12200  * Based on:
12201  * Roo JS
12202  * (c)) Alan Knowles
12203  * Licence : LGPL
12204  */
12205
12206
12207 /**
12208  * @class Roo.DomTemplate
12209  * @extends Roo.Template
12210  * An effort at a dom based template engine..
12211  *
12212  * Similar to XTemplate, except it uses dom parsing to create the template..
12213  *
12214  * Supported features:
12215  *
12216  *  Tags:
12217
12218 <pre><code>
12219       {a_variable} - output encoded.
12220       {a_variable.format:("Y-m-d")} - call a method on the variable
12221       {a_variable:raw} - unencoded output
12222       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12223       {a_variable:this.method_on_template(...)} - call a method on the template object.
12224  
12225 </code></pre>
12226  *  The tpl tag:
12227 <pre><code>
12228         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12229         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12230         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12231         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12232   
12233 </code></pre>
12234  *      
12235  */
12236 Roo.DomTemplate = function()
12237 {
12238      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12239      if (this.html) {
12240         this.compile();
12241      }
12242 };
12243
12244
12245 Roo.extend(Roo.DomTemplate, Roo.Template, {
12246     /**
12247      * id counter for sub templates.
12248      */
12249     id : 0,
12250     /**
12251      * flag to indicate if dom parser is inside a pre,
12252      * it will strip whitespace if not.
12253      */
12254     inPre : false,
12255     
12256     /**
12257      * The various sub templates
12258      */
12259     tpls : false,
12260     
12261     
12262     
12263     /**
12264      *
12265      * basic tag replacing syntax
12266      * WORD:WORD()
12267      *
12268      * // you can fake an object call by doing this
12269      *  x.t:(test,tesT) 
12270      * 
12271      */
12272     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12273     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12274     
12275     iterChild : function (node, method) {
12276         
12277         var oldPre = this.inPre;
12278         if (node.tagName == 'PRE') {
12279             this.inPre = true;
12280         }
12281         for( var i = 0; i < node.childNodes.length; i++) {
12282             method.call(this, node.childNodes[i]);
12283         }
12284         this.inPre = oldPre;
12285     },
12286     
12287     
12288     
12289     /**
12290      * compile the template
12291      *
12292      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12293      *
12294      */
12295     compile: function()
12296     {
12297         var s = this.html;
12298         
12299         // covert the html into DOM...
12300         var doc = false;
12301         var div =false;
12302         try {
12303             doc = document.implementation.createHTMLDocument("");
12304             doc.documentElement.innerHTML =   this.html  ;
12305             div = doc.documentElement;
12306         } catch (e) {
12307             // old IE... - nasty -- it causes all sorts of issues.. with
12308             // images getting pulled from server..
12309             div = document.createElement('div');
12310             div.innerHTML = this.html;
12311         }
12312         //doc.documentElement.innerHTML = htmlBody
12313          
12314         
12315         
12316         this.tpls = [];
12317         var _t = this;
12318         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12319         
12320         var tpls = this.tpls;
12321         
12322         // create a top level template from the snippet..
12323         
12324         //Roo.log(div.innerHTML);
12325         
12326         var tpl = {
12327             uid : 'master',
12328             id : this.id++,
12329             attr : false,
12330             value : false,
12331             body : div.innerHTML,
12332             
12333             forCall : false,
12334             execCall : false,
12335             dom : div,
12336             isTop : true
12337             
12338         };
12339         tpls.unshift(tpl);
12340         
12341         
12342         // compile them...
12343         this.tpls = [];
12344         Roo.each(tpls, function(tp){
12345             this.compileTpl(tp);
12346             this.tpls[tp.id] = tp;
12347         }, this);
12348         
12349         this.master = tpls[0];
12350         return this;
12351         
12352         
12353     },
12354     
12355     compileNode : function(node, istop) {
12356         // test for
12357         //Roo.log(node);
12358         
12359         
12360         // skip anything not a tag..
12361         if (node.nodeType != 1) {
12362             if (node.nodeType == 3 && !this.inPre) {
12363                 // reduce white space..
12364                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12365                 
12366             }
12367             return;
12368         }
12369         
12370         var tpl = {
12371             uid : false,
12372             id : false,
12373             attr : false,
12374             value : false,
12375             body : '',
12376             
12377             forCall : false,
12378             execCall : false,
12379             dom : false,
12380             isTop : istop
12381             
12382             
12383         };
12384         
12385         
12386         switch(true) {
12387             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12388             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12389             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12390             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12391             // no default..
12392         }
12393         
12394         
12395         if (!tpl.attr) {
12396             // just itterate children..
12397             this.iterChild(node,this.compileNode);
12398             return;
12399         }
12400         tpl.uid = this.id++;
12401         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12402         node.removeAttribute('roo-'+ tpl.attr);
12403         if (tpl.attr != 'name') {
12404             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12405             node.parentNode.replaceChild(placeholder,  node);
12406         } else {
12407             
12408             var placeholder =  document.createElement('span');
12409             placeholder.className = 'roo-tpl-' + tpl.value;
12410             node.parentNode.replaceChild(placeholder,  node);
12411         }
12412         
12413         // parent now sees '{domtplXXXX}
12414         this.iterChild(node,this.compileNode);
12415         
12416         // we should now have node body...
12417         var div = document.createElement('div');
12418         div.appendChild(node);
12419         tpl.dom = node;
12420         // this has the unfortunate side effect of converting tagged attributes
12421         // eg. href="{...}" into %7C...%7D
12422         // this has been fixed by searching for those combo's although it's a bit hacky..
12423         
12424         
12425         tpl.body = div.innerHTML;
12426         
12427         
12428          
12429         tpl.id = tpl.uid;
12430         switch(tpl.attr) {
12431             case 'for' :
12432                 switch (tpl.value) {
12433                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12434                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12435                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12436                 }
12437                 break;
12438             
12439             case 'exec':
12440                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12441                 break;
12442             
12443             case 'if':     
12444                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12445                 break;
12446             
12447             case 'name':
12448                 tpl.id  = tpl.value; // replace non characters???
12449                 break;
12450             
12451         }
12452         
12453         
12454         this.tpls.push(tpl);
12455         
12456         
12457         
12458     },
12459     
12460     
12461     
12462     
12463     /**
12464      * Compile a segment of the template into a 'sub-template'
12465      *
12466      * 
12467      * 
12468      *
12469      */
12470     compileTpl : function(tpl)
12471     {
12472         var fm = Roo.util.Format;
12473         var useF = this.disableFormats !== true;
12474         
12475         var sep = Roo.isGecko ? "+\n" : ",\n";
12476         
12477         var undef = function(str) {
12478             Roo.debug && Roo.log("Property not found :"  + str);
12479             return '';
12480         };
12481           
12482         //Roo.log(tpl.body);
12483         
12484         
12485         
12486         var fn = function(m, lbrace, name, format, args)
12487         {
12488             //Roo.log("ARGS");
12489             //Roo.log(arguments);
12490             args = args ? args.replace(/\\'/g,"'") : args;
12491             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12492             if (typeof(format) == 'undefined') {
12493                 format =  'htmlEncode'; 
12494             }
12495             if (format == 'raw' ) {
12496                 format = false;
12497             }
12498             
12499             if(name.substr(0, 6) == 'domtpl'){
12500                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12501             }
12502             
12503             // build an array of options to determine if value is undefined..
12504             
12505             // basically get 'xxxx.yyyy' then do
12506             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12507             //    (function () { Roo.log("Property not found"); return ''; })() :
12508             //    ......
12509             
12510             var udef_ar = [];
12511             var lookfor = '';
12512             Roo.each(name.split('.'), function(st) {
12513                 lookfor += (lookfor.length ? '.': '') + st;
12514                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12515             });
12516             
12517             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12518             
12519             
12520             if(format && useF){
12521                 
12522                 args = args ? ',' + args : "";
12523                  
12524                 if(format.substr(0, 5) != "this."){
12525                     format = "fm." + format + '(';
12526                 }else{
12527                     format = 'this.call("'+ format.substr(5) + '", ';
12528                     args = ", values";
12529                 }
12530                 
12531                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12532             }
12533              
12534             if (args && args.length) {
12535                 // called with xxyx.yuu:(test,test)
12536                 // change to ()
12537                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12538             }
12539             // raw.. - :raw modifier..
12540             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12541             
12542         };
12543         var body;
12544         // branched to use + in gecko and [].join() in others
12545         if(Roo.isGecko){
12546             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12547                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12548                     "';};};";
12549         }else{
12550             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12551             body.push(tpl.body.replace(/(\r\n|\n)/g,
12552                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12553             body.push("'].join('');};};");
12554             body = body.join('');
12555         }
12556         
12557         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12558        
12559         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12560         eval(body);
12561         
12562         return this;
12563     },
12564      
12565     /**
12566      * same as applyTemplate, except it's done to one of the subTemplates
12567      * when using named templates, you can do:
12568      *
12569      * var str = pl.applySubTemplate('your-name', values);
12570      *
12571      * 
12572      * @param {Number} id of the template
12573      * @param {Object} values to apply to template
12574      * @param {Object} parent (normaly the instance of this object)
12575      */
12576     applySubTemplate : function(id, values, parent)
12577     {
12578         
12579         
12580         var t = this.tpls[id];
12581         
12582         
12583         try { 
12584             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12585                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12586                 return '';
12587             }
12588         } catch(e) {
12589             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12590             Roo.log(values);
12591           
12592             return '';
12593         }
12594         try { 
12595             
12596             if(t.execCall && t.execCall.call(this, values, parent)){
12597                 return '';
12598             }
12599         } catch(e) {
12600             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12601             Roo.log(values);
12602             return '';
12603         }
12604         
12605         try {
12606             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12607             parent = t.target ? values : parent;
12608             if(t.forCall && vs instanceof Array){
12609                 var buf = [];
12610                 for(var i = 0, len = vs.length; i < len; i++){
12611                     try {
12612                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12613                     } catch (e) {
12614                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12615                         Roo.log(e.body);
12616                         //Roo.log(t.compiled);
12617                         Roo.log(vs[i]);
12618                     }   
12619                 }
12620                 return buf.join('');
12621             }
12622         } catch (e) {
12623             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12624             Roo.log(values);
12625             return '';
12626         }
12627         try {
12628             return t.compiled.call(this, vs, parent);
12629         } catch (e) {
12630             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12631             Roo.log(e.body);
12632             //Roo.log(t.compiled);
12633             Roo.log(values);
12634             return '';
12635         }
12636     },
12637
12638    
12639
12640     applyTemplate : function(values){
12641         return this.master.compiled.call(this, values, {});
12642         //var s = this.subs;
12643     },
12644
12645     apply : function(){
12646         return this.applyTemplate.apply(this, arguments);
12647     }
12648
12649  });
12650
12651 Roo.DomTemplate.from = function(el){
12652     el = Roo.getDom(el);
12653     return new Roo.Domtemplate(el.value || el.innerHTML);
12654 };/*
12655  * Based on:
12656  * Ext JS Library 1.1.1
12657  * Copyright(c) 2006-2007, Ext JS, LLC.
12658  *
12659  * Originally Released Under LGPL - original licence link has changed is not relivant.
12660  *
12661  * Fork - LGPL
12662  * <script type="text/javascript">
12663  */
12664
12665 /**
12666  * @class Roo.util.DelayedTask
12667  * Provides a convenient method of performing setTimeout where a new
12668  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12669  * You can use this class to buffer
12670  * the keypress events for a certain number of milliseconds, and perform only if they stop
12671  * for that amount of time.
12672  * @constructor The parameters to this constructor serve as defaults and are not required.
12673  * @param {Function} fn (optional) The default function to timeout
12674  * @param {Object} scope (optional) The default scope of that timeout
12675  * @param {Array} args (optional) The default Array of arguments
12676  */
12677 Roo.util.DelayedTask = function(fn, scope, args){
12678     var id = null, d, t;
12679
12680     var call = function(){
12681         var now = new Date().getTime();
12682         if(now - t >= d){
12683             clearInterval(id);
12684             id = null;
12685             fn.apply(scope, args || []);
12686         }
12687     };
12688     /**
12689      * Cancels any pending timeout and queues a new one
12690      * @param {Number} delay The milliseconds to delay
12691      * @param {Function} newFn (optional) Overrides function passed to constructor
12692      * @param {Object} newScope (optional) Overrides scope passed to constructor
12693      * @param {Array} newArgs (optional) Overrides args passed to constructor
12694      */
12695     this.delay = function(delay, newFn, newScope, newArgs){
12696         if(id && delay != d){
12697             this.cancel();
12698         }
12699         d = delay;
12700         t = new Date().getTime();
12701         fn = newFn || fn;
12702         scope = newScope || scope;
12703         args = newArgs || args;
12704         if(!id){
12705             id = setInterval(call, d);
12706         }
12707     };
12708
12709     /**
12710      * Cancel the last queued timeout
12711      */
12712     this.cancel = function(){
12713         if(id){
12714             clearInterval(id);
12715             id = null;
12716         }
12717     };
12718 };/*
12719  * Based on:
12720  * Ext JS Library 1.1.1
12721  * Copyright(c) 2006-2007, Ext JS, LLC.
12722  *
12723  * Originally Released Under LGPL - original licence link has changed is not relivant.
12724  *
12725  * Fork - LGPL
12726  * <script type="text/javascript">
12727  */
12728  
12729  
12730 Roo.util.TaskRunner = function(interval){
12731     interval = interval || 10;
12732     var tasks = [], removeQueue = [];
12733     var id = 0;
12734     var running = false;
12735
12736     var stopThread = function(){
12737         running = false;
12738         clearInterval(id);
12739         id = 0;
12740     };
12741
12742     var startThread = function(){
12743         if(!running){
12744             running = true;
12745             id = setInterval(runTasks, interval);
12746         }
12747     };
12748
12749     var removeTask = function(task){
12750         removeQueue.push(task);
12751         if(task.onStop){
12752             task.onStop();
12753         }
12754     };
12755
12756     var runTasks = function(){
12757         if(removeQueue.length > 0){
12758             for(var i = 0, len = removeQueue.length; i < len; i++){
12759                 tasks.remove(removeQueue[i]);
12760             }
12761             removeQueue = [];
12762             if(tasks.length < 1){
12763                 stopThread();
12764                 return;
12765             }
12766         }
12767         var now = new Date().getTime();
12768         for(var i = 0, len = tasks.length; i < len; ++i){
12769             var t = tasks[i];
12770             var itime = now - t.taskRunTime;
12771             if(t.interval <= itime){
12772                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12773                 t.taskRunTime = now;
12774                 if(rt === false || t.taskRunCount === t.repeat){
12775                     removeTask(t);
12776                     return;
12777                 }
12778             }
12779             if(t.duration && t.duration <= (now - t.taskStartTime)){
12780                 removeTask(t);
12781             }
12782         }
12783     };
12784
12785     /**
12786      * Queues a new task.
12787      * @param {Object} task
12788      */
12789     this.start = function(task){
12790         tasks.push(task);
12791         task.taskStartTime = new Date().getTime();
12792         task.taskRunTime = 0;
12793         task.taskRunCount = 0;
12794         startThread();
12795         return task;
12796     };
12797
12798     this.stop = function(task){
12799         removeTask(task);
12800         return task;
12801     };
12802
12803     this.stopAll = function(){
12804         stopThread();
12805         for(var i = 0, len = tasks.length; i < len; i++){
12806             if(tasks[i].onStop){
12807                 tasks[i].onStop();
12808             }
12809         }
12810         tasks = [];
12811         removeQueue = [];
12812     };
12813 };
12814
12815 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12816  * Based on:
12817  * Ext JS Library 1.1.1
12818  * Copyright(c) 2006-2007, Ext JS, LLC.
12819  *
12820  * Originally Released Under LGPL - original licence link has changed is not relivant.
12821  *
12822  * Fork - LGPL
12823  * <script type="text/javascript">
12824  */
12825
12826  
12827 /**
12828  * @class Roo.util.MixedCollection
12829  * @extends Roo.util.Observable
12830  * A Collection class that maintains both numeric indexes and keys and exposes events.
12831  * @constructor
12832  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12833  * collection (defaults to false)
12834  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12835  * and return the key value for that item.  This is used when available to look up the key on items that
12836  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12837  * equivalent to providing an implementation for the {@link #getKey} method.
12838  */
12839 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12840     this.items = [];
12841     this.map = {};
12842     this.keys = [];
12843     this.length = 0;
12844     this.addEvents({
12845         /**
12846          * @event clear
12847          * Fires when the collection is cleared.
12848          */
12849         "clear" : true,
12850         /**
12851          * @event add
12852          * Fires when an item is added to the collection.
12853          * @param {Number} index The index at which the item was added.
12854          * @param {Object} o The item added.
12855          * @param {String} key The key associated with the added item.
12856          */
12857         "add" : true,
12858         /**
12859          * @event replace
12860          * Fires when an item is replaced in the collection.
12861          * @param {String} key he key associated with the new added.
12862          * @param {Object} old The item being replaced.
12863          * @param {Object} new The new item.
12864          */
12865         "replace" : true,
12866         /**
12867          * @event remove
12868          * Fires when an item is removed from the collection.
12869          * @param {Object} o The item being removed.
12870          * @param {String} key (optional) The key associated with the removed item.
12871          */
12872         "remove" : true,
12873         "sort" : true
12874     });
12875     this.allowFunctions = allowFunctions === true;
12876     if(keyFn){
12877         this.getKey = keyFn;
12878     }
12879     Roo.util.MixedCollection.superclass.constructor.call(this);
12880 };
12881
12882 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12883     allowFunctions : false,
12884     
12885 /**
12886  * Adds an item to the collection.
12887  * @param {String} key The key to associate with the item
12888  * @param {Object} o The item to add.
12889  * @return {Object} The item added.
12890  */
12891     add : function(key, o){
12892         if(arguments.length == 1){
12893             o = arguments[0];
12894             key = this.getKey(o);
12895         }
12896         if(typeof key == "undefined" || key === null){
12897             this.length++;
12898             this.items.push(o);
12899             this.keys.push(null);
12900         }else{
12901             var old = this.map[key];
12902             if(old){
12903                 return this.replace(key, o);
12904             }
12905             this.length++;
12906             this.items.push(o);
12907             this.map[key] = o;
12908             this.keys.push(key);
12909         }
12910         this.fireEvent("add", this.length-1, o, key);
12911         return o;
12912     },
12913        
12914 /**
12915   * MixedCollection has a generic way to fetch keys if you implement getKey.
12916 <pre><code>
12917 // normal way
12918 var mc = new Roo.util.MixedCollection();
12919 mc.add(someEl.dom.id, someEl);
12920 mc.add(otherEl.dom.id, otherEl);
12921 //and so on
12922
12923 // using getKey
12924 var mc = new Roo.util.MixedCollection();
12925 mc.getKey = function(el){
12926    return el.dom.id;
12927 };
12928 mc.add(someEl);
12929 mc.add(otherEl);
12930
12931 // or via the constructor
12932 var mc = new Roo.util.MixedCollection(false, function(el){
12933    return el.dom.id;
12934 });
12935 mc.add(someEl);
12936 mc.add(otherEl);
12937 </code></pre>
12938  * @param o {Object} The item for which to find the key.
12939  * @return {Object} The key for the passed item.
12940  */
12941     getKey : function(o){
12942          return o.id; 
12943     },
12944    
12945 /**
12946  * Replaces an item in the collection.
12947  * @param {String} key The key associated with the item to replace, or the item to replace.
12948  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12949  * @return {Object}  The new item.
12950  */
12951     replace : function(key, o){
12952         if(arguments.length == 1){
12953             o = arguments[0];
12954             key = this.getKey(o);
12955         }
12956         var old = this.item(key);
12957         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12958              return this.add(key, o);
12959         }
12960         var index = this.indexOfKey(key);
12961         this.items[index] = o;
12962         this.map[key] = o;
12963         this.fireEvent("replace", key, old, o);
12964         return o;
12965     },
12966    
12967 /**
12968  * Adds all elements of an Array or an Object to the collection.
12969  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12970  * an Array of values, each of which are added to the collection.
12971  */
12972     addAll : function(objs){
12973         if(arguments.length > 1 || objs instanceof Array){
12974             var args = arguments.length > 1 ? arguments : objs;
12975             for(var i = 0, len = args.length; i < len; i++){
12976                 this.add(args[i]);
12977             }
12978         }else{
12979             for(var key in objs){
12980                 if(this.allowFunctions || typeof objs[key] != "function"){
12981                     this.add(key, objs[key]);
12982                 }
12983             }
12984         }
12985     },
12986    
12987 /**
12988  * Executes the specified function once for every item in the collection, passing each
12989  * item as the first and only parameter. returning false from the function will stop the iteration.
12990  * @param {Function} fn The function to execute for each item.
12991  * @param {Object} scope (optional) The scope in which to execute the function.
12992  */
12993     each : function(fn, scope){
12994         var items = [].concat(this.items); // each safe for removal
12995         for(var i = 0, len = items.length; i < len; i++){
12996             if(fn.call(scope || items[i], items[i], i, len) === false){
12997                 break;
12998             }
12999         }
13000     },
13001    
13002 /**
13003  * Executes the specified function once for every key in the collection, passing each
13004  * key, and its associated item as the first two parameters.
13005  * @param {Function} fn The function to execute for each item.
13006  * @param {Object} scope (optional) The scope in which to execute the function.
13007  */
13008     eachKey : function(fn, scope){
13009         for(var i = 0, len = this.keys.length; i < len; i++){
13010             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13011         }
13012     },
13013    
13014 /**
13015  * Returns the first item in the collection which elicits a true return value from the
13016  * passed selection function.
13017  * @param {Function} fn The selection function to execute for each item.
13018  * @param {Object} scope (optional) The scope in which to execute the function.
13019  * @return {Object} The first item in the collection which returned true from the selection function.
13020  */
13021     find : function(fn, scope){
13022         for(var i = 0, len = this.items.length; i < len; i++){
13023             if(fn.call(scope || window, this.items[i], this.keys[i])){
13024                 return this.items[i];
13025             }
13026         }
13027         return null;
13028     },
13029    
13030 /**
13031  * Inserts an item at the specified index in the collection.
13032  * @param {Number} index The index to insert the item at.
13033  * @param {String} key The key to associate with the new item, or the item itself.
13034  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13035  * @return {Object} The item inserted.
13036  */
13037     insert : function(index, key, o){
13038         if(arguments.length == 2){
13039             o = arguments[1];
13040             key = this.getKey(o);
13041         }
13042         if(index >= this.length){
13043             return this.add(key, o);
13044         }
13045         this.length++;
13046         this.items.splice(index, 0, o);
13047         if(typeof key != "undefined" && key != null){
13048             this.map[key] = o;
13049         }
13050         this.keys.splice(index, 0, key);
13051         this.fireEvent("add", index, o, key);
13052         return o;
13053     },
13054    
13055 /**
13056  * Removed an item from the collection.
13057  * @param {Object} o The item to remove.
13058  * @return {Object} The item removed.
13059  */
13060     remove : function(o){
13061         return this.removeAt(this.indexOf(o));
13062     },
13063    
13064 /**
13065  * Remove an item from a specified index in the collection.
13066  * @param {Number} index The index within the collection of the item to remove.
13067  */
13068     removeAt : function(index){
13069         if(index < this.length && index >= 0){
13070             this.length--;
13071             var o = this.items[index];
13072             this.items.splice(index, 1);
13073             var key = this.keys[index];
13074             if(typeof key != "undefined"){
13075                 delete this.map[key];
13076             }
13077             this.keys.splice(index, 1);
13078             this.fireEvent("remove", o, key);
13079         }
13080     },
13081    
13082 /**
13083  * Removed an item associated with the passed key fom the collection.
13084  * @param {String} key The key of the item to remove.
13085  */
13086     removeKey : function(key){
13087         return this.removeAt(this.indexOfKey(key));
13088     },
13089    
13090 /**
13091  * Returns the number of items in the collection.
13092  * @return {Number} the number of items in the collection.
13093  */
13094     getCount : function(){
13095         return this.length; 
13096     },
13097    
13098 /**
13099  * Returns index within the collection of the passed Object.
13100  * @param {Object} o The item to find the index of.
13101  * @return {Number} index of the item.
13102  */
13103     indexOf : function(o){
13104         if(!this.items.indexOf){
13105             for(var i = 0, len = this.items.length; i < len; i++){
13106                 if(this.items[i] == o) {
13107                     return i;
13108                 }
13109             }
13110             return -1;
13111         }else{
13112             return this.items.indexOf(o);
13113         }
13114     },
13115    
13116 /**
13117  * Returns index within the collection of the passed key.
13118  * @param {String} key The key to find the index of.
13119  * @return {Number} index of the key.
13120  */
13121     indexOfKey : function(key){
13122         if(!this.keys.indexOf){
13123             for(var i = 0, len = this.keys.length; i < len; i++){
13124                 if(this.keys[i] == key) {
13125                     return i;
13126                 }
13127             }
13128             return -1;
13129         }else{
13130             return this.keys.indexOf(key);
13131         }
13132     },
13133    
13134 /**
13135  * Returns the item associated with the passed key OR index. Key has priority over index.
13136  * @param {String/Number} key The key or index of the item.
13137  * @return {Object} The item associated with the passed key.
13138  */
13139     item : function(key){
13140         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13141         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13142     },
13143     
13144 /**
13145  * Returns the item at the specified index.
13146  * @param {Number} index The index of the item.
13147  * @return {Object}
13148  */
13149     itemAt : function(index){
13150         return this.items[index];
13151     },
13152     
13153 /**
13154  * Returns the item associated with the passed key.
13155  * @param {String/Number} key The key of the item.
13156  * @return {Object} The item associated with the passed key.
13157  */
13158     key : function(key){
13159         return this.map[key];
13160     },
13161    
13162 /**
13163  * Returns true if the collection contains the passed Object as an item.
13164  * @param {Object} o  The Object to look for in the collection.
13165  * @return {Boolean} True if the collection contains the Object as an item.
13166  */
13167     contains : function(o){
13168         return this.indexOf(o) != -1;
13169     },
13170    
13171 /**
13172  * Returns true if the collection contains the passed Object as a key.
13173  * @param {String} key The key to look for in the collection.
13174  * @return {Boolean} True if the collection contains the Object as a key.
13175  */
13176     containsKey : function(key){
13177         return typeof this.map[key] != "undefined";
13178     },
13179    
13180 /**
13181  * Removes all items from the collection.
13182  */
13183     clear : function(){
13184         this.length = 0;
13185         this.items = [];
13186         this.keys = [];
13187         this.map = {};
13188         this.fireEvent("clear");
13189     },
13190    
13191 /**
13192  * Returns the first item in the collection.
13193  * @return {Object} the first item in the collection..
13194  */
13195     first : function(){
13196         return this.items[0]; 
13197     },
13198    
13199 /**
13200  * Returns the last item in the collection.
13201  * @return {Object} the last item in the collection..
13202  */
13203     last : function(){
13204         return this.items[this.length-1];   
13205     },
13206     
13207     _sort : function(property, dir, fn){
13208         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13209         fn = fn || function(a, b){
13210             return a-b;
13211         };
13212         var c = [], k = this.keys, items = this.items;
13213         for(var i = 0, len = items.length; i < len; i++){
13214             c[c.length] = {key: k[i], value: items[i], index: i};
13215         }
13216         c.sort(function(a, b){
13217             var v = fn(a[property], b[property]) * dsc;
13218             if(v == 0){
13219                 v = (a.index < b.index ? -1 : 1);
13220             }
13221             return v;
13222         });
13223         for(var i = 0, len = c.length; i < len; i++){
13224             items[i] = c[i].value;
13225             k[i] = c[i].key;
13226         }
13227         this.fireEvent("sort", this);
13228     },
13229     
13230     /**
13231      * Sorts this collection with the passed comparison function
13232      * @param {String} direction (optional) "ASC" or "DESC"
13233      * @param {Function} fn (optional) comparison function
13234      */
13235     sort : function(dir, fn){
13236         this._sort("value", dir, fn);
13237     },
13238     
13239     /**
13240      * Sorts this collection by keys
13241      * @param {String} direction (optional) "ASC" or "DESC"
13242      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13243      */
13244     keySort : function(dir, fn){
13245         this._sort("key", dir, fn || function(a, b){
13246             return String(a).toUpperCase()-String(b).toUpperCase();
13247         });
13248     },
13249     
13250     /**
13251      * Returns a range of items in this collection
13252      * @param {Number} startIndex (optional) defaults to 0
13253      * @param {Number} endIndex (optional) default to the last item
13254      * @return {Array} An array of items
13255      */
13256     getRange : function(start, end){
13257         var items = this.items;
13258         if(items.length < 1){
13259             return [];
13260         }
13261         start = start || 0;
13262         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13263         var r = [];
13264         if(start <= end){
13265             for(var i = start; i <= end; i++) {
13266                     r[r.length] = items[i];
13267             }
13268         }else{
13269             for(var i = start; i >= end; i--) {
13270                     r[r.length] = items[i];
13271             }
13272         }
13273         return r;
13274     },
13275         
13276     /**
13277      * Filter the <i>objects</i> in this collection by a specific property. 
13278      * Returns a new collection that has been filtered.
13279      * @param {String} property A property on your objects
13280      * @param {String/RegExp} value Either string that the property values 
13281      * should start with or a RegExp to test against the property
13282      * @return {MixedCollection} The new filtered collection
13283      */
13284     filter : function(property, value){
13285         if(!value.exec){ // not a regex
13286             value = String(value);
13287             if(value.length == 0){
13288                 return this.clone();
13289             }
13290             value = new RegExp("^" + Roo.escapeRe(value), "i");
13291         }
13292         return this.filterBy(function(o){
13293             return o && value.test(o[property]);
13294         });
13295         },
13296     
13297     /**
13298      * Filter by a function. * Returns a new collection that has been filtered.
13299      * The passed function will be called with each 
13300      * object in the collection. If the function returns true, the value is included 
13301      * otherwise it is filtered.
13302      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13303      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13304      * @return {MixedCollection} The new filtered collection
13305      */
13306     filterBy : function(fn, scope){
13307         var r = new Roo.util.MixedCollection();
13308         r.getKey = this.getKey;
13309         var k = this.keys, it = this.items;
13310         for(var i = 0, len = it.length; i < len; i++){
13311             if(fn.call(scope||this, it[i], k[i])){
13312                                 r.add(k[i], it[i]);
13313                         }
13314         }
13315         return r;
13316     },
13317     
13318     /**
13319      * Creates a duplicate of this collection
13320      * @return {MixedCollection}
13321      */
13322     clone : function(){
13323         var r = new Roo.util.MixedCollection();
13324         var k = this.keys, it = this.items;
13325         for(var i = 0, len = it.length; i < len; i++){
13326             r.add(k[i], it[i]);
13327         }
13328         r.getKey = this.getKey;
13329         return r;
13330     }
13331 });
13332 /**
13333  * Returns the item associated with the passed key or index.
13334  * @method
13335  * @param {String/Number} key The key or index of the item.
13336  * @return {Object} The item associated with the passed key.
13337  */
13338 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13339  * Based on:
13340  * Ext JS Library 1.1.1
13341  * Copyright(c) 2006-2007, Ext JS, LLC.
13342  *
13343  * Originally Released Under LGPL - original licence link has changed is not relivant.
13344  *
13345  * Fork - LGPL
13346  * <script type="text/javascript">
13347  */
13348 /**
13349  * @class Roo.util.JSON
13350  * Modified version of Douglas Crockford"s json.js that doesn"t
13351  * mess with the Object prototype 
13352  * http://www.json.org/js.html
13353  * @singleton
13354  */
13355 Roo.util.JSON = new (function(){
13356     var useHasOwn = {}.hasOwnProperty ? true : false;
13357     
13358     // crashes Safari in some instances
13359     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13360     
13361     var pad = function(n) {
13362         return n < 10 ? "0" + n : n;
13363     };
13364     
13365     var m = {
13366         "\b": '\\b',
13367         "\t": '\\t',
13368         "\n": '\\n',
13369         "\f": '\\f',
13370         "\r": '\\r',
13371         '"' : '\\"',
13372         "\\": '\\\\'
13373     };
13374
13375     var encodeString = function(s){
13376         if (/["\\\x00-\x1f]/.test(s)) {
13377             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13378                 var c = m[b];
13379                 if(c){
13380                     return c;
13381                 }
13382                 c = b.charCodeAt();
13383                 return "\\u00" +
13384                     Math.floor(c / 16).toString(16) +
13385                     (c % 16).toString(16);
13386             }) + '"';
13387         }
13388         return '"' + s + '"';
13389     };
13390     
13391     var encodeArray = function(o){
13392         var a = ["["], b, i, l = o.length, v;
13393             for (i = 0; i < l; i += 1) {
13394                 v = o[i];
13395                 switch (typeof v) {
13396                     case "undefined":
13397                     case "function":
13398                     case "unknown":
13399                         break;
13400                     default:
13401                         if (b) {
13402                             a.push(',');
13403                         }
13404                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13405                         b = true;
13406                 }
13407             }
13408             a.push("]");
13409             return a.join("");
13410     };
13411     
13412     var encodeDate = function(o){
13413         return '"' + o.getFullYear() + "-" +
13414                 pad(o.getMonth() + 1) + "-" +
13415                 pad(o.getDate()) + "T" +
13416                 pad(o.getHours()) + ":" +
13417                 pad(o.getMinutes()) + ":" +
13418                 pad(o.getSeconds()) + '"';
13419     };
13420     
13421     /**
13422      * Encodes an Object, Array or other value
13423      * @param {Mixed} o The variable to encode
13424      * @return {String} The JSON string
13425      */
13426     this.encode = function(o)
13427     {
13428         // should this be extended to fully wrap stringify..
13429         
13430         if(typeof o == "undefined" || o === null){
13431             return "null";
13432         }else if(o instanceof Array){
13433             return encodeArray(o);
13434         }else if(o instanceof Date){
13435             return encodeDate(o);
13436         }else if(typeof o == "string"){
13437             return encodeString(o);
13438         }else if(typeof o == "number"){
13439             return isFinite(o) ? String(o) : "null";
13440         }else if(typeof o == "boolean"){
13441             return String(o);
13442         }else {
13443             var a = ["{"], b, i, v;
13444             for (i in o) {
13445                 if(!useHasOwn || o.hasOwnProperty(i)) {
13446                     v = o[i];
13447                     switch (typeof v) {
13448                     case "undefined":
13449                     case "function":
13450                     case "unknown":
13451                         break;
13452                     default:
13453                         if(b){
13454                             a.push(',');
13455                         }
13456                         a.push(this.encode(i), ":",
13457                                 v === null ? "null" : this.encode(v));
13458                         b = true;
13459                     }
13460                 }
13461             }
13462             a.push("}");
13463             return a.join("");
13464         }
13465     };
13466     
13467     /**
13468      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13469      * @param {String} json The JSON string
13470      * @return {Object} The resulting object
13471      */
13472     this.decode = function(json){
13473         
13474         return  /** eval:var:json */ eval("(" + json + ')');
13475     };
13476 })();
13477 /** 
13478  * Shorthand for {@link Roo.util.JSON#encode}
13479  * @member Roo encode 
13480  * @method */
13481 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13482 /** 
13483  * Shorthand for {@link Roo.util.JSON#decode}
13484  * @member Roo decode 
13485  * @method */
13486 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13487 /*
13488  * Based on:
13489  * Ext JS Library 1.1.1
13490  * Copyright(c) 2006-2007, Ext JS, LLC.
13491  *
13492  * Originally Released Under LGPL - original licence link has changed is not relivant.
13493  *
13494  * Fork - LGPL
13495  * <script type="text/javascript">
13496  */
13497  
13498 /**
13499  * @class Roo.util.Format
13500  * Reusable data formatting functions
13501  * @singleton
13502  */
13503 Roo.util.Format = function(){
13504     var trimRe = /^\s+|\s+$/g;
13505     return {
13506         /**
13507          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13508          * @param {String} value The string to truncate
13509          * @param {Number} length The maximum length to allow before truncating
13510          * @return {String} The converted text
13511          */
13512         ellipsis : function(value, len){
13513             if(value && value.length > len){
13514                 return value.substr(0, len-3)+"...";
13515             }
13516             return value;
13517         },
13518
13519         /**
13520          * Checks a reference and converts it to empty string if it is undefined
13521          * @param {Mixed} value Reference to check
13522          * @return {Mixed} Empty string if converted, otherwise the original value
13523          */
13524         undef : function(value){
13525             return typeof value != "undefined" ? value : "";
13526         },
13527
13528         /**
13529          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13530          * @param {String} value The string to encode
13531          * @return {String} The encoded text
13532          */
13533         htmlEncode : function(value){
13534             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13535         },
13536
13537         /**
13538          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13539          * @param {String} value The string to decode
13540          * @return {String} The decoded text
13541          */
13542         htmlDecode : function(value){
13543             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13544         },
13545
13546         /**
13547          * Trims any whitespace from either side of a string
13548          * @param {String} value The text to trim
13549          * @return {String} The trimmed text
13550          */
13551         trim : function(value){
13552             return String(value).replace(trimRe, "");
13553         },
13554
13555         /**
13556          * Returns a substring from within an original string
13557          * @param {String} value The original text
13558          * @param {Number} start The start index of the substring
13559          * @param {Number} length The length of the substring
13560          * @return {String} The substring
13561          */
13562         substr : function(value, start, length){
13563             return String(value).substr(start, length);
13564         },
13565
13566         /**
13567          * Converts a string to all lower case letters
13568          * @param {String} value The text to convert
13569          * @return {String} The converted text
13570          */
13571         lowercase : function(value){
13572             return String(value).toLowerCase();
13573         },
13574
13575         /**
13576          * Converts a string to all upper case letters
13577          * @param {String} value The text to convert
13578          * @return {String} The converted text
13579          */
13580         uppercase : function(value){
13581             return String(value).toUpperCase();
13582         },
13583
13584         /**
13585          * Converts the first character only of a string to upper case
13586          * @param {String} value The text to convert
13587          * @return {String} The converted text
13588          */
13589         capitalize : function(value){
13590             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13591         },
13592
13593         // private
13594         call : function(value, fn){
13595             if(arguments.length > 2){
13596                 var args = Array.prototype.slice.call(arguments, 2);
13597                 args.unshift(value);
13598                  
13599                 return /** eval:var:value */  eval(fn).apply(window, args);
13600             }else{
13601                 /** eval:var:value */
13602                 return /** eval:var:value */ eval(fn).call(window, value);
13603             }
13604         },
13605
13606        
13607         /**
13608          * safer version of Math.toFixed..??/
13609          * @param {Number/String} value The numeric value to format
13610          * @param {Number/String} value Decimal places 
13611          * @return {String} The formatted currency string
13612          */
13613         toFixed : function(v, n)
13614         {
13615             // why not use to fixed - precision is buggered???
13616             if (!n) {
13617                 return Math.round(v-0);
13618             }
13619             var fact = Math.pow(10,n+1);
13620             v = (Math.round((v-0)*fact))/fact;
13621             var z = (''+fact).substring(2);
13622             if (v == Math.floor(v)) {
13623                 return Math.floor(v) + '.' + z;
13624             }
13625             
13626             // now just padd decimals..
13627             var ps = String(v).split('.');
13628             var fd = (ps[1] + z);
13629             var r = fd.substring(0,n); 
13630             var rm = fd.substring(n); 
13631             if (rm < 5) {
13632                 return ps[0] + '.' + r;
13633             }
13634             r*=1; // turn it into a number;
13635             r++;
13636             if (String(r).length != n) {
13637                 ps[0]*=1;
13638                 ps[0]++;
13639                 r = String(r).substring(1); // chop the end off.
13640             }
13641             
13642             return ps[0] + '.' + r;
13643              
13644         },
13645         
13646         /**
13647          * Format a number as US currency
13648          * @param {Number/String} value The numeric value to format
13649          * @return {String} The formatted currency string
13650          */
13651         usMoney : function(v){
13652             return '$' + Roo.util.Format.number(v);
13653         },
13654         
13655         /**
13656          * Format a number
13657          * eventually this should probably emulate php's number_format
13658          * @param {Number/String} value The numeric value to format
13659          * @param {Number} decimals number of decimal places
13660          * @return {String} The formatted currency string
13661          */
13662         number : function(v,decimals)
13663         {
13664             // multiply and round.
13665             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13666             var mul = Math.pow(10, decimals);
13667             var zero = String(mul).substring(1);
13668             v = (Math.round((v-0)*mul))/mul;
13669             
13670             // if it's '0' number.. then
13671             
13672             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13673             v = String(v);
13674             var ps = v.split('.');
13675             var whole = ps[0];
13676             
13677             
13678             var r = /(\d+)(\d{3})/;
13679             // add comma's
13680             while (r.test(whole)) {
13681                 whole = whole.replace(r, '$1' + ',' + '$2');
13682             }
13683             
13684             
13685             var sub = ps[1] ?
13686                     // has decimals..
13687                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13688                     // does not have decimals
13689                     (decimals ? ('.' + zero) : '');
13690             
13691             
13692             return whole + sub ;
13693         },
13694         
13695         /**
13696          * Parse a value into a formatted date using the specified format pattern.
13697          * @param {Mixed} value The value to format
13698          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13699          * @return {String} The formatted date string
13700          */
13701         date : function(v, format){
13702             if(!v){
13703                 return "";
13704             }
13705             if(!(v instanceof Date)){
13706                 v = new Date(Date.parse(v));
13707             }
13708             return v.dateFormat(format || Roo.util.Format.defaults.date);
13709         },
13710
13711         /**
13712          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13713          * @param {String} format Any valid date format string
13714          * @return {Function} The date formatting function
13715          */
13716         dateRenderer : function(format){
13717             return function(v){
13718                 return Roo.util.Format.date(v, format);  
13719             };
13720         },
13721
13722         // private
13723         stripTagsRE : /<\/?[^>]+>/gi,
13724         
13725         /**
13726          * Strips all HTML tags
13727          * @param {Mixed} value The text from which to strip tags
13728          * @return {String} The stripped text
13729          */
13730         stripTags : function(v){
13731             return !v ? v : String(v).replace(this.stripTagsRE, "");
13732         }
13733     };
13734 }();
13735 Roo.util.Format.defaults = {
13736     date : 'd/M/Y'
13737 };/*
13738  * Based on:
13739  * Ext JS Library 1.1.1
13740  * Copyright(c) 2006-2007, Ext JS, LLC.
13741  *
13742  * Originally Released Under LGPL - original licence link has changed is not relivant.
13743  *
13744  * Fork - LGPL
13745  * <script type="text/javascript">
13746  */
13747
13748
13749  
13750
13751 /**
13752  * @class Roo.MasterTemplate
13753  * @extends Roo.Template
13754  * Provides a template that can have child templates. The syntax is:
13755 <pre><code>
13756 var t = new Roo.MasterTemplate(
13757         '&lt;select name="{name}"&gt;',
13758                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13759         '&lt;/select&gt;'
13760 );
13761 t.add('options', {value: 'foo', text: 'bar'});
13762 // or you can add multiple child elements in one shot
13763 t.addAll('options', [
13764     {value: 'foo', text: 'bar'},
13765     {value: 'foo2', text: 'bar2'},
13766     {value: 'foo3', text: 'bar3'}
13767 ]);
13768 // then append, applying the master template values
13769 t.append('my-form', {name: 'my-select'});
13770 </code></pre>
13771 * A name attribute for the child template is not required if you have only one child
13772 * template or you want to refer to them by index.
13773  */
13774 Roo.MasterTemplate = function(){
13775     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13776     this.originalHtml = this.html;
13777     var st = {};
13778     var m, re = this.subTemplateRe;
13779     re.lastIndex = 0;
13780     var subIndex = 0;
13781     while(m = re.exec(this.html)){
13782         var name = m[1], content = m[2];
13783         st[subIndex] = {
13784             name: name,
13785             index: subIndex,
13786             buffer: [],
13787             tpl : new Roo.Template(content)
13788         };
13789         if(name){
13790             st[name] = st[subIndex];
13791         }
13792         st[subIndex].tpl.compile();
13793         st[subIndex].tpl.call = this.call.createDelegate(this);
13794         subIndex++;
13795     }
13796     this.subCount = subIndex;
13797     this.subs = st;
13798 };
13799 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13800     /**
13801     * The regular expression used to match sub templates
13802     * @type RegExp
13803     * @property
13804     */
13805     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13806
13807     /**
13808      * Applies the passed values to a child template.
13809      * @param {String/Number} name (optional) The name or index of the child template
13810      * @param {Array/Object} values The values to be applied to the template
13811      * @return {MasterTemplate} this
13812      */
13813      add : function(name, values){
13814         if(arguments.length == 1){
13815             values = arguments[0];
13816             name = 0;
13817         }
13818         var s = this.subs[name];
13819         s.buffer[s.buffer.length] = s.tpl.apply(values);
13820         return this;
13821     },
13822
13823     /**
13824      * Applies all the passed values to a child template.
13825      * @param {String/Number} name (optional) The name or index of the child template
13826      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13827      * @param {Boolean} reset (optional) True to reset the template first
13828      * @return {MasterTemplate} this
13829      */
13830     fill : function(name, values, reset){
13831         var a = arguments;
13832         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13833             values = a[0];
13834             name = 0;
13835             reset = a[1];
13836         }
13837         if(reset){
13838             this.reset();
13839         }
13840         for(var i = 0, len = values.length; i < len; i++){
13841             this.add(name, values[i]);
13842         }
13843         return this;
13844     },
13845
13846     /**
13847      * Resets the template for reuse
13848      * @return {MasterTemplate} this
13849      */
13850      reset : function(){
13851         var s = this.subs;
13852         for(var i = 0; i < this.subCount; i++){
13853             s[i].buffer = [];
13854         }
13855         return this;
13856     },
13857
13858     applyTemplate : function(values){
13859         var s = this.subs;
13860         var replaceIndex = -1;
13861         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13862             return s[++replaceIndex].buffer.join("");
13863         });
13864         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13865     },
13866
13867     apply : function(){
13868         return this.applyTemplate.apply(this, arguments);
13869     },
13870
13871     compile : function(){return this;}
13872 });
13873
13874 /**
13875  * Alias for fill().
13876  * @method
13877  */
13878 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13879  /**
13880  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13881  * var tpl = Roo.MasterTemplate.from('element-id');
13882  * @param {String/HTMLElement} el
13883  * @param {Object} config
13884  * @static
13885  */
13886 Roo.MasterTemplate.from = function(el, config){
13887     el = Roo.getDom(el);
13888     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13889 };/*
13890  * Based on:
13891  * Ext JS Library 1.1.1
13892  * Copyright(c) 2006-2007, Ext JS, LLC.
13893  *
13894  * Originally Released Under LGPL - original licence link has changed is not relivant.
13895  *
13896  * Fork - LGPL
13897  * <script type="text/javascript">
13898  */
13899
13900  
13901 /**
13902  * @class Roo.util.CSS
13903  * Utility class for manipulating CSS rules
13904  * @singleton
13905  */
13906 Roo.util.CSS = function(){
13907         var rules = null;
13908         var doc = document;
13909
13910     var camelRe = /(-[a-z])/gi;
13911     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13912
13913    return {
13914    /**
13915     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13916     * tag and appended to the HEAD of the document.
13917     * @param {String|Object} cssText The text containing the css rules
13918     * @param {String} id An id to add to the stylesheet for later removal
13919     * @return {StyleSheet}
13920     */
13921     createStyleSheet : function(cssText, id){
13922         var ss;
13923         var head = doc.getElementsByTagName("head")[0];
13924         var nrules = doc.createElement("style");
13925         nrules.setAttribute("type", "text/css");
13926         if(id){
13927             nrules.setAttribute("id", id);
13928         }
13929         if (typeof(cssText) != 'string') {
13930             // support object maps..
13931             // not sure if this a good idea.. 
13932             // perhaps it should be merged with the general css handling
13933             // and handle js style props.
13934             var cssTextNew = [];
13935             for(var n in cssText) {
13936                 var citems = [];
13937                 for(var k in cssText[n]) {
13938                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13939                 }
13940                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13941                 
13942             }
13943             cssText = cssTextNew.join("\n");
13944             
13945         }
13946        
13947        
13948        if(Roo.isIE){
13949            head.appendChild(nrules);
13950            ss = nrules.styleSheet;
13951            ss.cssText = cssText;
13952        }else{
13953            try{
13954                 nrules.appendChild(doc.createTextNode(cssText));
13955            }catch(e){
13956                nrules.cssText = cssText; 
13957            }
13958            head.appendChild(nrules);
13959            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13960        }
13961        this.cacheStyleSheet(ss);
13962        return ss;
13963    },
13964
13965    /**
13966     * Removes a style or link tag by id
13967     * @param {String} id The id of the tag
13968     */
13969    removeStyleSheet : function(id){
13970        var existing = doc.getElementById(id);
13971        if(existing){
13972            existing.parentNode.removeChild(existing);
13973        }
13974    },
13975
13976    /**
13977     * Dynamically swaps an existing stylesheet reference for a new one
13978     * @param {String} id The id of an existing link tag to remove
13979     * @param {String} url The href of the new stylesheet to include
13980     */
13981    swapStyleSheet : function(id, url){
13982        this.removeStyleSheet(id);
13983        var ss = doc.createElement("link");
13984        ss.setAttribute("rel", "stylesheet");
13985        ss.setAttribute("type", "text/css");
13986        ss.setAttribute("id", id);
13987        ss.setAttribute("href", url);
13988        doc.getElementsByTagName("head")[0].appendChild(ss);
13989    },
13990    
13991    /**
13992     * Refresh the rule cache if you have dynamically added stylesheets
13993     * @return {Object} An object (hash) of rules indexed by selector
13994     */
13995    refreshCache : function(){
13996        return this.getRules(true);
13997    },
13998
13999    // private
14000    cacheStyleSheet : function(stylesheet){
14001        if(!rules){
14002            rules = {};
14003        }
14004        try{// try catch for cross domain access issue
14005            var ssRules = stylesheet.cssRules || stylesheet.rules;
14006            for(var j = ssRules.length-1; j >= 0; --j){
14007                rules[ssRules[j].selectorText] = ssRules[j];
14008            }
14009        }catch(e){}
14010    },
14011    
14012    /**
14013     * Gets all css rules for the document
14014     * @param {Boolean} refreshCache true to refresh the internal cache
14015     * @return {Object} An object (hash) of rules indexed by selector
14016     */
14017    getRules : function(refreshCache){
14018                 if(rules == null || refreshCache){
14019                         rules = {};
14020                         var ds = doc.styleSheets;
14021                         for(var i =0, len = ds.length; i < len; i++){
14022                             try{
14023                         this.cacheStyleSheet(ds[i]);
14024                     }catch(e){} 
14025                 }
14026                 }
14027                 return rules;
14028         },
14029         
14030         /**
14031     * Gets an an individual CSS rule by selector(s)
14032     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14033     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14034     * @return {CSSRule} The CSS rule or null if one is not found
14035     */
14036    getRule : function(selector, refreshCache){
14037                 var rs = this.getRules(refreshCache);
14038                 if(!(selector instanceof Array)){
14039                     return rs[selector];
14040                 }
14041                 for(var i = 0; i < selector.length; i++){
14042                         if(rs[selector[i]]){
14043                                 return rs[selector[i]];
14044                         }
14045                 }
14046                 return null;
14047         },
14048         
14049         
14050         /**
14051     * Updates a rule property
14052     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14053     * @param {String} property The css property
14054     * @param {String} value The new value for the property
14055     * @return {Boolean} true If a rule was found and updated
14056     */
14057    updateRule : function(selector, property, value){
14058                 if(!(selector instanceof Array)){
14059                         var rule = this.getRule(selector);
14060                         if(rule){
14061                                 rule.style[property.replace(camelRe, camelFn)] = value;
14062                                 return true;
14063                         }
14064                 }else{
14065                         for(var i = 0; i < selector.length; i++){
14066                                 if(this.updateRule(selector[i], property, value)){
14067                                         return true;
14068                                 }
14069                         }
14070                 }
14071                 return false;
14072         }
14073    };   
14074 }();/*
14075  * Based on:
14076  * Ext JS Library 1.1.1
14077  * Copyright(c) 2006-2007, Ext JS, LLC.
14078  *
14079  * Originally Released Under LGPL - original licence link has changed is not relivant.
14080  *
14081  * Fork - LGPL
14082  * <script type="text/javascript">
14083  */
14084
14085  
14086
14087 /**
14088  * @class Roo.util.ClickRepeater
14089  * @extends Roo.util.Observable
14090  * 
14091  * A wrapper class which can be applied to any element. Fires a "click" event while the
14092  * mouse is pressed. The interval between firings may be specified in the config but
14093  * defaults to 10 milliseconds.
14094  * 
14095  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14096  * 
14097  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14098  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14099  * Similar to an autorepeat key delay.
14100  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14101  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14102  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14103  *           "interval" and "delay" are ignored. "immediate" is honored.
14104  * @cfg {Boolean} preventDefault True to prevent the default click event
14105  * @cfg {Boolean} stopDefault True to stop the default click event
14106  * 
14107  * @history
14108  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14109  *     2007-02-02 jvs Renamed to ClickRepeater
14110  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14111  *
14112  *  @constructor
14113  * @param {String/HTMLElement/Element} el The element to listen on
14114  * @param {Object} config
14115  **/
14116 Roo.util.ClickRepeater = function(el, config)
14117 {
14118     this.el = Roo.get(el);
14119     this.el.unselectable();
14120
14121     Roo.apply(this, config);
14122
14123     this.addEvents({
14124     /**
14125      * @event mousedown
14126      * Fires when the mouse button is depressed.
14127      * @param {Roo.util.ClickRepeater} this
14128      */
14129         "mousedown" : true,
14130     /**
14131      * @event click
14132      * Fires on a specified interval during the time the element is pressed.
14133      * @param {Roo.util.ClickRepeater} this
14134      */
14135         "click" : true,
14136     /**
14137      * @event mouseup
14138      * Fires when the mouse key is released.
14139      * @param {Roo.util.ClickRepeater} this
14140      */
14141         "mouseup" : true
14142     });
14143
14144     this.el.on("mousedown", this.handleMouseDown, this);
14145     if(this.preventDefault || this.stopDefault){
14146         this.el.on("click", function(e){
14147             if(this.preventDefault){
14148                 e.preventDefault();
14149             }
14150             if(this.stopDefault){
14151                 e.stopEvent();
14152             }
14153         }, this);
14154     }
14155
14156     // allow inline handler
14157     if(this.handler){
14158         this.on("click", this.handler,  this.scope || this);
14159     }
14160
14161     Roo.util.ClickRepeater.superclass.constructor.call(this);
14162 };
14163
14164 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14165     interval : 20,
14166     delay: 250,
14167     preventDefault : true,
14168     stopDefault : false,
14169     timer : 0,
14170
14171     // private
14172     handleMouseDown : function(){
14173         clearTimeout(this.timer);
14174         this.el.blur();
14175         if(this.pressClass){
14176             this.el.addClass(this.pressClass);
14177         }
14178         this.mousedownTime = new Date();
14179
14180         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14181         this.el.on("mouseout", this.handleMouseOut, this);
14182
14183         this.fireEvent("mousedown", this);
14184         this.fireEvent("click", this);
14185         
14186         this.timer = this.click.defer(this.delay || this.interval, this);
14187     },
14188
14189     // private
14190     click : function(){
14191         this.fireEvent("click", this);
14192         this.timer = this.click.defer(this.getInterval(), this);
14193     },
14194
14195     // private
14196     getInterval: function(){
14197         if(!this.accelerate){
14198             return this.interval;
14199         }
14200         var pressTime = this.mousedownTime.getElapsed();
14201         if(pressTime < 500){
14202             return 400;
14203         }else if(pressTime < 1700){
14204             return 320;
14205         }else if(pressTime < 2600){
14206             return 250;
14207         }else if(pressTime < 3500){
14208             return 180;
14209         }else if(pressTime < 4400){
14210             return 140;
14211         }else if(pressTime < 5300){
14212             return 80;
14213         }else if(pressTime < 6200){
14214             return 50;
14215         }else{
14216             return 10;
14217         }
14218     },
14219
14220     // private
14221     handleMouseOut : function(){
14222         clearTimeout(this.timer);
14223         if(this.pressClass){
14224             this.el.removeClass(this.pressClass);
14225         }
14226         this.el.on("mouseover", this.handleMouseReturn, this);
14227     },
14228
14229     // private
14230     handleMouseReturn : function(){
14231         this.el.un("mouseover", this.handleMouseReturn);
14232         if(this.pressClass){
14233             this.el.addClass(this.pressClass);
14234         }
14235         this.click();
14236     },
14237
14238     // private
14239     handleMouseUp : function(){
14240         clearTimeout(this.timer);
14241         this.el.un("mouseover", this.handleMouseReturn);
14242         this.el.un("mouseout", this.handleMouseOut);
14243         Roo.get(document).un("mouseup", this.handleMouseUp);
14244         this.el.removeClass(this.pressClass);
14245         this.fireEvent("mouseup", this);
14246     }
14247 });/*
14248  * Based on:
14249  * Ext JS Library 1.1.1
14250  * Copyright(c) 2006-2007, Ext JS, LLC.
14251  *
14252  * Originally Released Under LGPL - original licence link has changed is not relivant.
14253  *
14254  * Fork - LGPL
14255  * <script type="text/javascript">
14256  */
14257
14258  
14259 /**
14260  * @class Roo.KeyNav
14261  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14262  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14263  * way to implement custom navigation schemes for any UI component.</p>
14264  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14265  * pageUp, pageDown, del, home, end.  Usage:</p>
14266  <pre><code>
14267 var nav = new Roo.KeyNav("my-element", {
14268     "left" : function(e){
14269         this.moveLeft(e.ctrlKey);
14270     },
14271     "right" : function(e){
14272         this.moveRight(e.ctrlKey);
14273     },
14274     "enter" : function(e){
14275         this.save();
14276     },
14277     scope : this
14278 });
14279 </code></pre>
14280  * @constructor
14281  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14282  * @param {Object} config The config
14283  */
14284 Roo.KeyNav = function(el, config){
14285     this.el = Roo.get(el);
14286     Roo.apply(this, config);
14287     if(!this.disabled){
14288         this.disabled = true;
14289         this.enable();
14290     }
14291 };
14292
14293 Roo.KeyNav.prototype = {
14294     /**
14295      * @cfg {Boolean} disabled
14296      * True to disable this KeyNav instance (defaults to false)
14297      */
14298     disabled : false,
14299     /**
14300      * @cfg {String} defaultEventAction
14301      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14302      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14303      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14304      */
14305     defaultEventAction: "stopEvent",
14306     /**
14307      * @cfg {Boolean} forceKeyDown
14308      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14309      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14310      * handle keydown instead of keypress.
14311      */
14312     forceKeyDown : false,
14313
14314     // private
14315     prepareEvent : function(e){
14316         var k = e.getKey();
14317         var h = this.keyToHandler[k];
14318         //if(h && this[h]){
14319         //    e.stopPropagation();
14320         //}
14321         if(Roo.isSafari && h && k >= 37 && k <= 40){
14322             e.stopEvent();
14323         }
14324     },
14325
14326     // private
14327     relay : function(e){
14328         var k = e.getKey();
14329         var h = this.keyToHandler[k];
14330         if(h && this[h]){
14331             if(this.doRelay(e, this[h], h) !== true){
14332                 e[this.defaultEventAction]();
14333             }
14334         }
14335     },
14336
14337     // private
14338     doRelay : function(e, h, hname){
14339         return h.call(this.scope || this, e);
14340     },
14341
14342     // possible handlers
14343     enter : false,
14344     left : false,
14345     right : false,
14346     up : false,
14347     down : false,
14348     tab : false,
14349     esc : false,
14350     pageUp : false,
14351     pageDown : false,
14352     del : false,
14353     home : false,
14354     end : false,
14355
14356     // quick lookup hash
14357     keyToHandler : {
14358         37 : "left",
14359         39 : "right",
14360         38 : "up",
14361         40 : "down",
14362         33 : "pageUp",
14363         34 : "pageDown",
14364         46 : "del",
14365         36 : "home",
14366         35 : "end",
14367         13 : "enter",
14368         27 : "esc",
14369         9  : "tab"
14370     },
14371
14372         /**
14373          * Enable this KeyNav
14374          */
14375         enable: function(){
14376                 if(this.disabled){
14377             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14378             // the EventObject will normalize Safari automatically
14379             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14380                 this.el.on("keydown", this.relay,  this);
14381             }else{
14382                 this.el.on("keydown", this.prepareEvent,  this);
14383                 this.el.on("keypress", this.relay,  this);
14384             }
14385                     this.disabled = false;
14386                 }
14387         },
14388
14389         /**
14390          * Disable this KeyNav
14391          */
14392         disable: function(){
14393                 if(!this.disabled){
14394                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14395                 this.el.un("keydown", this.relay);
14396             }else{
14397                 this.el.un("keydown", this.prepareEvent);
14398                 this.el.un("keypress", this.relay);
14399             }
14400                     this.disabled = true;
14401                 }
14402         }
14403 };/*
14404  * Based on:
14405  * Ext JS Library 1.1.1
14406  * Copyright(c) 2006-2007, Ext JS, LLC.
14407  *
14408  * Originally Released Under LGPL - original licence link has changed is not relivant.
14409  *
14410  * Fork - LGPL
14411  * <script type="text/javascript">
14412  */
14413
14414  
14415 /**
14416  * @class Roo.KeyMap
14417  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14418  * The constructor accepts the same config object as defined by {@link #addBinding}.
14419  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14420  * combination it will call the function with this signature (if the match is a multi-key
14421  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14422  * A KeyMap can also handle a string representation of keys.<br />
14423  * Usage:
14424  <pre><code>
14425 // map one key by key code
14426 var map = new Roo.KeyMap("my-element", {
14427     key: 13, // or Roo.EventObject.ENTER
14428     fn: myHandler,
14429     scope: myObject
14430 });
14431
14432 // map multiple keys to one action by string
14433 var map = new Roo.KeyMap("my-element", {
14434     key: "a\r\n\t",
14435     fn: myHandler,
14436     scope: myObject
14437 });
14438
14439 // map multiple keys to multiple actions by strings and array of codes
14440 var map = new Roo.KeyMap("my-element", [
14441     {
14442         key: [10,13],
14443         fn: function(){ alert("Return was pressed"); }
14444     }, {
14445         key: "abc",
14446         fn: function(){ alert('a, b or c was pressed'); }
14447     }, {
14448         key: "\t",
14449         ctrl:true,
14450         shift:true,
14451         fn: function(){ alert('Control + shift + tab was pressed.'); }
14452     }
14453 ]);
14454 </code></pre>
14455  * <b>Note: A KeyMap starts enabled</b>
14456  * @constructor
14457  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14458  * @param {Object} config The config (see {@link #addBinding})
14459  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14460  */
14461 Roo.KeyMap = function(el, config, eventName){
14462     this.el  = Roo.get(el);
14463     this.eventName = eventName || "keydown";
14464     this.bindings = [];
14465     if(config){
14466         this.addBinding(config);
14467     }
14468     this.enable();
14469 };
14470
14471 Roo.KeyMap.prototype = {
14472     /**
14473      * True to stop the event from bubbling and prevent the default browser action if the
14474      * key was handled by the KeyMap (defaults to false)
14475      * @type Boolean
14476      */
14477     stopEvent : false,
14478
14479     /**
14480      * Add a new binding to this KeyMap. The following config object properties are supported:
14481      * <pre>
14482 Property    Type             Description
14483 ----------  ---------------  ----------------------------------------------------------------------
14484 key         String/Array     A single keycode or an array of keycodes to handle
14485 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14486 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14487 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14488 fn          Function         The function to call when KeyMap finds the expected key combination
14489 scope       Object           The scope of the callback function
14490 </pre>
14491      *
14492      * Usage:
14493      * <pre><code>
14494 // Create a KeyMap
14495 var map = new Roo.KeyMap(document, {
14496     key: Roo.EventObject.ENTER,
14497     fn: handleKey,
14498     scope: this
14499 });
14500
14501 //Add a new binding to the existing KeyMap later
14502 map.addBinding({
14503     key: 'abc',
14504     shift: true,
14505     fn: handleKey,
14506     scope: this
14507 });
14508 </code></pre>
14509      * @param {Object/Array} config A single KeyMap config or an array of configs
14510      */
14511         addBinding : function(config){
14512         if(config instanceof Array){
14513             for(var i = 0, len = config.length; i < len; i++){
14514                 this.addBinding(config[i]);
14515             }
14516             return;
14517         }
14518         var keyCode = config.key,
14519             shift = config.shift, 
14520             ctrl = config.ctrl, 
14521             alt = config.alt,
14522             fn = config.fn,
14523             scope = config.scope;
14524         if(typeof keyCode == "string"){
14525             var ks = [];
14526             var keyString = keyCode.toUpperCase();
14527             for(var j = 0, len = keyString.length; j < len; j++){
14528                 ks.push(keyString.charCodeAt(j));
14529             }
14530             keyCode = ks;
14531         }
14532         var keyArray = keyCode instanceof Array;
14533         var handler = function(e){
14534             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14535                 var k = e.getKey();
14536                 if(keyArray){
14537                     for(var i = 0, len = keyCode.length; i < len; i++){
14538                         if(keyCode[i] == k){
14539                           if(this.stopEvent){
14540                               e.stopEvent();
14541                           }
14542                           fn.call(scope || window, k, e);
14543                           return;
14544                         }
14545                     }
14546                 }else{
14547                     if(k == keyCode){
14548                         if(this.stopEvent){
14549                            e.stopEvent();
14550                         }
14551                         fn.call(scope || window, k, e);
14552                     }
14553                 }
14554             }
14555         };
14556         this.bindings.push(handler);  
14557         },
14558
14559     /**
14560      * Shorthand for adding a single key listener
14561      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14562      * following options:
14563      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14564      * @param {Function} fn The function to call
14565      * @param {Object} scope (optional) The scope of the function
14566      */
14567     on : function(key, fn, scope){
14568         var keyCode, shift, ctrl, alt;
14569         if(typeof key == "object" && !(key instanceof Array)){
14570             keyCode = key.key;
14571             shift = key.shift;
14572             ctrl = key.ctrl;
14573             alt = key.alt;
14574         }else{
14575             keyCode = key;
14576         }
14577         this.addBinding({
14578             key: keyCode,
14579             shift: shift,
14580             ctrl: ctrl,
14581             alt: alt,
14582             fn: fn,
14583             scope: scope
14584         })
14585     },
14586
14587     // private
14588     handleKeyDown : function(e){
14589             if(this.enabled){ //just in case
14590             var b = this.bindings;
14591             for(var i = 0, len = b.length; i < len; i++){
14592                 b[i].call(this, e);
14593             }
14594             }
14595         },
14596         
14597         /**
14598          * Returns true if this KeyMap is enabled
14599          * @return {Boolean} 
14600          */
14601         isEnabled : function(){
14602             return this.enabled;  
14603         },
14604         
14605         /**
14606          * Enables this KeyMap
14607          */
14608         enable: function(){
14609                 if(!this.enabled){
14610                     this.el.on(this.eventName, this.handleKeyDown, this);
14611                     this.enabled = true;
14612                 }
14613         },
14614
14615         /**
14616          * Disable this KeyMap
14617          */
14618         disable: function(){
14619                 if(this.enabled){
14620                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14621                     this.enabled = false;
14622                 }
14623         }
14624 };/*
14625  * Based on:
14626  * Ext JS Library 1.1.1
14627  * Copyright(c) 2006-2007, Ext JS, LLC.
14628  *
14629  * Originally Released Under LGPL - original licence link has changed is not relivant.
14630  *
14631  * Fork - LGPL
14632  * <script type="text/javascript">
14633  */
14634
14635  
14636 /**
14637  * @class Roo.util.TextMetrics
14638  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14639  * wide, in pixels, a given block of text will be.
14640  * @singleton
14641  */
14642 Roo.util.TextMetrics = function(){
14643     var shared;
14644     return {
14645         /**
14646          * Measures the size of the specified text
14647          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14648          * that can affect the size of the rendered text
14649          * @param {String} text The text to measure
14650          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14651          * in order to accurately measure the text height
14652          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14653          */
14654         measure : function(el, text, fixedWidth){
14655             if(!shared){
14656                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14657             }
14658             shared.bind(el);
14659             shared.setFixedWidth(fixedWidth || 'auto');
14660             return shared.getSize(text);
14661         },
14662
14663         /**
14664          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14665          * the overhead of multiple calls to initialize the style properties on each measurement.
14666          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14667          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14668          * in order to accurately measure the text height
14669          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14670          */
14671         createInstance : function(el, fixedWidth){
14672             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14673         }
14674     };
14675 }();
14676
14677  
14678
14679 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14680     var ml = new Roo.Element(document.createElement('div'));
14681     document.body.appendChild(ml.dom);
14682     ml.position('absolute');
14683     ml.setLeftTop(-1000, -1000);
14684     ml.hide();
14685
14686     if(fixedWidth){
14687         ml.setWidth(fixedWidth);
14688     }
14689      
14690     var instance = {
14691         /**
14692          * Returns the size of the specified text based on the internal element's style and width properties
14693          * @memberOf Roo.util.TextMetrics.Instance#
14694          * @param {String} text The text to measure
14695          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14696          */
14697         getSize : function(text){
14698             ml.update(text);
14699             var s = ml.getSize();
14700             ml.update('');
14701             return s;
14702         },
14703
14704         /**
14705          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14706          * that can affect the size of the rendered text
14707          * @memberOf Roo.util.TextMetrics.Instance#
14708          * @param {String/HTMLElement} el The element, dom node or id
14709          */
14710         bind : function(el){
14711             ml.setStyle(
14712                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14713             );
14714         },
14715
14716         /**
14717          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14718          * to set a fixed width in order to accurately measure the text height.
14719          * @memberOf Roo.util.TextMetrics.Instance#
14720          * @param {Number} width The width to set on the element
14721          */
14722         setFixedWidth : function(width){
14723             ml.setWidth(width);
14724         },
14725
14726         /**
14727          * Returns the measured width of the specified text
14728          * @memberOf Roo.util.TextMetrics.Instance#
14729          * @param {String} text The text to measure
14730          * @return {Number} width The width in pixels
14731          */
14732         getWidth : function(text){
14733             ml.dom.style.width = 'auto';
14734             return this.getSize(text).width;
14735         },
14736
14737         /**
14738          * Returns the measured height of the specified text.  For multiline text, be sure to call
14739          * {@link #setFixedWidth} if necessary.
14740          * @memberOf Roo.util.TextMetrics.Instance#
14741          * @param {String} text The text to measure
14742          * @return {Number} height The height in pixels
14743          */
14744         getHeight : function(text){
14745             return this.getSize(text).height;
14746         }
14747     };
14748
14749     instance.bind(bindTo);
14750
14751     return instance;
14752 };
14753
14754 // backwards compat
14755 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14756  * Based on:
14757  * Ext JS Library 1.1.1
14758  * Copyright(c) 2006-2007, Ext JS, LLC.
14759  *
14760  * Originally Released Under LGPL - original licence link has changed is not relivant.
14761  *
14762  * Fork - LGPL
14763  * <script type="text/javascript">
14764  */
14765
14766 /**
14767  * @class Roo.state.Provider
14768  * Abstract base class for state provider implementations. This class provides methods
14769  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14770  * Provider interface.
14771  */
14772 Roo.state.Provider = function(){
14773     /**
14774      * @event statechange
14775      * Fires when a state change occurs.
14776      * @param {Provider} this This state provider
14777      * @param {String} key The state key which was changed
14778      * @param {String} value The encoded value for the state
14779      */
14780     this.addEvents({
14781         "statechange": true
14782     });
14783     this.state = {};
14784     Roo.state.Provider.superclass.constructor.call(this);
14785 };
14786 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14787     /**
14788      * Returns the current value for a key
14789      * @param {String} name The key name
14790      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14791      * @return {Mixed} The state data
14792      */
14793     get : function(name, defaultValue){
14794         return typeof this.state[name] == "undefined" ?
14795             defaultValue : this.state[name];
14796     },
14797     
14798     /**
14799      * Clears a value from the state
14800      * @param {String} name The key name
14801      */
14802     clear : function(name){
14803         delete this.state[name];
14804         this.fireEvent("statechange", this, name, null);
14805     },
14806     
14807     /**
14808      * Sets the value for a key
14809      * @param {String} name The key name
14810      * @param {Mixed} value The value to set
14811      */
14812     set : function(name, value){
14813         this.state[name] = value;
14814         this.fireEvent("statechange", this, name, value);
14815     },
14816     
14817     /**
14818      * Decodes a string previously encoded with {@link #encodeValue}.
14819      * @param {String} value The value to decode
14820      * @return {Mixed} The decoded value
14821      */
14822     decodeValue : function(cookie){
14823         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14824         var matches = re.exec(unescape(cookie));
14825         if(!matches || !matches[1]) {
14826             return; // non state cookie
14827         }
14828         var type = matches[1];
14829         var v = matches[2];
14830         switch(type){
14831             case "n":
14832                 return parseFloat(v);
14833             case "d":
14834                 return new Date(Date.parse(v));
14835             case "b":
14836                 return (v == "1");
14837             case "a":
14838                 var all = [];
14839                 var values = v.split("^");
14840                 for(var i = 0, len = values.length; i < len; i++){
14841                     all.push(this.decodeValue(values[i]));
14842                 }
14843                 return all;
14844            case "o":
14845                 var all = {};
14846                 var values = v.split("^");
14847                 for(var i = 0, len = values.length; i < len; i++){
14848                     var kv = values[i].split("=");
14849                     all[kv[0]] = this.decodeValue(kv[1]);
14850                 }
14851                 return all;
14852            default:
14853                 return v;
14854         }
14855     },
14856     
14857     /**
14858      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14859      * @param {Mixed} value The value to encode
14860      * @return {String} The encoded value
14861      */
14862     encodeValue : function(v){
14863         var enc;
14864         if(typeof v == "number"){
14865             enc = "n:" + v;
14866         }else if(typeof v == "boolean"){
14867             enc = "b:" + (v ? "1" : "0");
14868         }else if(v instanceof Date){
14869             enc = "d:" + v.toGMTString();
14870         }else if(v instanceof Array){
14871             var flat = "";
14872             for(var i = 0, len = v.length; i < len; i++){
14873                 flat += this.encodeValue(v[i]);
14874                 if(i != len-1) {
14875                     flat += "^";
14876                 }
14877             }
14878             enc = "a:" + flat;
14879         }else if(typeof v == "object"){
14880             var flat = "";
14881             for(var key in v){
14882                 if(typeof v[key] != "function"){
14883                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14884                 }
14885             }
14886             enc = "o:" + flat.substring(0, flat.length-1);
14887         }else{
14888             enc = "s:" + v;
14889         }
14890         return escape(enc);        
14891     }
14892 });
14893
14894 /*
14895  * Based on:
14896  * Ext JS Library 1.1.1
14897  * Copyright(c) 2006-2007, Ext JS, LLC.
14898  *
14899  * Originally Released Under LGPL - original licence link has changed is not relivant.
14900  *
14901  * Fork - LGPL
14902  * <script type="text/javascript">
14903  */
14904 /**
14905  * @class Roo.state.Manager
14906  * This is the global state manager. By default all components that are "state aware" check this class
14907  * for state information if you don't pass them a custom state provider. In order for this class
14908  * to be useful, it must be initialized with a provider when your application initializes.
14909  <pre><code>
14910 // in your initialization function
14911 init : function(){
14912    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14913    ...
14914    // supposed you have a {@link Roo.BorderLayout}
14915    var layout = new Roo.BorderLayout(...);
14916    layout.restoreState();
14917    // or a {Roo.BasicDialog}
14918    var dialog = new Roo.BasicDialog(...);
14919    dialog.restoreState();
14920  </code></pre>
14921  * @singleton
14922  */
14923 Roo.state.Manager = function(){
14924     var provider = new Roo.state.Provider();
14925     
14926     return {
14927         /**
14928          * Configures the default state provider for your application
14929          * @param {Provider} stateProvider The state provider to set
14930          */
14931         setProvider : function(stateProvider){
14932             provider = stateProvider;
14933         },
14934         
14935         /**
14936          * Returns the current value for a key
14937          * @param {String} name The key name
14938          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14939          * @return {Mixed} The state data
14940          */
14941         get : function(key, defaultValue){
14942             return provider.get(key, defaultValue);
14943         },
14944         
14945         /**
14946          * Sets the value for a key
14947          * @param {String} name The key name
14948          * @param {Mixed} value The state data
14949          */
14950          set : function(key, value){
14951             provider.set(key, value);
14952         },
14953         
14954         /**
14955          * Clears a value from the state
14956          * @param {String} name The key name
14957          */
14958         clear : function(key){
14959             provider.clear(key);
14960         },
14961         
14962         /**
14963          * Gets the currently configured state provider
14964          * @return {Provider} The state provider
14965          */
14966         getProvider : function(){
14967             return provider;
14968         }
14969     };
14970 }();
14971 /*
14972  * Based on:
14973  * Ext JS Library 1.1.1
14974  * Copyright(c) 2006-2007, Ext JS, LLC.
14975  *
14976  * Originally Released Under LGPL - original licence link has changed is not relivant.
14977  *
14978  * Fork - LGPL
14979  * <script type="text/javascript">
14980  */
14981 /**
14982  * @class Roo.state.CookieProvider
14983  * @extends Roo.state.Provider
14984  * The default Provider implementation which saves state via cookies.
14985  * <br />Usage:
14986  <pre><code>
14987    var cp = new Roo.state.CookieProvider({
14988        path: "/cgi-bin/",
14989        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14990        domain: "roojs.com"
14991    })
14992    Roo.state.Manager.setProvider(cp);
14993  </code></pre>
14994  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14995  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14996  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14997  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14998  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14999  * domain the page is running on including the 'www' like 'www.roojs.com')
15000  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15001  * @constructor
15002  * Create a new CookieProvider
15003  * @param {Object} config The configuration object
15004  */
15005 Roo.state.CookieProvider = function(config){
15006     Roo.state.CookieProvider.superclass.constructor.call(this);
15007     this.path = "/";
15008     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15009     this.domain = null;
15010     this.secure = false;
15011     Roo.apply(this, config);
15012     this.state = this.readCookies();
15013 };
15014
15015 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15016     // private
15017     set : function(name, value){
15018         if(typeof value == "undefined" || value === null){
15019             this.clear(name);
15020             return;
15021         }
15022         this.setCookie(name, value);
15023         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15024     },
15025
15026     // private
15027     clear : function(name){
15028         this.clearCookie(name);
15029         Roo.state.CookieProvider.superclass.clear.call(this, name);
15030     },
15031
15032     // private
15033     readCookies : function(){
15034         var cookies = {};
15035         var c = document.cookie + ";";
15036         var re = /\s?(.*?)=(.*?);/g;
15037         var matches;
15038         while((matches = re.exec(c)) != null){
15039             var name = matches[1];
15040             var value = matches[2];
15041             if(name && name.substring(0,3) == "ys-"){
15042                 cookies[name.substr(3)] = this.decodeValue(value);
15043             }
15044         }
15045         return cookies;
15046     },
15047
15048     // private
15049     setCookie : function(name, value){
15050         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15051            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15052            ((this.path == null) ? "" : ("; path=" + this.path)) +
15053            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15054            ((this.secure == true) ? "; secure" : "");
15055     },
15056
15057     // private
15058     clearCookie : function(name){
15059         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15060            ((this.path == null) ? "" : ("; path=" + this.path)) +
15061            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15062            ((this.secure == true) ? "; secure" : "");
15063     }
15064 });/*
15065  * Based on:
15066  * Ext JS Library 1.1.1
15067  * Copyright(c) 2006-2007, Ext JS, LLC.
15068  *
15069  * Originally Released Under LGPL - original licence link has changed is not relivant.
15070  *
15071  * Fork - LGPL
15072  * <script type="text/javascript">
15073  */
15074  
15075
15076 /**
15077  * @class Roo.ComponentMgr
15078  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15079  * @singleton
15080  */
15081 Roo.ComponentMgr = function(){
15082     var all = new Roo.util.MixedCollection();
15083
15084     return {
15085         /**
15086          * Registers a component.
15087          * @param {Roo.Component} c The component
15088          */
15089         register : function(c){
15090             all.add(c);
15091         },
15092
15093         /**
15094          * Unregisters a component.
15095          * @param {Roo.Component} c The component
15096          */
15097         unregister : function(c){
15098             all.remove(c);
15099         },
15100
15101         /**
15102          * Returns a component by id
15103          * @param {String} id The component id
15104          */
15105         get : function(id){
15106             return all.get(id);
15107         },
15108
15109         /**
15110          * Registers a function that will be called when a specified component is added to ComponentMgr
15111          * @param {String} id The component id
15112          * @param {Funtction} fn The callback function
15113          * @param {Object} scope The scope of the callback
15114          */
15115         onAvailable : function(id, fn, scope){
15116             all.on("add", function(index, o){
15117                 if(o.id == id){
15118                     fn.call(scope || o, o);
15119                     all.un("add", fn, scope);
15120                 }
15121             });
15122         }
15123     };
15124 }();/*
15125  * Based on:
15126  * Ext JS Library 1.1.1
15127  * Copyright(c) 2006-2007, Ext JS, LLC.
15128  *
15129  * Originally Released Under LGPL - original licence link has changed is not relivant.
15130  *
15131  * Fork - LGPL
15132  * <script type="text/javascript">
15133  */
15134  
15135 /**
15136  * @class Roo.Component
15137  * @extends Roo.util.Observable
15138  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15139  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15140  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15141  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15142  * All visual components (widgets) that require rendering into a layout should subclass Component.
15143  * @constructor
15144  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15145  * element and its id used as the component id.  If a string is passed, it is assumed to be the id of an existing element
15146  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15147  */
15148 Roo.Component = function(config){
15149     config = config || {};
15150     if(config.tagName || config.dom || typeof config == "string"){ // element object
15151         config = {el: config, id: config.id || config};
15152     }
15153     this.initialConfig = config;
15154
15155     Roo.apply(this, config);
15156     this.addEvents({
15157         /**
15158          * @event disable
15159          * Fires after the component is disabled.
15160              * @param {Roo.Component} this
15161              */
15162         disable : true,
15163         /**
15164          * @event enable
15165          * Fires after the component is enabled.
15166              * @param {Roo.Component} this
15167              */
15168         enable : true,
15169         /**
15170          * @event beforeshow
15171          * Fires before the component is shown.  Return false to stop the show.
15172              * @param {Roo.Component} this
15173              */
15174         beforeshow : true,
15175         /**
15176          * @event show
15177          * Fires after the component is shown.
15178              * @param {Roo.Component} this
15179              */
15180         show : true,
15181         /**
15182          * @event beforehide
15183          * Fires before the component is hidden. Return false to stop the hide.
15184              * @param {Roo.Component} this
15185              */
15186         beforehide : true,
15187         /**
15188          * @event hide
15189          * Fires after the component is hidden.
15190              * @param {Roo.Component} this
15191              */
15192         hide : true,
15193         /**
15194          * @event beforerender
15195          * Fires before the component is rendered. Return false to stop the render.
15196              * @param {Roo.Component} this
15197              */
15198         beforerender : true,
15199         /**
15200          * @event render
15201          * Fires after the component is rendered.
15202              * @param {Roo.Component} this
15203              */
15204         render : true,
15205         /**
15206          * @event beforedestroy
15207          * Fires before the component is destroyed. Return false to stop the destroy.
15208              * @param {Roo.Component} this
15209              */
15210         beforedestroy : true,
15211         /**
15212          * @event destroy
15213          * Fires after the component is destroyed.
15214              * @param {Roo.Component} this
15215              */
15216         destroy : true
15217     });
15218     if(!this.id){
15219         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15220     }
15221     Roo.ComponentMgr.register(this);
15222     Roo.Component.superclass.constructor.call(this);
15223     this.initComponent();
15224     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15225         this.render(this.renderTo);
15226         delete this.renderTo;
15227     }
15228 };
15229
15230 /** @private */
15231 Roo.Component.AUTO_ID = 1000;
15232
15233 Roo.extend(Roo.Component, Roo.util.Observable, {
15234     /**
15235      * @scope Roo.Component.prototype
15236      * @type {Boolean}
15237      * true if this component is hidden. Read-only.
15238      */
15239     hidden : false,
15240     /**
15241      * @type {Boolean}
15242      * true if this component is disabled. Read-only.
15243      */
15244     disabled : false,
15245     /**
15246      * @type {Boolean}
15247      * true if this component has been rendered. Read-only.
15248      */
15249     rendered : false,
15250     
15251     /** @cfg {String} disableClass
15252      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15253      */
15254     disabledClass : "x-item-disabled",
15255         /** @cfg {Boolean} allowDomMove
15256          * Whether the component can move the Dom node when rendering (defaults to true).
15257          */
15258     allowDomMove : true,
15259     /** @cfg {String} hideMode (display|visibility)
15260      * How this component should hidden. Supported values are
15261      * "visibility" (css visibility), "offsets" (negative offset position) and
15262      * "display" (css display) - defaults to "display".
15263      */
15264     hideMode: 'display',
15265
15266     /** @private */
15267     ctype : "Roo.Component",
15268
15269     /**
15270      * @cfg {String} actionMode 
15271      * which property holds the element that used for  hide() / show() / disable() / enable()
15272      * default is 'el' 
15273      */
15274     actionMode : "el",
15275
15276     /** @private */
15277     getActionEl : function(){
15278         return this[this.actionMode];
15279     },
15280
15281     initComponent : Roo.emptyFn,
15282     /**
15283      * If this is a lazy rendering component, render it to its container element.
15284      * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15285      */
15286     render : function(container, position){
15287         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15288             if(!container && this.el){
15289                 this.el = Roo.get(this.el);
15290                 container = this.el.dom.parentNode;
15291                 this.allowDomMove = false;
15292             }
15293             this.container = Roo.get(container);
15294             this.rendered = true;
15295             if(position !== undefined){
15296                 if(typeof position == 'number'){
15297                     position = this.container.dom.childNodes[position];
15298                 }else{
15299                     position = Roo.getDom(position);
15300                 }
15301             }
15302             this.onRender(this.container, position || null);
15303             if(this.cls){
15304                 this.el.addClass(this.cls);
15305                 delete this.cls;
15306             }
15307             if(this.style){
15308                 this.el.applyStyles(this.style);
15309                 delete this.style;
15310             }
15311             this.fireEvent("render", this);
15312             this.afterRender(this.container);
15313             if(this.hidden){
15314                 this.hide();
15315             }
15316             if(this.disabled){
15317                 this.disable();
15318             }
15319         }
15320         return this;
15321     },
15322
15323     /** @private */
15324     // default function is not really useful
15325     onRender : function(ct, position){
15326         if(this.el){
15327             this.el = Roo.get(this.el);
15328             if(this.allowDomMove !== false){
15329                 ct.dom.insertBefore(this.el.dom, position);
15330             }
15331         }
15332     },
15333
15334     /** @private */
15335     getAutoCreate : function(){
15336         var cfg = typeof this.autoCreate == "object" ?
15337                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15338         if(this.id && !cfg.id){
15339             cfg.id = this.id;
15340         }
15341         return cfg;
15342     },
15343
15344     /** @private */
15345     afterRender : Roo.emptyFn,
15346
15347     /**
15348      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15349      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15350      */
15351     destroy : function(){
15352         if(this.fireEvent("beforedestroy", this) !== false){
15353             this.purgeListeners();
15354             this.beforeDestroy();
15355             if(this.rendered){
15356                 this.el.removeAllListeners();
15357                 this.el.remove();
15358                 if(this.actionMode == "container"){
15359                     this.container.remove();
15360                 }
15361             }
15362             this.onDestroy();
15363             Roo.ComponentMgr.unregister(this);
15364             this.fireEvent("destroy", this);
15365         }
15366     },
15367
15368         /** @private */
15369     beforeDestroy : function(){
15370
15371     },
15372
15373         /** @private */
15374         onDestroy : function(){
15375
15376     },
15377
15378     /**
15379      * Returns the underlying {@link Roo.Element}.
15380      * @return {Roo.Element} The element
15381      */
15382     getEl : function(){
15383         return this.el;
15384     },
15385
15386     /**
15387      * Returns the id of this component.
15388      * @return {String}
15389      */
15390     getId : function(){
15391         return this.id;
15392     },
15393
15394     /**
15395      * Try to focus this component.
15396      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15397      * @return {Roo.Component} this
15398      */
15399     focus : function(selectText){
15400         if(this.rendered){
15401             this.el.focus();
15402             if(selectText === true){
15403                 this.el.dom.select();
15404             }
15405         }
15406         return this;
15407     },
15408
15409     /** @private */
15410     blur : function(){
15411         if(this.rendered){
15412             this.el.blur();
15413         }
15414         return this;
15415     },
15416
15417     /**
15418      * Disable this component.
15419      * @return {Roo.Component} this
15420      */
15421     disable : function(){
15422         if(this.rendered){
15423             this.onDisable();
15424         }
15425         this.disabled = true;
15426         this.fireEvent("disable", this);
15427         return this;
15428     },
15429
15430         // private
15431     onDisable : function(){
15432         this.getActionEl().addClass(this.disabledClass);
15433         this.el.dom.disabled = true;
15434     },
15435
15436     /**
15437      * Enable this component.
15438      * @return {Roo.Component} this
15439      */
15440     enable : function(){
15441         if(this.rendered){
15442             this.onEnable();
15443         }
15444         this.disabled = false;
15445         this.fireEvent("enable", this);
15446         return this;
15447     },
15448
15449         // private
15450     onEnable : function(){
15451         this.getActionEl().removeClass(this.disabledClass);
15452         this.el.dom.disabled = false;
15453     },
15454
15455     /**
15456      * Convenience function for setting disabled/enabled by boolean.
15457      * @param {Boolean} disabled
15458      */
15459     setDisabled : function(disabled){
15460         this[disabled ? "disable" : "enable"]();
15461     },
15462
15463     /**
15464      * Show this component.
15465      * @return {Roo.Component} this
15466      */
15467     show: function(){
15468         if(this.fireEvent("beforeshow", this) !== false){
15469             this.hidden = false;
15470             if(this.rendered){
15471                 this.onShow();
15472             }
15473             this.fireEvent("show", this);
15474         }
15475         return this;
15476     },
15477
15478     // private
15479     onShow : function(){
15480         var ae = this.getActionEl();
15481         if(this.hideMode == 'visibility'){
15482             ae.dom.style.visibility = "visible";
15483         }else if(this.hideMode == 'offsets'){
15484             ae.removeClass('x-hidden');
15485         }else{
15486             ae.dom.style.display = "";
15487         }
15488     },
15489
15490     /**
15491      * Hide this component.
15492      * @return {Roo.Component} this
15493      */
15494     hide: function(){
15495         if(this.fireEvent("beforehide", this) !== false){
15496             this.hidden = true;
15497             if(this.rendered){
15498                 this.onHide();
15499             }
15500             this.fireEvent("hide", this);
15501         }
15502         return this;
15503     },
15504
15505     // private
15506     onHide : function(){
15507         var ae = this.getActionEl();
15508         if(this.hideMode == 'visibility'){
15509             ae.dom.style.visibility = "hidden";
15510         }else if(this.hideMode == 'offsets'){
15511             ae.addClass('x-hidden');
15512         }else{
15513             ae.dom.style.display = "none";
15514         }
15515     },
15516
15517     /**
15518      * Convenience function to hide or show this component by boolean.
15519      * @param {Boolean} visible True to show, false to hide
15520      * @return {Roo.Component} this
15521      */
15522     setVisible: function(visible){
15523         if(visible) {
15524             this.show();
15525         }else{
15526             this.hide();
15527         }
15528         return this;
15529     },
15530
15531     /**
15532      * Returns true if this component is visible.
15533      */
15534     isVisible : function(){
15535         return this.getActionEl().isVisible();
15536     },
15537
15538     cloneConfig : function(overrides){
15539         overrides = overrides || {};
15540         var id = overrides.id || Roo.id();
15541         var cfg = Roo.applyIf(overrides, this.initialConfig);
15542         cfg.id = id; // prevent dup id
15543         return new this.constructor(cfg);
15544     }
15545 });/*
15546  * Based on:
15547  * Ext JS Library 1.1.1
15548  * Copyright(c) 2006-2007, Ext JS, LLC.
15549  *
15550  * Originally Released Under LGPL - original licence link has changed is not relivant.
15551  *
15552  * Fork - LGPL
15553  * <script type="text/javascript">
15554  */
15555
15556 /**
15557  * @class Roo.BoxComponent
15558  * @extends Roo.Component
15559  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15560  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15561  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15562  * layout containers.
15563  * @constructor
15564  * @param {Roo.Element/String/Object} config The configuration options.
15565  */
15566 Roo.BoxComponent = function(config){
15567     Roo.Component.call(this, config);
15568     this.addEvents({
15569         /**
15570          * @event resize
15571          * Fires after the component is resized.
15572              * @param {Roo.Component} this
15573              * @param {Number} adjWidth The box-adjusted width that was set
15574              * @param {Number} adjHeight The box-adjusted height that was set
15575              * @param {Number} rawWidth The width that was originally specified
15576              * @param {Number} rawHeight The height that was originally specified
15577              */
15578         resize : true,
15579         /**
15580          * @event move
15581          * Fires after the component is moved.
15582              * @param {Roo.Component} this
15583              * @param {Number} x The new x position
15584              * @param {Number} y The new y position
15585              */
15586         move : true
15587     });
15588 };
15589
15590 Roo.extend(Roo.BoxComponent, Roo.Component, {
15591     // private, set in afterRender to signify that the component has been rendered
15592     boxReady : false,
15593     // private, used to defer height settings to subclasses
15594     deferHeight: false,
15595     /** @cfg {Number} width
15596      * width (optional) size of component
15597      */
15598      /** @cfg {Number} height
15599      * height (optional) size of component
15600      */
15601      
15602     /**
15603      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15604      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15605      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15606      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15607      * @return {Roo.BoxComponent} this
15608      */
15609     setSize : function(w, h){
15610         // support for standard size objects
15611         if(typeof w == 'object'){
15612             h = w.height;
15613             w = w.width;
15614         }
15615         // not rendered
15616         if(!this.boxReady){
15617             this.width = w;
15618             this.height = h;
15619             return this;
15620         }
15621
15622         // prevent recalcs when not needed
15623         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15624             return this;
15625         }
15626         this.lastSize = {width: w, height: h};
15627
15628         var adj = this.adjustSize(w, h);
15629         var aw = adj.width, ah = adj.height;
15630         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15631             var rz = this.getResizeEl();
15632             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15633                 rz.setSize(aw, ah);
15634             }else if(!this.deferHeight && ah !== undefined){
15635                 rz.setHeight(ah);
15636             }else if(aw !== undefined){
15637                 rz.setWidth(aw);
15638             }
15639             this.onResize(aw, ah, w, h);
15640             this.fireEvent('resize', this, aw, ah, w, h);
15641         }
15642         return this;
15643     },
15644
15645     /**
15646      * Gets the current size of the component's underlying element.
15647      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15648      */
15649     getSize : function(){
15650         return this.el.getSize();
15651     },
15652
15653     /**
15654      * Gets the current XY position of the component's underlying element.
15655      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15656      * @return {Array} The XY position of the element (e.g., [100, 200])
15657      */
15658     getPosition : function(local){
15659         if(local === true){
15660             return [this.el.getLeft(true), this.el.getTop(true)];
15661         }
15662         return this.xy || this.el.getXY();
15663     },
15664
15665     /**
15666      * Gets the current box measurements of the component's underlying element.
15667      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15668      * @returns {Object} box An object in the format {x, y, width, height}
15669      */
15670     getBox : function(local){
15671         var s = this.el.getSize();
15672         if(local){
15673             s.x = this.el.getLeft(true);
15674             s.y = this.el.getTop(true);
15675         }else{
15676             var xy = this.xy || this.el.getXY();
15677             s.x = xy[0];
15678             s.y = xy[1];
15679         }
15680         return s;
15681     },
15682
15683     /**
15684      * Sets the current box measurements of the component's underlying element.
15685      * @param {Object} box An object in the format {x, y, width, height}
15686      * @returns {Roo.BoxComponent} this
15687      */
15688     updateBox : function(box){
15689         this.setSize(box.width, box.height);
15690         this.setPagePosition(box.x, box.y);
15691         return this;
15692     },
15693
15694     // protected
15695     getResizeEl : function(){
15696         return this.resizeEl || this.el;
15697     },
15698
15699     // protected
15700     getPositionEl : function(){
15701         return this.positionEl || this.el;
15702     },
15703
15704     /**
15705      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15706      * This method fires the move event.
15707      * @param {Number} left The new left
15708      * @param {Number} top The new top
15709      * @returns {Roo.BoxComponent} this
15710      */
15711     setPosition : function(x, y){
15712         this.x = x;
15713         this.y = y;
15714         if(!this.boxReady){
15715             return this;
15716         }
15717         var adj = this.adjustPosition(x, y);
15718         var ax = adj.x, ay = adj.y;
15719
15720         var el = this.getPositionEl();
15721         if(ax !== undefined || ay !== undefined){
15722             if(ax !== undefined && ay !== undefined){
15723                 el.setLeftTop(ax, ay);
15724             }else if(ax !== undefined){
15725                 el.setLeft(ax);
15726             }else if(ay !== undefined){
15727                 el.setTop(ay);
15728             }
15729             this.onPosition(ax, ay);
15730             this.fireEvent('move', this, ax, ay);
15731         }
15732         return this;
15733     },
15734
15735     /**
15736      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15737      * This method fires the move event.
15738      * @param {Number} x The new x position
15739      * @param {Number} y The new y position
15740      * @returns {Roo.BoxComponent} this
15741      */
15742     setPagePosition : function(x, y){
15743         this.pageX = x;
15744         this.pageY = y;
15745         if(!this.boxReady){
15746             return;
15747         }
15748         if(x === undefined || y === undefined){ // cannot translate undefined points
15749             return;
15750         }
15751         var p = this.el.translatePoints(x, y);
15752         this.setPosition(p.left, p.top);
15753         return this;
15754     },
15755
15756     // private
15757     onRender : function(ct, position){
15758         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15759         if(this.resizeEl){
15760             this.resizeEl = Roo.get(this.resizeEl);
15761         }
15762         if(this.positionEl){
15763             this.positionEl = Roo.get(this.positionEl);
15764         }
15765     },
15766
15767     // private
15768     afterRender : function(){
15769         Roo.BoxComponent.superclass.afterRender.call(this);
15770         this.boxReady = true;
15771         this.setSize(this.width, this.height);
15772         if(this.x || this.y){
15773             this.setPosition(this.x, this.y);
15774         }
15775         if(this.pageX || this.pageY){
15776             this.setPagePosition(this.pageX, this.pageY);
15777         }
15778     },
15779
15780     /**
15781      * Force the component's size to recalculate based on the underlying element's current height and width.
15782      * @returns {Roo.BoxComponent} this
15783      */
15784     syncSize : function(){
15785         delete this.lastSize;
15786         this.setSize(this.el.getWidth(), this.el.getHeight());
15787         return this;
15788     },
15789
15790     /**
15791      * Called after the component is resized, this method is empty by default but can be implemented by any
15792      * subclass that needs to perform custom logic after a resize occurs.
15793      * @param {Number} adjWidth The box-adjusted width that was set
15794      * @param {Number} adjHeight The box-adjusted height that was set
15795      * @param {Number} rawWidth The width that was originally specified
15796      * @param {Number} rawHeight The height that was originally specified
15797      */
15798     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15799
15800     },
15801
15802     /**
15803      * Called after the component is moved, this method is empty by default but can be implemented by any
15804      * subclass that needs to perform custom logic after a move occurs.
15805      * @param {Number} x The new x position
15806      * @param {Number} y The new y position
15807      */
15808     onPosition : function(x, y){
15809
15810     },
15811
15812     // private
15813     adjustSize : function(w, h){
15814         if(this.autoWidth){
15815             w = 'auto';
15816         }
15817         if(this.autoHeight){
15818             h = 'auto';
15819         }
15820         return {width : w, height: h};
15821     },
15822
15823     // private
15824     adjustPosition : function(x, y){
15825         return {x : x, y: y};
15826     }
15827 });/*
15828  * Original code for Roojs - LGPL
15829  * <script type="text/javascript">
15830  */
15831  
15832 /**
15833  * @class Roo.XComponent
15834  * A delayed Element creator...
15835  * Or a way to group chunks of interface together.
15836  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15837  *  used in conjunction with XComponent.build() it will create an instance of each element,
15838  *  then call addxtype() to build the User interface.
15839  * 
15840  * Mypart.xyx = new Roo.XComponent({
15841
15842     parent : 'Mypart.xyz', // empty == document.element.!!
15843     order : '001',
15844     name : 'xxxx'
15845     region : 'xxxx'
15846     disabled : function() {} 
15847      
15848     tree : function() { // return an tree of xtype declared components
15849         var MODULE = this;
15850         return 
15851         {
15852             xtype : 'NestedLayoutPanel',
15853             // technicall
15854         }
15855      ]
15856  *})
15857  *
15858  *
15859  * It can be used to build a big heiracy, with parent etc.
15860  * or you can just use this to render a single compoent to a dom element
15861  * MYPART.render(Roo.Element | String(id) | dom_element )
15862  *
15863  *
15864  * Usage patterns.
15865  *
15866  * Classic Roo
15867  *
15868  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15869  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15870  *
15871  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15872  *
15873  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15874  * - if mulitple topModules exist, the last one is defined as the top module.
15875  *
15876  * Embeded Roo
15877  * 
15878  * When the top level or multiple modules are to embedded into a existing HTML page,
15879  * the parent element can container '#id' of the element where the module will be drawn.
15880  *
15881  * Bootstrap Roo
15882  *
15883  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15884  * it relies more on a include mechanism, where sub modules are included into an outer page.
15885  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15886  * 
15887  * Bootstrap Roo Included elements
15888  *
15889  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15890  * hence confusing the component builder as it thinks there are multiple top level elements. 
15891  *
15892  * 
15893  * 
15894  * @extends Roo.util.Observable
15895  * @constructor
15896  * @param cfg {Object} configuration of component
15897  * 
15898  */
15899 Roo.XComponent = function(cfg) {
15900     Roo.apply(this, cfg);
15901     this.addEvents({ 
15902         /**
15903              * @event built
15904              * Fires when this the componnt is built
15905              * @param {Roo.XComponent} c the component
15906              */
15907         'built' : true
15908         
15909     });
15910     this.region = this.region || 'center'; // default..
15911     Roo.XComponent.register(this);
15912     this.modules = false;
15913     this.el = false; // where the layout goes..
15914     
15915     
15916 }
15917 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15918     /**
15919      * @property el
15920      * The created element (with Roo.factory())
15921      * @type {Roo.Layout}
15922      */
15923     el  : false,
15924     
15925     /**
15926      * @property el
15927      * for BC  - use el in new code
15928      * @type {Roo.Layout}
15929      */
15930     panel : false,
15931     
15932     /**
15933      * @property layout
15934      * for BC  - use el in new code
15935      * @type {Roo.Layout}
15936      */
15937     layout : false,
15938     
15939      /**
15940      * @cfg {Function|boolean} disabled
15941      * If this module is disabled by some rule, return true from the funtion
15942      */
15943     disabled : false,
15944     
15945     /**
15946      * @cfg {String} parent 
15947      * Name of parent element which it get xtype added to..
15948      */
15949     parent: false,
15950     
15951     /**
15952      * @cfg {String} order
15953      * Used to set the order in which elements are created (usefull for multiple tabs)
15954      */
15955     
15956     order : false,
15957     /**
15958      * @cfg {String} name
15959      * String to display while loading.
15960      */
15961     name : false,
15962     /**
15963      * @cfg {String} region
15964      * Region to render component to (defaults to center)
15965      */
15966     region : 'center',
15967     
15968     /**
15969      * @cfg {Array} items
15970      * A single item array - the first element is the root of the tree..
15971      * It's done this way to stay compatible with the Xtype system...
15972      */
15973     items : false,
15974     
15975     /**
15976      * @property _tree
15977      * The method that retuns the tree of parts that make up this compoennt 
15978      * @type {function}
15979      */
15980     _tree  : false,
15981     
15982      /**
15983      * render
15984      * render element to dom or tree
15985      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15986      */
15987     
15988     render : function(el)
15989     {
15990         
15991         el = el || false;
15992         var hp = this.parent ? 1 : 0;
15993         Roo.debug &&  Roo.log(this);
15994         
15995         var tree = this._tree ? this._tree() : this.tree();
15996
15997         
15998         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15999             // if parent is a '#.....' string, then let's use that..
16000             var ename = this.parent.substr(1);
16001             this.parent = false;
16002             Roo.debug && Roo.log(ename);
16003             switch (ename) {
16004                 case 'bootstrap-body':
16005                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16006                         // this is the BorderLayout standard?
16007                        this.parent = { el : true };
16008                        break;
16009                     }
16010                     
16011                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
16012                         this.parent = { el :  new  Roo.bootstrap.Body() };
16013                         Roo.debug && Roo.log("setting el to doc body");
16014                          
16015                     } else {
16016                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16017                     }
16018                     break;
16019                 case 'bootstrap':
16020                     this.parent = { el : true};
16021                     // fall through
16022                 default:
16023                     el = Roo.get(ename);
16024                     break;
16025             }
16026                 
16027             
16028             if (!el && !this.parent) {
16029                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16030                 return;
16031             }
16032         }
16033         Roo.debug && Roo.log("EL:");
16034         Roo.debug && Roo.log(el);
16035         Roo.debug && Roo.log("this.parent.el:");
16036         Roo.debug && Roo.log(this.parent.el);
16037         
16038
16039         // altertive root elements ??? - we need a better way to indicate these.
16040         var is_alt = Roo.XComponent.is_alt ||
16041                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16042                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16043                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16044         
16045         
16046         
16047         if (!this.parent && is_alt) {
16048             //el = Roo.get(document.body);
16049             this.parent = { el : true };
16050         }
16051             
16052             
16053         
16054         if (!this.parent) {
16055             
16056             Roo.debug && Roo.log("no parent - creating one");
16057             
16058             el = el ? Roo.get(el) : false;      
16059             
16060             // it's a top level one..
16061             this.parent =  {
16062                 el : new Roo.BorderLayout(el || document.body, {
16063                 
16064                      center: {
16065                          titlebar: false,
16066                          autoScroll:false,
16067                          closeOnTab: true,
16068                          tabPosition: 'top',
16069                           //resizeTabs: true,
16070                          alwaysShowTabs: el && hp? false :  true,
16071                          hideTabs: el || !hp ? true :  false,
16072                          minTabWidth: 140
16073                      }
16074                  })
16075             };
16076         }
16077         
16078         if (!this.parent.el) {
16079                 // probably an old style ctor, which has been disabled.
16080                 return;
16081
16082         }
16083                 // The 'tree' method is  '_tree now' 
16084             
16085         tree.region = tree.region || this.region;
16086         var is_body = false;
16087         if (this.parent.el === true) {
16088             // bootstrap... - body..
16089             this.parent.el = Roo.factory(tree);
16090             is_body = true;
16091         }
16092         
16093         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16094         this.fireEvent('built', this);
16095         
16096         this.panel = this.el;
16097         this.layout = this.panel.layout;
16098         this.parentLayout = this.parent.layout  || false;  
16099          
16100     }
16101     
16102 });
16103
16104 Roo.apply(Roo.XComponent, {
16105     /**
16106      * @property  hideProgress
16107      * true to disable the building progress bar.. usefull on single page renders.
16108      * @type Boolean
16109      */
16110     hideProgress : false,
16111     /**
16112      * @property  buildCompleted
16113      * True when the builder has completed building the interface.
16114      * @type Boolean
16115      */
16116     buildCompleted : false,
16117      
16118     /**
16119      * @property  topModule
16120      * the upper most module - uses document.element as it's constructor.
16121      * @type Object
16122      */
16123      
16124     topModule  : false,
16125       
16126     /**
16127      * @property  modules
16128      * array of modules to be created by registration system.
16129      * @type {Array} of Roo.XComponent
16130      */
16131     
16132     modules : [],
16133     /**
16134      * @property  elmodules
16135      * array of modules to be created by which use #ID 
16136      * @type {Array} of Roo.XComponent
16137      */
16138      
16139     elmodules : [],
16140
16141      /**
16142      * @property  is_alt
16143      * Is an alternative Root - normally used by bootstrap or other systems,
16144      *    where the top element in the tree can wrap 'body' 
16145      * @type {boolean}  (default false)
16146      */
16147      
16148     is_alt : false,
16149     /**
16150      * @property  build_from_html
16151      * Build elements from html - used by bootstrap HTML stuff 
16152      *    - this is cleared after build is completed
16153      * @type {boolean}    (default false)
16154      */
16155      
16156     build_from_html : false,
16157     /**
16158      * Register components to be built later.
16159      *
16160      * This solves the following issues
16161      * - Building is not done on page load, but after an authentication process has occured.
16162      * - Interface elements are registered on page load
16163      * - Parent Interface elements may not be loaded before child, so this handles that..
16164      * 
16165      *
16166      * example:
16167      * 
16168      * MyApp.register({
16169           order : '000001',
16170           module : 'Pman.Tab.projectMgr',
16171           region : 'center',
16172           parent : 'Pman.layout',
16173           disabled : false,  // or use a function..
16174         })
16175      
16176      * * @param {Object} details about module
16177      */
16178     register : function(obj) {
16179                 
16180         Roo.XComponent.event.fireEvent('register', obj);
16181         switch(typeof(obj.disabled) ) {
16182                 
16183             case 'undefined':
16184                 break;
16185             
16186             case 'function':
16187                 if ( obj.disabled() ) {
16188                         return;
16189                 }
16190                 break;
16191             
16192             default:
16193                 if (obj.disabled) {
16194                         return;
16195                 }
16196                 break;
16197         }
16198                 
16199         this.modules.push(obj);
16200          
16201     },
16202     /**
16203      * convert a string to an object..
16204      * eg. 'AAA.BBB' -> finds AAA.BBB
16205
16206      */
16207     
16208     toObject : function(str)
16209     {
16210         if (!str || typeof(str) == 'object') {
16211             return str;
16212         }
16213         if (str.substring(0,1) == '#') {
16214             return str;
16215         }
16216
16217         var ar = str.split('.');
16218         var rt, o;
16219         rt = ar.shift();
16220             /** eval:var:o */
16221         try {
16222             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16223         } catch (e) {
16224             throw "Module not found : " + str;
16225         }
16226         
16227         if (o === false) {
16228             throw "Module not found : " + str;
16229         }
16230         Roo.each(ar, function(e) {
16231             if (typeof(o[e]) == 'undefined') {
16232                 throw "Module not found : " + str;
16233             }
16234             o = o[e];
16235         });
16236         
16237         return o;
16238         
16239     },
16240     
16241     
16242     /**
16243      * move modules into their correct place in the tree..
16244      * 
16245      */
16246     preBuild : function ()
16247     {
16248         var _t = this;
16249         Roo.each(this.modules , function (obj)
16250         {
16251             Roo.XComponent.event.fireEvent('beforebuild', obj);
16252             
16253             var opar = obj.parent;
16254             try { 
16255                 obj.parent = this.toObject(opar);
16256             } catch(e) {
16257                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16258                 return;
16259             }
16260             
16261             if (!obj.parent) {
16262                 Roo.debug && Roo.log("GOT top level module");
16263                 Roo.debug && Roo.log(obj);
16264                 obj.modules = new Roo.util.MixedCollection(false, 
16265                     function(o) { return o.order + '' }
16266                 );
16267                 this.topModule = obj;
16268                 return;
16269             }
16270                         // parent is a string (usually a dom element name..)
16271             if (typeof(obj.parent) == 'string') {
16272                 this.elmodules.push(obj);
16273                 return;
16274             }
16275             if (obj.parent.constructor != Roo.XComponent) {
16276                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16277             }
16278             if (!obj.parent.modules) {
16279                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16280                     function(o) { return o.order + '' }
16281                 );
16282             }
16283             if (obj.parent.disabled) {
16284                 obj.disabled = true;
16285             }
16286             obj.parent.modules.add(obj);
16287         }, this);
16288     },
16289     
16290      /**
16291      * make a list of modules to build.
16292      * @return {Array} list of modules. 
16293      */ 
16294     
16295     buildOrder : function()
16296     {
16297         var _this = this;
16298         var cmp = function(a,b) {   
16299             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16300         };
16301         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16302             throw "No top level modules to build";
16303         }
16304         
16305         // make a flat list in order of modules to build.
16306         var mods = this.topModule ? [ this.topModule ] : [];
16307                 
16308         
16309         // elmodules (is a list of DOM based modules )
16310         Roo.each(this.elmodules, function(e) {
16311             mods.push(e);
16312             if (!this.topModule &&
16313                 typeof(e.parent) == 'string' &&
16314                 e.parent.substring(0,1) == '#' &&
16315                 Roo.get(e.parent.substr(1))
16316                ) {
16317                 
16318                 _this.topModule = e;
16319             }
16320             
16321         });
16322
16323         
16324         // add modules to their parents..
16325         var addMod = function(m) {
16326             Roo.debug && Roo.log("build Order: add: " + m.name);
16327                 
16328             mods.push(m);
16329             if (m.modules && !m.disabled) {
16330                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16331                 m.modules.keySort('ASC',  cmp );
16332                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16333     
16334                 m.modules.each(addMod);
16335             } else {
16336                 Roo.debug && Roo.log("build Order: no child modules");
16337             }
16338             // not sure if this is used any more..
16339             if (m.finalize) {
16340                 m.finalize.name = m.name + " (clean up) ";
16341                 mods.push(m.finalize);
16342             }
16343             
16344         }
16345         if (this.topModule && this.topModule.modules) { 
16346             this.topModule.modules.keySort('ASC',  cmp );
16347             this.topModule.modules.each(addMod);
16348         } 
16349         return mods;
16350     },
16351     
16352      /**
16353      * Build the registered modules.
16354      * @param {Object} parent element.
16355      * @param {Function} optional method to call after module has been added.
16356      * 
16357      */ 
16358    
16359     build : function(opts) 
16360     {
16361         
16362         if (typeof(opts) != 'undefined') {
16363             Roo.apply(this,opts);
16364         }
16365         
16366         this.preBuild();
16367         var mods = this.buildOrder();
16368       
16369         //this.allmods = mods;
16370         //Roo.debug && Roo.log(mods);
16371         //return;
16372         if (!mods.length) { // should not happen
16373             throw "NO modules!!!";
16374         }
16375         
16376         
16377         var msg = "Building Interface...";
16378         // flash it up as modal - so we store the mask!?
16379         if (!this.hideProgress && Roo.MessageBox) {
16380             Roo.MessageBox.show({ title: 'loading' });
16381             Roo.MessageBox.show({
16382                title: "Please wait...",
16383                msg: msg,
16384                width:450,
16385                progress:true,
16386                closable:false,
16387                modal: false
16388               
16389             });
16390         }
16391         var total = mods.length;
16392         
16393         var _this = this;
16394         var progressRun = function() {
16395             if (!mods.length) {
16396                 Roo.debug && Roo.log('hide?');
16397                 if (!this.hideProgress && Roo.MessageBox) {
16398                     Roo.MessageBox.hide();
16399                 }
16400                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16401                 
16402                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16403                 
16404                 // THE END...
16405                 return false;   
16406             }
16407             
16408             var m = mods.shift();
16409             
16410             
16411             Roo.debug && Roo.log(m);
16412             // not sure if this is supported any more.. - modules that are are just function
16413             if (typeof(m) == 'function') { 
16414                 m.call(this);
16415                 return progressRun.defer(10, _this);
16416             } 
16417             
16418             
16419             msg = "Building Interface " + (total  - mods.length) + 
16420                     " of " + total + 
16421                     (m.name ? (' - ' + m.name) : '');
16422                         Roo.debug && Roo.log(msg);
16423             if (!this.hideProgress &&  Roo.MessageBox) { 
16424                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16425             }
16426             
16427          
16428             // is the module disabled?
16429             var disabled = (typeof(m.disabled) == 'function') ?
16430                 m.disabled.call(m.module.disabled) : m.disabled;    
16431             
16432             
16433             if (disabled) {
16434                 return progressRun(); // we do not update the display!
16435             }
16436             
16437             // now build 
16438             
16439                         
16440                         
16441             m.render();
16442             // it's 10 on top level, and 1 on others??? why...
16443             return progressRun.defer(10, _this);
16444              
16445         }
16446         progressRun.defer(1, _this);
16447      
16448         
16449         
16450     },
16451         
16452         
16453         /**
16454          * Event Object.
16455          *
16456          *
16457          */
16458         event: false, 
16459     /**
16460          * wrapper for event.on - aliased later..  
16461          * Typically use to register a event handler for register:
16462          *
16463          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16464          *
16465          */
16466     on : false
16467    
16468     
16469     
16470 });
16471
16472 Roo.XComponent.event = new Roo.util.Observable({
16473                 events : { 
16474                         /**
16475                          * @event register
16476                          * Fires when an Component is registered,
16477                          * set the disable property on the Component to stop registration.
16478                          * @param {Roo.XComponent} c the component being registerd.
16479                          * 
16480                          */
16481                         'register' : true,
16482             /**
16483                          * @event beforebuild
16484                          * Fires before each Component is built
16485                          * can be used to apply permissions.
16486                          * @param {Roo.XComponent} c the component being registerd.
16487                          * 
16488                          */
16489                         'beforebuild' : true,
16490                         /**
16491                          * @event buildcomplete
16492                          * Fires on the top level element when all elements have been built
16493                          * @param {Roo.XComponent} the top level component.
16494                          */
16495                         'buildcomplete' : true
16496                         
16497                 }
16498 });
16499
16500 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16501  //
16502  /**
16503  * marked - a markdown parser
16504  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16505  * https://github.com/chjj/marked
16506  */
16507
16508
16509 /**
16510  *
16511  * Roo.Markdown - is a very crude wrapper around marked..
16512  *
16513  * usage:
16514  * 
16515  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16516  * 
16517  * Note: move the sample code to the bottom of this
16518  * file before uncommenting it.
16519  *
16520  */
16521
16522 Roo.Markdown = {};
16523 Roo.Markdown.toHtml = function(text) {
16524     
16525     var c = new Roo.Markdown.marked.setOptions({
16526             renderer: new Roo.Markdown.marked.Renderer(),
16527             gfm: true,
16528             tables: true,
16529             breaks: false,
16530             pedantic: false,
16531             sanitize: false,
16532             smartLists: true,
16533             smartypants: false
16534           });
16535     // A FEW HACKS!!?
16536     
16537     text = text.replace(/\\\n/g,' ');
16538     return Roo.Markdown.marked(text);
16539 };
16540 //
16541 // converter
16542 //
16543 // Wraps all "globals" so that the only thing
16544 // exposed is makeHtml().
16545 //
16546 (function() {
16547     
16548     /**
16549      * Block-Level Grammar
16550      */
16551     
16552     var block = {
16553       newline: /^\n+/,
16554       code: /^( {4}[^\n]+\n*)+/,
16555       fences: noop,
16556       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16557       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16558       nptable: noop,
16559       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16560       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16561       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16562       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16563       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16564       table: noop,
16565       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16566       text: /^[^\n]+/
16567     };
16568     
16569     block.bullet = /(?:[*+-]|\d+\.)/;
16570     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16571     block.item = replace(block.item, 'gm')
16572       (/bull/g, block.bullet)
16573       ();
16574     
16575     block.list = replace(block.list)
16576       (/bull/g, block.bullet)
16577       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16578       ('def', '\\n+(?=' + block.def.source + ')')
16579       ();
16580     
16581     block.blockquote = replace(block.blockquote)
16582       ('def', block.def)
16583       ();
16584     
16585     block._tag = '(?!(?:'
16586       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16587       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16588       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16589     
16590     block.html = replace(block.html)
16591       ('comment', /<!--[\s\S]*?-->/)
16592       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16593       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16594       (/tag/g, block._tag)
16595       ();
16596     
16597     block.paragraph = replace(block.paragraph)
16598       ('hr', block.hr)
16599       ('heading', block.heading)
16600       ('lheading', block.lheading)
16601       ('blockquote', block.blockquote)
16602       ('tag', '<' + block._tag)
16603       ('def', block.def)
16604       ();
16605     
16606     /**
16607      * Normal Block Grammar
16608      */
16609     
16610     block.normal = merge({}, block);
16611     
16612     /**
16613      * GFM Block Grammar
16614      */
16615     
16616     block.gfm = merge({}, block.normal, {
16617       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16618       paragraph: /^/,
16619       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16620     });
16621     
16622     block.gfm.paragraph = replace(block.paragraph)
16623       ('(?!', '(?!'
16624         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16625         + block.list.source.replace('\\1', '\\3') + '|')
16626       ();
16627     
16628     /**
16629      * GFM + Tables Block Grammar
16630      */
16631     
16632     block.tables = merge({}, block.gfm, {
16633       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16634       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16635     });
16636     
16637     /**
16638      * Block Lexer
16639      */
16640     
16641     function Lexer(options) {
16642       this.tokens = [];
16643       this.tokens.links = {};
16644       this.options = options || marked.defaults;
16645       this.rules = block.normal;
16646     
16647       if (this.options.gfm) {
16648         if (this.options.tables) {
16649           this.rules = block.tables;
16650         } else {
16651           this.rules = block.gfm;
16652         }
16653       }
16654     }
16655     
16656     /**
16657      * Expose Block Rules
16658      */
16659     
16660     Lexer.rules = block;
16661     
16662     /**
16663      * Static Lex Method
16664      */
16665     
16666     Lexer.lex = function(src, options) {
16667       var lexer = new Lexer(options);
16668       return lexer.lex(src);
16669     };
16670     
16671     /**
16672      * Preprocessing
16673      */
16674     
16675     Lexer.prototype.lex = function(src) {
16676       src = src
16677         .replace(/\r\n|\r/g, '\n')
16678         .replace(/\t/g, '    ')
16679         .replace(/\u00a0/g, ' ')
16680         .replace(/\u2424/g, '\n');
16681     
16682       return this.token(src, true);
16683     };
16684     
16685     /**
16686      * Lexing
16687      */
16688     
16689     Lexer.prototype.token = function(src, top, bq) {
16690       var src = src.replace(/^ +$/gm, '')
16691         , next
16692         , loose
16693         , cap
16694         , bull
16695         , b
16696         , item
16697         , space
16698         , i
16699         , l;
16700     
16701       while (src) {
16702         // newline
16703         if (cap = this.rules.newline.exec(src)) {
16704           src = src.substring(cap[0].length);
16705           if (cap[0].length > 1) {
16706             this.tokens.push({
16707               type: 'space'
16708             });
16709           }
16710         }
16711     
16712         // code
16713         if (cap = this.rules.code.exec(src)) {
16714           src = src.substring(cap[0].length);
16715           cap = cap[0].replace(/^ {4}/gm, '');
16716           this.tokens.push({
16717             type: 'code',
16718             text: !this.options.pedantic
16719               ? cap.replace(/\n+$/, '')
16720               : cap
16721           });
16722           continue;
16723         }
16724     
16725         // fences (gfm)
16726         if (cap = this.rules.fences.exec(src)) {
16727           src = src.substring(cap[0].length);
16728           this.tokens.push({
16729             type: 'code',
16730             lang: cap[2],
16731             text: cap[3] || ''
16732           });
16733           continue;
16734         }
16735     
16736         // heading
16737         if (cap = this.rules.heading.exec(src)) {
16738           src = src.substring(cap[0].length);
16739           this.tokens.push({
16740             type: 'heading',
16741             depth: cap[1].length,
16742             text: cap[2]
16743           });
16744           continue;
16745         }
16746     
16747         // table no leading pipe (gfm)
16748         if (top && (cap = this.rules.nptable.exec(src))) {
16749           src = src.substring(cap[0].length);
16750     
16751           item = {
16752             type: 'table',
16753             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16754             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16755             cells: cap[3].replace(/\n$/, '').split('\n')
16756           };
16757     
16758           for (i = 0; i < item.align.length; i++) {
16759             if (/^ *-+: *$/.test(item.align[i])) {
16760               item.align[i] = 'right';
16761             } else if (/^ *:-+: *$/.test(item.align[i])) {
16762               item.align[i] = 'center';
16763             } else if (/^ *:-+ *$/.test(item.align[i])) {
16764               item.align[i] = 'left';
16765             } else {
16766               item.align[i] = null;
16767             }
16768           }
16769     
16770           for (i = 0; i < item.cells.length; i++) {
16771             item.cells[i] = item.cells[i].split(/ *\| */);
16772           }
16773     
16774           this.tokens.push(item);
16775     
16776           continue;
16777         }
16778     
16779         // lheading
16780         if (cap = this.rules.lheading.exec(src)) {
16781           src = src.substring(cap[0].length);
16782           this.tokens.push({
16783             type: 'heading',
16784             depth: cap[2] === '=' ? 1 : 2,
16785             text: cap[1]
16786           });
16787           continue;
16788         }
16789     
16790         // hr
16791         if (cap = this.rules.hr.exec(src)) {
16792           src = src.substring(cap[0].length);
16793           this.tokens.push({
16794             type: 'hr'
16795           });
16796           continue;
16797         }
16798     
16799         // blockquote
16800         if (cap = this.rules.blockquote.exec(src)) {
16801           src = src.substring(cap[0].length);
16802     
16803           this.tokens.push({
16804             type: 'blockquote_start'
16805           });
16806     
16807           cap = cap[0].replace(/^ *> ?/gm, '');
16808     
16809           // Pass `top` to keep the current
16810           // "toplevel" state. This is exactly
16811           // how markdown.pl works.
16812           this.token(cap, top, true);
16813     
16814           this.tokens.push({
16815             type: 'blockquote_end'
16816           });
16817     
16818           continue;
16819         }
16820     
16821         // list
16822         if (cap = this.rules.list.exec(src)) {
16823           src = src.substring(cap[0].length);
16824           bull = cap[2];
16825     
16826           this.tokens.push({
16827             type: 'list_start',
16828             ordered: bull.length > 1
16829           });
16830     
16831           // Get each top-level item.
16832           cap = cap[0].match(this.rules.item);
16833     
16834           next = false;
16835           l = cap.length;
16836           i = 0;
16837     
16838           for (; i < l; i++) {
16839             item = cap[i];
16840     
16841             // Remove the list item's bullet
16842             // so it is seen as the next token.
16843             space = item.length;
16844             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16845     
16846             // Outdent whatever the
16847             // list item contains. Hacky.
16848             if (~item.indexOf('\n ')) {
16849               space -= item.length;
16850               item = !this.options.pedantic
16851                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16852                 : item.replace(/^ {1,4}/gm, '');
16853             }
16854     
16855             // Determine whether the next list item belongs here.
16856             // Backpedal if it does not belong in this list.
16857             if (this.options.smartLists && i !== l - 1) {
16858               b = block.bullet.exec(cap[i + 1])[0];
16859               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16860                 src = cap.slice(i + 1).join('\n') + src;
16861                 i = l - 1;
16862               }
16863             }
16864     
16865             // Determine whether item is loose or not.
16866             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16867             // for discount behavior.
16868             loose = next || /\n\n(?!\s*$)/.test(item);
16869             if (i !== l - 1) {
16870               next = item.charAt(item.length - 1) === '\n';
16871               if (!loose) { loose = next; }
16872             }
16873     
16874             this.tokens.push({
16875               type: loose
16876                 ? 'loose_item_start'
16877                 : 'list_item_start'
16878             });
16879     
16880             // Recurse.
16881             this.token(item, false, bq);
16882     
16883             this.tokens.push({
16884               type: 'list_item_end'
16885             });
16886           }
16887     
16888           this.tokens.push({
16889             type: 'list_end'
16890           });
16891     
16892           continue;
16893         }
16894     
16895         // html
16896         if (cap = this.rules.html.exec(src)) {
16897           src = src.substring(cap[0].length);
16898           this.tokens.push({
16899             type: this.options.sanitize
16900               ? 'paragraph'
16901               : 'html',
16902             pre: !this.options.sanitizer
16903               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
16904             text: cap[0]
16905           });
16906           continue;
16907         }
16908     
16909         // def
16910         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
16911           src = src.substring(cap[0].length);
16912           this.tokens.links[cap[1].toLowerCase()] = {
16913             href: cap[2],
16914             title: cap[3]
16915           };
16916           continue;
16917         }
16918     
16919         // table (gfm)
16920         if (top && (cap = this.rules.table.exec(src))) {
16921           src = src.substring(cap[0].length);
16922     
16923           item = {
16924             type: 'table',
16925             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16926             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16927             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
16928           };
16929     
16930           for (i = 0; i < item.align.length; i++) {
16931             if (/^ *-+: *$/.test(item.align[i])) {
16932               item.align[i] = 'right';
16933             } else if (/^ *:-+: *$/.test(item.align[i])) {
16934               item.align[i] = 'center';
16935             } else if (/^ *:-+ *$/.test(item.align[i])) {
16936               item.align[i] = 'left';
16937             } else {
16938               item.align[i] = null;
16939             }
16940           }
16941     
16942           for (i = 0; i < item.cells.length; i++) {
16943             item.cells[i] = item.cells[i]
16944               .replace(/^ *\| *| *\| *$/g, '')
16945               .split(/ *\| */);
16946           }
16947     
16948           this.tokens.push(item);
16949     
16950           continue;
16951         }
16952     
16953         // top-level paragraph
16954         if (top && (cap = this.rules.paragraph.exec(src))) {
16955           src = src.substring(cap[0].length);
16956           this.tokens.push({
16957             type: 'paragraph',
16958             text: cap[1].charAt(cap[1].length - 1) === '\n'
16959               ? cap[1].slice(0, -1)
16960               : cap[1]
16961           });
16962           continue;
16963         }
16964     
16965         // text
16966         if (cap = this.rules.text.exec(src)) {
16967           // Top-level should never reach here.
16968           src = src.substring(cap[0].length);
16969           this.tokens.push({
16970             type: 'text',
16971             text: cap[0]
16972           });
16973           continue;
16974         }
16975     
16976         if (src) {
16977           throw new
16978             Error('Infinite loop on byte: ' + src.charCodeAt(0));
16979         }
16980       }
16981     
16982       return this.tokens;
16983     };
16984     
16985     /**
16986      * Inline-Level Grammar
16987      */
16988     
16989     var inline = {
16990       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
16991       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
16992       url: noop,
16993       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
16994       link: /^!?\[(inside)\]\(href\)/,
16995       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
16996       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
16997       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
16998       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
16999       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17000       br: /^ {2,}\n(?!\s*$)/,
17001       del: noop,
17002       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17003     };
17004     
17005     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17006     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17007     
17008     inline.link = replace(inline.link)
17009       ('inside', inline._inside)
17010       ('href', inline._href)
17011       ();
17012     
17013     inline.reflink = replace(inline.reflink)
17014       ('inside', inline._inside)
17015       ();
17016     
17017     /**
17018      * Normal Inline Grammar
17019      */
17020     
17021     inline.normal = merge({}, inline);
17022     
17023     /**
17024      * Pedantic Inline Grammar
17025      */
17026     
17027     inline.pedantic = merge({}, inline.normal, {
17028       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17029       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17030     });
17031     
17032     /**
17033      * GFM Inline Grammar
17034      */
17035     
17036     inline.gfm = merge({}, inline.normal, {
17037       escape: replace(inline.escape)('])', '~|])')(),
17038       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17039       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17040       text: replace(inline.text)
17041         (']|', '~]|')
17042         ('|', '|https?://|')
17043         ()
17044     });
17045     
17046     /**
17047      * GFM + Line Breaks Inline Grammar
17048      */
17049     
17050     inline.breaks = merge({}, inline.gfm, {
17051       br: replace(inline.br)('{2,}', '*')(),
17052       text: replace(inline.gfm.text)('{2,}', '*')()
17053     });
17054     
17055     /**
17056      * Inline Lexer & Compiler
17057      */
17058     
17059     function InlineLexer(links, options) {
17060       this.options = options || marked.defaults;
17061       this.links = links;
17062       this.rules = inline.normal;
17063       this.renderer = this.options.renderer || new Renderer;
17064       this.renderer.options = this.options;
17065     
17066       if (!this.links) {
17067         throw new
17068           Error('Tokens array requires a `links` property.');
17069       }
17070     
17071       if (this.options.gfm) {
17072         if (this.options.breaks) {
17073           this.rules = inline.breaks;
17074         } else {
17075           this.rules = inline.gfm;
17076         }
17077       } else if (this.options.pedantic) {
17078         this.rules = inline.pedantic;
17079       }
17080     }
17081     
17082     /**
17083      * Expose Inline Rules
17084      */
17085     
17086     InlineLexer.rules = inline;
17087     
17088     /**
17089      * Static Lexing/Compiling Method
17090      */
17091     
17092     InlineLexer.output = function(src, links, options) {
17093       var inline = new InlineLexer(links, options);
17094       return inline.output(src);
17095     };
17096     
17097     /**
17098      * Lexing/Compiling
17099      */
17100     
17101     InlineLexer.prototype.output = function(src) {
17102       var out = ''
17103         , link
17104         , text
17105         , href
17106         , cap;
17107     
17108       while (src) {
17109         // escape
17110         if (cap = this.rules.escape.exec(src)) {
17111           src = src.substring(cap[0].length);
17112           out += cap[1];
17113           continue;
17114         }
17115     
17116         // autolink
17117         if (cap = this.rules.autolink.exec(src)) {
17118           src = src.substring(cap[0].length);
17119           if (cap[2] === '@') {
17120             text = cap[1].charAt(6) === ':'
17121               ? this.mangle(cap[1].substring(7))
17122               : this.mangle(cap[1]);
17123             href = this.mangle('mailto:') + text;
17124           } else {
17125             text = escape(cap[1]);
17126             href = text;
17127           }
17128           out += this.renderer.link(href, null, text);
17129           continue;
17130         }
17131     
17132         // url (gfm)
17133         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17134           src = src.substring(cap[0].length);
17135           text = escape(cap[1]);
17136           href = text;
17137           out += this.renderer.link(href, null, text);
17138           continue;
17139         }
17140     
17141         // tag
17142         if (cap = this.rules.tag.exec(src)) {
17143           if (!this.inLink && /^<a /i.test(cap[0])) {
17144             this.inLink = true;
17145           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17146             this.inLink = false;
17147           }
17148           src = src.substring(cap[0].length);
17149           out += this.options.sanitize
17150             ? this.options.sanitizer
17151               ? this.options.sanitizer(cap[0])
17152               : escape(cap[0])
17153             : cap[0];
17154           continue;
17155         }
17156     
17157         // link
17158         if (cap = this.rules.link.exec(src)) {
17159           src = src.substring(cap[0].length);
17160           this.inLink = true;
17161           out += this.outputLink(cap, {
17162             href: cap[2],
17163             title: cap[3]
17164           });
17165           this.inLink = false;
17166           continue;
17167         }
17168     
17169         // reflink, nolink
17170         if ((cap = this.rules.reflink.exec(src))
17171             || (cap = this.rules.nolink.exec(src))) {
17172           src = src.substring(cap[0].length);
17173           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17174           link = this.links[link.toLowerCase()];
17175           if (!link || !link.href) {
17176             out += cap[0].charAt(0);
17177             src = cap[0].substring(1) + src;
17178             continue;
17179           }
17180           this.inLink = true;
17181           out += this.outputLink(cap, link);
17182           this.inLink = false;
17183           continue;
17184         }
17185     
17186         // strong
17187         if (cap = this.rules.strong.exec(src)) {
17188           src = src.substring(cap[0].length);
17189           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17190           continue;
17191         }
17192     
17193         // em
17194         if (cap = this.rules.em.exec(src)) {
17195           src = src.substring(cap[0].length);
17196           out += this.renderer.em(this.output(cap[2] || cap[1]));
17197           continue;
17198         }
17199     
17200         // code
17201         if (cap = this.rules.code.exec(src)) {
17202           src = src.substring(cap[0].length);
17203           out += this.renderer.codespan(escape(cap[2], true));
17204           continue;
17205         }
17206     
17207         // br
17208         if (cap = this.rules.br.exec(src)) {
17209           src = src.substring(cap[0].length);
17210           out += this.renderer.br();
17211           continue;
17212         }
17213     
17214         // del (gfm)
17215         if (cap = this.rules.del.exec(src)) {
17216           src = src.substring(cap[0].length);
17217           out += this.renderer.del(this.output(cap[1]));
17218           continue;
17219         }
17220     
17221         // text
17222         if (cap = this.rules.text.exec(src)) {
17223           src = src.substring(cap[0].length);
17224           out += this.renderer.text(escape(this.smartypants(cap[0])));
17225           continue;
17226         }
17227     
17228         if (src) {
17229           throw new
17230             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17231         }
17232       }
17233     
17234       return out;
17235     };
17236     
17237     /**
17238      * Compile Link
17239      */
17240     
17241     InlineLexer.prototype.outputLink = function(cap, link) {
17242       var href = escape(link.href)
17243         , title = link.title ? escape(link.title) : null;
17244     
17245       return cap[0].charAt(0) !== '!'
17246         ? this.renderer.link(href, title, this.output(cap[1]))
17247         : this.renderer.image(href, title, escape(cap[1]));
17248     };
17249     
17250     /**
17251      * Smartypants Transformations
17252      */
17253     
17254     InlineLexer.prototype.smartypants = function(text) {
17255       if (!this.options.smartypants)  { return text; }
17256       return text
17257         // em-dashes
17258         .replace(/---/g, '\u2014')
17259         // en-dashes
17260         .replace(/--/g, '\u2013')
17261         // opening singles
17262         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17263         // closing singles & apostrophes
17264         .replace(/'/g, '\u2019')
17265         // opening doubles
17266         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17267         // closing doubles
17268         .replace(/"/g, '\u201d')
17269         // ellipses
17270         .replace(/\.{3}/g, '\u2026');
17271     };
17272     
17273     /**
17274      * Mangle Links
17275      */
17276     
17277     InlineLexer.prototype.mangle = function(text) {
17278       if (!this.options.mangle) { return text; }
17279       var out = ''
17280         , l = text.length
17281         , i = 0
17282         , ch;
17283     
17284       for (; i < l; i++) {
17285         ch = text.charCodeAt(i);
17286         if (Math.random() > 0.5) {
17287           ch = 'x' + ch.toString(16);
17288         }
17289         out += '&#' + ch + ';';
17290       }
17291     
17292       return out;
17293     };
17294     
17295     /**
17296      * Renderer
17297      */
17298     
17299     function Renderer(options) {
17300       this.options = options || {};
17301     }
17302     
17303     Renderer.prototype.code = function(code, lang, escaped) {
17304       if (this.options.highlight) {
17305         var out = this.options.highlight(code, lang);
17306         if (out != null && out !== code) {
17307           escaped = true;
17308           code = out;
17309         }
17310       } else {
17311             // hack!!! - it's already escapeD?
17312             escaped = true;
17313       }
17314     
17315       if (!lang) {
17316         return '<pre><code>'
17317           + (escaped ? code : escape(code, true))
17318           + '\n</code></pre>';
17319       }
17320     
17321       return '<pre><code class="'
17322         + this.options.langPrefix
17323         + escape(lang, true)
17324         + '">'
17325         + (escaped ? code : escape(code, true))
17326         + '\n</code></pre>\n';
17327     };
17328     
17329     Renderer.prototype.blockquote = function(quote) {
17330       return '<blockquote>\n' + quote + '</blockquote>\n';
17331     };
17332     
17333     Renderer.prototype.html = function(html) {
17334       return html;
17335     };
17336     
17337     Renderer.prototype.heading = function(text, level, raw) {
17338       return '<h'
17339         + level
17340         + ' id="'
17341         + this.options.headerPrefix
17342         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17343         + '">'
17344         + text
17345         + '</h'
17346         + level
17347         + '>\n';
17348     };
17349     
17350     Renderer.prototype.hr = function() {
17351       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17352     };
17353     
17354     Renderer.prototype.list = function(body, ordered) {
17355       var type = ordered ? 'ol' : 'ul';
17356       return '<' + type + '>\n' + body + '</' + type + '>\n';
17357     };
17358     
17359     Renderer.prototype.listitem = function(text) {
17360       return '<li>' + text + '</li>\n';
17361     };
17362     
17363     Renderer.prototype.paragraph = function(text) {
17364       return '<p>' + text + '</p>\n';
17365     };
17366     
17367     Renderer.prototype.table = function(header, body) {
17368       return '<table class="table table-striped">\n'
17369         + '<thead>\n'
17370         + header
17371         + '</thead>\n'
17372         + '<tbody>\n'
17373         + body
17374         + '</tbody>\n'
17375         + '</table>\n';
17376     };
17377     
17378     Renderer.prototype.tablerow = function(content) {
17379       return '<tr>\n' + content + '</tr>\n';
17380     };
17381     
17382     Renderer.prototype.tablecell = function(content, flags) {
17383       var type = flags.header ? 'th' : 'td';
17384       var tag = flags.align
17385         ? '<' + type + ' style="text-align:' + flags.align + '">'
17386         : '<' + type + '>';
17387       return tag + content + '</' + type + '>\n';
17388     };
17389     
17390     // span level renderer
17391     Renderer.prototype.strong = function(text) {
17392       return '<strong>' + text + '</strong>';
17393     };
17394     
17395     Renderer.prototype.em = function(text) {
17396       return '<em>' + text + '</em>';
17397     };
17398     
17399     Renderer.prototype.codespan = function(text) {
17400       return '<code>' + text + '</code>';
17401     };
17402     
17403     Renderer.prototype.br = function() {
17404       return this.options.xhtml ? '<br/>' : '<br>';
17405     };
17406     
17407     Renderer.prototype.del = function(text) {
17408       return '<del>' + text + '</del>';
17409     };
17410     
17411     Renderer.prototype.link = function(href, title, text) {
17412       if (this.options.sanitize) {
17413         try {
17414           var prot = decodeURIComponent(unescape(href))
17415             .replace(/[^\w:]/g, '')
17416             .toLowerCase();
17417         } catch (e) {
17418           return '';
17419         }
17420         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17421           return '';
17422         }
17423       }
17424       var out = '<a href="' + href + '"';
17425       if (title) {
17426         out += ' title="' + title + '"';
17427       }
17428       out += '>' + text + '</a>';
17429       return out;
17430     };
17431     
17432     Renderer.prototype.image = function(href, title, text) {
17433       var out = '<img src="' + href + '" alt="' + text + '"';
17434       if (title) {
17435         out += ' title="' + title + '"';
17436       }
17437       out += this.options.xhtml ? '/>' : '>';
17438       return out;
17439     };
17440     
17441     Renderer.prototype.text = function(text) {
17442       return text;
17443     };
17444     
17445     /**
17446      * Parsing & Compiling
17447      */
17448     
17449     function Parser(options) {
17450       this.tokens = [];
17451       this.token = null;
17452       this.options = options || marked.defaults;
17453       this.options.renderer = this.options.renderer || new Renderer;
17454       this.renderer = this.options.renderer;
17455       this.renderer.options = this.options;
17456     }
17457     
17458     /**
17459      * Static Parse Method
17460      */
17461     
17462     Parser.parse = function(src, options, renderer) {
17463       var parser = new Parser(options, renderer);
17464       return parser.parse(src);
17465     };
17466     
17467     /**
17468      * Parse Loop
17469      */
17470     
17471     Parser.prototype.parse = function(src) {
17472       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17473       this.tokens = src.reverse();
17474     
17475       var out = '';
17476       while (this.next()) {
17477         out += this.tok();
17478       }
17479     
17480       return out;
17481     };
17482     
17483     /**
17484      * Next Token
17485      */
17486     
17487     Parser.prototype.next = function() {
17488       return this.token = this.tokens.pop();
17489     };
17490     
17491     /**
17492      * Preview Next Token
17493      */
17494     
17495     Parser.prototype.peek = function() {
17496       return this.tokens[this.tokens.length - 1] || 0;
17497     };
17498     
17499     /**
17500      * Parse Text Tokens
17501      */
17502     
17503     Parser.prototype.parseText = function() {
17504       var body = this.token.text;
17505     
17506       while (this.peek().type === 'text') {
17507         body += '\n' + this.next().text;
17508       }
17509     
17510       return this.inline.output(body);
17511     };
17512     
17513     /**
17514      * Parse Current Token
17515      */
17516     
17517     Parser.prototype.tok = function() {
17518       switch (this.token.type) {
17519         case 'space': {
17520           return '';
17521         }
17522         case 'hr': {
17523           return this.renderer.hr();
17524         }
17525         case 'heading': {
17526           return this.renderer.heading(
17527             this.inline.output(this.token.text),
17528             this.token.depth,
17529             this.token.text);
17530         }
17531         case 'code': {
17532           return this.renderer.code(this.token.text,
17533             this.token.lang,
17534             this.token.escaped);
17535         }
17536         case 'table': {
17537           var header = ''
17538             , body = ''
17539             , i
17540             , row
17541             , cell
17542             , flags
17543             , j;
17544     
17545           // header
17546           cell = '';
17547           for (i = 0; i < this.token.header.length; i++) {
17548             flags = { header: true, align: this.token.align[i] };
17549             cell += this.renderer.tablecell(
17550               this.inline.output(this.token.header[i]),
17551               { header: true, align: this.token.align[i] }
17552             );
17553           }
17554           header += this.renderer.tablerow(cell);
17555     
17556           for (i = 0; i < this.token.cells.length; i++) {
17557             row = this.token.cells[i];
17558     
17559             cell = '';
17560             for (j = 0; j < row.length; j++) {
17561               cell += this.renderer.tablecell(
17562                 this.inline.output(row[j]),
17563                 { header: false, align: this.token.align[j] }
17564               );
17565             }
17566     
17567             body += this.renderer.tablerow(cell);
17568           }
17569           return this.renderer.table(header, body);
17570         }
17571         case 'blockquote_start': {
17572           var body = '';
17573     
17574           while (this.next().type !== 'blockquote_end') {
17575             body += this.tok();
17576           }
17577     
17578           return this.renderer.blockquote(body);
17579         }
17580         case 'list_start': {
17581           var body = ''
17582             , ordered = this.token.ordered;
17583     
17584           while (this.next().type !== 'list_end') {
17585             body += this.tok();
17586           }
17587     
17588           return this.renderer.list(body, ordered);
17589         }
17590         case 'list_item_start': {
17591           var body = '';
17592     
17593           while (this.next().type !== 'list_item_end') {
17594             body += this.token.type === 'text'
17595               ? this.parseText()
17596               : this.tok();
17597           }
17598     
17599           return this.renderer.listitem(body);
17600         }
17601         case 'loose_item_start': {
17602           var body = '';
17603     
17604           while (this.next().type !== 'list_item_end') {
17605             body += this.tok();
17606           }
17607     
17608           return this.renderer.listitem(body);
17609         }
17610         case 'html': {
17611           var html = !this.token.pre && !this.options.pedantic
17612             ? this.inline.output(this.token.text)
17613             : this.token.text;
17614           return this.renderer.html(html);
17615         }
17616         case 'paragraph': {
17617           return this.renderer.paragraph(this.inline.output(this.token.text));
17618         }
17619         case 'text': {
17620           return this.renderer.paragraph(this.parseText());
17621         }
17622       }
17623     };
17624     
17625     /**
17626      * Helpers
17627      */
17628     
17629     function escape(html, encode) {
17630       return html
17631         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17632         .replace(/</g, '&lt;')
17633         .replace(/>/g, '&gt;')
17634         .replace(/"/g, '&quot;')
17635         .replace(/'/g, '&#39;');
17636     }
17637     
17638     function unescape(html) {
17639         // explicitly match decimal, hex, and named HTML entities 
17640       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17641         n = n.toLowerCase();
17642         if (n === 'colon') { return ':'; }
17643         if (n.charAt(0) === '#') {
17644           return n.charAt(1) === 'x'
17645             ? String.fromCharCode(parseInt(n.substring(2), 16))
17646             : String.fromCharCode(+n.substring(1));
17647         }
17648         return '';
17649       });
17650     }
17651     
17652     function replace(regex, opt) {
17653       regex = regex.source;
17654       opt = opt || '';
17655       return function self(name, val) {
17656         if (!name) { return new RegExp(regex, opt); }
17657         val = val.source || val;
17658         val = val.replace(/(^|[^\[])\^/g, '$1');
17659         regex = regex.replace(name, val);
17660         return self;
17661       };
17662     }
17663     
17664     function noop() {}
17665     noop.exec = noop;
17666     
17667     function merge(obj) {
17668       var i = 1
17669         , target
17670         , key;
17671     
17672       for (; i < arguments.length; i++) {
17673         target = arguments[i];
17674         for (key in target) {
17675           if (Object.prototype.hasOwnProperty.call(target, key)) {
17676             obj[key] = target[key];
17677           }
17678         }
17679       }
17680     
17681       return obj;
17682     }
17683     
17684     
17685     /**
17686      * Marked
17687      */
17688     
17689     function marked(src, opt, callback) {
17690       if (callback || typeof opt === 'function') {
17691         if (!callback) {
17692           callback = opt;
17693           opt = null;
17694         }
17695     
17696         opt = merge({}, marked.defaults, opt || {});
17697     
17698         var highlight = opt.highlight
17699           , tokens
17700           , pending
17701           , i = 0;
17702     
17703         try {
17704           tokens = Lexer.lex(src, opt)
17705         } catch (e) {
17706           return callback(e);
17707         }
17708     
17709         pending = tokens.length;
17710     
17711         var done = function(err) {
17712           if (err) {
17713             opt.highlight = highlight;
17714             return callback(err);
17715           }
17716     
17717           var out;
17718     
17719           try {
17720             out = Parser.parse(tokens, opt);
17721           } catch (e) {
17722             err = e;
17723           }
17724     
17725           opt.highlight = highlight;
17726     
17727           return err
17728             ? callback(err)
17729             : callback(null, out);
17730         };
17731     
17732         if (!highlight || highlight.length < 3) {
17733           return done();
17734         }
17735     
17736         delete opt.highlight;
17737     
17738         if (!pending) { return done(); }
17739     
17740         for (; i < tokens.length; i++) {
17741           (function(token) {
17742             if (token.type !== 'code') {
17743               return --pending || done();
17744             }
17745             return highlight(token.text, token.lang, function(err, code) {
17746               if (err) { return done(err); }
17747               if (code == null || code === token.text) {
17748                 return --pending || done();
17749               }
17750               token.text = code;
17751               token.escaped = true;
17752               --pending || done();
17753             });
17754           })(tokens[i]);
17755         }
17756     
17757         return;
17758       }
17759       try {
17760         if (opt) { opt = merge({}, marked.defaults, opt); }
17761         return Parser.parse(Lexer.lex(src, opt), opt);
17762       } catch (e) {
17763         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17764         if ((opt || marked.defaults).silent) {
17765           return '<p>An error occured:</p><pre>'
17766             + escape(e.message + '', true)
17767             + '</pre>';
17768         }
17769         throw e;
17770       }
17771     }
17772     
17773     /**
17774      * Options
17775      */
17776     
17777     marked.options =
17778     marked.setOptions = function(opt) {
17779       merge(marked.defaults, opt);
17780       return marked;
17781     };
17782     
17783     marked.defaults = {
17784       gfm: true,
17785       tables: true,
17786       breaks: false,
17787       pedantic: false,
17788       sanitize: false,
17789       sanitizer: null,
17790       mangle: true,
17791       smartLists: false,
17792       silent: false,
17793       highlight: null,
17794       langPrefix: 'lang-',
17795       smartypants: false,
17796       headerPrefix: '',
17797       renderer: new Renderer,
17798       xhtml: false
17799     };
17800     
17801     /**
17802      * Expose
17803      */
17804     
17805     marked.Parser = Parser;
17806     marked.parser = Parser.parse;
17807     
17808     marked.Renderer = Renderer;
17809     
17810     marked.Lexer = Lexer;
17811     marked.lexer = Lexer.lex;
17812     
17813     marked.InlineLexer = InlineLexer;
17814     marked.inlineLexer = InlineLexer.output;
17815     
17816     marked.parse = marked;
17817     
17818     Roo.Markdown.marked = marked;
17819
17820 })();/*
17821  * Based on:
17822  * Ext JS Library 1.1.1
17823  * Copyright(c) 2006-2007, Ext JS, LLC.
17824  *
17825  * Originally Released Under LGPL - original licence link has changed is not relivant.
17826  *
17827  * Fork - LGPL
17828  * <script type="text/javascript">
17829  */
17830
17831
17832
17833 /*
17834  * These classes are derivatives of the similarly named classes in the YUI Library.
17835  * The original license:
17836  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17837  * Code licensed under the BSD License:
17838  * http://developer.yahoo.net/yui/license.txt
17839  */
17840
17841 (function() {
17842
17843 var Event=Roo.EventManager;
17844 var Dom=Roo.lib.Dom;
17845
17846 /**
17847  * @class Roo.dd.DragDrop
17848  * @extends Roo.util.Observable
17849  * Defines the interface and base operation of items that that can be
17850  * dragged or can be drop targets.  It was designed to be extended, overriding
17851  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17852  * Up to three html elements can be associated with a DragDrop instance:
17853  * <ul>
17854  * <li>linked element: the element that is passed into the constructor.
17855  * This is the element which defines the boundaries for interaction with
17856  * other DragDrop objects.</li>
17857  * <li>handle element(s): The drag operation only occurs if the element that
17858  * was clicked matches a handle element.  By default this is the linked
17859  * element, but there are times that you will want only a portion of the
17860  * linked element to initiate the drag operation, and the setHandleElId()
17861  * method provides a way to define this.</li>
17862  * <li>drag element: this represents the element that would be moved along
17863  * with the cursor during a drag operation.  By default, this is the linked
17864  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
17865  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17866  * </li>
17867  * </ul>
17868  * This class should not be instantiated until the onload event to ensure that
17869  * the associated elements are available.
17870  * The following would define a DragDrop obj that would interact with any
17871  * other DragDrop obj in the "group1" group:
17872  * <pre>
17873  *  dd = new Roo.dd.DragDrop("div1", "group1");
17874  * </pre>
17875  * Since none of the event handlers have been implemented, nothing would
17876  * actually happen if you were to run the code above.  Normally you would
17877  * override this class or one of the default implementations, but you can
17878  * also override the methods you want on an instance of the class...
17879  * <pre>
17880  *  dd.onDragDrop = function(e, id) {
17881  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
17882  *  }
17883  * </pre>
17884  * @constructor
17885  * @param {String} id of the element that is linked to this instance
17886  * @param {String} sGroup the group of related DragDrop objects
17887  * @param {object} config an object containing configurable attributes
17888  *                Valid properties for DragDrop:
17889  *                    padding, isTarget, maintainOffset, primaryButtonOnly
17890  */
17891 Roo.dd.DragDrop = function(id, sGroup, config) {
17892     if (id) {
17893         this.init(id, sGroup, config);
17894     }
17895     
17896 };
17897
17898 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
17899
17900     /**
17901      * The id of the element associated with this object.  This is what we
17902      * refer to as the "linked element" because the size and position of
17903      * this element is used to determine when the drag and drop objects have
17904      * interacted.
17905      * @property id
17906      * @type String
17907      */
17908     id: null,
17909
17910     /**
17911      * Configuration attributes passed into the constructor
17912      * @property config
17913      * @type object
17914      */
17915     config: null,
17916
17917     /**
17918      * The id of the element that will be dragged.  By default this is same
17919      * as the linked element , but could be changed to another element. Ex:
17920      * Roo.dd.DDProxy
17921      * @property dragElId
17922      * @type String
17923      * @private
17924      */
17925     dragElId: null,
17926
17927     /**
17928      * the id of the element that initiates the drag operation.  By default
17929      * this is the linked element, but could be changed to be a child of this
17930      * element.  This lets us do things like only starting the drag when the
17931      * header element within the linked html element is clicked.
17932      * @property handleElId
17933      * @type String
17934      * @private
17935      */
17936     handleElId: null,
17937
17938     /**
17939      * An associative array of HTML tags that will be ignored if clicked.
17940      * @property invalidHandleTypes
17941      * @type {string: string}
17942      */
17943     invalidHandleTypes: null,
17944
17945     /**
17946      * An associative array of ids for elements that will be ignored if clicked
17947      * @property invalidHandleIds
17948      * @type {string: string}
17949      */
17950     invalidHandleIds: null,
17951
17952     /**
17953      * An indexted array of css class names for elements that will be ignored
17954      * if clicked.
17955      * @property invalidHandleClasses
17956      * @type string[]
17957      */
17958     invalidHandleClasses: null,
17959
17960     /**
17961      * The linked element's absolute X position at the time the drag was
17962      * started
17963      * @property startPageX
17964      * @type int
17965      * @private
17966      */
17967     startPageX: 0,
17968
17969     /**
17970      * The linked element's absolute X position at the time the drag was
17971      * started
17972      * @property startPageY
17973      * @type int
17974      * @private
17975      */
17976     startPageY: 0,
17977
17978     /**
17979      * The group defines a logical collection of DragDrop objects that are
17980      * related.  Instances only get events when interacting with other
17981      * DragDrop object in the same group.  This lets us define multiple
17982      * groups using a single DragDrop subclass if we want.
17983      * @property groups
17984      * @type {string: string}
17985      */
17986     groups: null,
17987
17988     /**
17989      * Individual drag/drop instances can be locked.  This will prevent
17990      * onmousedown start drag.
17991      * @property locked
17992      * @type boolean
17993      * @private
17994      */
17995     locked: false,
17996
17997     /**
17998      * Lock this instance
17999      * @method lock
18000      */
18001     lock: function() { this.locked = true; },
18002
18003     /**
18004      * Unlock this instace
18005      * @method unlock
18006      */
18007     unlock: function() { this.locked = false; },
18008
18009     /**
18010      * By default, all insances can be a drop target.  This can be disabled by
18011      * setting isTarget to false.
18012      * @method isTarget
18013      * @type boolean
18014      */
18015     isTarget: true,
18016
18017     /**
18018      * The padding configured for this drag and drop object for calculating
18019      * the drop zone intersection with this object.
18020      * @method padding
18021      * @type int[]
18022      */
18023     padding: null,
18024
18025     /**
18026      * Cached reference to the linked element
18027      * @property _domRef
18028      * @private
18029      */
18030     _domRef: null,
18031
18032     /**
18033      * Internal typeof flag
18034      * @property __ygDragDrop
18035      * @private
18036      */
18037     __ygDragDrop: true,
18038
18039     /**
18040      * Set to true when horizontal contraints are applied
18041      * @property constrainX
18042      * @type boolean
18043      * @private
18044      */
18045     constrainX: false,
18046
18047     /**
18048      * Set to true when vertical contraints are applied
18049      * @property constrainY
18050      * @type boolean
18051      * @private
18052      */
18053     constrainY: false,
18054
18055     /**
18056      * The left constraint
18057      * @property minX
18058      * @type int
18059      * @private
18060      */
18061     minX: 0,
18062
18063     /**
18064      * The right constraint
18065      * @property maxX
18066      * @type int
18067      * @private
18068      */
18069     maxX: 0,
18070
18071     /**
18072      * The up constraint
18073      * @property minY
18074      * @type int
18075      * @type int
18076      * @private
18077      */
18078     minY: 0,
18079
18080     /**
18081      * The down constraint
18082      * @property maxY
18083      * @type int
18084      * @private
18085      */
18086     maxY: 0,
18087
18088     /**
18089      * Maintain offsets when we resetconstraints.  Set to true when you want
18090      * the position of the element relative to its parent to stay the same
18091      * when the page changes
18092      *
18093      * @property maintainOffset
18094      * @type boolean
18095      */
18096     maintainOffset: false,
18097
18098     /**
18099      * Array of pixel locations the element will snap to if we specified a
18100      * horizontal graduation/interval.  This array is generated automatically
18101      * when you define a tick interval.
18102      * @property xTicks
18103      * @type int[]
18104      */
18105     xTicks: null,
18106
18107     /**
18108      * Array of pixel locations the element will snap to if we specified a
18109      * vertical graduation/interval.  This array is generated automatically
18110      * when you define a tick interval.
18111      * @property yTicks
18112      * @type int[]
18113      */
18114     yTicks: null,
18115
18116     /**
18117      * By default the drag and drop instance will only respond to the primary
18118      * button click (left button for a right-handed mouse).  Set to true to
18119      * allow drag and drop to start with any mouse click that is propogated
18120      * by the browser
18121      * @property primaryButtonOnly
18122      * @type boolean
18123      */
18124     primaryButtonOnly: true,
18125
18126     /**
18127      * The availabe property is false until the linked dom element is accessible.
18128      * @property available
18129      * @type boolean
18130      */
18131     available: false,
18132
18133     /**
18134      * By default, drags can only be initiated if the mousedown occurs in the
18135      * region the linked element is.  This is done in part to work around a
18136      * bug in some browsers that mis-report the mousedown if the previous
18137      * mouseup happened outside of the window.  This property is set to true
18138      * if outer handles are defined.
18139      *
18140      * @property hasOuterHandles
18141      * @type boolean
18142      * @default false
18143      */
18144     hasOuterHandles: false,
18145
18146     /**
18147      * Code that executes immediately before the startDrag event
18148      * @method b4StartDrag
18149      * @private
18150      */
18151     b4StartDrag: function(x, y) { },
18152
18153     /**
18154      * Abstract method called after a drag/drop object is clicked
18155      * and the drag or mousedown time thresholds have beeen met.
18156      * @method startDrag
18157      * @param {int} X click location
18158      * @param {int} Y click location
18159      */
18160     startDrag: function(x, y) { /* override this */ },
18161
18162     /**
18163      * Code that executes immediately before the onDrag event
18164      * @method b4Drag
18165      * @private
18166      */
18167     b4Drag: function(e) { },
18168
18169     /**
18170      * Abstract method called during the onMouseMove event while dragging an
18171      * object.
18172      * @method onDrag
18173      * @param {Event} e the mousemove event
18174      */
18175     onDrag: function(e) { /* override this */ },
18176
18177     /**
18178      * Abstract method called when this element fist begins hovering over
18179      * another DragDrop obj
18180      * @method onDragEnter
18181      * @param {Event} e the mousemove event
18182      * @param {String|DragDrop[]} id In POINT mode, the element
18183      * id this is hovering over.  In INTERSECT mode, an array of one or more
18184      * dragdrop items being hovered over.
18185      */
18186     onDragEnter: function(e, id) { /* override this */ },
18187
18188     /**
18189      * Code that executes immediately before the onDragOver event
18190      * @method b4DragOver
18191      * @private
18192      */
18193     b4DragOver: function(e) { },
18194
18195     /**
18196      * Abstract method called when this element is hovering over another
18197      * DragDrop obj
18198      * @method onDragOver
18199      * @param {Event} e the mousemove event
18200      * @param {String|DragDrop[]} id In POINT mode, the element
18201      * id this is hovering over.  In INTERSECT mode, an array of dd items
18202      * being hovered over.
18203      */
18204     onDragOver: function(e, id) { /* override this */ },
18205
18206     /**
18207      * Code that executes immediately before the onDragOut event
18208      * @method b4DragOut
18209      * @private
18210      */
18211     b4DragOut: function(e) { },
18212
18213     /**
18214      * Abstract method called when we are no longer hovering over an element
18215      * @method onDragOut
18216      * @param {Event} e the mousemove event
18217      * @param {String|DragDrop[]} id In POINT mode, the element
18218      * id this was hovering over.  In INTERSECT mode, an array of dd items
18219      * that the mouse is no longer over.
18220      */
18221     onDragOut: function(e, id) { /* override this */ },
18222
18223     /**
18224      * Code that executes immediately before the onDragDrop event
18225      * @method b4DragDrop
18226      * @private
18227      */
18228     b4DragDrop: function(e) { },
18229
18230     /**
18231      * Abstract method called when this item is dropped on another DragDrop
18232      * obj
18233      * @method onDragDrop
18234      * @param {Event} e the mouseup event
18235      * @param {String|DragDrop[]} id In POINT mode, the element
18236      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18237      * was dropped on.
18238      */
18239     onDragDrop: function(e, id) { /* override this */ },
18240
18241     /**
18242      * Abstract method called when this item is dropped on an area with no
18243      * drop target
18244      * @method onInvalidDrop
18245      * @param {Event} e the mouseup event
18246      */
18247     onInvalidDrop: function(e) { /* override this */ },
18248
18249     /**
18250      * Code that executes immediately before the endDrag event
18251      * @method b4EndDrag
18252      * @private
18253      */
18254     b4EndDrag: function(e) { },
18255
18256     /**
18257      * Fired when we are done dragging the object
18258      * @method endDrag
18259      * @param {Event} e the mouseup event
18260      */
18261     endDrag: function(e) { /* override this */ },
18262
18263     /**
18264      * Code executed immediately before the onMouseDown event
18265      * @method b4MouseDown
18266      * @param {Event} e the mousedown event
18267      * @private
18268      */
18269     b4MouseDown: function(e) {  },
18270
18271     /**
18272      * Event handler that fires when a drag/drop obj gets a mousedown
18273      * @method onMouseDown
18274      * @param {Event} e the mousedown event
18275      */
18276     onMouseDown: function(e) { /* override this */ },
18277
18278     /**
18279      * Event handler that fires when a drag/drop obj gets a mouseup
18280      * @method onMouseUp
18281      * @param {Event} e the mouseup event
18282      */
18283     onMouseUp: function(e) { /* override this */ },
18284
18285     /**
18286      * Override the onAvailable method to do what is needed after the initial
18287      * position was determined.
18288      * @method onAvailable
18289      */
18290     onAvailable: function () {
18291     },
18292
18293     /*
18294      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18295      * @type Object
18296      */
18297     defaultPadding : {left:0, right:0, top:0, bottom:0},
18298
18299     /*
18300      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18301  *
18302  * Usage:
18303  <pre><code>
18304  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18305                 { dragElId: "existingProxyDiv" });
18306  dd.startDrag = function(){
18307      this.constrainTo("parent-id");
18308  };
18309  </code></pre>
18310  * Or you can initalize it using the {@link Roo.Element} object:
18311  <pre><code>
18312  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18313      startDrag : function(){
18314          this.constrainTo("parent-id");
18315      }
18316  });
18317  </code></pre>
18318      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18319      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18320      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18321      * an object containing the sides to pad. For example: {right:10, bottom:10}
18322      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18323      */
18324     constrainTo : function(constrainTo, pad, inContent){
18325         if(typeof pad == "number"){
18326             pad = {left: pad, right:pad, top:pad, bottom:pad};
18327         }
18328         pad = pad || this.defaultPadding;
18329         var b = Roo.get(this.getEl()).getBox();
18330         var ce = Roo.get(constrainTo);
18331         var s = ce.getScroll();
18332         var c, cd = ce.dom;
18333         if(cd == document.body){
18334             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18335         }else{
18336             xy = ce.getXY();
18337             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18338         }
18339
18340
18341         var topSpace = b.y - c.y;
18342         var leftSpace = b.x - c.x;
18343
18344         this.resetConstraints();
18345         this.setXConstraint(leftSpace - (pad.left||0), // left
18346                 c.width - leftSpace - b.width - (pad.right||0) //right
18347         );
18348         this.setYConstraint(topSpace - (pad.top||0), //top
18349                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18350         );
18351     },
18352
18353     /**
18354      * Returns a reference to the linked element
18355      * @method getEl
18356      * @return {HTMLElement} the html element
18357      */
18358     getEl: function() {
18359         if (!this._domRef) {
18360             this._domRef = Roo.getDom(this.id);
18361         }
18362
18363         return this._domRef;
18364     },
18365
18366     /**
18367      * Returns a reference to the actual element to drag.  By default this is
18368      * the same as the html element, but it can be assigned to another
18369      * element. An example of this can be found in Roo.dd.DDProxy
18370      * @method getDragEl
18371      * @return {HTMLElement} the html element
18372      */
18373     getDragEl: function() {
18374         return Roo.getDom(this.dragElId);
18375     },
18376
18377     /**
18378      * Sets up the DragDrop object.  Must be called in the constructor of any
18379      * Roo.dd.DragDrop subclass
18380      * @method init
18381      * @param id the id of the linked element
18382      * @param {String} sGroup the group of related items
18383      * @param {object} config configuration attributes
18384      */
18385     init: function(id, sGroup, config) {
18386         this.initTarget(id, sGroup, config);
18387         if (!Roo.isTouch) {
18388             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18389         }
18390         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18391         // Event.on(this.id, "selectstart", Event.preventDefault);
18392     },
18393
18394     /**
18395      * Initializes Targeting functionality only... the object does not
18396      * get a mousedown handler.
18397      * @method initTarget
18398      * @param id the id of the linked element
18399      * @param {String} sGroup the group of related items
18400      * @param {object} config configuration attributes
18401      */
18402     initTarget: function(id, sGroup, config) {
18403
18404         // configuration attributes
18405         this.config = config || {};
18406
18407         // create a local reference to the drag and drop manager
18408         this.DDM = Roo.dd.DDM;
18409         // initialize the groups array
18410         this.groups = {};
18411
18412         // assume that we have an element reference instead of an id if the
18413         // parameter is not a string
18414         if (typeof id !== "string") {
18415             id = Roo.id(id);
18416         }
18417
18418         // set the id
18419         this.id = id;
18420
18421         // add to an interaction group
18422         this.addToGroup((sGroup) ? sGroup : "default");
18423
18424         // We don't want to register this as the handle with the manager
18425         // so we just set the id rather than calling the setter.
18426         this.handleElId = id;
18427
18428         // the linked element is the element that gets dragged by default
18429         this.setDragElId(id);
18430
18431         // by default, clicked anchors will not start drag operations.
18432         this.invalidHandleTypes = { A: "A" };
18433         this.invalidHandleIds = {};
18434         this.invalidHandleClasses = [];
18435
18436         this.applyConfig();
18437
18438         this.handleOnAvailable();
18439     },
18440
18441     /**
18442      * Applies the configuration parameters that were passed into the constructor.
18443      * This is supposed to happen at each level through the inheritance chain.  So
18444      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18445      * DragDrop in order to get all of the parameters that are available in
18446      * each object.
18447      * @method applyConfig
18448      */
18449     applyConfig: function() {
18450
18451         // configurable properties:
18452         //    padding, isTarget, maintainOffset, primaryButtonOnly
18453         this.padding           = this.config.padding || [0, 0, 0, 0];
18454         this.isTarget          = (this.config.isTarget !== false);
18455         this.maintainOffset    = (this.config.maintainOffset);
18456         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18457
18458     },
18459
18460     /**
18461      * Executed when the linked element is available
18462      * @method handleOnAvailable
18463      * @private
18464      */
18465     handleOnAvailable: function() {
18466         this.available = true;
18467         this.resetConstraints();
18468         this.onAvailable();
18469     },
18470
18471      /**
18472      * Configures the padding for the target zone in px.  Effectively expands
18473      * (or reduces) the virtual object size for targeting calculations.
18474      * Supports css-style shorthand; if only one parameter is passed, all sides
18475      * will have that padding, and if only two are passed, the top and bottom
18476      * will have the first param, the left and right the second.
18477      * @method setPadding
18478      * @param {int} iTop    Top pad
18479      * @param {int} iRight  Right pad
18480      * @param {int} iBot    Bot pad
18481      * @param {int} iLeft   Left pad
18482      */
18483     setPadding: function(iTop, iRight, iBot, iLeft) {
18484         // this.padding = [iLeft, iRight, iTop, iBot];
18485         if (!iRight && 0 !== iRight) {
18486             this.padding = [iTop, iTop, iTop, iTop];
18487         } else if (!iBot && 0 !== iBot) {
18488             this.padding = [iTop, iRight, iTop, iRight];
18489         } else {
18490             this.padding = [iTop, iRight, iBot, iLeft];
18491         }
18492     },
18493
18494     /**
18495      * Stores the initial placement of the linked element.
18496      * @method setInitialPosition
18497      * @param {int} diffX   the X offset, default 0
18498      * @param {int} diffY   the Y offset, default 0
18499      */
18500     setInitPosition: function(diffX, diffY) {
18501         var el = this.getEl();
18502
18503         if (!this.DDM.verifyEl(el)) {
18504             return;
18505         }
18506
18507         var dx = diffX || 0;
18508         var dy = diffY || 0;
18509
18510         var p = Dom.getXY( el );
18511
18512         this.initPageX = p[0] - dx;
18513         this.initPageY = p[1] - dy;
18514
18515         this.lastPageX = p[0];
18516         this.lastPageY = p[1];
18517
18518
18519         this.setStartPosition(p);
18520     },
18521
18522     /**
18523      * Sets the start position of the element.  This is set when the obj
18524      * is initialized, the reset when a drag is started.
18525      * @method setStartPosition
18526      * @param pos current position (from previous lookup)
18527      * @private
18528      */
18529     setStartPosition: function(pos) {
18530         var p = pos || Dom.getXY( this.getEl() );
18531         this.deltaSetXY = null;
18532
18533         this.startPageX = p[0];
18534         this.startPageY = p[1];
18535     },
18536
18537     /**
18538      * Add this instance to a group of related drag/drop objects.  All
18539      * instances belong to at least one group, and can belong to as many
18540      * groups as needed.
18541      * @method addToGroup
18542      * @param sGroup {string} the name of the group
18543      */
18544     addToGroup: function(sGroup) {
18545         this.groups[sGroup] = true;
18546         this.DDM.regDragDrop(this, sGroup);
18547     },
18548
18549     /**
18550      * Remove's this instance from the supplied interaction group
18551      * @method removeFromGroup
18552      * @param {string}  sGroup  The group to drop
18553      */
18554     removeFromGroup: function(sGroup) {
18555         if (this.groups[sGroup]) {
18556             delete this.groups[sGroup];
18557         }
18558
18559         this.DDM.removeDDFromGroup(this, sGroup);
18560     },
18561
18562     /**
18563      * Allows you to specify that an element other than the linked element
18564      * will be moved with the cursor during a drag
18565      * @method setDragElId
18566      * @param id {string} the id of the element that will be used to initiate the drag
18567      */
18568     setDragElId: function(id) {
18569         this.dragElId = id;
18570     },
18571
18572     /**
18573      * Allows you to specify a child of the linked element that should be
18574      * used to initiate the drag operation.  An example of this would be if
18575      * you have a content div with text and links.  Clicking anywhere in the
18576      * content area would normally start the drag operation.  Use this method
18577      * to specify that an element inside of the content div is the element
18578      * that starts the drag operation.
18579      * @method setHandleElId
18580      * @param id {string} the id of the element that will be used to
18581      * initiate the drag.
18582      */
18583     setHandleElId: function(id) {
18584         if (typeof id !== "string") {
18585             id = Roo.id(id);
18586         }
18587         this.handleElId = id;
18588         this.DDM.regHandle(this.id, id);
18589     },
18590
18591     /**
18592      * Allows you to set an element outside of the linked element as a drag
18593      * handle
18594      * @method setOuterHandleElId
18595      * @param id the id of the element that will be used to initiate the drag
18596      */
18597     setOuterHandleElId: function(id) {
18598         if (typeof id !== "string") {
18599             id = Roo.id(id);
18600         }
18601         Event.on(id, "mousedown",
18602                 this.handleMouseDown, this);
18603         this.setHandleElId(id);
18604
18605         this.hasOuterHandles = true;
18606     },
18607
18608     /**
18609      * Remove all drag and drop hooks for this element
18610      * @method unreg
18611      */
18612     unreg: function() {
18613         Event.un(this.id, "mousedown",
18614                 this.handleMouseDown);
18615         Event.un(this.id, "touchstart",
18616                 this.handleMouseDown);
18617         this._domRef = null;
18618         this.DDM._remove(this);
18619     },
18620
18621     destroy : function(){
18622         this.unreg();
18623     },
18624
18625     /**
18626      * Returns true if this instance is locked, or the drag drop mgr is locked
18627      * (meaning that all drag/drop is disabled on the page.)
18628      * @method isLocked
18629      * @return {boolean} true if this obj or all drag/drop is locked, else
18630      * false
18631      */
18632     isLocked: function() {
18633         return (this.DDM.isLocked() || this.locked);
18634     },
18635
18636     /**
18637      * Fired when this object is clicked
18638      * @method handleMouseDown
18639      * @param {Event} e
18640      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18641      * @private
18642      */
18643     handleMouseDown: function(e, oDD){
18644      
18645         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18646             //Roo.log('not touch/ button !=0');
18647             return;
18648         }
18649         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18650             return; // double touch..
18651         }
18652         
18653
18654         if (this.isLocked()) {
18655             //Roo.log('locked');
18656             return;
18657         }
18658
18659         this.DDM.refreshCache(this.groups);
18660 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18661         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18662         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18663             //Roo.log('no outer handes or not over target');
18664                 // do nothing.
18665         } else {
18666 //            Roo.log('check validator');
18667             if (this.clickValidator(e)) {
18668 //                Roo.log('validate success');
18669                 // set the initial element position
18670                 this.setStartPosition();
18671
18672
18673                 this.b4MouseDown(e);
18674                 this.onMouseDown(e);
18675
18676                 this.DDM.handleMouseDown(e, this);
18677
18678                 this.DDM.stopEvent(e);
18679             } else {
18680
18681
18682             }
18683         }
18684     },
18685
18686     clickValidator: function(e) {
18687         var target = e.getTarget();
18688         return ( this.isValidHandleChild(target) &&
18689                     (this.id == this.handleElId ||
18690                         this.DDM.handleWasClicked(target, this.id)) );
18691     },
18692
18693     /**
18694      * Allows you to specify a tag name that should not start a drag operation
18695      * when clicked.  This is designed to facilitate embedding links within a
18696      * drag handle that do something other than start the drag.
18697      * @method addInvalidHandleType
18698      * @param {string} tagName the type of element to exclude
18699      */
18700     addInvalidHandleType: function(tagName) {
18701         var type = tagName.toUpperCase();
18702         this.invalidHandleTypes[type] = type;
18703     },
18704
18705     /**
18706      * Lets you to specify an element id for a child of a drag handle
18707      * that should not initiate a drag
18708      * @method addInvalidHandleId
18709      * @param {string} id the element id of the element you wish to ignore
18710      */
18711     addInvalidHandleId: function(id) {
18712         if (typeof id !== "string") {
18713             id = Roo.id(id);
18714         }
18715         this.invalidHandleIds[id] = id;
18716     },
18717
18718     /**
18719      * Lets you specify a css class of elements that will not initiate a drag
18720      * @method addInvalidHandleClass
18721      * @param {string} cssClass the class of the elements you wish to ignore
18722      */
18723     addInvalidHandleClass: function(cssClass) {
18724         this.invalidHandleClasses.push(cssClass);
18725     },
18726
18727     /**
18728      * Unsets an excluded tag name set by addInvalidHandleType
18729      * @method removeInvalidHandleType
18730      * @param {string} tagName the type of element to unexclude
18731      */
18732     removeInvalidHandleType: function(tagName) {
18733         var type = tagName.toUpperCase();
18734         // this.invalidHandleTypes[type] = null;
18735         delete this.invalidHandleTypes[type];
18736     },
18737
18738     /**
18739      * Unsets an invalid handle id
18740      * @method removeInvalidHandleId
18741      * @param {string} id the id of the element to re-enable
18742      */
18743     removeInvalidHandleId: function(id) {
18744         if (typeof id !== "string") {
18745             id = Roo.id(id);
18746         }
18747         delete this.invalidHandleIds[id];
18748     },
18749
18750     /**
18751      * Unsets an invalid css class
18752      * @method removeInvalidHandleClass
18753      * @param {string} cssClass the class of the element(s) you wish to
18754      * re-enable
18755      */
18756     removeInvalidHandleClass: function(cssClass) {
18757         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18758             if (this.invalidHandleClasses[i] == cssClass) {
18759                 delete this.invalidHandleClasses[i];
18760             }
18761         }
18762     },
18763
18764     /**
18765      * Checks the tag exclusion list to see if this click should be ignored
18766      * @method isValidHandleChild
18767      * @param {HTMLElement} node the HTMLElement to evaluate
18768      * @return {boolean} true if this is a valid tag type, false if not
18769      */
18770     isValidHandleChild: function(node) {
18771
18772         var valid = true;
18773         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18774         var nodeName;
18775         try {
18776             nodeName = node.nodeName.toUpperCase();
18777         } catch(e) {
18778             nodeName = node.nodeName;
18779         }
18780         valid = valid && !this.invalidHandleTypes[nodeName];
18781         valid = valid && !this.invalidHandleIds[node.id];
18782
18783         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18784             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18785         }
18786
18787
18788         return valid;
18789
18790     },
18791
18792     /**
18793      * Create the array of horizontal tick marks if an interval was specified
18794      * in setXConstraint().
18795      * @method setXTicks
18796      * @private
18797      */
18798     setXTicks: function(iStartX, iTickSize) {
18799         this.xTicks = [];
18800         this.xTickSize = iTickSize;
18801
18802         var tickMap = {};
18803
18804         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18805             if (!tickMap[i]) {
18806                 this.xTicks[this.xTicks.length] = i;
18807                 tickMap[i] = true;
18808             }
18809         }
18810
18811         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18812             if (!tickMap[i]) {
18813                 this.xTicks[this.xTicks.length] = i;
18814                 tickMap[i] = true;
18815             }
18816         }
18817
18818         this.xTicks.sort(this.DDM.numericSort) ;
18819     },
18820
18821     /**
18822      * Create the array of vertical tick marks if an interval was specified in
18823      * setYConstraint().
18824      * @method setYTicks
18825      * @private
18826      */
18827     setYTicks: function(iStartY, iTickSize) {
18828         this.yTicks = [];
18829         this.yTickSize = iTickSize;
18830
18831         var tickMap = {};
18832
18833         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18834             if (!tickMap[i]) {
18835                 this.yTicks[this.yTicks.length] = i;
18836                 tickMap[i] = true;
18837             }
18838         }
18839
18840         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18841             if (!tickMap[i]) {
18842                 this.yTicks[this.yTicks.length] = i;
18843                 tickMap[i] = true;
18844             }
18845         }
18846
18847         this.yTicks.sort(this.DDM.numericSort) ;
18848     },
18849
18850     /**
18851      * By default, the element can be dragged any place on the screen.  Use
18852      * this method to limit the horizontal travel of the element.  Pass in
18853      * 0,0 for the parameters if you want to lock the drag to the y axis.
18854      * @method setXConstraint
18855      * @param {int} iLeft the number of pixels the element can move to the left
18856      * @param {int} iRight the number of pixels the element can move to the
18857      * right
18858      * @param {int} iTickSize optional parameter for specifying that the
18859      * element
18860      * should move iTickSize pixels at a time.
18861      */
18862     setXConstraint: function(iLeft, iRight, iTickSize) {
18863         this.leftConstraint = iLeft;
18864         this.rightConstraint = iRight;
18865
18866         this.minX = this.initPageX - iLeft;
18867         this.maxX = this.initPageX + iRight;
18868         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18869
18870         this.constrainX = true;
18871     },
18872
18873     /**
18874      * Clears any constraints applied to this instance.  Also clears ticks
18875      * since they can't exist independent of a constraint at this time.
18876      * @method clearConstraints
18877      */
18878     clearConstraints: function() {
18879         this.constrainX = false;
18880         this.constrainY = false;
18881         this.clearTicks();
18882     },
18883
18884     /**
18885      * Clears any tick interval defined for this instance
18886      * @method clearTicks
18887      */
18888     clearTicks: function() {
18889         this.xTicks = null;
18890         this.yTicks = null;
18891         this.xTickSize = 0;
18892         this.yTickSize = 0;
18893     },
18894
18895     /**
18896      * By default, the element can be dragged any place on the screen.  Set
18897      * this to limit the vertical travel of the element.  Pass in 0,0 for the
18898      * parameters if you want to lock the drag to the x axis.
18899      * @method setYConstraint
18900      * @param {int} iUp the number of pixels the element can move up
18901      * @param {int} iDown the number of pixels the element can move down
18902      * @param {int} iTickSize optional parameter for specifying that the
18903      * element should move iTickSize pixels at a time.
18904      */
18905     setYConstraint: function(iUp, iDown, iTickSize) {
18906         this.topConstraint = iUp;
18907         this.bottomConstraint = iDown;
18908
18909         this.minY = this.initPageY - iUp;
18910         this.maxY = this.initPageY + iDown;
18911         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
18912
18913         this.constrainY = true;
18914
18915     },
18916
18917     /**
18918      * resetConstraints must be called if you manually reposition a dd element.
18919      * @method resetConstraints
18920      * @param {boolean} maintainOffset
18921      */
18922     resetConstraints: function() {
18923
18924
18925         // Maintain offsets if necessary
18926         if (this.initPageX || this.initPageX === 0) {
18927             // figure out how much this thing has moved
18928             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
18929             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
18930
18931             this.setInitPosition(dx, dy);
18932
18933         // This is the first time we have detected the element's position
18934         } else {
18935             this.setInitPosition();
18936         }
18937
18938         if (this.constrainX) {
18939             this.setXConstraint( this.leftConstraint,
18940                                  this.rightConstraint,
18941                                  this.xTickSize        );
18942         }
18943
18944         if (this.constrainY) {
18945             this.setYConstraint( this.topConstraint,
18946                                  this.bottomConstraint,
18947                                  this.yTickSize         );
18948         }
18949     },
18950
18951     /**
18952      * Normally the drag element is moved pixel by pixel, but we can specify
18953      * that it move a number of pixels at a time.  This method resolves the
18954      * location when we have it set up like this.
18955      * @method getTick
18956      * @param {int} val where we want to place the object
18957      * @param {int[]} tickArray sorted array of valid points
18958      * @return {int} the closest tick
18959      * @private
18960      */
18961     getTick: function(val, tickArray) {
18962
18963         if (!tickArray) {
18964             // If tick interval is not defined, it is effectively 1 pixel,
18965             // so we return the value passed to us.
18966             return val;
18967         } else if (tickArray[0] >= val) {
18968             // The value is lower than the first tick, so we return the first
18969             // tick.
18970             return tickArray[0];
18971         } else {
18972             for (var i=0, len=tickArray.length; i<len; ++i) {
18973                 var next = i + 1;
18974                 if (tickArray[next] && tickArray[next] >= val) {
18975                     var diff1 = val - tickArray[i];
18976                     var diff2 = tickArray[next] - val;
18977                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
18978                 }
18979             }
18980
18981             // The value is larger than the last tick, so we return the last
18982             // tick.
18983             return tickArray[tickArray.length - 1];
18984         }
18985     },
18986
18987     /**
18988      * toString method
18989      * @method toString
18990      * @return {string} string representation of the dd obj
18991      */
18992     toString: function() {
18993         return ("DragDrop " + this.id);
18994     }
18995
18996 });
18997
18998 })();
18999 /*
19000  * Based on:
19001  * Ext JS Library 1.1.1
19002  * Copyright(c) 2006-2007, Ext JS, LLC.
19003  *
19004  * Originally Released Under LGPL - original licence link has changed is not relivant.
19005  *
19006  * Fork - LGPL
19007  * <script type="text/javascript">
19008  */
19009
19010
19011 /**
19012  * The drag and drop utility provides a framework for building drag and drop
19013  * applications.  In addition to enabling drag and drop for specific elements,
19014  * the drag and drop elements are tracked by the manager class, and the
19015  * interactions between the various elements are tracked during the drag and
19016  * the implementing code is notified about these important moments.
19017  */
19018
19019 // Only load the library once.  Rewriting the manager class would orphan
19020 // existing drag and drop instances.
19021 if (!Roo.dd.DragDropMgr) {
19022
19023 /**
19024  * @class Roo.dd.DragDropMgr
19025  * DragDropMgr is a singleton that tracks the element interaction for
19026  * all DragDrop items in the window.  Generally, you will not call
19027  * this class directly, but it does have helper methods that could
19028  * be useful in your DragDrop implementations.
19029  * @singleton
19030  */
19031 Roo.dd.DragDropMgr = function() {
19032
19033     var Event = Roo.EventManager;
19034
19035     return {
19036
19037         /**
19038          * Two dimensional Array of registered DragDrop objects.  The first
19039          * dimension is the DragDrop item group, the second the DragDrop
19040          * object.
19041          * @property ids
19042          * @type {string: string}
19043          * @private
19044          * @static
19045          */
19046         ids: {},
19047
19048         /**
19049          * Array of element ids defined as drag handles.  Used to determine
19050          * if the element that generated the mousedown event is actually the
19051          * handle and not the html element itself.
19052          * @property handleIds
19053          * @type {string: string}
19054          * @private
19055          * @static
19056          */
19057         handleIds: {},
19058
19059         /**
19060          * the DragDrop object that is currently being dragged
19061          * @property dragCurrent
19062          * @type DragDrop
19063          * @private
19064          * @static
19065          **/
19066         dragCurrent: null,
19067
19068         /**
19069          * the DragDrop object(s) that are being hovered over
19070          * @property dragOvers
19071          * @type Array
19072          * @private
19073          * @static
19074          */
19075         dragOvers: {},
19076
19077         /**
19078          * the X distance between the cursor and the object being dragged
19079          * @property deltaX
19080          * @type int
19081          * @private
19082          * @static
19083          */
19084         deltaX: 0,
19085
19086         /**
19087          * the Y distance between the cursor and the object being dragged
19088          * @property deltaY
19089          * @type int
19090          * @private
19091          * @static
19092          */
19093         deltaY: 0,
19094
19095         /**
19096          * Flag to determine if we should prevent the default behavior of the
19097          * events we define. By default this is true, but this can be set to
19098          * false if you need the default behavior (not recommended)
19099          * @property preventDefault
19100          * @type boolean
19101          * @static
19102          */
19103         preventDefault: true,
19104
19105         /**
19106          * Flag to determine if we should stop the propagation of the events
19107          * we generate. This is true by default but you may want to set it to
19108          * false if the html element contains other features that require the
19109          * mouse click.
19110          * @property stopPropagation
19111          * @type boolean
19112          * @static
19113          */
19114         stopPropagation: true,
19115
19116         /**
19117          * Internal flag that is set to true when drag and drop has been
19118          * intialized
19119          * @property initialized
19120          * @private
19121          * @static
19122          */
19123         initalized: false,
19124
19125         /**
19126          * All drag and drop can be disabled.
19127          * @property locked
19128          * @private
19129          * @static
19130          */
19131         locked: false,
19132
19133         /**
19134          * Called the first time an element is registered.
19135          * @method init
19136          * @private
19137          * @static
19138          */
19139         init: function() {
19140             this.initialized = true;
19141         },
19142
19143         /**
19144          * In point mode, drag and drop interaction is defined by the
19145          * location of the cursor during the drag/drop
19146          * @property POINT
19147          * @type int
19148          * @static
19149          */
19150         POINT: 0,
19151
19152         /**
19153          * In intersect mode, drag and drop interactio nis defined by the
19154          * overlap of two or more drag and drop objects.
19155          * @property INTERSECT
19156          * @type int
19157          * @static
19158          */
19159         INTERSECT: 1,
19160
19161         /**
19162          * The current drag and drop mode.  Default: POINT
19163          * @property mode
19164          * @type int
19165          * @static
19166          */
19167         mode: 0,
19168
19169         /**
19170          * Runs method on all drag and drop objects
19171          * @method _execOnAll
19172          * @private
19173          * @static
19174          */
19175         _execOnAll: function(sMethod, args) {
19176             for (var i in this.ids) {
19177                 for (var j in this.ids[i]) {
19178                     var oDD = this.ids[i][j];
19179                     if (! this.isTypeOfDD(oDD)) {
19180                         continue;
19181                     }
19182                     oDD[sMethod].apply(oDD, args);
19183                 }
19184             }
19185         },
19186
19187         /**
19188          * Drag and drop initialization.  Sets up the global event handlers
19189          * @method _onLoad
19190          * @private
19191          * @static
19192          */
19193         _onLoad: function() {
19194
19195             this.init();
19196
19197             if (!Roo.isTouch) {
19198                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19199                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19200             }
19201             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19202             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19203             
19204             Event.on(window,   "unload",    this._onUnload, this, true);
19205             Event.on(window,   "resize",    this._onResize, this, true);
19206             // Event.on(window,   "mouseout",    this._test);
19207
19208         },
19209
19210         /**
19211          * Reset constraints on all drag and drop objs
19212          * @method _onResize
19213          * @private
19214          * @static
19215          */
19216         _onResize: function(e) {
19217             this._execOnAll("resetConstraints", []);
19218         },
19219
19220         /**
19221          * Lock all drag and drop functionality
19222          * @method lock
19223          * @static
19224          */
19225         lock: function() { this.locked = true; },
19226
19227         /**
19228          * Unlock all drag and drop functionality
19229          * @method unlock
19230          * @static
19231          */
19232         unlock: function() { this.locked = false; },
19233
19234         /**
19235          * Is drag and drop locked?
19236          * @method isLocked
19237          * @return {boolean} True if drag and drop is locked, false otherwise.
19238          * @static
19239          */
19240         isLocked: function() { return this.locked; },
19241
19242         /**
19243          * Location cache that is set for all drag drop objects when a drag is
19244          * initiated, cleared when the drag is finished.
19245          * @property locationCache
19246          * @private
19247          * @static
19248          */
19249         locationCache: {},
19250
19251         /**
19252          * Set useCache to false if you want to force object the lookup of each
19253          * drag and drop linked element constantly during a drag.
19254          * @property useCache
19255          * @type boolean
19256          * @static
19257          */
19258         useCache: true,
19259
19260         /**
19261          * The number of pixels that the mouse needs to move after the
19262          * mousedown before the drag is initiated.  Default=3;
19263          * @property clickPixelThresh
19264          * @type int
19265          * @static
19266          */
19267         clickPixelThresh: 3,
19268
19269         /**
19270          * The number of milliseconds after the mousedown event to initiate the
19271          * drag if we don't get a mouseup event. Default=1000
19272          * @property clickTimeThresh
19273          * @type int
19274          * @static
19275          */
19276         clickTimeThresh: 350,
19277
19278         /**
19279          * Flag that indicates that either the drag pixel threshold or the
19280          * mousdown time threshold has been met
19281          * @property dragThreshMet
19282          * @type boolean
19283          * @private
19284          * @static
19285          */
19286         dragThreshMet: false,
19287
19288         /**
19289          * Timeout used for the click time threshold
19290          * @property clickTimeout
19291          * @type Object
19292          * @private
19293          * @static
19294          */
19295         clickTimeout: null,
19296
19297         /**
19298          * The X position of the mousedown event stored for later use when a
19299          * drag threshold is met.
19300          * @property startX
19301          * @type int
19302          * @private
19303          * @static
19304          */
19305         startX: 0,
19306
19307         /**
19308          * The Y position of the mousedown event stored for later use when a
19309          * drag threshold is met.
19310          * @property startY
19311          * @type int
19312          * @private
19313          * @static
19314          */
19315         startY: 0,
19316
19317         /**
19318          * Each DragDrop instance must be registered with the DragDropMgr.
19319          * This is executed in DragDrop.init()
19320          * @method regDragDrop
19321          * @param {DragDrop} oDD the DragDrop object to register
19322          * @param {String} sGroup the name of the group this element belongs to
19323          * @static
19324          */
19325         regDragDrop: function(oDD, sGroup) {
19326             if (!this.initialized) { this.init(); }
19327
19328             if (!this.ids[sGroup]) {
19329                 this.ids[sGroup] = {};
19330             }
19331             this.ids[sGroup][oDD.id] = oDD;
19332         },
19333
19334         /**
19335          * Removes the supplied dd instance from the supplied group. Executed
19336          * by DragDrop.removeFromGroup, so don't call this function directly.
19337          * @method removeDDFromGroup
19338          * @private
19339          * @static
19340          */
19341         removeDDFromGroup: function(oDD, sGroup) {
19342             if (!this.ids[sGroup]) {
19343                 this.ids[sGroup] = {};
19344             }
19345
19346             var obj = this.ids[sGroup];
19347             if (obj && obj[oDD.id]) {
19348                 delete obj[oDD.id];
19349             }
19350         },
19351
19352         /**
19353          * Unregisters a drag and drop item.  This is executed in
19354          * DragDrop.unreg, use that method instead of calling this directly.
19355          * @method _remove
19356          * @private
19357          * @static
19358          */
19359         _remove: function(oDD) {
19360             for (var g in oDD.groups) {
19361                 if (g && this.ids[g][oDD.id]) {
19362                     delete this.ids[g][oDD.id];
19363                 }
19364             }
19365             delete this.handleIds[oDD.id];
19366         },
19367
19368         /**
19369          * Each DragDrop handle element must be registered.  This is done
19370          * automatically when executing DragDrop.setHandleElId()
19371          * @method regHandle
19372          * @param {String} sDDId the DragDrop id this element is a handle for
19373          * @param {String} sHandleId the id of the element that is the drag
19374          * handle
19375          * @static
19376          */
19377         regHandle: function(sDDId, sHandleId) {
19378             if (!this.handleIds[sDDId]) {
19379                 this.handleIds[sDDId] = {};
19380             }
19381             this.handleIds[sDDId][sHandleId] = sHandleId;
19382         },
19383
19384         /**
19385          * Utility function to determine if a given element has been
19386          * registered as a drag drop item.
19387          * @method isDragDrop
19388          * @param {String} id the element id to check
19389          * @return {boolean} true if this element is a DragDrop item,
19390          * false otherwise
19391          * @static
19392          */
19393         isDragDrop: function(id) {
19394             return ( this.getDDById(id) ) ? true : false;
19395         },
19396
19397         /**
19398          * Returns the drag and drop instances that are in all groups the
19399          * passed in instance belongs to.
19400          * @method getRelated
19401          * @param {DragDrop} p_oDD the obj to get related data for
19402          * @param {boolean} bTargetsOnly if true, only return targetable objs
19403          * @return {DragDrop[]} the related instances
19404          * @static
19405          */
19406         getRelated: function(p_oDD, bTargetsOnly) {
19407             var oDDs = [];
19408             for (var i in p_oDD.groups) {
19409                 for (j in this.ids[i]) {
19410                     var dd = this.ids[i][j];
19411                     if (! this.isTypeOfDD(dd)) {
19412                         continue;
19413                     }
19414                     if (!bTargetsOnly || dd.isTarget) {
19415                         oDDs[oDDs.length] = dd;
19416                     }
19417                 }
19418             }
19419
19420             return oDDs;
19421         },
19422
19423         /**
19424          * Returns true if the specified dd target is a legal target for
19425          * the specifice drag obj
19426          * @method isLegalTarget
19427          * @param {DragDrop} the drag obj
19428          * @param {DragDrop} the target
19429          * @return {boolean} true if the target is a legal target for the
19430          * dd obj
19431          * @static
19432          */
19433         isLegalTarget: function (oDD, oTargetDD) {
19434             var targets = this.getRelated(oDD, true);
19435             for (var i=0, len=targets.length;i<len;++i) {
19436                 if (targets[i].id == oTargetDD.id) {
19437                     return true;
19438                 }
19439             }
19440
19441             return false;
19442         },
19443
19444         /**
19445          * My goal is to be able to transparently determine if an object is
19446          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19447          * returns "object", oDD.constructor.toString() always returns
19448          * "DragDrop" and not the name of the subclass.  So for now it just
19449          * evaluates a well-known variable in DragDrop.
19450          * @method isTypeOfDD
19451          * @param {Object} the object to evaluate
19452          * @return {boolean} true if typeof oDD = DragDrop
19453          * @static
19454          */
19455         isTypeOfDD: function (oDD) {
19456             return (oDD && oDD.__ygDragDrop);
19457         },
19458
19459         /**
19460          * Utility function to determine if a given element has been
19461          * registered as a drag drop handle for the given Drag Drop object.
19462          * @method isHandle
19463          * @param {String} id the element id to check
19464          * @return {boolean} true if this element is a DragDrop handle, false
19465          * otherwise
19466          * @static
19467          */
19468         isHandle: function(sDDId, sHandleId) {
19469             return ( this.handleIds[sDDId] &&
19470                             this.handleIds[sDDId][sHandleId] );
19471         },
19472
19473         /**
19474          * Returns the DragDrop instance for a given id
19475          * @method getDDById
19476          * @param {String} id the id of the DragDrop object
19477          * @return {DragDrop} the drag drop object, null if it is not found
19478          * @static
19479          */
19480         getDDById: function(id) {
19481             for (var i in this.ids) {
19482                 if (this.ids[i][id]) {
19483                     return this.ids[i][id];
19484                 }
19485             }
19486             return null;
19487         },
19488
19489         /**
19490          * Fired after a registered DragDrop object gets the mousedown event.
19491          * Sets up the events required to track the object being dragged
19492          * @method handleMouseDown
19493          * @param {Event} e the event
19494          * @param oDD the DragDrop object being dragged
19495          * @private
19496          * @static
19497          */
19498         handleMouseDown: function(e, oDD) {
19499             if(Roo.QuickTips){
19500                 Roo.QuickTips.disable();
19501             }
19502             this.currentTarget = e.getTarget();
19503
19504             this.dragCurrent = oDD;
19505
19506             var el = oDD.getEl();
19507
19508             // track start position
19509             this.startX = e.getPageX();
19510             this.startY = e.getPageY();
19511
19512             this.deltaX = this.startX - el.offsetLeft;
19513             this.deltaY = this.startY - el.offsetTop;
19514
19515             this.dragThreshMet = false;
19516
19517             this.clickTimeout = setTimeout(
19518                     function() {
19519                         var DDM = Roo.dd.DDM;
19520                         DDM.startDrag(DDM.startX, DDM.startY);
19521                     },
19522                     this.clickTimeThresh );
19523         },
19524
19525         /**
19526          * Fired when either the drag pixel threshol or the mousedown hold
19527          * time threshold has been met.
19528          * @method startDrag
19529          * @param x {int} the X position of the original mousedown
19530          * @param y {int} the Y position of the original mousedown
19531          * @static
19532          */
19533         startDrag: function(x, y) {
19534             clearTimeout(this.clickTimeout);
19535             if (this.dragCurrent) {
19536                 this.dragCurrent.b4StartDrag(x, y);
19537                 this.dragCurrent.startDrag(x, y);
19538             }
19539             this.dragThreshMet = true;
19540         },
19541
19542         /**
19543          * Internal function to handle the mouseup event.  Will be invoked
19544          * from the context of the document.
19545          * @method handleMouseUp
19546          * @param {Event} e the event
19547          * @private
19548          * @static
19549          */
19550         handleMouseUp: function(e) {
19551
19552             if(Roo.QuickTips){
19553                 Roo.QuickTips.enable();
19554             }
19555             if (! this.dragCurrent) {
19556                 return;
19557             }
19558
19559             clearTimeout(this.clickTimeout);
19560
19561             if (this.dragThreshMet) {
19562                 this.fireEvents(e, true);
19563             } else {
19564             }
19565
19566             this.stopDrag(e);
19567
19568             this.stopEvent(e);
19569         },
19570
19571         /**
19572          * Utility to stop event propagation and event default, if these
19573          * features are turned on.
19574          * @method stopEvent
19575          * @param {Event} e the event as returned by this.getEvent()
19576          * @static
19577          */
19578         stopEvent: function(e){
19579             if(this.stopPropagation) {
19580                 e.stopPropagation();
19581             }
19582
19583             if (this.preventDefault) {
19584                 e.preventDefault();
19585             }
19586         },
19587
19588         /**
19589          * Internal function to clean up event handlers after the drag
19590          * operation is complete
19591          * @method stopDrag
19592          * @param {Event} e the event
19593          * @private
19594          * @static
19595          */
19596         stopDrag: function(e) {
19597             // Fire the drag end event for the item that was dragged
19598             if (this.dragCurrent) {
19599                 if (this.dragThreshMet) {
19600                     this.dragCurrent.b4EndDrag(e);
19601                     this.dragCurrent.endDrag(e);
19602                 }
19603
19604                 this.dragCurrent.onMouseUp(e);
19605             }
19606
19607             this.dragCurrent = null;
19608             this.dragOvers = {};
19609         },
19610
19611         /**
19612          * Internal function to handle the mousemove event.  Will be invoked
19613          * from the context of the html element.
19614          *
19615          * @TODO figure out what we can do about mouse events lost when the
19616          * user drags objects beyond the window boundary.  Currently we can
19617          * detect this in internet explorer by verifying that the mouse is
19618          * down during the mousemove event.  Firefox doesn't give us the
19619          * button state on the mousemove event.
19620          * @method handleMouseMove
19621          * @param {Event} e the event
19622          * @private
19623          * @static
19624          */
19625         handleMouseMove: function(e) {
19626             if (! this.dragCurrent) {
19627                 return true;
19628             }
19629
19630             // var button = e.which || e.button;
19631
19632             // check for IE mouseup outside of page boundary
19633             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19634                 this.stopEvent(e);
19635                 return this.handleMouseUp(e);
19636             }
19637
19638             if (!this.dragThreshMet) {
19639                 var diffX = Math.abs(this.startX - e.getPageX());
19640                 var diffY = Math.abs(this.startY - e.getPageY());
19641                 if (diffX > this.clickPixelThresh ||
19642                             diffY > this.clickPixelThresh) {
19643                     this.startDrag(this.startX, this.startY);
19644                 }
19645             }
19646
19647             if (this.dragThreshMet) {
19648                 this.dragCurrent.b4Drag(e);
19649                 this.dragCurrent.onDrag(e);
19650                 if(!this.dragCurrent.moveOnly){
19651                     this.fireEvents(e, false);
19652                 }
19653             }
19654
19655             this.stopEvent(e);
19656
19657             return true;
19658         },
19659
19660         /**
19661          * Iterates over all of the DragDrop elements to find ones we are
19662          * hovering over or dropping on
19663          * @method fireEvents
19664          * @param {Event} e the event
19665          * @param {boolean} isDrop is this a drop op or a mouseover op?
19666          * @private
19667          * @static
19668          */
19669         fireEvents: function(e, isDrop) {
19670             var dc = this.dragCurrent;
19671
19672             // If the user did the mouse up outside of the window, we could
19673             // get here even though we have ended the drag.
19674             if (!dc || dc.isLocked()) {
19675                 return;
19676             }
19677
19678             var pt = e.getPoint();
19679
19680             // cache the previous dragOver array
19681             var oldOvers = [];
19682
19683             var outEvts   = [];
19684             var overEvts  = [];
19685             var dropEvts  = [];
19686             var enterEvts = [];
19687
19688             // Check to see if the object(s) we were hovering over is no longer
19689             // being hovered over so we can fire the onDragOut event
19690             for (var i in this.dragOvers) {
19691
19692                 var ddo = this.dragOvers[i];
19693
19694                 if (! this.isTypeOfDD(ddo)) {
19695                     continue;
19696                 }
19697
19698                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19699                     outEvts.push( ddo );
19700                 }
19701
19702                 oldOvers[i] = true;
19703                 delete this.dragOvers[i];
19704             }
19705
19706             for (var sGroup in dc.groups) {
19707
19708                 if ("string" != typeof sGroup) {
19709                     continue;
19710                 }
19711
19712                 for (i in this.ids[sGroup]) {
19713                     var oDD = this.ids[sGroup][i];
19714                     if (! this.isTypeOfDD(oDD)) {
19715                         continue;
19716                     }
19717
19718                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19719                         if (this.isOverTarget(pt, oDD, this.mode)) {
19720                             // look for drop interactions
19721                             if (isDrop) {
19722                                 dropEvts.push( oDD );
19723                             // look for drag enter and drag over interactions
19724                             } else {
19725
19726                                 // initial drag over: dragEnter fires
19727                                 if (!oldOvers[oDD.id]) {
19728                                     enterEvts.push( oDD );
19729                                 // subsequent drag overs: dragOver fires
19730                                 } else {
19731                                     overEvts.push( oDD );
19732                                 }
19733
19734                                 this.dragOvers[oDD.id] = oDD;
19735                             }
19736                         }
19737                     }
19738                 }
19739             }
19740
19741             if (this.mode) {
19742                 if (outEvts.length) {
19743                     dc.b4DragOut(e, outEvts);
19744                     dc.onDragOut(e, outEvts);
19745                 }
19746
19747                 if (enterEvts.length) {
19748                     dc.onDragEnter(e, enterEvts);
19749                 }
19750
19751                 if (overEvts.length) {
19752                     dc.b4DragOver(e, overEvts);
19753                     dc.onDragOver(e, overEvts);
19754                 }
19755
19756                 if (dropEvts.length) {
19757                     dc.b4DragDrop(e, dropEvts);
19758                     dc.onDragDrop(e, dropEvts);
19759                 }
19760
19761             } else {
19762                 // fire dragout events
19763                 var len = 0;
19764                 for (i=0, len=outEvts.length; i<len; ++i) {
19765                     dc.b4DragOut(e, outEvts[i].id);
19766                     dc.onDragOut(e, outEvts[i].id);
19767                 }
19768
19769                 // fire enter events
19770                 for (i=0,len=enterEvts.length; i<len; ++i) {
19771                     // dc.b4DragEnter(e, oDD.id);
19772                     dc.onDragEnter(e, enterEvts[i].id);
19773                 }
19774
19775                 // fire over events
19776                 for (i=0,len=overEvts.length; i<len; ++i) {
19777                     dc.b4DragOver(e, overEvts[i].id);
19778                     dc.onDragOver(e, overEvts[i].id);
19779                 }
19780
19781                 // fire drop events
19782                 for (i=0, len=dropEvts.length; i<len; ++i) {
19783                     dc.b4DragDrop(e, dropEvts[i].id);
19784                     dc.onDragDrop(e, dropEvts[i].id);
19785                 }
19786
19787             }
19788
19789             // notify about a drop that did not find a target
19790             if (isDrop && !dropEvts.length) {
19791                 dc.onInvalidDrop(e);
19792             }
19793
19794         },
19795
19796         /**
19797          * Helper function for getting the best match from the list of drag
19798          * and drop objects returned by the drag and drop events when we are
19799          * in INTERSECT mode.  It returns either the first object that the
19800          * cursor is over, or the object that has the greatest overlap with
19801          * the dragged element.
19802          * @method getBestMatch
19803          * @param  {DragDrop[]} dds The array of drag and drop objects
19804          * targeted
19805          * @return {DragDrop}       The best single match
19806          * @static
19807          */
19808         getBestMatch: function(dds) {
19809             var winner = null;
19810             // Return null if the input is not what we expect
19811             //if (!dds || !dds.length || dds.length == 0) {
19812                // winner = null;
19813             // If there is only one item, it wins
19814             //} else if (dds.length == 1) {
19815
19816             var len = dds.length;
19817
19818             if (len == 1) {
19819                 winner = dds[0];
19820             } else {
19821                 // Loop through the targeted items
19822                 for (var i=0; i<len; ++i) {
19823                     var dd = dds[i];
19824                     // If the cursor is over the object, it wins.  If the
19825                     // cursor is over multiple matches, the first one we come
19826                     // to wins.
19827                     if (dd.cursorIsOver) {
19828                         winner = dd;
19829                         break;
19830                     // Otherwise the object with the most overlap wins
19831                     } else {
19832                         if (!winner ||
19833                             winner.overlap.getArea() < dd.overlap.getArea()) {
19834                             winner = dd;
19835                         }
19836                     }
19837                 }
19838             }
19839
19840             return winner;
19841         },
19842
19843         /**
19844          * Refreshes the cache of the top-left and bottom-right points of the
19845          * drag and drop objects in the specified group(s).  This is in the
19846          * format that is stored in the drag and drop instance, so typical
19847          * usage is:
19848          * <code>
19849          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19850          * </code>
19851          * Alternatively:
19852          * <code>
19853          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19854          * </code>
19855          * @TODO this really should be an indexed array.  Alternatively this
19856          * method could accept both.
19857          * @method refreshCache
19858          * @param {Object} groups an associative array of groups to refresh
19859          * @static
19860          */
19861         refreshCache: function(groups) {
19862             for (var sGroup in groups) {
19863                 if ("string" != typeof sGroup) {
19864                     continue;
19865                 }
19866                 for (var i in this.ids[sGroup]) {
19867                     var oDD = this.ids[sGroup][i];
19868
19869                     if (this.isTypeOfDD(oDD)) {
19870                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19871                         var loc = this.getLocation(oDD);
19872                         if (loc) {
19873                             this.locationCache[oDD.id] = loc;
19874                         } else {
19875                             delete this.locationCache[oDD.id];
19876                             // this will unregister the drag and drop object if
19877                             // the element is not in a usable state
19878                             // oDD.unreg();
19879                         }
19880                     }
19881                 }
19882             }
19883         },
19884
19885         /**
19886          * This checks to make sure an element exists and is in the DOM.  The
19887          * main purpose is to handle cases where innerHTML is used to remove
19888          * drag and drop objects from the DOM.  IE provides an 'unspecified
19889          * error' when trying to access the offsetParent of such an element
19890          * @method verifyEl
19891          * @param {HTMLElement} el the element to check
19892          * @return {boolean} true if the element looks usable
19893          * @static
19894          */
19895         verifyEl: function(el) {
19896             if (el) {
19897                 var parent;
19898                 if(Roo.isIE){
19899                     try{
19900                         parent = el.offsetParent;
19901                     }catch(e){}
19902                 }else{
19903                     parent = el.offsetParent;
19904                 }
19905                 if (parent) {
19906                     return true;
19907                 }
19908             }
19909
19910             return false;
19911         },
19912
19913         /**
19914          * Returns a Region object containing the drag and drop element's position
19915          * and size, including the padding configured for it
19916          * @method getLocation
19917          * @param {DragDrop} oDD the drag and drop object to get the
19918          *                       location for
19919          * @return {Roo.lib.Region} a Region object representing the total area
19920          *                             the element occupies, including any padding
19921          *                             the instance is configured for.
19922          * @static
19923          */
19924         getLocation: function(oDD) {
19925             if (! this.isTypeOfDD(oDD)) {
19926                 return null;
19927             }
19928
19929             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
19930
19931             try {
19932                 pos= Roo.lib.Dom.getXY(el);
19933             } catch (e) { }
19934
19935             if (!pos) {
19936                 return null;
19937             }
19938
19939             x1 = pos[0];
19940             x2 = x1 + el.offsetWidth;
19941             y1 = pos[1];
19942             y2 = y1 + el.offsetHeight;
19943
19944             t = y1 - oDD.padding[0];
19945             r = x2 + oDD.padding[1];
19946             b = y2 + oDD.padding[2];
19947             l = x1 - oDD.padding[3];
19948
19949             return new Roo.lib.Region( t, r, b, l );
19950         },
19951
19952         /**
19953          * Checks the cursor location to see if it over the target
19954          * @method isOverTarget
19955          * @param {Roo.lib.Point} pt The point to evaluate
19956          * @param {DragDrop} oTarget the DragDrop object we are inspecting
19957          * @return {boolean} true if the mouse is over the target
19958          * @private
19959          * @static
19960          */
19961         isOverTarget: function(pt, oTarget, intersect) {
19962             // use cache if available
19963             var loc = this.locationCache[oTarget.id];
19964             if (!loc || !this.useCache) {
19965                 loc = this.getLocation(oTarget);
19966                 this.locationCache[oTarget.id] = loc;
19967
19968             }
19969
19970             if (!loc) {
19971                 return false;
19972             }
19973
19974             oTarget.cursorIsOver = loc.contains( pt );
19975
19976             // DragDrop is using this as a sanity check for the initial mousedown
19977             // in this case we are done.  In POINT mode, if the drag obj has no
19978             // contraints, we are also done. Otherwise we need to evaluate the
19979             // location of the target as related to the actual location of the
19980             // dragged element.
19981             var dc = this.dragCurrent;
19982             if (!dc || !dc.getTargetCoord ||
19983                     (!intersect && !dc.constrainX && !dc.constrainY)) {
19984                 return oTarget.cursorIsOver;
19985             }
19986
19987             oTarget.overlap = null;
19988
19989             // Get the current location of the drag element, this is the
19990             // location of the mouse event less the delta that represents
19991             // where the original mousedown happened on the element.  We
19992             // need to consider constraints and ticks as well.
19993             var pos = dc.getTargetCoord(pt.x, pt.y);
19994
19995             var el = dc.getDragEl();
19996             var curRegion = new Roo.lib.Region( pos.y,
19997                                                    pos.x + el.offsetWidth,
19998                                                    pos.y + el.offsetHeight,
19999                                                    pos.x );
20000
20001             var overlap = curRegion.intersect(loc);
20002
20003             if (overlap) {
20004                 oTarget.overlap = overlap;
20005                 return (intersect) ? true : oTarget.cursorIsOver;
20006             } else {
20007                 return false;
20008             }
20009         },
20010
20011         /**
20012          * unload event handler
20013          * @method _onUnload
20014          * @private
20015          * @static
20016          */
20017         _onUnload: function(e, me) {
20018             Roo.dd.DragDropMgr.unregAll();
20019         },
20020
20021         /**
20022          * Cleans up the drag and drop events and objects.
20023          * @method unregAll
20024          * @private
20025          * @static
20026          */
20027         unregAll: function() {
20028
20029             if (this.dragCurrent) {
20030                 this.stopDrag();
20031                 this.dragCurrent = null;
20032             }
20033
20034             this._execOnAll("unreg", []);
20035
20036             for (i in this.elementCache) {
20037                 delete this.elementCache[i];
20038             }
20039
20040             this.elementCache = {};
20041             this.ids = {};
20042         },
20043
20044         /**
20045          * A cache of DOM elements
20046          * @property elementCache
20047          * @private
20048          * @static
20049          */
20050         elementCache: {},
20051
20052         /**
20053          * Get the wrapper for the DOM element specified
20054          * @method getElWrapper
20055          * @param {String} id the id of the element to get
20056          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20057          * @private
20058          * @deprecated This wrapper isn't that useful
20059          * @static
20060          */
20061         getElWrapper: function(id) {
20062             var oWrapper = this.elementCache[id];
20063             if (!oWrapper || !oWrapper.el) {
20064                 oWrapper = this.elementCache[id] =
20065                     new this.ElementWrapper(Roo.getDom(id));
20066             }
20067             return oWrapper;
20068         },
20069
20070         /**
20071          * Returns the actual DOM element
20072          * @method getElement
20073          * @param {String} id the id of the elment to get
20074          * @return {Object} The element
20075          * @deprecated use Roo.getDom instead
20076          * @static
20077          */
20078         getElement: function(id) {
20079             return Roo.getDom(id);
20080         },
20081
20082         /**
20083          * Returns the style property for the DOM element (i.e.,
20084          * document.getElById(id).style)
20085          * @method getCss
20086          * @param {String} id the id of the elment to get
20087          * @return {Object} The style property of the element
20088          * @deprecated use Roo.getDom instead
20089          * @static
20090          */
20091         getCss: function(id) {
20092             var el = Roo.getDom(id);
20093             return (el) ? el.style : null;
20094         },
20095
20096         /**
20097          * Inner class for cached elements
20098          * @class DragDropMgr.ElementWrapper
20099          * @for DragDropMgr
20100          * @private
20101          * @deprecated
20102          */
20103         ElementWrapper: function(el) {
20104                 /**
20105                  * The element
20106                  * @property el
20107                  */
20108                 this.el = el || null;
20109                 /**
20110                  * The element id
20111                  * @property id
20112                  */
20113                 this.id = this.el && el.id;
20114                 /**
20115                  * A reference to the style property
20116                  * @property css
20117                  */
20118                 this.css = this.el && el.style;
20119             },
20120
20121         /**
20122          * Returns the X position of an html element
20123          * @method getPosX
20124          * @param el the element for which to get the position
20125          * @return {int} the X coordinate
20126          * @for DragDropMgr
20127          * @deprecated use Roo.lib.Dom.getX instead
20128          * @static
20129          */
20130         getPosX: function(el) {
20131             return Roo.lib.Dom.getX(el);
20132         },
20133
20134         /**
20135          * Returns the Y position of an html element
20136          * @method getPosY
20137          * @param el the element for which to get the position
20138          * @return {int} the Y coordinate
20139          * @deprecated use Roo.lib.Dom.getY instead
20140          * @static
20141          */
20142         getPosY: function(el) {
20143             return Roo.lib.Dom.getY(el);
20144         },
20145
20146         /**
20147          * Swap two nodes.  In IE, we use the native method, for others we
20148          * emulate the IE behavior
20149          * @method swapNode
20150          * @param n1 the first node to swap
20151          * @param n2 the other node to swap
20152          * @static
20153          */
20154         swapNode: function(n1, n2) {
20155             if (n1.swapNode) {
20156                 n1.swapNode(n2);
20157             } else {
20158                 var p = n2.parentNode;
20159                 var s = n2.nextSibling;
20160
20161                 if (s == n1) {
20162                     p.insertBefore(n1, n2);
20163                 } else if (n2 == n1.nextSibling) {
20164                     p.insertBefore(n2, n1);
20165                 } else {
20166                     n1.parentNode.replaceChild(n2, n1);
20167                     p.insertBefore(n1, s);
20168                 }
20169             }
20170         },
20171
20172         /**
20173          * Returns the current scroll position
20174          * @method getScroll
20175          * @private
20176          * @static
20177          */
20178         getScroll: function () {
20179             var t, l, dde=document.documentElement, db=document.body;
20180             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20181                 t = dde.scrollTop;
20182                 l = dde.scrollLeft;
20183             } else if (db) {
20184                 t = db.scrollTop;
20185                 l = db.scrollLeft;
20186             } else {
20187
20188             }
20189             return { top: t, left: l };
20190         },
20191
20192         /**
20193          * Returns the specified element style property
20194          * @method getStyle
20195          * @param {HTMLElement} el          the element
20196          * @param {string}      styleProp   the style property
20197          * @return {string} The value of the style property
20198          * @deprecated use Roo.lib.Dom.getStyle
20199          * @static
20200          */
20201         getStyle: function(el, styleProp) {
20202             return Roo.fly(el).getStyle(styleProp);
20203         },
20204
20205         /**
20206          * Gets the scrollTop
20207          * @method getScrollTop
20208          * @return {int} the document's scrollTop
20209          * @static
20210          */
20211         getScrollTop: function () { return this.getScroll().top; },
20212
20213         /**
20214          * Gets the scrollLeft
20215          * @method getScrollLeft
20216          * @return {int} the document's scrollTop
20217          * @static
20218          */
20219         getScrollLeft: function () { return this.getScroll().left; },
20220
20221         /**
20222          * Sets the x/y position of an element to the location of the
20223          * target element.
20224          * @method moveToEl
20225          * @param {HTMLElement} moveEl      The element to move
20226          * @param {HTMLElement} targetEl    The position reference element
20227          * @static
20228          */
20229         moveToEl: function (moveEl, targetEl) {
20230             var aCoord = Roo.lib.Dom.getXY(targetEl);
20231             Roo.lib.Dom.setXY(moveEl, aCoord);
20232         },
20233
20234         /**
20235          * Numeric array sort function
20236          * @method numericSort
20237          * @static
20238          */
20239         numericSort: function(a, b) { return (a - b); },
20240
20241         /**
20242          * Internal counter
20243          * @property _timeoutCount
20244          * @private
20245          * @static
20246          */
20247         _timeoutCount: 0,
20248
20249         /**
20250          * Trying to make the load order less important.  Without this we get
20251          * an error if this file is loaded before the Event Utility.
20252          * @method _addListeners
20253          * @private
20254          * @static
20255          */
20256         _addListeners: function() {
20257             var DDM = Roo.dd.DDM;
20258             if ( Roo.lib.Event && document ) {
20259                 DDM._onLoad();
20260             } else {
20261                 if (DDM._timeoutCount > 2000) {
20262                 } else {
20263                     setTimeout(DDM._addListeners, 10);
20264                     if (document && document.body) {
20265                         DDM._timeoutCount += 1;
20266                     }
20267                 }
20268             }
20269         },
20270
20271         /**
20272          * Recursively searches the immediate parent and all child nodes for
20273          * the handle element in order to determine wheter or not it was
20274          * clicked.
20275          * @method handleWasClicked
20276          * @param node the html element to inspect
20277          * @static
20278          */
20279         handleWasClicked: function(node, id) {
20280             if (this.isHandle(id, node.id)) {
20281                 return true;
20282             } else {
20283                 // check to see if this is a text node child of the one we want
20284                 var p = node.parentNode;
20285
20286                 while (p) {
20287                     if (this.isHandle(id, p.id)) {
20288                         return true;
20289                     } else {
20290                         p = p.parentNode;
20291                     }
20292                 }
20293             }
20294
20295             return false;
20296         }
20297
20298     };
20299
20300 }();
20301
20302 // shorter alias, save a few bytes
20303 Roo.dd.DDM = Roo.dd.DragDropMgr;
20304 Roo.dd.DDM._addListeners();
20305
20306 }/*
20307  * Based on:
20308  * Ext JS Library 1.1.1
20309  * Copyright(c) 2006-2007, Ext JS, LLC.
20310  *
20311  * Originally Released Under LGPL - original licence link has changed is not relivant.
20312  *
20313  * Fork - LGPL
20314  * <script type="text/javascript">
20315  */
20316
20317 /**
20318  * @class Roo.dd.DD
20319  * A DragDrop implementation where the linked element follows the
20320  * mouse cursor during a drag.
20321  * @extends Roo.dd.DragDrop
20322  * @constructor
20323  * @param {String} id the id of the linked element
20324  * @param {String} sGroup the group of related DragDrop items
20325  * @param {object} config an object containing configurable attributes
20326  *                Valid properties for DD:
20327  *                    scroll
20328  */
20329 Roo.dd.DD = function(id, sGroup, config) {
20330     if (id) {
20331         this.init(id, sGroup, config);
20332     }
20333 };
20334
20335 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20336
20337     /**
20338      * When set to true, the utility automatically tries to scroll the browser
20339      * window wehn a drag and drop element is dragged near the viewport boundary.
20340      * Defaults to true.
20341      * @property scroll
20342      * @type boolean
20343      */
20344     scroll: true,
20345
20346     /**
20347      * Sets the pointer offset to the distance between the linked element's top
20348      * left corner and the location the element was clicked
20349      * @method autoOffset
20350      * @param {int} iPageX the X coordinate of the click
20351      * @param {int} iPageY the Y coordinate of the click
20352      */
20353     autoOffset: function(iPageX, iPageY) {
20354         var x = iPageX - this.startPageX;
20355         var y = iPageY - this.startPageY;
20356         this.setDelta(x, y);
20357     },
20358
20359     /**
20360      * Sets the pointer offset.  You can call this directly to force the
20361      * offset to be in a particular location (e.g., pass in 0,0 to set it
20362      * to the center of the object)
20363      * @method setDelta
20364      * @param {int} iDeltaX the distance from the left
20365      * @param {int} iDeltaY the distance from the top
20366      */
20367     setDelta: function(iDeltaX, iDeltaY) {
20368         this.deltaX = iDeltaX;
20369         this.deltaY = iDeltaY;
20370     },
20371
20372     /**
20373      * Sets the drag element to the location of the mousedown or click event,
20374      * maintaining the cursor location relative to the location on the element
20375      * that was clicked.  Override this if you want to place the element in a
20376      * location other than where the cursor is.
20377      * @method setDragElPos
20378      * @param {int} iPageX the X coordinate of the mousedown or drag event
20379      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20380      */
20381     setDragElPos: function(iPageX, iPageY) {
20382         // the first time we do this, we are going to check to make sure
20383         // the element has css positioning
20384
20385         var el = this.getDragEl();
20386         this.alignElWithMouse(el, iPageX, iPageY);
20387     },
20388
20389     /**
20390      * Sets the element to the location of the mousedown or click event,
20391      * maintaining the cursor location relative to the location on the element
20392      * that was clicked.  Override this if you want to place the element in a
20393      * location other than where the cursor is.
20394      * @method alignElWithMouse
20395      * @param {HTMLElement} el the element to move
20396      * @param {int} iPageX the X coordinate of the mousedown or drag event
20397      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20398      */
20399     alignElWithMouse: function(el, iPageX, iPageY) {
20400         var oCoord = this.getTargetCoord(iPageX, iPageY);
20401         var fly = el.dom ? el : Roo.fly(el);
20402         if (!this.deltaSetXY) {
20403             var aCoord = [oCoord.x, oCoord.y];
20404             fly.setXY(aCoord);
20405             var newLeft = fly.getLeft(true);
20406             var newTop  = fly.getTop(true);
20407             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20408         } else {
20409             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20410         }
20411
20412         this.cachePosition(oCoord.x, oCoord.y);
20413         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20414         return oCoord;
20415     },
20416
20417     /**
20418      * Saves the most recent position so that we can reset the constraints and
20419      * tick marks on-demand.  We need to know this so that we can calculate the
20420      * number of pixels the element is offset from its original position.
20421      * @method cachePosition
20422      * @param iPageX the current x position (optional, this just makes it so we
20423      * don't have to look it up again)
20424      * @param iPageY the current y position (optional, this just makes it so we
20425      * don't have to look it up again)
20426      */
20427     cachePosition: function(iPageX, iPageY) {
20428         if (iPageX) {
20429             this.lastPageX = iPageX;
20430             this.lastPageY = iPageY;
20431         } else {
20432             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20433             this.lastPageX = aCoord[0];
20434             this.lastPageY = aCoord[1];
20435         }
20436     },
20437
20438     /**
20439      * Auto-scroll the window if the dragged object has been moved beyond the
20440      * visible window boundary.
20441      * @method autoScroll
20442      * @param {int} x the drag element's x position
20443      * @param {int} y the drag element's y position
20444      * @param {int} h the height of the drag element
20445      * @param {int} w the width of the drag element
20446      * @private
20447      */
20448     autoScroll: function(x, y, h, w) {
20449
20450         if (this.scroll) {
20451             // The client height
20452             var clientH = Roo.lib.Dom.getViewWidth();
20453
20454             // The client width
20455             var clientW = Roo.lib.Dom.getViewHeight();
20456
20457             // The amt scrolled down
20458             var st = this.DDM.getScrollTop();
20459
20460             // The amt scrolled right
20461             var sl = this.DDM.getScrollLeft();
20462
20463             // Location of the bottom of the element
20464             var bot = h + y;
20465
20466             // Location of the right of the element
20467             var right = w + x;
20468
20469             // The distance from the cursor to the bottom of the visible area,
20470             // adjusted so that we don't scroll if the cursor is beyond the
20471             // element drag constraints
20472             var toBot = (clientH + st - y - this.deltaY);
20473
20474             // The distance from the cursor to the right of the visible area
20475             var toRight = (clientW + sl - x - this.deltaX);
20476
20477
20478             // How close to the edge the cursor must be before we scroll
20479             // var thresh = (document.all) ? 100 : 40;
20480             var thresh = 40;
20481
20482             // How many pixels to scroll per autoscroll op.  This helps to reduce
20483             // clunky scrolling. IE is more sensitive about this ... it needs this
20484             // value to be higher.
20485             var scrAmt = (document.all) ? 80 : 30;
20486
20487             // Scroll down if we are near the bottom of the visible page and the
20488             // obj extends below the crease
20489             if ( bot > clientH && toBot < thresh ) {
20490                 window.scrollTo(sl, st + scrAmt);
20491             }
20492
20493             // Scroll up if the window is scrolled down and the top of the object
20494             // goes above the top border
20495             if ( y < st && st > 0 && y - st < thresh ) {
20496                 window.scrollTo(sl, st - scrAmt);
20497             }
20498
20499             // Scroll right if the obj is beyond the right border and the cursor is
20500             // near the border.
20501             if ( right > clientW && toRight < thresh ) {
20502                 window.scrollTo(sl + scrAmt, st);
20503             }
20504
20505             // Scroll left if the window has been scrolled to the right and the obj
20506             // extends past the left border
20507             if ( x < sl && sl > 0 && x - sl < thresh ) {
20508                 window.scrollTo(sl - scrAmt, st);
20509             }
20510         }
20511     },
20512
20513     /**
20514      * Finds the location the element should be placed if we want to move
20515      * it to where the mouse location less the click offset would place us.
20516      * @method getTargetCoord
20517      * @param {int} iPageX the X coordinate of the click
20518      * @param {int} iPageY the Y coordinate of the click
20519      * @return an object that contains the coordinates (Object.x and Object.y)
20520      * @private
20521      */
20522     getTargetCoord: function(iPageX, iPageY) {
20523
20524
20525         var x = iPageX - this.deltaX;
20526         var y = iPageY - this.deltaY;
20527
20528         if (this.constrainX) {
20529             if (x < this.minX) { x = this.minX; }
20530             if (x > this.maxX) { x = this.maxX; }
20531         }
20532
20533         if (this.constrainY) {
20534             if (y < this.minY) { y = this.minY; }
20535             if (y > this.maxY) { y = this.maxY; }
20536         }
20537
20538         x = this.getTick(x, this.xTicks);
20539         y = this.getTick(y, this.yTicks);
20540
20541
20542         return {x:x, y:y};
20543     },
20544
20545     /*
20546      * Sets up config options specific to this class. Overrides
20547      * Roo.dd.DragDrop, but all versions of this method through the
20548      * inheritance chain are called
20549      */
20550     applyConfig: function() {
20551         Roo.dd.DD.superclass.applyConfig.call(this);
20552         this.scroll = (this.config.scroll !== false);
20553     },
20554
20555     /*
20556      * Event that fires prior to the onMouseDown event.  Overrides
20557      * Roo.dd.DragDrop.
20558      */
20559     b4MouseDown: function(e) {
20560         // this.resetConstraints();
20561         this.autoOffset(e.getPageX(),
20562                             e.getPageY());
20563     },
20564
20565     /*
20566      * Event that fires prior to the onDrag event.  Overrides
20567      * Roo.dd.DragDrop.
20568      */
20569     b4Drag: function(e) {
20570         this.setDragElPos(e.getPageX(),
20571                             e.getPageY());
20572     },
20573
20574     toString: function() {
20575         return ("DD " + this.id);
20576     }
20577
20578     //////////////////////////////////////////////////////////////////////////
20579     // Debugging ygDragDrop events that can be overridden
20580     //////////////////////////////////////////////////////////////////////////
20581     /*
20582     startDrag: function(x, y) {
20583     },
20584
20585     onDrag: function(e) {
20586     },
20587
20588     onDragEnter: function(e, id) {
20589     },
20590
20591     onDragOver: function(e, id) {
20592     },
20593
20594     onDragOut: function(e, id) {
20595     },
20596
20597     onDragDrop: function(e, id) {
20598     },
20599
20600     endDrag: function(e) {
20601     }
20602
20603     */
20604
20605 });/*
20606  * Based on:
20607  * Ext JS Library 1.1.1
20608  * Copyright(c) 2006-2007, Ext JS, LLC.
20609  *
20610  * Originally Released Under LGPL - original licence link has changed is not relivant.
20611  *
20612  * Fork - LGPL
20613  * <script type="text/javascript">
20614  */
20615
20616 /**
20617  * @class Roo.dd.DDProxy
20618  * A DragDrop implementation that inserts an empty, bordered div into
20619  * the document that follows the cursor during drag operations.  At the time of
20620  * the click, the frame div is resized to the dimensions of the linked html
20621  * element, and moved to the exact location of the linked element.
20622  *
20623  * References to the "frame" element refer to the single proxy element that
20624  * was created to be dragged in place of all DDProxy elements on the
20625  * page.
20626  *
20627  * @extends Roo.dd.DD
20628  * @constructor
20629  * @param {String} id the id of the linked html element
20630  * @param {String} sGroup the group of related DragDrop objects
20631  * @param {object} config an object containing configurable attributes
20632  *                Valid properties for DDProxy in addition to those in DragDrop:
20633  *                   resizeFrame, centerFrame, dragElId
20634  */
20635 Roo.dd.DDProxy = function(id, sGroup, config) {
20636     if (id) {
20637         this.init(id, sGroup, config);
20638         this.initFrame();
20639     }
20640 };
20641
20642 /**
20643  * The default drag frame div id
20644  * @property Roo.dd.DDProxy.dragElId
20645  * @type String
20646  * @static
20647  */
20648 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20649
20650 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20651
20652     /**
20653      * By default we resize the drag frame to be the same size as the element
20654      * we want to drag (this is to get the frame effect).  We can turn it off
20655      * if we want a different behavior.
20656      * @property resizeFrame
20657      * @type boolean
20658      */
20659     resizeFrame: true,
20660
20661     /**
20662      * By default the frame is positioned exactly where the drag element is, so
20663      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20664      * you do not have constraints on the obj is to have the drag frame centered
20665      * around the cursor.  Set centerFrame to true for this effect.
20666      * @property centerFrame
20667      * @type boolean
20668      */
20669     centerFrame: false,
20670
20671     /**
20672      * Creates the proxy element if it does not yet exist
20673      * @method createFrame
20674      */
20675     createFrame: function() {
20676         var self = this;
20677         var body = document.body;
20678
20679         if (!body || !body.firstChild) {
20680             setTimeout( function() { self.createFrame(); }, 50 );
20681             return;
20682         }
20683
20684         var div = this.getDragEl();
20685
20686         if (!div) {
20687             div    = document.createElement("div");
20688             div.id = this.dragElId;
20689             var s  = div.style;
20690
20691             s.position   = "absolute";
20692             s.visibility = "hidden";
20693             s.cursor     = "move";
20694             s.border     = "2px solid #aaa";
20695             s.zIndex     = 999;
20696
20697             // appendChild can blow up IE if invoked prior to the window load event
20698             // while rendering a table.  It is possible there are other scenarios
20699             // that would cause this to happen as well.
20700             body.insertBefore(div, body.firstChild);
20701         }
20702     },
20703
20704     /**
20705      * Initialization for the drag frame element.  Must be called in the
20706      * constructor of all subclasses
20707      * @method initFrame
20708      */
20709     initFrame: function() {
20710         this.createFrame();
20711     },
20712
20713     applyConfig: function() {
20714         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20715
20716         this.resizeFrame = (this.config.resizeFrame !== false);
20717         this.centerFrame = (this.config.centerFrame);
20718         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20719     },
20720
20721     /**
20722      * Resizes the drag frame to the dimensions of the clicked object, positions
20723      * it over the object, and finally displays it
20724      * @method showFrame
20725      * @param {int} iPageX X click position
20726      * @param {int} iPageY Y click position
20727      * @private
20728      */
20729     showFrame: function(iPageX, iPageY) {
20730         var el = this.getEl();
20731         var dragEl = this.getDragEl();
20732         var s = dragEl.style;
20733
20734         this._resizeProxy();
20735
20736         if (this.centerFrame) {
20737             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20738                            Math.round(parseInt(s.height, 10)/2) );
20739         }
20740
20741         this.setDragElPos(iPageX, iPageY);
20742
20743         Roo.fly(dragEl).show();
20744     },
20745
20746     /**
20747      * The proxy is automatically resized to the dimensions of the linked
20748      * element when a drag is initiated, unless resizeFrame is set to false
20749      * @method _resizeProxy
20750      * @private
20751      */
20752     _resizeProxy: function() {
20753         if (this.resizeFrame) {
20754             var el = this.getEl();
20755             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20756         }
20757     },
20758
20759     // overrides Roo.dd.DragDrop
20760     b4MouseDown: function(e) {
20761         var x = e.getPageX();
20762         var y = e.getPageY();
20763         this.autoOffset(x, y);
20764         this.setDragElPos(x, y);
20765     },
20766
20767     // overrides Roo.dd.DragDrop
20768     b4StartDrag: function(x, y) {
20769         // show the drag frame
20770         this.showFrame(x, y);
20771     },
20772
20773     // overrides Roo.dd.DragDrop
20774     b4EndDrag: function(e) {
20775         Roo.fly(this.getDragEl()).hide();
20776     },
20777
20778     // overrides Roo.dd.DragDrop
20779     // By default we try to move the element to the last location of the frame.
20780     // This is so that the default behavior mirrors that of Roo.dd.DD.
20781     endDrag: function(e) {
20782
20783         var lel = this.getEl();
20784         var del = this.getDragEl();
20785
20786         // Show the drag frame briefly so we can get its position
20787         del.style.visibility = "";
20788
20789         this.beforeMove();
20790         // Hide the linked element before the move to get around a Safari
20791         // rendering bug.
20792         lel.style.visibility = "hidden";
20793         Roo.dd.DDM.moveToEl(lel, del);
20794         del.style.visibility = "hidden";
20795         lel.style.visibility = "";
20796
20797         this.afterDrag();
20798     },
20799
20800     beforeMove : function(){
20801
20802     },
20803
20804     afterDrag : function(){
20805
20806     },
20807
20808     toString: function() {
20809         return ("DDProxy " + this.id);
20810     }
20811
20812 });
20813 /*
20814  * Based on:
20815  * Ext JS Library 1.1.1
20816  * Copyright(c) 2006-2007, Ext JS, LLC.
20817  *
20818  * Originally Released Under LGPL - original licence link has changed is not relivant.
20819  *
20820  * Fork - LGPL
20821  * <script type="text/javascript">
20822  */
20823
20824  /**
20825  * @class Roo.dd.DDTarget
20826  * A DragDrop implementation that does not move, but can be a drop
20827  * target.  You would get the same result by simply omitting implementation
20828  * for the event callbacks, but this way we reduce the processing cost of the
20829  * event listener and the callbacks.
20830  * @extends Roo.dd.DragDrop
20831  * @constructor
20832  * @param {String} id the id of the element that is a drop target
20833  * @param {String} sGroup the group of related DragDrop objects
20834  * @param {object} config an object containing configurable attributes
20835  *                 Valid properties for DDTarget in addition to those in
20836  *                 DragDrop:
20837  *                    none
20838  */
20839 Roo.dd.DDTarget = function(id, sGroup, config) {
20840     if (id) {
20841         this.initTarget(id, sGroup, config);
20842     }
20843     if (config.listeners || config.events) { 
20844        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20845             listeners : config.listeners || {}, 
20846             events : config.events || {} 
20847         });    
20848     }
20849 };
20850
20851 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20852 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20853     toString: function() {
20854         return ("DDTarget " + this.id);
20855     }
20856 });
20857 /*
20858  * Based on:
20859  * Ext JS Library 1.1.1
20860  * Copyright(c) 2006-2007, Ext JS, LLC.
20861  *
20862  * Originally Released Under LGPL - original licence link has changed is not relivant.
20863  *
20864  * Fork - LGPL
20865  * <script type="text/javascript">
20866  */
20867  
20868
20869 /**
20870  * @class Roo.dd.ScrollManager
20871  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20872  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20873  * @singleton
20874  */
20875 Roo.dd.ScrollManager = function(){
20876     var ddm = Roo.dd.DragDropMgr;
20877     var els = {};
20878     var dragEl = null;
20879     var proc = {};
20880     
20881     
20882     
20883     var onStop = function(e){
20884         dragEl = null;
20885         clearProc();
20886     };
20887     
20888     var triggerRefresh = function(){
20889         if(ddm.dragCurrent){
20890              ddm.refreshCache(ddm.dragCurrent.groups);
20891         }
20892     };
20893     
20894     var doScroll = function(){
20895         if(ddm.dragCurrent){
20896             var dds = Roo.dd.ScrollManager;
20897             if(!dds.animate){
20898                 if(proc.el.scroll(proc.dir, dds.increment)){
20899                     triggerRefresh();
20900                 }
20901             }else{
20902                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
20903             }
20904         }
20905     };
20906     
20907     var clearProc = function(){
20908         if(proc.id){
20909             clearInterval(proc.id);
20910         }
20911         proc.id = 0;
20912         proc.el = null;
20913         proc.dir = "";
20914     };
20915     
20916     var startProc = function(el, dir){
20917          Roo.log('scroll startproc');
20918         clearProc();
20919         proc.el = el;
20920         proc.dir = dir;
20921         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
20922     };
20923     
20924     var onFire = function(e, isDrop){
20925        
20926         if(isDrop || !ddm.dragCurrent){ return; }
20927         var dds = Roo.dd.ScrollManager;
20928         if(!dragEl || dragEl != ddm.dragCurrent){
20929             dragEl = ddm.dragCurrent;
20930             // refresh regions on drag start
20931             dds.refreshCache();
20932         }
20933         
20934         var xy = Roo.lib.Event.getXY(e);
20935         var pt = new Roo.lib.Point(xy[0], xy[1]);
20936         for(var id in els){
20937             var el = els[id], r = el._region;
20938             if(r && r.contains(pt) && el.isScrollable()){
20939                 if(r.bottom - pt.y <= dds.thresh){
20940                     if(proc.el != el){
20941                         startProc(el, "down");
20942                     }
20943                     return;
20944                 }else if(r.right - pt.x <= dds.thresh){
20945                     if(proc.el != el){
20946                         startProc(el, "left");
20947                     }
20948                     return;
20949                 }else if(pt.y - r.top <= dds.thresh){
20950                     if(proc.el != el){
20951                         startProc(el, "up");
20952                     }
20953                     return;
20954                 }else if(pt.x - r.left <= dds.thresh){
20955                     if(proc.el != el){
20956                         startProc(el, "right");
20957                     }
20958                     return;
20959                 }
20960             }
20961         }
20962         clearProc();
20963     };
20964     
20965     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
20966     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
20967     
20968     return {
20969         /**
20970          * Registers new overflow element(s) to auto scroll
20971          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
20972          */
20973         register : function(el){
20974             if(el instanceof Array){
20975                 for(var i = 0, len = el.length; i < len; i++) {
20976                         this.register(el[i]);
20977                 }
20978             }else{
20979                 el = Roo.get(el);
20980                 els[el.id] = el;
20981             }
20982             Roo.dd.ScrollManager.els = els;
20983         },
20984         
20985         /**
20986          * Unregisters overflow element(s) so they are no longer scrolled
20987          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
20988          */
20989         unregister : function(el){
20990             if(el instanceof Array){
20991                 for(var i = 0, len = el.length; i < len; i++) {
20992                         this.unregister(el[i]);
20993                 }
20994             }else{
20995                 el = Roo.get(el);
20996                 delete els[el.id];
20997             }
20998         },
20999         
21000         /**
21001          * The number of pixels from the edge of a container the pointer needs to be to 
21002          * trigger scrolling (defaults to 25)
21003          * @type Number
21004          */
21005         thresh : 25,
21006         
21007         /**
21008          * The number of pixels to scroll in each scroll increment (defaults to 50)
21009          * @type Number
21010          */
21011         increment : 100,
21012         
21013         /**
21014          * The frequency of scrolls in milliseconds (defaults to 500)
21015          * @type Number
21016          */
21017         frequency : 500,
21018         
21019         /**
21020          * True to animate the scroll (defaults to true)
21021          * @type Boolean
21022          */
21023         animate: true,
21024         
21025         /**
21026          * The animation duration in seconds - 
21027          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21028          * @type Number
21029          */
21030         animDuration: .4,
21031         
21032         /**
21033          * Manually trigger a cache refresh.
21034          */
21035         refreshCache : function(){
21036             for(var id in els){
21037                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21038                     els[id]._region = els[id].getRegion();
21039                 }
21040             }
21041         }
21042     };
21043 }();/*
21044  * Based on:
21045  * Ext JS Library 1.1.1
21046  * Copyright(c) 2006-2007, Ext JS, LLC.
21047  *
21048  * Originally Released Under LGPL - original licence link has changed is not relivant.
21049  *
21050  * Fork - LGPL
21051  * <script type="text/javascript">
21052  */
21053  
21054
21055 /**
21056  * @class Roo.dd.Registry
21057  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21058  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21059  * @singleton
21060  */
21061 Roo.dd.Registry = function(){
21062     var elements = {}; 
21063     var handles = {}; 
21064     var autoIdSeed = 0;
21065
21066     var getId = function(el, autogen){
21067         if(typeof el == "string"){
21068             return el;
21069         }
21070         var id = el.id;
21071         if(!id && autogen !== false){
21072             id = "roodd-" + (++autoIdSeed);
21073             el.id = id;
21074         }
21075         return id;
21076     };
21077     
21078     return {
21079     /**
21080      * Register a drag drop element
21081      * @param {String|HTMLElement} element The id or DOM node to register
21082      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21083      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21084      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21085      * populated in the data object (if applicable):
21086      * <pre>
21087 Value      Description<br />
21088 ---------  ------------------------------------------<br />
21089 handles    Array of DOM nodes that trigger dragging<br />
21090            for the element being registered<br />
21091 isHandle   True if the element passed in triggers<br />
21092            dragging itself, else false
21093 </pre>
21094      */
21095         register : function(el, data){
21096             data = data || {};
21097             if(typeof el == "string"){
21098                 el = document.getElementById(el);
21099             }
21100             data.ddel = el;
21101             elements[getId(el)] = data;
21102             if(data.isHandle !== false){
21103                 handles[data.ddel.id] = data;
21104             }
21105             if(data.handles){
21106                 var hs = data.handles;
21107                 for(var i = 0, len = hs.length; i < len; i++){
21108                         handles[getId(hs[i])] = data;
21109                 }
21110             }
21111         },
21112
21113     /**
21114      * Unregister a drag drop element
21115      * @param {String|HTMLElement}  element The id or DOM node to unregister
21116      */
21117         unregister : function(el){
21118             var id = getId(el, false);
21119             var data = elements[id];
21120             if(data){
21121                 delete elements[id];
21122                 if(data.handles){
21123                     var hs = data.handles;
21124                     for(var i = 0, len = hs.length; i < len; i++){
21125                         delete handles[getId(hs[i], false)];
21126                     }
21127                 }
21128             }
21129         },
21130
21131     /**
21132      * Returns the handle registered for a DOM Node by id
21133      * @param {String|HTMLElement} id The DOM node or id to look up
21134      * @return {Object} handle The custom handle data
21135      */
21136         getHandle : function(id){
21137             if(typeof id != "string"){ // must be element?
21138                 id = id.id;
21139             }
21140             return handles[id];
21141         },
21142
21143     /**
21144      * Returns the handle that is registered for the DOM node that is the target of the event
21145      * @param {Event} e The event
21146      * @return {Object} handle The custom handle data
21147      */
21148         getHandleFromEvent : function(e){
21149             var t = Roo.lib.Event.getTarget(e);
21150             return t ? handles[t.id] : null;
21151         },
21152
21153     /**
21154      * Returns a custom data object that is registered for a DOM node by id
21155      * @param {String|HTMLElement} id The DOM node or id to look up
21156      * @return {Object} data The custom data
21157      */
21158         getTarget : function(id){
21159             if(typeof id != "string"){ // must be element?
21160                 id = id.id;
21161             }
21162             return elements[id];
21163         },
21164
21165     /**
21166      * Returns a custom data object that is registered for the DOM node that is the target of the event
21167      * @param {Event} e The event
21168      * @return {Object} data The custom data
21169      */
21170         getTargetFromEvent : function(e){
21171             var t = Roo.lib.Event.getTarget(e);
21172             return t ? elements[t.id] || handles[t.id] : null;
21173         }
21174     };
21175 }();/*
21176  * Based on:
21177  * Ext JS Library 1.1.1
21178  * Copyright(c) 2006-2007, Ext JS, LLC.
21179  *
21180  * Originally Released Under LGPL - original licence link has changed is not relivant.
21181  *
21182  * Fork - LGPL
21183  * <script type="text/javascript">
21184  */
21185  
21186
21187 /**
21188  * @class Roo.dd.StatusProxy
21189  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21190  * default drag proxy used by all Roo.dd components.
21191  * @constructor
21192  * @param {Object} config
21193  */
21194 Roo.dd.StatusProxy = function(config){
21195     Roo.apply(this, config);
21196     this.id = this.id || Roo.id();
21197     this.el = new Roo.Layer({
21198         dh: {
21199             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21200                 {tag: "div", cls: "x-dd-drop-icon"},
21201                 {tag: "div", cls: "x-dd-drag-ghost"}
21202             ]
21203         }, 
21204         shadow: !config || config.shadow !== false
21205     });
21206     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21207     this.dropStatus = this.dropNotAllowed;
21208 };
21209
21210 Roo.dd.StatusProxy.prototype = {
21211     /**
21212      * @cfg {String} dropAllowed
21213      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21214      */
21215     dropAllowed : "x-dd-drop-ok",
21216     /**
21217      * @cfg {String} dropNotAllowed
21218      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21219      */
21220     dropNotAllowed : "x-dd-drop-nodrop",
21221
21222     /**
21223      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21224      * over the current target element.
21225      * @param {String} cssClass The css class for the new drop status indicator image
21226      */
21227     setStatus : function(cssClass){
21228         cssClass = cssClass || this.dropNotAllowed;
21229         if(this.dropStatus != cssClass){
21230             this.el.replaceClass(this.dropStatus, cssClass);
21231             this.dropStatus = cssClass;
21232         }
21233     },
21234
21235     /**
21236      * Resets the status indicator to the default dropNotAllowed value
21237      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21238      */
21239     reset : function(clearGhost){
21240         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21241         this.dropStatus = this.dropNotAllowed;
21242         if(clearGhost){
21243             this.ghost.update("");
21244         }
21245     },
21246
21247     /**
21248      * Updates the contents of the ghost element
21249      * @param {String} html The html that will replace the current innerHTML of the ghost element
21250      */
21251     update : function(html){
21252         if(typeof html == "string"){
21253             this.ghost.update(html);
21254         }else{
21255             this.ghost.update("");
21256             html.style.margin = "0";
21257             this.ghost.dom.appendChild(html);
21258         }
21259         // ensure float = none set?? cant remember why though.
21260         var el = this.ghost.dom.firstChild;
21261                 if(el){
21262                         Roo.fly(el).setStyle('float', 'none');
21263                 }
21264     },
21265     
21266     /**
21267      * Returns the underlying proxy {@link Roo.Layer}
21268      * @return {Roo.Layer} el
21269     */
21270     getEl : function(){
21271         return this.el;
21272     },
21273
21274     /**
21275      * Returns the ghost element
21276      * @return {Roo.Element} el
21277      */
21278     getGhost : function(){
21279         return this.ghost;
21280     },
21281
21282     /**
21283      * Hides the proxy
21284      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21285      */
21286     hide : function(clear){
21287         this.el.hide();
21288         if(clear){
21289             this.reset(true);
21290         }
21291     },
21292
21293     /**
21294      * Stops the repair animation if it's currently running
21295      */
21296     stop : function(){
21297         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21298             this.anim.stop();
21299         }
21300     },
21301
21302     /**
21303      * Displays this proxy
21304      */
21305     show : function(){
21306         this.el.show();
21307     },
21308
21309     /**
21310      * Force the Layer to sync its shadow and shim positions to the element
21311      */
21312     sync : function(){
21313         this.el.sync();
21314     },
21315
21316     /**
21317      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21318      * invalid drop operation by the item being dragged.
21319      * @param {Array} xy The XY position of the element ([x, y])
21320      * @param {Function} callback The function to call after the repair is complete
21321      * @param {Object} scope The scope in which to execute the callback
21322      */
21323     repair : function(xy, callback, scope){
21324         this.callback = callback;
21325         this.scope = scope;
21326         if(xy && this.animRepair !== false){
21327             this.el.addClass("x-dd-drag-repair");
21328             this.el.hideUnders(true);
21329             this.anim = this.el.shift({
21330                 duration: this.repairDuration || .5,
21331                 easing: 'easeOut',
21332                 xy: xy,
21333                 stopFx: true,
21334                 callback: this.afterRepair,
21335                 scope: this
21336             });
21337         }else{
21338             this.afterRepair();
21339         }
21340     },
21341
21342     // private
21343     afterRepair : function(){
21344         this.hide(true);
21345         if(typeof this.callback == "function"){
21346             this.callback.call(this.scope || this);
21347         }
21348         this.callback = null;
21349         this.scope = null;
21350     }
21351 };/*
21352  * Based on:
21353  * Ext JS Library 1.1.1
21354  * Copyright(c) 2006-2007, Ext JS, LLC.
21355  *
21356  * Originally Released Under LGPL - original licence link has changed is not relivant.
21357  *
21358  * Fork - LGPL
21359  * <script type="text/javascript">
21360  */
21361
21362 /**
21363  * @class Roo.dd.DragSource
21364  * @extends Roo.dd.DDProxy
21365  * A simple class that provides the basic implementation needed to make any element draggable.
21366  * @constructor
21367  * @param {String/HTMLElement/Element} el The container element
21368  * @param {Object} config
21369  */
21370 Roo.dd.DragSource = function(el, config){
21371     this.el = Roo.get(el);
21372     this.dragData = {};
21373     
21374     Roo.apply(this, config);
21375     
21376     if(!this.proxy){
21377         this.proxy = new Roo.dd.StatusProxy();
21378     }
21379
21380     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21381           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21382     
21383     this.dragging = false;
21384 };
21385
21386 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21387     /**
21388      * @cfg {String} dropAllowed
21389      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21390      */
21391     dropAllowed : "x-dd-drop-ok",
21392     /**
21393      * @cfg {String} dropNotAllowed
21394      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21395      */
21396     dropNotAllowed : "x-dd-drop-nodrop",
21397
21398     /**
21399      * Returns the data object associated with this drag source
21400      * @return {Object} data An object containing arbitrary data
21401      */
21402     getDragData : function(e){
21403         return this.dragData;
21404     },
21405
21406     // private
21407     onDragEnter : function(e, id){
21408         var target = Roo.dd.DragDropMgr.getDDById(id);
21409         this.cachedTarget = target;
21410         if(this.beforeDragEnter(target, e, id) !== false){
21411             if(target.isNotifyTarget){
21412                 var status = target.notifyEnter(this, e, this.dragData);
21413                 this.proxy.setStatus(status);
21414             }else{
21415                 this.proxy.setStatus(this.dropAllowed);
21416             }
21417             
21418             if(this.afterDragEnter){
21419                 /**
21420                  * An empty function by default, but provided so that you can perform a custom action
21421                  * when the dragged item enters the drop target by providing an implementation.
21422                  * @param {Roo.dd.DragDrop} target The drop target
21423                  * @param {Event} e The event object
21424                  * @param {String} id The id of the dragged element
21425                  * @method afterDragEnter
21426                  */
21427                 this.afterDragEnter(target, e, id);
21428             }
21429         }
21430     },
21431
21432     /**
21433      * An empty function by default, but provided so that you can perform a custom action
21434      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21435      * @param {Roo.dd.DragDrop} target The drop target
21436      * @param {Event} e The event object
21437      * @param {String} id The id of the dragged element
21438      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21439      */
21440     beforeDragEnter : function(target, e, id){
21441         return true;
21442     },
21443
21444     // private
21445     alignElWithMouse: function() {
21446         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21447         this.proxy.sync();
21448     },
21449
21450     // private
21451     onDragOver : function(e, id){
21452         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21453         if(this.beforeDragOver(target, e, id) !== false){
21454             if(target.isNotifyTarget){
21455                 var status = target.notifyOver(this, e, this.dragData);
21456                 this.proxy.setStatus(status);
21457             }
21458
21459             if(this.afterDragOver){
21460                 /**
21461                  * An empty function by default, but provided so that you can perform a custom action
21462                  * while the dragged item is over the drop target by providing an implementation.
21463                  * @param {Roo.dd.DragDrop} target The drop target
21464                  * @param {Event} e The event object
21465                  * @param {String} id The id of the dragged element
21466                  * @method afterDragOver
21467                  */
21468                 this.afterDragOver(target, e, id);
21469             }
21470         }
21471     },
21472
21473     /**
21474      * An empty function by default, but provided so that you can perform a custom action
21475      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21476      * @param {Roo.dd.DragDrop} target The drop target
21477      * @param {Event} e The event object
21478      * @param {String} id The id of the dragged element
21479      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21480      */
21481     beforeDragOver : function(target, e, id){
21482         return true;
21483     },
21484
21485     // private
21486     onDragOut : function(e, id){
21487         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21488         if(this.beforeDragOut(target, e, id) !== false){
21489             if(target.isNotifyTarget){
21490                 target.notifyOut(this, e, this.dragData);
21491             }
21492             this.proxy.reset();
21493             if(this.afterDragOut){
21494                 /**
21495                  * An empty function by default, but provided so that you can perform a custom action
21496                  * after the dragged item is dragged out of the target without dropping.
21497                  * @param {Roo.dd.DragDrop} target The drop target
21498                  * @param {Event} e The event object
21499                  * @param {String} id The id of the dragged element
21500                  * @method afterDragOut
21501                  */
21502                 this.afterDragOut(target, e, id);
21503             }
21504         }
21505         this.cachedTarget = null;
21506     },
21507
21508     /**
21509      * An empty function by default, but provided so that you can perform a custom action before the dragged
21510      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21511      * @param {Roo.dd.DragDrop} target The drop target
21512      * @param {Event} e The event object
21513      * @param {String} id The id of the dragged element
21514      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21515      */
21516     beforeDragOut : function(target, e, id){
21517         return true;
21518     },
21519     
21520     // private
21521     onDragDrop : function(e, id){
21522         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21523         if(this.beforeDragDrop(target, e, id) !== false){
21524             if(target.isNotifyTarget){
21525                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21526                     this.onValidDrop(target, e, id);
21527                 }else{
21528                     this.onInvalidDrop(target, e, id);
21529                 }
21530             }else{
21531                 this.onValidDrop(target, e, id);
21532             }
21533             
21534             if(this.afterDragDrop){
21535                 /**
21536                  * An empty function by default, but provided so that you can perform a custom action
21537                  * after a valid drag drop has occurred by providing an implementation.
21538                  * @param {Roo.dd.DragDrop} target The drop target
21539                  * @param {Event} e The event object
21540                  * @param {String} id The id of the dropped element
21541                  * @method afterDragDrop
21542                  */
21543                 this.afterDragDrop(target, e, id);
21544             }
21545         }
21546         delete this.cachedTarget;
21547     },
21548
21549     /**
21550      * An empty function by default, but provided so that you can perform a custom action before the dragged
21551      * item is dropped onto the target and optionally cancel the onDragDrop.
21552      * @param {Roo.dd.DragDrop} target The drop target
21553      * @param {Event} e The event object
21554      * @param {String} id The id of the dragged element
21555      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21556      */
21557     beforeDragDrop : function(target, e, id){
21558         return true;
21559     },
21560
21561     // private
21562     onValidDrop : function(target, e, id){
21563         this.hideProxy();
21564         if(this.afterValidDrop){
21565             /**
21566              * An empty function by default, but provided so that you can perform a custom action
21567              * after a valid drop has occurred by providing an implementation.
21568              * @param {Object} target The target DD 
21569              * @param {Event} e The event object
21570              * @param {String} id The id of the dropped element
21571              * @method afterInvalidDrop
21572              */
21573             this.afterValidDrop(target, e, id);
21574         }
21575     },
21576
21577     // private
21578     getRepairXY : function(e, data){
21579         return this.el.getXY();  
21580     },
21581
21582     // private
21583     onInvalidDrop : function(target, e, id){
21584         this.beforeInvalidDrop(target, e, id);
21585         if(this.cachedTarget){
21586             if(this.cachedTarget.isNotifyTarget){
21587                 this.cachedTarget.notifyOut(this, e, this.dragData);
21588             }
21589             this.cacheTarget = null;
21590         }
21591         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21592
21593         if(this.afterInvalidDrop){
21594             /**
21595              * An empty function by default, but provided so that you can perform a custom action
21596              * after an invalid drop has occurred by providing an implementation.
21597              * @param {Event} e The event object
21598              * @param {String} id The id of the dropped element
21599              * @method afterInvalidDrop
21600              */
21601             this.afterInvalidDrop(e, id);
21602         }
21603     },
21604
21605     // private
21606     afterRepair : function(){
21607         if(Roo.enableFx){
21608             this.el.highlight(this.hlColor || "c3daf9");
21609         }
21610         this.dragging = false;
21611     },
21612
21613     /**
21614      * An empty function by default, but provided so that you can perform a custom action after an invalid
21615      * drop has occurred.
21616      * @param {Roo.dd.DragDrop} target The drop target
21617      * @param {Event} e The event object
21618      * @param {String} id The id of the dragged element
21619      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21620      */
21621     beforeInvalidDrop : function(target, e, id){
21622         return true;
21623     },
21624
21625     // private
21626     handleMouseDown : function(e){
21627         if(this.dragging) {
21628             return;
21629         }
21630         var data = this.getDragData(e);
21631         if(data && this.onBeforeDrag(data, e) !== false){
21632             this.dragData = data;
21633             this.proxy.stop();
21634             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21635         } 
21636     },
21637
21638     /**
21639      * An empty function by default, but provided so that you can perform a custom action before the initial
21640      * drag event begins and optionally cancel it.
21641      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21642      * @param {Event} e The event object
21643      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21644      */
21645     onBeforeDrag : function(data, e){
21646         return true;
21647     },
21648
21649     /**
21650      * An empty function by default, but provided so that you can perform a custom action once the initial
21651      * drag event has begun.  The drag cannot be canceled from this function.
21652      * @param {Number} x The x position of the click on the dragged object
21653      * @param {Number} y The y position of the click on the dragged object
21654      */
21655     onStartDrag : Roo.emptyFn,
21656
21657     // private - YUI override
21658     startDrag : function(x, y){
21659         this.proxy.reset();
21660         this.dragging = true;
21661         this.proxy.update("");
21662         this.onInitDrag(x, y);
21663         this.proxy.show();
21664     },
21665
21666     // private
21667     onInitDrag : function(x, y){
21668         var clone = this.el.dom.cloneNode(true);
21669         clone.id = Roo.id(); // prevent duplicate ids
21670         this.proxy.update(clone);
21671         this.onStartDrag(x, y);
21672         return true;
21673     },
21674
21675     /**
21676      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21677      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21678      */
21679     getProxy : function(){
21680         return this.proxy;  
21681     },
21682
21683     /**
21684      * Hides the drag source's {@link Roo.dd.StatusProxy}
21685      */
21686     hideProxy : function(){
21687         this.proxy.hide();  
21688         this.proxy.reset(true);
21689         this.dragging = false;
21690     },
21691
21692     // private
21693     triggerCacheRefresh : function(){
21694         Roo.dd.DDM.refreshCache(this.groups);
21695     },
21696
21697     // private - override to prevent hiding
21698     b4EndDrag: function(e) {
21699     },
21700
21701     // private - override to prevent moving
21702     endDrag : function(e){
21703         this.onEndDrag(this.dragData, e);
21704     },
21705
21706     // private
21707     onEndDrag : function(data, e){
21708     },
21709     
21710     // private - pin to cursor
21711     autoOffset : function(x, y) {
21712         this.setDelta(-12, -20);
21713     }    
21714 });/*
21715  * Based on:
21716  * Ext JS Library 1.1.1
21717  * Copyright(c) 2006-2007, Ext JS, LLC.
21718  *
21719  * Originally Released Under LGPL - original licence link has changed is not relivant.
21720  *
21721  * Fork - LGPL
21722  * <script type="text/javascript">
21723  */
21724
21725
21726 /**
21727  * @class Roo.dd.DropTarget
21728  * @extends Roo.dd.DDTarget
21729  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21730  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21731  * @constructor
21732  * @param {String/HTMLElement/Element} el The container element
21733  * @param {Object} config
21734  */
21735 Roo.dd.DropTarget = function(el, config){
21736     this.el = Roo.get(el);
21737     
21738     var listeners = false; ;
21739     if (config && config.listeners) {
21740         listeners= config.listeners;
21741         delete config.listeners;
21742     }
21743     Roo.apply(this, config);
21744     
21745     if(this.containerScroll){
21746         Roo.dd.ScrollManager.register(this.el);
21747     }
21748     this.addEvents( {
21749          /**
21750          * @scope Roo.dd.DropTarget
21751          */
21752          
21753          /**
21754          * @event enter
21755          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21756          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21757          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21758          * 
21759          * IMPORTANT : it should set this.overClass and this.dropAllowed
21760          * 
21761          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21762          * @param {Event} e The event
21763          * @param {Object} data An object containing arbitrary data supplied by the drag source
21764          */
21765         "enter" : true,
21766         
21767          /**
21768          * @event over
21769          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21770          * This method will be called on every mouse movement while the drag source is over the drop target.
21771          * This default implementation simply returns the dropAllowed config value.
21772          * 
21773          * IMPORTANT : it should set this.dropAllowed
21774          * 
21775          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21776          * @param {Event} e The event
21777          * @param {Object} data An object containing arbitrary data supplied by the drag source
21778          
21779          */
21780         "over" : true,
21781         /**
21782          * @event out
21783          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21784          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21785          * overClass (if any) from the drop element.
21786          * 
21787          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21788          * @param {Event} e The event
21789          * @param {Object} data An object containing arbitrary data supplied by the drag source
21790          */
21791          "out" : true,
21792          
21793         /**
21794          * @event drop
21795          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21796          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21797          * implementation that does something to process the drop event and returns true so that the drag source's
21798          * repair action does not run.
21799          * 
21800          * IMPORTANT : it should set this.success
21801          * 
21802          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21803          * @param {Event} e The event
21804          * @param {Object} data An object containing arbitrary data supplied by the drag source
21805         */
21806          "drop" : true
21807     });
21808             
21809      
21810     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21811         this.el.dom, 
21812         this.ddGroup || this.group,
21813         {
21814             isTarget: true,
21815             listeners : listeners || {} 
21816            
21817         
21818         }
21819     );
21820
21821 };
21822
21823 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21824     /**
21825      * @cfg {String} overClass
21826      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21827      */
21828      /**
21829      * @cfg {String} ddGroup
21830      * The drag drop group to handle drop events for
21831      */
21832      
21833     /**
21834      * @cfg {String} dropAllowed
21835      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21836      */
21837     dropAllowed : "x-dd-drop-ok",
21838     /**
21839      * @cfg {String} dropNotAllowed
21840      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21841      */
21842     dropNotAllowed : "x-dd-drop-nodrop",
21843     /**
21844      * @cfg {boolean} success
21845      * set this after drop listener.. 
21846      */
21847     success : false,
21848     /**
21849      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21850      * if the drop point is valid for over/enter..
21851      */
21852     valid : false,
21853     // private
21854     isTarget : true,
21855
21856     // private
21857     isNotifyTarget : true,
21858     
21859     /**
21860      * @hide
21861      */
21862     notifyEnter : function(dd, e, data)
21863     {
21864         this.valid = true;
21865         this.fireEvent('enter', dd, e, data);
21866         if(this.overClass){
21867             this.el.addClass(this.overClass);
21868         }
21869         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21870             this.valid ? this.dropAllowed : this.dropNotAllowed
21871         );
21872     },
21873
21874     /**
21875      * @hide
21876      */
21877     notifyOver : function(dd, e, data)
21878     {
21879         this.valid = true;
21880         this.fireEvent('over', dd, e, data);
21881         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21882             this.valid ? this.dropAllowed : this.dropNotAllowed
21883         );
21884     },
21885
21886     /**
21887      * @hide
21888      */
21889     notifyOut : function(dd, e, data)
21890     {
21891         this.fireEvent('out', dd, e, data);
21892         if(this.overClass){
21893             this.el.removeClass(this.overClass);
21894         }
21895     },
21896
21897     /**
21898      * @hide
21899      */
21900     notifyDrop : function(dd, e, data)
21901     {
21902         this.success = false;
21903         this.fireEvent('drop', dd, e, data);
21904         return this.success;
21905     }
21906 });/*
21907  * Based on:
21908  * Ext JS Library 1.1.1
21909  * Copyright(c) 2006-2007, Ext JS, LLC.
21910  *
21911  * Originally Released Under LGPL - original licence link has changed is not relivant.
21912  *
21913  * Fork - LGPL
21914  * <script type="text/javascript">
21915  */
21916
21917
21918 /**
21919  * @class Roo.dd.DragZone
21920  * @extends Roo.dd.DragSource
21921  * This class provides a container DD instance that proxies for multiple child node sources.<br />
21922  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
21923  * @constructor
21924  * @param {String/HTMLElement/Element} el The container element
21925  * @param {Object} config
21926  */
21927 Roo.dd.DragZone = function(el, config){
21928     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
21929     if(this.containerScroll){
21930         Roo.dd.ScrollManager.register(this.el);
21931     }
21932 };
21933
21934 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
21935     /**
21936      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
21937      * for auto scrolling during drag operations.
21938      */
21939     /**
21940      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
21941      * method after a failed drop (defaults to "c3daf9" - light blue)
21942      */
21943
21944     /**
21945      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
21946      * for a valid target to drag based on the mouse down. Override this method
21947      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
21948      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
21949      * @param {EventObject} e The mouse down event
21950      * @return {Object} The dragData
21951      */
21952     getDragData : function(e){
21953         return Roo.dd.Registry.getHandleFromEvent(e);
21954     },
21955     
21956     /**
21957      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
21958      * this.dragData.ddel
21959      * @param {Number} x The x position of the click on the dragged object
21960      * @param {Number} y The y position of the click on the dragged object
21961      * @return {Boolean} true to continue the drag, false to cancel
21962      */
21963     onInitDrag : function(x, y){
21964         this.proxy.update(this.dragData.ddel.cloneNode(true));
21965         this.onStartDrag(x, y);
21966         return true;
21967     },
21968     
21969     /**
21970      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
21971      */
21972     afterRepair : function(){
21973         if(Roo.enableFx){
21974             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
21975         }
21976         this.dragging = false;
21977     },
21978
21979     /**
21980      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
21981      * the XY of this.dragData.ddel
21982      * @param {EventObject} e The mouse up event
21983      * @return {Array} The xy location (e.g. [100, 200])
21984      */
21985     getRepairXY : function(e){
21986         return Roo.Element.fly(this.dragData.ddel).getXY();  
21987     }
21988 });/*
21989  * Based on:
21990  * Ext JS Library 1.1.1
21991  * Copyright(c) 2006-2007, Ext JS, LLC.
21992  *
21993  * Originally Released Under LGPL - original licence link has changed is not relivant.
21994  *
21995  * Fork - LGPL
21996  * <script type="text/javascript">
21997  */
21998 /**
21999  * @class Roo.dd.DropZone
22000  * @extends Roo.dd.DropTarget
22001  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22002  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22003  * @constructor
22004  * @param {String/HTMLElement/Element} el The container element
22005  * @param {Object} config
22006  */
22007 Roo.dd.DropZone = function(el, config){
22008     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22009 };
22010
22011 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22012     /**
22013      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22014      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22015      * provide your own custom lookup.
22016      * @param {Event} e The event
22017      * @return {Object} data The custom data
22018      */
22019     getTargetFromEvent : function(e){
22020         return Roo.dd.Registry.getTargetFromEvent(e);
22021     },
22022
22023     /**
22024      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22025      * that it has registered.  This method has no default implementation and should be overridden to provide
22026      * node-specific processing if necessary.
22027      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22028      * {@link #getTargetFromEvent} for this node)
22029      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22030      * @param {Event} e The event
22031      * @param {Object} data An object containing arbitrary data supplied by the drag source
22032      */
22033     onNodeEnter : function(n, dd, e, data){
22034         
22035     },
22036
22037     /**
22038      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22039      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22040      * overridden to provide the proper feedback.
22041      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22042      * {@link #getTargetFromEvent} for this node)
22043      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22044      * @param {Event} e The event
22045      * @param {Object} data An object containing arbitrary data supplied by the drag source
22046      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22047      * underlying {@link Roo.dd.StatusProxy} can be updated
22048      */
22049     onNodeOver : function(n, dd, e, data){
22050         return this.dropAllowed;
22051     },
22052
22053     /**
22054      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22055      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22056      * node-specific processing if necessary.
22057      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22058      * {@link #getTargetFromEvent} for this node)
22059      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22060      * @param {Event} e The event
22061      * @param {Object} data An object containing arbitrary data supplied by the drag source
22062      */
22063     onNodeOut : function(n, dd, e, data){
22064         
22065     },
22066
22067     /**
22068      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22069      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22070      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22071      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22072      * {@link #getTargetFromEvent} for this node)
22073      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22074      * @param {Event} e The event
22075      * @param {Object} data An object containing arbitrary data supplied by the drag source
22076      * @return {Boolean} True if the drop was valid, else false
22077      */
22078     onNodeDrop : function(n, dd, e, data){
22079         return false;
22080     },
22081
22082     /**
22083      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22084      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22085      * it should be overridden to provide the proper feedback if necessary.
22086      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22087      * @param {Event} e The event
22088      * @param {Object} data An object containing arbitrary data supplied by the drag source
22089      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22090      * underlying {@link Roo.dd.StatusProxy} can be updated
22091      */
22092     onContainerOver : function(dd, e, data){
22093         return this.dropNotAllowed;
22094     },
22095
22096     /**
22097      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22098      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22099      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22100      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22101      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22102      * @param {Event} e The event
22103      * @param {Object} data An object containing arbitrary data supplied by the drag source
22104      * @return {Boolean} True if the drop was valid, else false
22105      */
22106     onContainerDrop : function(dd, e, data){
22107         return false;
22108     },
22109
22110     /**
22111      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22112      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22113      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22114      * you should override this method and provide a custom implementation.
22115      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22116      * @param {Event} e The event
22117      * @param {Object} data An object containing arbitrary data supplied by the drag source
22118      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22119      * underlying {@link Roo.dd.StatusProxy} can be updated
22120      */
22121     notifyEnter : function(dd, e, data){
22122         return this.dropNotAllowed;
22123     },
22124
22125     /**
22126      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22127      * This method will be called on every mouse movement while the drag source is over the drop zone.
22128      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22129      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22130      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22131      * registered node, it will call {@link #onContainerOver}.
22132      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22133      * @param {Event} e The event
22134      * @param {Object} data An object containing arbitrary data supplied by the drag source
22135      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22136      * underlying {@link Roo.dd.StatusProxy} can be updated
22137      */
22138     notifyOver : function(dd, e, data){
22139         var n = this.getTargetFromEvent(e);
22140         if(!n){ // not over valid drop target
22141             if(this.lastOverNode){
22142                 this.onNodeOut(this.lastOverNode, dd, e, data);
22143                 this.lastOverNode = null;
22144             }
22145             return this.onContainerOver(dd, e, data);
22146         }
22147         if(this.lastOverNode != n){
22148             if(this.lastOverNode){
22149                 this.onNodeOut(this.lastOverNode, dd, e, data);
22150             }
22151             this.onNodeEnter(n, dd, e, data);
22152             this.lastOverNode = n;
22153         }
22154         return this.onNodeOver(n, dd, e, data);
22155     },
22156
22157     /**
22158      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22159      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22160      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22161      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22162      * @param {Event} e The event
22163      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22164      */
22165     notifyOut : function(dd, e, data){
22166         if(this.lastOverNode){
22167             this.onNodeOut(this.lastOverNode, dd, e, data);
22168             this.lastOverNode = null;
22169         }
22170     },
22171
22172     /**
22173      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22174      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22175      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22176      * otherwise it will call {@link #onContainerDrop}.
22177      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22178      * @param {Event} e The event
22179      * @param {Object} data An object containing arbitrary data supplied by the drag source
22180      * @return {Boolean} True if the drop was valid, else false
22181      */
22182     notifyDrop : function(dd, e, data){
22183         if(this.lastOverNode){
22184             this.onNodeOut(this.lastOverNode, dd, e, data);
22185             this.lastOverNode = null;
22186         }
22187         var n = this.getTargetFromEvent(e);
22188         return n ?
22189             this.onNodeDrop(n, dd, e, data) :
22190             this.onContainerDrop(dd, e, data);
22191     },
22192
22193     // private
22194     triggerCacheRefresh : function(){
22195         Roo.dd.DDM.refreshCache(this.groups);
22196     }  
22197 });