roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isGecko = !isSafari && ua.indexOf("gecko") > -1,
61         isBorderBox = isIE && !isStrict,
62         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64         isLinux = (ua.indexOf("linux") != -1),
65         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66         isIOS = /iphone|ipad/.test(ua),
67         isAndroid = /android/.test(ua),
68         isTouch =  (function() {
69             try {
70                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
71                     window.addEventListener('touchstart', function __set_has_touch__ () {
72                         Roo.isTouch = true;
73                         window.removeEventListener('touchstart', __set_has_touch__);
74                     });
75                     return false; // no touch on chrome!?
76                 }
77                 document.createEvent("TouchEvent");  
78                 return true;  
79             } catch (e) {  
80                 return false;  
81             } 
82             
83         })();
84     // remove css image flicker
85         if(isIE && !isIE7){
86         try{
87             document.execCommand("BackgroundImageCache", false, true);
88         }catch(e){}
89     }
90     
91     Roo.apply(Roo, {
92         /**
93          * True if the browser is in strict mode
94          * @type Boolean
95          */
96         isStrict : isStrict,
97         /**
98          * True if the page is running over SSL
99          * @type Boolean
100          */
101         isSecure : isSecure,
102         /**
103          * True when the document is fully initialized and ready for action
104          * @type Boolean
105          */
106         isReady : false,
107         /**
108          * Turn on debugging output (currently only the factory uses this)
109          * @type Boolean
110          */
111         
112         debug: false,
113
114         /**
115          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
116          * @type Boolean
117          */
118         enableGarbageCollector : true,
119
120         /**
121          * True to automatically purge event listeners after uncaching an element (defaults to false).
122          * Note: this only happens if enableGarbageCollector is true.
123          * @type Boolean
124          */
125         enableListenerCollection:false,
126
127         /**
128          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
129          * the IE insecure content warning (defaults to javascript:false).
130          * @type String
131          */
132         SSL_SECURE_URL : "javascript:false",
133
134         /**
135          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
136          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
137          * @type String
138          */
139         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
140
141         emptyFn : function(){},
142         
143         /**
144          * Copies all the properties of config to obj if they don't already exist.
145          * @param {Object} obj The receiver of the properties
146          * @param {Object} config The source of the properties
147          * @return {Object} returns obj
148          */
149         applyIf : function(o, c){
150             if(o && c){
151                 for(var p in c){
152                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
153                 }
154             }
155             return o;
156         },
157
158         /**
159          * Applies event listeners to elements by selectors when the document is ready.
160          * The event name is specified with an @ suffix.
161 <pre><code>
162 Roo.addBehaviors({
163    // add a listener for click on all anchors in element with id foo
164    '#foo a@click' : function(e, t){
165        // do something
166    },
167
168    // add the same listener to multiple selectors (separated by comma BEFORE the @)
169    '#foo a, #bar span.some-class@mouseover' : function(){
170        // do something
171    }
172 });
173 </code></pre>
174          * @param {Object} obj The list of behaviors to apply
175          */
176         addBehaviors : function(o){
177             if(!Roo.isReady){
178                 Roo.onReady(function(){
179                     Roo.addBehaviors(o);
180                 });
181                 return;
182             }
183             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
184             for(var b in o){
185                 var parts = b.split('@');
186                 if(parts[1]){ // for Object prototype breakers
187                     var s = parts[0];
188                     if(!cache[s]){
189                         cache[s] = Roo.select(s);
190                     }
191                     cache[s].on(parts[1], o[b]);
192                 }
193             }
194             cache = null;
195         },
196
197         /**
198          * Generates unique ids. If the element already has an id, it is unchanged
199          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
200          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
201          * @return {String} The generated Id.
202          */
203         id : function(el, prefix){
204             prefix = prefix || "roo-gen";
205             el = Roo.getDom(el);
206             var id = prefix + (++idSeed);
207             return el ? (el.id ? el.id : (el.id = id)) : id;
208         },
209          
210        
211         /**
212          * Extends one class with another class and optionally overrides members with the passed literal. This class
213          * also adds the function "override()" to the class that can be used to override
214          * members on an instance.
215          * @param {Object} subclass The class inheriting the functionality
216          * @param {Object} superclass The class being extended
217          * @param {Object} overrides (optional) A literal with members
218          * @method extend
219          */
220         extend : function(){
221             // inline overrides
222             var io = function(o){
223                 for(var m in o){
224                     this[m] = o[m];
225                 }
226             };
227             return function(sb, sp, overrides){
228                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
229                     overrides = sp;
230                     sp = sb;
231                     sb = function(){sp.apply(this, arguments);};
232                 }
233                 var F = function(){}, sbp, spp = sp.prototype;
234                 F.prototype = spp;
235                 sbp = sb.prototype = new F();
236                 sbp.constructor=sb;
237                 sb.superclass=spp;
238                 
239                 if(spp.constructor == Object.prototype.constructor){
240                     spp.constructor=sp;
241                    
242                 }
243                 
244                 sb.override = function(o){
245                     Roo.override(sb, o);
246                 };
247                 sbp.override = io;
248                 Roo.override(sb, overrides);
249                 return sb;
250             };
251         }(),
252
253         /**
254          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
255          * Usage:<pre><code>
256 Roo.override(MyClass, {
257     newMethod1: function(){
258         // etc.
259     },
260     newMethod2: function(foo){
261         // etc.
262     }
263 });
264  </code></pre>
265          * @param {Object} origclass The class to override
266          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
267          * containing one or more methods.
268          * @method override
269          */
270         override : function(origclass, overrides){
271             if(overrides){
272                 var p = origclass.prototype;
273                 for(var method in overrides){
274                     p[method] = overrides[method];
275                 }
276             }
277         },
278         /**
279          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
280          * <pre><code>
281 Roo.namespace('Company', 'Company.data');
282 Company.Widget = function() { ... }
283 Company.data.CustomStore = function(config) { ... }
284 </code></pre>
285          * @param {String} namespace1
286          * @param {String} namespace2
287          * @param {String} etc
288          * @method namespace
289          */
290         namespace : function(){
291             var a=arguments, o=null, i, j, d, rt;
292             for (i=0; i<a.length; ++i) {
293                 d=a[i].split(".");
294                 rt = d[0];
295                 /** eval:var:o */
296                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
297                 for (j=1; j<d.length; ++j) {
298                     o[d[j]]=o[d[j]] || {};
299                     o=o[d[j]];
300                 }
301             }
302         },
303         /**
304          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
305          * <pre><code>
306 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
307 Roo.factory(conf, Roo.data);
308 </code></pre>
309          * @param {String} classname
310          * @param {String} namespace (optional)
311          * @method factory
312          */
313          
314         factory : function(c, ns)
315         {
316             // no xtype, no ns or c.xns - or forced off by c.xns
317             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
318                 return c;
319             }
320             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
321             if (c.constructor == ns[c.xtype]) {// already created...
322                 return c;
323             }
324             if (ns[c.xtype]) {
325                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
326                 var ret = new ns[c.xtype](c);
327                 ret.xns = false;
328                 return ret;
329             }
330             c.xns = false; // prevent recursion..
331             return c;
332         },
333          /**
334          * Logs to console if it can.
335          *
336          * @param {String|Object} string
337          * @method log
338          */
339         log : function(s)
340         {
341             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
342                 return; // alerT?
343             }
344             console.log(s);
345             
346         },
347         /**
348          * 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.
349          * @param {Object} o
350          * @return {String}
351          */
352         urlEncode : function(o){
353             if(!o){
354                 return "";
355             }
356             var buf = [];
357             for(var key in o){
358                 var ov = o[key], k = Roo.encodeURIComponent(key);
359                 var type = typeof ov;
360                 if(type == 'undefined'){
361                     buf.push(k, "=&");
362                 }else if(type != "function" && type != "object"){
363                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
364                 }else if(ov instanceof Array){
365                     if (ov.length) {
366                             for(var i = 0, len = ov.length; i < len; i++) {
367                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
368                             }
369                         } else {
370                             buf.push(k, "=&");
371                         }
372                 }
373             }
374             buf.pop();
375             return buf.join("");
376         },
377          /**
378          * Safe version of encodeURIComponent
379          * @param {String} data 
380          * @return {String} 
381          */
382         
383         encodeURIComponent : function (data)
384         {
385             try {
386                 return encodeURIComponent(data);
387             } catch(e) {} // should be an uri encode error.
388             
389             if (data == '' || data == null){
390                return '';
391             }
392             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
393             function nibble_to_hex(nibble){
394                 var chars = '0123456789ABCDEF';
395                 return chars.charAt(nibble);
396             }
397             data = data.toString();
398             var buffer = '';
399             for(var i=0; i<data.length; i++){
400                 var c = data.charCodeAt(i);
401                 var bs = new Array();
402                 if (c > 0x10000){
403                         // 4 bytes
404                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
405                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
406                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
407                     bs[3] = 0x80 | (c & 0x3F);
408                 }else if (c > 0x800){
409                          // 3 bytes
410                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
411                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
412                     bs[2] = 0x80 | (c & 0x3F);
413                 }else if (c > 0x80){
414                        // 2 bytes
415                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
416                     bs[1] = 0x80 | (c & 0x3F);
417                 }else{
418                         // 1 byte
419                     bs[0] = c;
420                 }
421                 for(var j=0; j<bs.length; j++){
422                     var b = bs[j];
423                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
424                             + nibble_to_hex(b &0x0F);
425                     buffer += '%'+hex;
426                }
427             }
428             return buffer;    
429              
430         },
431
432         /**
433          * 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]}.
434          * @param {String} string
435          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
436          * @return {Object} A literal with members
437          */
438         urlDecode : function(string, overwrite){
439             if(!string || !string.length){
440                 return {};
441             }
442             var obj = {};
443             var pairs = string.split('&');
444             var pair, name, value;
445             for(var i = 0, len = pairs.length; i < len; i++){
446                 pair = pairs[i].split('=');
447                 name = decodeURIComponent(pair[0]);
448                 value = decodeURIComponent(pair[1]);
449                 if(overwrite !== true){
450                     if(typeof obj[name] == "undefined"){
451                         obj[name] = value;
452                     }else if(typeof obj[name] == "string"){
453                         obj[name] = [obj[name]];
454                         obj[name].push(value);
455                     }else{
456                         obj[name].push(value);
457                     }
458                 }else{
459                     obj[name] = value;
460                 }
461             }
462             return obj;
463         },
464
465         /**
466          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
467          * passed array is not really an array, your function is called once with it.
468          * The supplied function is called with (Object item, Number index, Array allItems).
469          * @param {Array/NodeList/Mixed} array
470          * @param {Function} fn
471          * @param {Object} scope
472          */
473         each : function(array, fn, scope){
474             if(typeof array.length == "undefined" || typeof array == "string"){
475                 array = [array];
476             }
477             for(var i = 0, len = array.length; i < len; i++){
478                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
479             }
480         },
481
482         // deprecated
483         combine : function(){
484             var as = arguments, l = as.length, r = [];
485             for(var i = 0; i < l; i++){
486                 var a = as[i];
487                 if(a instanceof Array){
488                     r = r.concat(a);
489                 }else if(a.length !== undefined && !a.substr){
490                     r = r.concat(Array.prototype.slice.call(a, 0));
491                 }else{
492                     r.push(a);
493                 }
494             }
495             return r;
496         },
497
498         /**
499          * Escapes the passed string for use in a regular expression
500          * @param {String} str
501          * @return {String}
502          */
503         escapeRe : function(s) {
504             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
505         },
506
507         // internal
508         callback : function(cb, scope, args, delay){
509             if(typeof cb == "function"){
510                 if(delay){
511                     cb.defer(delay, scope, args || []);
512                 }else{
513                     cb.apply(scope, args || []);
514                 }
515             }
516         },
517
518         /**
519          * Return the dom node for the passed string (id), dom node, or Roo.Element
520          * @param {String/HTMLElement/Roo.Element} el
521          * @return HTMLElement
522          */
523         getDom : function(el){
524             if(!el){
525                 return null;
526             }
527             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
528         },
529
530         /**
531         * Shorthand for {@link Roo.ComponentMgr#get}
532         * @param {String} id
533         * @return Roo.Component
534         */
535         getCmp : function(id){
536             return Roo.ComponentMgr.get(id);
537         },
538          
539         num : function(v, defaultValue){
540             if(typeof v != 'number'){
541                 return defaultValue;
542             }
543             return v;
544         },
545
546         destroy : function(){
547             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
548                 var as = a[i];
549                 if(as){
550                     if(as.dom){
551                         as.removeAllListeners();
552                         as.remove();
553                         continue;
554                     }
555                     if(typeof as.purgeListeners == 'function'){
556                         as.purgeListeners();
557                     }
558                     if(typeof as.destroy == 'function'){
559                         as.destroy();
560                     }
561                 }
562             }
563         },
564
565         // inpired by a similar function in mootools library
566         /**
567          * Returns the type of object that is passed in. If the object passed in is null or undefined it
568          * return false otherwise it returns one of the following values:<ul>
569          * <li><b>string</b>: If the object passed is a string</li>
570          * <li><b>number</b>: If the object passed is a number</li>
571          * <li><b>boolean</b>: If the object passed is a boolean value</li>
572          * <li><b>function</b>: If the object passed is a function reference</li>
573          * <li><b>object</b>: If the object passed is an object</li>
574          * <li><b>array</b>: If the object passed is an array</li>
575          * <li><b>regexp</b>: If the object passed is a regular expression</li>
576          * <li><b>element</b>: If the object passed is a DOM Element</li>
577          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
578          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
579          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
580          * @param {Mixed} object
581          * @return {String}
582          */
583         type : function(o){
584             if(o === undefined || o === null){
585                 return false;
586             }
587             if(o.htmlElement){
588                 return 'element';
589             }
590             var t = typeof o;
591             if(t == 'object' && o.nodeName) {
592                 switch(o.nodeType) {
593                     case 1: return 'element';
594                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
595                 }
596             }
597             if(t == 'object' || t == 'function') {
598                 switch(o.constructor) {
599                     case Array: return 'array';
600                     case RegExp: return 'regexp';
601                 }
602                 if(typeof o.length == 'number' && typeof o.item == 'function') {
603                     return 'nodelist';
604                 }
605             }
606             return t;
607         },
608
609         /**
610          * Returns true if the passed value is null, undefined or an empty string (optional).
611          * @param {Mixed} value The value to test
612          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
613          * @return {Boolean}
614          */
615         isEmpty : function(v, allowBlank){
616             return v === null || v === undefined || (!allowBlank ? v === '' : false);
617         },
618         
619         /** @type Boolean */
620         isOpera : isOpera,
621         /** @type Boolean */
622         isSafari : isSafari,
623         /** @type Boolean */
624         isFirefox : isFirefox,
625         /** @type Boolean */
626         isIE : isIE,
627         /** @type Boolean */
628         isIE7 : isIE7,
629         /** @type Boolean */
630         isIE11 : isIE11,
631         /** @type Boolean */
632         isGecko : isGecko,
633         /** @type Boolean */
634         isBorderBox : isBorderBox,
635         /** @type Boolean */
636         isWindows : isWindows,
637         /** @type Boolean */
638         isLinux : isLinux,
639         /** @type Boolean */
640         isMac : isMac,
641         /** @type Boolean */
642         isIOS : isIOS,
643         /** @type Boolean */
644         isAndroid : isAndroid,
645         /** @type Boolean */
646         isTouch : isTouch,
647
648         /**
649          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
650          * you may want to set this to true.
651          * @type Boolean
652          */
653         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
654         
655         
656                 
657         /**
658          * Selects a single element as a Roo Element
659          * This is about as close as you can get to jQuery's $('do crazy stuff')
660          * @param {String} selector The selector/xpath query
661          * @param {Node} root (optional) The start of the query (defaults to document).
662          * @return {Roo.Element}
663          */
664         selectNode : function(selector, root) 
665         {
666             var node = Roo.DomQuery.selectNode(selector,root);
667             return node ? Roo.get(node) : new Roo.Element(false);
668         }
669         
670     });
671
672
673 })();
674
675 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
676                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
677                 "Roo.app", "Roo.ux",
678                 "Roo.bootstrap",
679                 "Roo.bootstrap.dash");
680 /*
681  * Based on:
682  * Ext JS Library 1.1.1
683  * Copyright(c) 2006-2007, Ext JS, LLC.
684  *
685  * Originally Released Under LGPL - original licence link has changed is not relivant.
686  *
687  * Fork - LGPL
688  * <script type="text/javascript">
689  */
690
691 (function() {    
692     // wrappedn so fnCleanup is not in global scope...
693     if(Roo.isIE) {
694         function fnCleanUp() {
695             var p = Function.prototype;
696             delete p.createSequence;
697             delete p.defer;
698             delete p.createDelegate;
699             delete p.createCallback;
700             delete p.createInterceptor;
701
702             window.detachEvent("onunload", fnCleanUp);
703         }
704         window.attachEvent("onunload", fnCleanUp);
705     }
706 })();
707
708
709 /**
710  * @class Function
711  * These functions are available on every Function object (any JavaScript function).
712  */
713 Roo.apply(Function.prototype, {
714      /**
715      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
716      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
717      * Will create a function that is bound to those 2 args.
718      * @return {Function} The new function
719     */
720     createCallback : function(/*args...*/){
721         // make args available, in function below
722         var args = arguments;
723         var method = this;
724         return function() {
725             return method.apply(window, args);
726         };
727     },
728
729     /**
730      * Creates a delegate (callback) that sets the scope to obj.
731      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
732      * Will create a function that is automatically scoped to this.
733      * @param {Object} obj (optional) The object for which the scope is set
734      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
735      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
736      *                                             if a number the args are inserted at the specified position
737      * @return {Function} The new function
738      */
739     createDelegate : function(obj, args, appendArgs){
740         var method = this;
741         return function() {
742             var callArgs = args || arguments;
743             if(appendArgs === true){
744                 callArgs = Array.prototype.slice.call(arguments, 0);
745                 callArgs = callArgs.concat(args);
746             }else if(typeof appendArgs == "number"){
747                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
748                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
749                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
750             }
751             return method.apply(obj || window, callArgs);
752         };
753     },
754
755     /**
756      * Calls this function after the number of millseconds specified.
757      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
758      * @param {Object} obj (optional) The object for which the scope is set
759      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761      *                                             if a number the args are inserted at the specified position
762      * @return {Number} The timeout id that can be used with clearTimeout
763      */
764     defer : function(millis, obj, args, appendArgs){
765         var fn = this.createDelegate(obj, args, appendArgs);
766         if(millis){
767             return setTimeout(fn, millis);
768         }
769         fn();
770         return 0;
771     },
772     /**
773      * Create a combined function call sequence of the original function + the passed function.
774      * The resulting function returns the results of the original function.
775      * The passed fcn is called with the parameters of the original function
776      * @param {Function} fcn The function to sequence
777      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
778      * @return {Function} The new function
779      */
780     createSequence : function(fcn, scope){
781         if(typeof fcn != "function"){
782             return this;
783         }
784         var method = this;
785         return function() {
786             var retval = method.apply(this || window, arguments);
787             fcn.apply(scope || this || window, arguments);
788             return retval;
789         };
790     },
791
792     /**
793      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
794      * The resulting function returns the results of the original function.
795      * The passed fcn is called with the parameters of the original function.
796      * @addon
797      * @param {Function} fcn The function to call before the original
798      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
799      * @return {Function} The new function
800      */
801     createInterceptor : function(fcn, scope){
802         if(typeof fcn != "function"){
803             return this;
804         }
805         var method = this;
806         return function() {
807             fcn.target = this;
808             fcn.method = method;
809             if(fcn.apply(scope || this || window, arguments) === false){
810                 return;
811             }
812             return method.apply(this || window, arguments);
813         };
814     }
815 });
816 /*
817  * Based on:
818  * Ext JS Library 1.1.1
819  * Copyright(c) 2006-2007, Ext JS, LLC.
820  *
821  * Originally Released Under LGPL - original licence link has changed is not relivant.
822  *
823  * Fork - LGPL
824  * <script type="text/javascript">
825  */
826
827 Roo.applyIf(String, {
828     
829     /** @scope String */
830     
831     /**
832      * Escapes the passed string for ' and \
833      * @param {String} string The string to escape
834      * @return {String} The escaped string
835      * @static
836      */
837     escape : function(string) {
838         return string.replace(/('|\\)/g, "\\$1");
839     },
840
841     /**
842      * Pads the left side of a string with a specified character.  This is especially useful
843      * for normalizing number and date strings.  Example usage:
844      * <pre><code>
845 var s = String.leftPad('123', 5, '0');
846 // s now contains the string: '00123'
847 </code></pre>
848      * @param {String} string The original string
849      * @param {Number} size The total length of the output string
850      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
851      * @return {String} The padded string
852      * @static
853      */
854     leftPad : function (val, size, ch) {
855         var result = new String(val);
856         if(ch === null || ch === undefined || ch === '') {
857             ch = " ";
858         }
859         while (result.length < size) {
860             result = ch + result;
861         }
862         return result;
863     },
864
865     /**
866      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
867      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
868      * <pre><code>
869 var cls = 'my-class', text = 'Some text';
870 var s = String.format('<div class="{0}">{1}</div>', cls, text);
871 // s now contains the string: '<div class="my-class">Some text</div>'
872 </code></pre>
873      * @param {String} string The tokenized string to be formatted
874      * @param {String} value1 The value to replace token {0}
875      * @param {String} value2 Etc...
876      * @return {String} The formatted string
877      * @static
878      */
879     format : function(format){
880         var args = Array.prototype.slice.call(arguments, 1);
881         return format.replace(/\{(\d+)\}/g, function(m, i){
882             return Roo.util.Format.htmlEncode(args[i]);
883         });
884     }
885 });
886
887 /**
888  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
889  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
890  * they are already different, the first value passed in is returned.  Note that this method returns the new value
891  * but does not change the current string.
892  * <pre><code>
893 // alternate sort directions
894 sort = sort.toggle('ASC', 'DESC');
895
896 // instead of conditional logic:
897 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
898 </code></pre>
899  * @param {String} value The value to compare to the current string
900  * @param {String} other The new value to use if the string already equals the first value passed in
901  * @return {String} The new value
902  */
903  
904 String.prototype.toggle = function(value, other){
905     return this == value ? other : value;
906 };/*
907  * Based on:
908  * Ext JS Library 1.1.1
909  * Copyright(c) 2006-2007, Ext JS, LLC.
910  *
911  * Originally Released Under LGPL - original licence link has changed is not relivant.
912  *
913  * Fork - LGPL
914  * <script type="text/javascript">
915  */
916
917  /**
918  * @class Number
919  */
920 Roo.applyIf(Number.prototype, {
921     /**
922      * Checks whether or not the current number is within a desired range.  If the number is already within the
923      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
924      * exceeded.  Note that this method returns the constrained value but does not change the current number.
925      * @param {Number} min The minimum number in the range
926      * @param {Number} max The maximum number in the range
927      * @return {Number} The constrained value if outside the range, otherwise the current value
928      */
929     constrain : function(min, max){
930         return Math.min(Math.max(this, min), max);
931     }
932 });/*
933  * Based on:
934  * Ext JS Library 1.1.1
935  * Copyright(c) 2006-2007, Ext JS, LLC.
936  *
937  * Originally Released Under LGPL - original licence link has changed is not relivant.
938  *
939  * Fork - LGPL
940  * <script type="text/javascript">
941  */
942  /**
943  * @class Array
944  */
945 Roo.applyIf(Array.prototype, {
946     /**
947      * 
948      * Checks whether or not the specified object exists in the array.
949      * @param {Object} o The object to check for
950      * @return {Number} The index of o in the array (or -1 if it is not found)
951      */
952     indexOf : function(o){
953        for (var i = 0, len = this.length; i < len; i++){
954               if(this[i] == o) { return i; }
955        }
956            return -1;
957     },
958
959     /**
960      * Removes the specified object from the array.  If the object is not found nothing happens.
961      * @param {Object} o The object to remove
962      */
963     remove : function(o){
964        var index = this.indexOf(o);
965        if(index != -1){
966            this.splice(index, 1);
967        }
968     },
969     /**
970      * Map (JS 1.6 compatibility)
971      * @param {Function} function  to call
972      */
973     map : function(fun )
974     {
975         var len = this.length >>> 0;
976         if (typeof fun != "function") {
977             throw new TypeError();
978         }
979         var res = new Array(len);
980         var thisp = arguments[1];
981         for (var i = 0; i < len; i++)
982         {
983             if (i in this) {
984                 res[i] = fun.call(thisp, this[i], i, this);
985             }
986         }
987
988         return res;
989     }
990     
991 });
992
993
994  
995 /*
996  * Based on:
997  * Ext JS Library 1.1.1
998  * Copyright(c) 2006-2007, Ext JS, LLC.
999  *
1000  * Originally Released Under LGPL - original licence link has changed is not relivant.
1001  *
1002  * Fork - LGPL
1003  * <script type="text/javascript">
1004  */
1005
1006 /**
1007  * @class Date
1008  *
1009  * The date parsing and format syntax is a subset of
1010  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1011  * supported will provide results equivalent to their PHP versions.
1012  *
1013  * Following is the list of all currently supported formats:
1014  *<pre>
1015 Sample date:
1016 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1017
1018 Format  Output      Description
1019 ------  ----------  --------------------------------------------------------------
1020   d      10         Day of the month, 2 digits with leading zeros
1021   D      Wed        A textual representation of a day, three letters
1022   j      10         Day of the month without leading zeros
1023   l      Wednesday  A full textual representation of the day of the week
1024   S      th         English ordinal day of month suffix, 2 chars (use with j)
1025   w      3          Numeric representation of the day of the week
1026   z      9          The julian date, or day of the year (0-365)
1027   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1028   F      January    A full textual representation of the month
1029   m      01         Numeric representation of a month, with leading zeros
1030   M      Jan        Month name abbreviation, three letters
1031   n      1          Numeric representation of a month, without leading zeros
1032   t      31         Number of days in the given month
1033   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1034   Y      2007       A full numeric representation of a year, 4 digits
1035   y      07         A two digit representation of a year
1036   a      pm         Lowercase Ante meridiem and Post meridiem
1037   A      PM         Uppercase Ante meridiem and Post meridiem
1038   g      3          12-hour format of an hour without leading zeros
1039   G      15         24-hour format of an hour without leading zeros
1040   h      03         12-hour format of an hour with leading zeros
1041   H      15         24-hour format of an hour with leading zeros
1042   i      05         Minutes with leading zeros
1043   s      01         Seconds, with leading zeros
1044   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1045   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1046   T      CST        Timezone setting of the machine running the code
1047   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1048 </pre>
1049  *
1050  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1051  * <pre><code>
1052 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1053 document.write(dt.format('Y-m-d'));                         //2007-01-10
1054 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1055 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
1056  </code></pre>
1057  *
1058  * Here are some standard date/time patterns that you might find helpful.  They
1059  * are not part of the source of Date.js, but to use them you can simply copy this
1060  * block of code into any script that is included after Date.js and they will also become
1061  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1062  * <pre><code>
1063 Date.patterns = {
1064     ISO8601Long:"Y-m-d H:i:s",
1065     ISO8601Short:"Y-m-d",
1066     ShortDate: "n/j/Y",
1067     LongDate: "l, F d, Y",
1068     FullDateTime: "l, F d, Y g:i:s A",
1069     MonthDay: "F d",
1070     ShortTime: "g:i A",
1071     LongTime: "g:i:s A",
1072     SortableDateTime: "Y-m-d\\TH:i:s",
1073     UniversalSortableDateTime: "Y-m-d H:i:sO",
1074     YearMonth: "F, Y"
1075 };
1076 </code></pre>
1077  *
1078  * Example usage:
1079  * <pre><code>
1080 var dt = new Date();
1081 document.write(dt.format(Date.patterns.ShortDate));
1082  </code></pre>
1083  */
1084
1085 /*
1086  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1087  * They generate precompiled functions from date formats instead of parsing and
1088  * processing the pattern every time you format a date.  These functions are available
1089  * on every Date object (any javascript function).
1090  *
1091  * The original article and download are here:
1092  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1093  *
1094  */
1095  
1096  
1097  // was in core
1098 /**
1099  Returns the number of milliseconds between this date and date
1100  @param {Date} date (optional) Defaults to now
1101  @return {Number} The diff in milliseconds
1102  @member Date getElapsed
1103  */
1104 Date.prototype.getElapsed = function(date) {
1105         return Math.abs((date || new Date()).getTime()-this.getTime());
1106 };
1107 // was in date file..
1108
1109
1110 // private
1111 Date.parseFunctions = {count:0};
1112 // private
1113 Date.parseRegexes = [];
1114 // private
1115 Date.formatFunctions = {count:0};
1116
1117 // private
1118 Date.prototype.dateFormat = function(format) {
1119     if (Date.formatFunctions[format] == null) {
1120         Date.createNewFormat(format);
1121     }
1122     var func = Date.formatFunctions[format];
1123     return this[func]();
1124 };
1125
1126
1127 /**
1128  * Formats a date given the supplied format string
1129  * @param {String} format The format string
1130  * @return {String} The formatted date
1131  * @method
1132  */
1133 Date.prototype.format = Date.prototype.dateFormat;
1134
1135 // private
1136 Date.createNewFormat = function(format) {
1137     var funcName = "format" + Date.formatFunctions.count++;
1138     Date.formatFunctions[format] = funcName;
1139     var code = "Date.prototype." + funcName + " = function(){return ";
1140     var special = false;
1141     var ch = '';
1142     for (var i = 0; i < format.length; ++i) {
1143         ch = format.charAt(i);
1144         if (!special && ch == "\\") {
1145             special = true;
1146         }
1147         else if (special) {
1148             special = false;
1149             code += "'" + String.escape(ch) + "' + ";
1150         }
1151         else {
1152             code += Date.getFormatCode(ch);
1153         }
1154     }
1155     /** eval:var:zzzzzzzzzzzzz */
1156     eval(code.substring(0, code.length - 3) + ";}");
1157 };
1158
1159 // private
1160 Date.getFormatCode = function(character) {
1161     switch (character) {
1162     case "d":
1163         return "String.leftPad(this.getDate(), 2, '0') + ";
1164     case "D":
1165         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1166     case "j":
1167         return "this.getDate() + ";
1168     case "l":
1169         return "Date.dayNames[this.getDay()] + ";
1170     case "S":
1171         return "this.getSuffix() + ";
1172     case "w":
1173         return "this.getDay() + ";
1174     case "z":
1175         return "this.getDayOfYear() + ";
1176     case "W":
1177         return "this.getWeekOfYear() + ";
1178     case "F":
1179         return "Date.monthNames[this.getMonth()] + ";
1180     case "m":
1181         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1182     case "M":
1183         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1184     case "n":
1185         return "(this.getMonth() + 1) + ";
1186     case "t":
1187         return "this.getDaysInMonth() + ";
1188     case "L":
1189         return "(this.isLeapYear() ? 1 : 0) + ";
1190     case "Y":
1191         return "this.getFullYear() + ";
1192     case "y":
1193         return "('' + this.getFullYear()).substring(2, 4) + ";
1194     case "a":
1195         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1196     case "A":
1197         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1198     case "g":
1199         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1200     case "G":
1201         return "this.getHours() + ";
1202     case "h":
1203         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1204     case "H":
1205         return "String.leftPad(this.getHours(), 2, '0') + ";
1206     case "i":
1207         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1208     case "s":
1209         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1210     case "O":
1211         return "this.getGMTOffset() + ";
1212     case "P":
1213         return "this.getGMTColonOffset() + ";
1214     case "T":
1215         return "this.getTimezone() + ";
1216     case "Z":
1217         return "(this.getTimezoneOffset() * -60) + ";
1218     default:
1219         return "'" + String.escape(character) + "' + ";
1220     }
1221 };
1222
1223 /**
1224  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1225  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1226  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1227  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1228  * string or the parse operation will fail.
1229  * Example Usage:
1230 <pre><code>
1231 //dt = Fri May 25 2007 (current date)
1232 var dt = new Date();
1233
1234 //dt = Thu May 25 2006 (today's month/day in 2006)
1235 dt = Date.parseDate("2006", "Y");
1236
1237 //dt = Sun Jan 15 2006 (all date parts specified)
1238 dt = Date.parseDate("2006-1-15", "Y-m-d");
1239
1240 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1241 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1242 </code></pre>
1243  * @param {String} input The unparsed date as a string
1244  * @param {String} format The format the date is in
1245  * @return {Date} The parsed date
1246  * @static
1247  */
1248 Date.parseDate = function(input, format) {
1249     if (Date.parseFunctions[format] == null) {
1250         Date.createParser(format);
1251     }
1252     var func = Date.parseFunctions[format];
1253     return Date[func](input);
1254 };
1255 /**
1256  * @private
1257  */
1258
1259 Date.createParser = function(format) {
1260     var funcName = "parse" + Date.parseFunctions.count++;
1261     var regexNum = Date.parseRegexes.length;
1262     var currentGroup = 1;
1263     Date.parseFunctions[format] = funcName;
1264
1265     var code = "Date." + funcName + " = function(input){\n"
1266         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1267         + "var d = new Date();\n"
1268         + "y = d.getFullYear();\n"
1269         + "m = d.getMonth();\n"
1270         + "d = d.getDate();\n"
1271         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1272         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1273         + "if (results && results.length > 0) {";
1274     var regex = "";
1275
1276     var special = false;
1277     var ch = '';
1278     for (var i = 0; i < format.length; ++i) {
1279         ch = format.charAt(i);
1280         if (!special && ch == "\\") {
1281             special = true;
1282         }
1283         else if (special) {
1284             special = false;
1285             regex += String.escape(ch);
1286         }
1287         else {
1288             var obj = Date.formatCodeToRegex(ch, currentGroup);
1289             currentGroup += obj.g;
1290             regex += obj.s;
1291             if (obj.g && obj.c) {
1292                 code += obj.c;
1293             }
1294         }
1295     }
1296
1297     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1298         + "{v = new Date(y, m, d, h, i, s);}\n"
1299         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1300         + "{v = new Date(y, m, d, h, i);}\n"
1301         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1302         + "{v = new Date(y, m, d, h);}\n"
1303         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1304         + "{v = new Date(y, m, d);}\n"
1305         + "else if (y >= 0 && m >= 0)\n"
1306         + "{v = new Date(y, m);}\n"
1307         + "else if (y >= 0)\n"
1308         + "{v = new Date(y);}\n"
1309         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1310         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1311         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1312         + ";}";
1313
1314     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1315     /** eval:var:zzzzzzzzzzzzz */
1316     eval(code);
1317 };
1318
1319 // private
1320 Date.formatCodeToRegex = function(character, currentGroup) {
1321     switch (character) {
1322     case "D":
1323         return {g:0,
1324         c:null,
1325         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1326     case "j":
1327         return {g:1,
1328             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1329             s:"(\\d{1,2})"}; // day of month without leading zeroes
1330     case "d":
1331         return {g:1,
1332             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1333             s:"(\\d{2})"}; // day of month with leading zeroes
1334     case "l":
1335         return {g:0,
1336             c:null,
1337             s:"(?:" + Date.dayNames.join("|") + ")"};
1338     case "S":
1339         return {g:0,
1340             c:null,
1341             s:"(?:st|nd|rd|th)"};
1342     case "w":
1343         return {g:0,
1344             c:null,
1345             s:"\\d"};
1346     case "z":
1347         return {g:0,
1348             c:null,
1349             s:"(?:\\d{1,3})"};
1350     case "W":
1351         return {g:0,
1352             c:null,
1353             s:"(?:\\d{2})"};
1354     case "F":
1355         return {g:1,
1356             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1357             s:"(" + Date.monthNames.join("|") + ")"};
1358     case "M":
1359         return {g:1,
1360             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1361             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1362     case "n":
1363         return {g:1,
1364             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1365             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1366     case "m":
1367         return {g:1,
1368             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1369             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1370     case "t":
1371         return {g:0,
1372             c:null,
1373             s:"\\d{1,2}"};
1374     case "L":
1375         return {g:0,
1376             c:null,
1377             s:"(?:1|0)"};
1378     case "Y":
1379         return {g:1,
1380             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1381             s:"(\\d{4})"};
1382     case "y":
1383         return {g:1,
1384             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1385                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1386             s:"(\\d{1,2})"};
1387     case "a":
1388         return {g:1,
1389             c:"if (results[" + currentGroup + "] == 'am') {\n"
1390                 + "if (h == 12) { h = 0; }\n"
1391                 + "} else { if (h < 12) { h += 12; }}",
1392             s:"(am|pm)"};
1393     case "A":
1394         return {g:1,
1395             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1396                 + "if (h == 12) { h = 0; }\n"
1397                 + "} else { if (h < 12) { h += 12; }}",
1398             s:"(AM|PM)"};
1399     case "g":
1400     case "G":
1401         return {g:1,
1402             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1403             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1404     case "h":
1405     case "H":
1406         return {g:1,
1407             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1408             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1409     case "i":
1410         return {g:1,
1411             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1412             s:"(\\d{2})"};
1413     case "s":
1414         return {g:1,
1415             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1416             s:"(\\d{2})"};
1417     case "O":
1418         return {g:1,
1419             c:[
1420                 "o = results[", currentGroup, "];\n",
1421                 "var sn = o.substring(0,1);\n", // get + / - sign
1422                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1423                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1424                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1425                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1426             ].join(""),
1427             s:"([+\-]\\d{2,4})"};
1428     
1429     
1430     case "P":
1431         return {g:1,
1432                 c:[
1433                    "o = results[", currentGroup, "];\n",
1434                    "var sn = o.substring(0,1);\n",
1435                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1436                    "var mn = o.substring(4,6) % 60;\n",
1437                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1438                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1439             ].join(""),
1440             s:"([+\-]\\d{4})"};
1441     case "T":
1442         return {g:0,
1443             c:null,
1444             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1445     case "Z":
1446         return {g:1,
1447             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1448                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1449             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1450     default:
1451         return {g:0,
1452             c:null,
1453             s:String.escape(character)};
1454     }
1455 };
1456
1457 /**
1458  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1459  * @return {String} The abbreviated timezone name (e.g. 'CST')
1460  */
1461 Date.prototype.getTimezone = function() {
1462     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1463 };
1464
1465 /**
1466  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1467  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1468  */
1469 Date.prototype.getGMTOffset = function() {
1470     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1471         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1472         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1473 };
1474
1475 /**
1476  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1477  * @return {String} 2-characters representing hours and 2-characters representing minutes
1478  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1479  */
1480 Date.prototype.getGMTColonOffset = function() {
1481         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1482                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1483                 + ":"
1484                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1485 }
1486
1487 /**
1488  * Get the numeric day number of the year, adjusted for leap year.
1489  * @return {Number} 0 through 364 (365 in leap years)
1490  */
1491 Date.prototype.getDayOfYear = function() {
1492     var num = 0;
1493     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1494     for (var i = 0; i < this.getMonth(); ++i) {
1495         num += Date.daysInMonth[i];
1496     }
1497     return num + this.getDate() - 1;
1498 };
1499
1500 /**
1501  * Get the string representation of the numeric week number of the year
1502  * (equivalent to the format specifier 'W').
1503  * @return {String} '00' through '52'
1504  */
1505 Date.prototype.getWeekOfYear = function() {
1506     // Skip to Thursday of this week
1507     var now = this.getDayOfYear() + (4 - this.getDay());
1508     // Find the first Thursday of the year
1509     var jan1 = new Date(this.getFullYear(), 0, 1);
1510     var then = (7 - jan1.getDay() + 4);
1511     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1512 };
1513
1514 /**
1515  * Whether or not the current date is in a leap year.
1516  * @return {Boolean} True if the current date is in a leap year, else false
1517  */
1518 Date.prototype.isLeapYear = function() {
1519     var year = this.getFullYear();
1520     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1521 };
1522
1523 /**
1524  * Get the first day of the current month, adjusted for leap year.  The returned value
1525  * is the numeric day index within the week (0-6) which can be used in conjunction with
1526  * the {@link #monthNames} array to retrieve the textual day name.
1527  * Example:
1528  *<pre><code>
1529 var dt = new Date('1/10/2007');
1530 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1531 </code></pre>
1532  * @return {Number} The day number (0-6)
1533  */
1534 Date.prototype.getFirstDayOfMonth = function() {
1535     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1536     return (day < 0) ? (day + 7) : day;
1537 };
1538
1539 /**
1540  * Get the last day of the current month, adjusted for leap year.  The returned value
1541  * is the numeric day index within the week (0-6) which can be used in conjunction with
1542  * the {@link #monthNames} array to retrieve the textual day name.
1543  * Example:
1544  *<pre><code>
1545 var dt = new Date('1/10/2007');
1546 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1547 </code></pre>
1548  * @return {Number} The day number (0-6)
1549  */
1550 Date.prototype.getLastDayOfMonth = function() {
1551     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1552     return (day < 0) ? (day + 7) : day;
1553 };
1554
1555
1556 /**
1557  * Get the first date of this date's month
1558  * @return {Date}
1559  */
1560 Date.prototype.getFirstDateOfMonth = function() {
1561     return new Date(this.getFullYear(), this.getMonth(), 1);
1562 };
1563
1564 /**
1565  * Get the last date of this date's month
1566  * @return {Date}
1567  */
1568 Date.prototype.getLastDateOfMonth = function() {
1569     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1570 };
1571 /**
1572  * Get the number of days in the current month, adjusted for leap year.
1573  * @return {Number} The number of days in the month
1574  */
1575 Date.prototype.getDaysInMonth = function() {
1576     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1577     return Date.daysInMonth[this.getMonth()];
1578 };
1579
1580 /**
1581  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1582  * @return {String} 'st, 'nd', 'rd' or 'th'
1583  */
1584 Date.prototype.getSuffix = function() {
1585     switch (this.getDate()) {
1586         case 1:
1587         case 21:
1588         case 31:
1589             return "st";
1590         case 2:
1591         case 22:
1592             return "nd";
1593         case 3:
1594         case 23:
1595             return "rd";
1596         default:
1597             return "th";
1598     }
1599 };
1600
1601 // private
1602 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1603
1604 /**
1605  * An array of textual month names.
1606  * Override these values for international dates, for example...
1607  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1608  * @type Array
1609  * @static
1610  */
1611 Date.monthNames =
1612    ["January",
1613     "February",
1614     "March",
1615     "April",
1616     "May",
1617     "June",
1618     "July",
1619     "August",
1620     "September",
1621     "October",
1622     "November",
1623     "December"];
1624
1625 /**
1626  * An array of textual day names.
1627  * Override these values for international dates, for example...
1628  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1629  * @type Array
1630  * @static
1631  */
1632 Date.dayNames =
1633    ["Sunday",
1634     "Monday",
1635     "Tuesday",
1636     "Wednesday",
1637     "Thursday",
1638     "Friday",
1639     "Saturday"];
1640
1641 // private
1642 Date.y2kYear = 50;
1643 // private
1644 Date.monthNumbers = {
1645     Jan:0,
1646     Feb:1,
1647     Mar:2,
1648     Apr:3,
1649     May:4,
1650     Jun:5,
1651     Jul:6,
1652     Aug:7,
1653     Sep:8,
1654     Oct:9,
1655     Nov:10,
1656     Dec:11};
1657
1658 /**
1659  * Creates and returns a new Date instance with the exact same date value as the called instance.
1660  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1661  * variable will also be changed.  When the intention is to create a new variable that will not
1662  * modify the original instance, you should create a clone.
1663  *
1664  * Example of correctly cloning a date:
1665  * <pre><code>
1666 //wrong way:
1667 var orig = new Date('10/1/2006');
1668 var copy = orig;
1669 copy.setDate(5);
1670 document.write(orig);  //returns 'Thu Oct 05 2006'!
1671
1672 //correct way:
1673 var orig = new Date('10/1/2006');
1674 var copy = orig.clone();
1675 copy.setDate(5);
1676 document.write(orig);  //returns 'Thu Oct 01 2006'
1677 </code></pre>
1678  * @return {Date} The new Date instance
1679  */
1680 Date.prototype.clone = function() {
1681         return new Date(this.getTime());
1682 };
1683
1684 /**
1685  * Clears any time information from this date
1686  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1687  @return {Date} this or the clone
1688  */
1689 Date.prototype.clearTime = function(clone){
1690     if(clone){
1691         return this.clone().clearTime();
1692     }
1693     this.setHours(0);
1694     this.setMinutes(0);
1695     this.setSeconds(0);
1696     this.setMilliseconds(0);
1697     return this;
1698 };
1699
1700 // private
1701 // safari setMonth is broken -- check that this is only donw once...
1702 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1703     Date.brokenSetMonth = Date.prototype.setMonth;
1704         Date.prototype.setMonth = function(num){
1705                 if(num <= -1){
1706                         var n = Math.ceil(-num);
1707                         var back_year = Math.ceil(n/12);
1708                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1709                         this.setFullYear(this.getFullYear() - back_year);
1710                         return Date.brokenSetMonth.call(this, month);
1711                 } else {
1712                         return Date.brokenSetMonth.apply(this, arguments);
1713                 }
1714         };
1715 }
1716
1717 /** Date interval constant 
1718 * @static 
1719 * @type String */
1720 Date.MILLI = "ms";
1721 /** Date interval constant 
1722 * @static 
1723 * @type String */
1724 Date.SECOND = "s";
1725 /** Date interval constant 
1726 * @static 
1727 * @type String */
1728 Date.MINUTE = "mi";
1729 /** Date interval constant 
1730 * @static 
1731 * @type String */
1732 Date.HOUR = "h";
1733 /** Date interval constant 
1734 * @static 
1735 * @type String */
1736 Date.DAY = "d";
1737 /** Date interval constant 
1738 * @static 
1739 * @type String */
1740 Date.MONTH = "mo";
1741 /** Date interval constant 
1742 * @static 
1743 * @type String */
1744 Date.YEAR = "y";
1745
1746 /**
1747  * Provides a convenient method of performing basic date arithmetic.  This method
1748  * does not modify the Date instance being called - it creates and returns
1749  * a new Date instance containing the resulting date value.
1750  *
1751  * Examples:
1752  * <pre><code>
1753 //Basic usage:
1754 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1755 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1756
1757 //Negative values will subtract correctly:
1758 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1759 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1760
1761 //You can even chain several calls together in one line!
1762 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1763 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1764  </code></pre>
1765  *
1766  * @param {String} interval   A valid date interval enum value
1767  * @param {Number} value      The amount to add to the current date
1768  * @return {Date} The new Date instance
1769  */
1770 Date.prototype.add = function(interval, value){
1771   var d = this.clone();
1772   if (!interval || value === 0) { return d; }
1773   switch(interval.toLowerCase()){
1774     case Date.MILLI:
1775       d.setMilliseconds(this.getMilliseconds() + value);
1776       break;
1777     case Date.SECOND:
1778       d.setSeconds(this.getSeconds() + value);
1779       break;
1780     case Date.MINUTE:
1781       d.setMinutes(this.getMinutes() + value);
1782       break;
1783     case Date.HOUR:
1784       d.setHours(this.getHours() + value);
1785       break;
1786     case Date.DAY:
1787       d.setDate(this.getDate() + value);
1788       break;
1789     case Date.MONTH:
1790       var day = this.getDate();
1791       if(day > 28){
1792           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1793       }
1794       d.setDate(day);
1795       d.setMonth(this.getMonth() + value);
1796       break;
1797     case Date.YEAR:
1798       d.setFullYear(this.getFullYear() + value);
1799       break;
1800   }
1801   return d;
1802 };
1803 /*
1804  * Based on:
1805  * Ext JS Library 1.1.1
1806  * Copyright(c) 2006-2007, Ext JS, LLC.
1807  *
1808  * Originally Released Under LGPL - original licence link has changed is not relivant.
1809  *
1810  * Fork - LGPL
1811  * <script type="text/javascript">
1812  */
1813
1814 /**
1815  * @class Roo.lib.Dom
1816  * @static
1817  * 
1818  * Dom utils (from YIU afaik)
1819  * 
1820  **/
1821 Roo.lib.Dom = {
1822     /**
1823      * Get the view width
1824      * @param {Boolean} full True will get the full document, otherwise it's the view width
1825      * @return {Number} The width
1826      */
1827      
1828     getViewWidth : function(full) {
1829         return full ? this.getDocumentWidth() : this.getViewportWidth();
1830     },
1831     /**
1832      * Get the view height
1833      * @param {Boolean} full True will get the full document, otherwise it's the view height
1834      * @return {Number} The height
1835      */
1836     getViewHeight : function(full) {
1837         return full ? this.getDocumentHeight() : this.getViewportHeight();
1838     },
1839
1840     getDocumentHeight: function() {
1841         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1842         return Math.max(scrollHeight, this.getViewportHeight());
1843     },
1844
1845     getDocumentWidth: function() {
1846         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1847         return Math.max(scrollWidth, this.getViewportWidth());
1848     },
1849
1850     getViewportHeight: function() {
1851         var height = self.innerHeight;
1852         var mode = document.compatMode;
1853
1854         if ((mode || Roo.isIE) && !Roo.isOpera) {
1855             height = (mode == "CSS1Compat") ?
1856                      document.documentElement.clientHeight :
1857                      document.body.clientHeight;
1858         }
1859
1860         return height;
1861     },
1862
1863     getViewportWidth: function() {
1864         var width = self.innerWidth;
1865         var mode = document.compatMode;
1866
1867         if (mode || Roo.isIE) {
1868             width = (mode == "CSS1Compat") ?
1869                     document.documentElement.clientWidth :
1870                     document.body.clientWidth;
1871         }
1872         return width;
1873     },
1874
1875     isAncestor : function(p, c) {
1876         p = Roo.getDom(p);
1877         c = Roo.getDom(c);
1878         if (!p || !c) {
1879             return false;
1880         }
1881
1882         if (p.contains && !Roo.isSafari) {
1883             return p.contains(c);
1884         } else if (p.compareDocumentPosition) {
1885             return !!(p.compareDocumentPosition(c) & 16);
1886         } else {
1887             var parent = c.parentNode;
1888             while (parent) {
1889                 if (parent == p) {
1890                     return true;
1891                 }
1892                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1893                     return false;
1894                 }
1895                 parent = parent.parentNode;
1896             }
1897             return false;
1898         }
1899     },
1900
1901     getRegion : function(el) {
1902         return Roo.lib.Region.getRegion(el);
1903     },
1904
1905     getY : function(el) {
1906         return this.getXY(el)[1];
1907     },
1908
1909     getX : function(el) {
1910         return this.getXY(el)[0];
1911     },
1912
1913     getXY : function(el) {
1914         var p, pe, b, scroll, bd = document.body;
1915         el = Roo.getDom(el);
1916         var fly = Roo.lib.AnimBase.fly;
1917         if (el.getBoundingClientRect) {
1918             b = el.getBoundingClientRect();
1919             scroll = fly(document).getScroll();
1920             return [b.left + scroll.left, b.top + scroll.top];
1921         }
1922         var x = 0, y = 0;
1923
1924         p = el;
1925
1926         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1927
1928         while (p) {
1929
1930             x += p.offsetLeft;
1931             y += p.offsetTop;
1932
1933             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1934                 hasAbsolute = true;
1935             }
1936
1937             if (Roo.isGecko) {
1938                 pe = fly(p);
1939
1940                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1941                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1942
1943
1944                 x += bl;
1945                 y += bt;
1946
1947
1948                 if (p != el && pe.getStyle('overflow') != 'visible') {
1949                     x += bl;
1950                     y += bt;
1951                 }
1952             }
1953             p = p.offsetParent;
1954         }
1955
1956         if (Roo.isSafari && hasAbsolute) {
1957             x -= bd.offsetLeft;
1958             y -= bd.offsetTop;
1959         }
1960
1961         if (Roo.isGecko && !hasAbsolute) {
1962             var dbd = fly(bd);
1963             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1964             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1965         }
1966
1967         p = el.parentNode;
1968         while (p && p != bd) {
1969             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1970                 x -= p.scrollLeft;
1971                 y -= p.scrollTop;
1972             }
1973             p = p.parentNode;
1974         }
1975         return [x, y];
1976     },
1977  
1978   
1979
1980
1981     setXY : function(el, xy) {
1982         el = Roo.fly(el, '_setXY');
1983         el.position();
1984         var pts = el.translatePoints(xy);
1985         if (xy[0] !== false) {
1986             el.dom.style.left = pts.left + "px";
1987         }
1988         if (xy[1] !== false) {
1989             el.dom.style.top = pts.top + "px";
1990         }
1991     },
1992
1993     setX : function(el, x) {
1994         this.setXY(el, [x, false]);
1995     },
1996
1997     setY : function(el, y) {
1998         this.setXY(el, [false, y]);
1999     }
2000 };
2001 /*
2002  * Portions of this file are based on pieces of Yahoo User Interface Library
2003  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2004  * YUI licensed under the BSD License:
2005  * http://developer.yahoo.net/yui/license.txt
2006  * <script type="text/javascript">
2007  *
2008  */
2009
2010 Roo.lib.Event = function() {
2011     var loadComplete = false;
2012     var listeners = [];
2013     var unloadListeners = [];
2014     var retryCount = 0;
2015     var onAvailStack = [];
2016     var counter = 0;
2017     var lastError = null;
2018
2019     return {
2020         POLL_RETRYS: 200,
2021         POLL_INTERVAL: 20,
2022         EL: 0,
2023         TYPE: 1,
2024         FN: 2,
2025         WFN: 3,
2026         OBJ: 3,
2027         ADJ_SCOPE: 4,
2028         _interval: null,
2029
2030         startInterval: function() {
2031             if (!this._interval) {
2032                 var self = this;
2033                 var callback = function() {
2034                     self._tryPreloadAttach();
2035                 };
2036                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2037
2038             }
2039         },
2040
2041         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2042             onAvailStack.push({ id:         p_id,
2043                 fn:         p_fn,
2044                 obj:        p_obj,
2045                 override:   p_override,
2046                 checkReady: false    });
2047
2048             retryCount = this.POLL_RETRYS;
2049             this.startInterval();
2050         },
2051
2052
2053         addListener: function(el, eventName, fn) {
2054             el = Roo.getDom(el);
2055             if (!el || !fn) {
2056                 return false;
2057             }
2058
2059             if ("unload" == eventName) {
2060                 unloadListeners[unloadListeners.length] =
2061                 [el, eventName, fn];
2062                 return true;
2063             }
2064
2065             var wrappedFn = function(e) {
2066                 return fn(Roo.lib.Event.getEvent(e));
2067             };
2068
2069             var li = [el, eventName, fn, wrappedFn];
2070
2071             var index = listeners.length;
2072             listeners[index] = li;
2073
2074             this.doAdd(el, eventName, wrappedFn, false);
2075             return true;
2076
2077         },
2078
2079
2080         removeListener: function(el, eventName, fn) {
2081             var i, len;
2082
2083             el = Roo.getDom(el);
2084
2085             if(!fn) {
2086                 return this.purgeElement(el, false, eventName);
2087             }
2088
2089
2090             if ("unload" == eventName) {
2091
2092                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2093                     var li = unloadListeners[i];
2094                     if (li &&
2095                         li[0] == el &&
2096                         li[1] == eventName &&
2097                         li[2] == fn) {
2098                         unloadListeners.splice(i, 1);
2099                         return true;
2100                     }
2101                 }
2102
2103                 return false;
2104             }
2105
2106             var cacheItem = null;
2107
2108
2109             var index = arguments[3];
2110
2111             if ("undefined" == typeof index) {
2112                 index = this._getCacheIndex(el, eventName, fn);
2113             }
2114
2115             if (index >= 0) {
2116                 cacheItem = listeners[index];
2117             }
2118
2119             if (!el || !cacheItem) {
2120                 return false;
2121             }
2122
2123             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2124
2125             delete listeners[index][this.WFN];
2126             delete listeners[index][this.FN];
2127             listeners.splice(index, 1);
2128
2129             return true;
2130
2131         },
2132
2133
2134         getTarget: function(ev, resolveTextNode) {
2135             ev = ev.browserEvent || ev;
2136             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2137             var t = ev.target || ev.srcElement;
2138             return this.resolveTextNode(t);
2139         },
2140
2141
2142         resolveTextNode: function(node) {
2143             if (Roo.isSafari && node && 3 == node.nodeType) {
2144                 return node.parentNode;
2145             } else {
2146                 return node;
2147             }
2148         },
2149
2150
2151         getPageX: function(ev) {
2152             ev = ev.browserEvent || ev;
2153             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2154             var x = ev.pageX;
2155             if (!x && 0 !== x) {
2156                 x = ev.clientX || 0;
2157
2158                 if (Roo.isIE) {
2159                     x += this.getScroll()[1];
2160                 }
2161             }
2162
2163             return x;
2164         },
2165
2166
2167         getPageY: function(ev) {
2168             ev = ev.browserEvent || ev;
2169             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2170             var y = ev.pageY;
2171             if (!y && 0 !== y) {
2172                 y = ev.clientY || 0;
2173
2174                 if (Roo.isIE) {
2175                     y += this.getScroll()[0];
2176                 }
2177             }
2178
2179
2180             return y;
2181         },
2182
2183
2184         getXY: function(ev) {
2185             ev = ev.browserEvent || ev;
2186             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2187             return [this.getPageX(ev), this.getPageY(ev)];
2188         },
2189
2190
2191         getRelatedTarget: function(ev) {
2192             ev = ev.browserEvent || ev;
2193             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2194             var t = ev.relatedTarget;
2195             if (!t) {
2196                 if (ev.type == "mouseout") {
2197                     t = ev.toElement;
2198                 } else if (ev.type == "mouseover") {
2199                     t = ev.fromElement;
2200                 }
2201             }
2202
2203             return this.resolveTextNode(t);
2204         },
2205
2206
2207         getTime: function(ev) {
2208             ev = ev.browserEvent || ev;
2209             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2210             if (!ev.time) {
2211                 var t = new Date().getTime();
2212                 try {
2213                     ev.time = t;
2214                 } catch(ex) {
2215                     this.lastError = ex;
2216                     return t;
2217                 }
2218             }
2219
2220             return ev.time;
2221         },
2222
2223
2224         stopEvent: function(ev) {
2225             this.stopPropagation(ev);
2226             this.preventDefault(ev);
2227         },
2228
2229
2230         stopPropagation: function(ev) {
2231             ev = ev.browserEvent || ev;
2232             if (ev.stopPropagation) {
2233                 ev.stopPropagation();
2234             } else {
2235                 ev.cancelBubble = true;
2236             }
2237         },
2238
2239
2240         preventDefault: function(ev) {
2241             ev = ev.browserEvent || ev;
2242             if(ev.preventDefault) {
2243                 ev.preventDefault();
2244             } else {
2245                 ev.returnValue = false;
2246             }
2247         },
2248
2249
2250         getEvent: function(e) {
2251             var ev = e || window.event;
2252             if (!ev) {
2253                 var c = this.getEvent.caller;
2254                 while (c) {
2255                     ev = c.arguments[0];
2256                     if (ev && Event == ev.constructor) {
2257                         break;
2258                     }
2259                     c = c.caller;
2260                 }
2261             }
2262             return ev;
2263         },
2264
2265
2266         getCharCode: function(ev) {
2267             ev = ev.browserEvent || ev;
2268             return ev.charCode || ev.keyCode || 0;
2269         },
2270
2271
2272         _getCacheIndex: function(el, eventName, fn) {
2273             for (var i = 0,len = listeners.length; i < len; ++i) {
2274                 var li = listeners[i];
2275                 if (li &&
2276                     li[this.FN] == fn &&
2277                     li[this.EL] == el &&
2278                     li[this.TYPE] == eventName) {
2279                     return i;
2280                 }
2281             }
2282
2283             return -1;
2284         },
2285
2286
2287         elCache: {},
2288
2289
2290         getEl: function(id) {
2291             return document.getElementById(id);
2292         },
2293
2294
2295         clearCache: function() {
2296         },
2297
2298
2299         _load: function(e) {
2300             loadComplete = true;
2301             var EU = Roo.lib.Event;
2302
2303
2304             if (Roo.isIE) {
2305                 EU.doRemove(window, "load", EU._load);
2306             }
2307         },
2308
2309
2310         _tryPreloadAttach: function() {
2311
2312             if (this.locked) {
2313                 return false;
2314             }
2315
2316             this.locked = true;
2317
2318
2319             var tryAgain = !loadComplete;
2320             if (!tryAgain) {
2321                 tryAgain = (retryCount > 0);
2322             }
2323
2324
2325             var notAvail = [];
2326             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2327                 var item = onAvailStack[i];
2328                 if (item) {
2329                     var el = this.getEl(item.id);
2330
2331                     if (el) {
2332                         if (!item.checkReady ||
2333                             loadComplete ||
2334                             el.nextSibling ||
2335                             (document && document.body)) {
2336
2337                             var scope = el;
2338                             if (item.override) {
2339                                 if (item.override === true) {
2340                                     scope = item.obj;
2341                                 } else {
2342                                     scope = item.override;
2343                                 }
2344                             }
2345                             item.fn.call(scope, item.obj);
2346                             onAvailStack[i] = null;
2347                         }
2348                     } else {
2349                         notAvail.push(item);
2350                     }
2351                 }
2352             }
2353
2354             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2355
2356             if (tryAgain) {
2357
2358                 this.startInterval();
2359             } else {
2360                 clearInterval(this._interval);
2361                 this._interval = null;
2362             }
2363
2364             this.locked = false;
2365
2366             return true;
2367
2368         },
2369
2370
2371         purgeElement: function(el, recurse, eventName) {
2372             var elListeners = this.getListeners(el, eventName);
2373             if (elListeners) {
2374                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2375                     var l = elListeners[i];
2376                     this.removeListener(el, l.type, l.fn);
2377                 }
2378             }
2379
2380             if (recurse && el && el.childNodes) {
2381                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2382                     this.purgeElement(el.childNodes[i], recurse, eventName);
2383                 }
2384             }
2385         },
2386
2387
2388         getListeners: function(el, eventName) {
2389             var results = [], searchLists;
2390             if (!eventName) {
2391                 searchLists = [listeners, unloadListeners];
2392             } else if (eventName == "unload") {
2393                 searchLists = [unloadListeners];
2394             } else {
2395                 searchLists = [listeners];
2396             }
2397
2398             for (var j = 0; j < searchLists.length; ++j) {
2399                 var searchList = searchLists[j];
2400                 if (searchList && searchList.length > 0) {
2401                     for (var i = 0,len = searchList.length; i < len; ++i) {
2402                         var l = searchList[i];
2403                         if (l && l[this.EL] === el &&
2404                             (!eventName || eventName === l[this.TYPE])) {
2405                             results.push({
2406                                 type:   l[this.TYPE],
2407                                 fn:     l[this.FN],
2408                                 obj:    l[this.OBJ],
2409                                 adjust: l[this.ADJ_SCOPE],
2410                                 index:  i
2411                             });
2412                         }
2413                     }
2414                 }
2415             }
2416
2417             return (results.length) ? results : null;
2418         },
2419
2420
2421         _unload: function(e) {
2422
2423             var EU = Roo.lib.Event, i, j, l, len, index;
2424
2425             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2426                 l = unloadListeners[i];
2427                 if (l) {
2428                     var scope = window;
2429                     if (l[EU.ADJ_SCOPE]) {
2430                         if (l[EU.ADJ_SCOPE] === true) {
2431                             scope = l[EU.OBJ];
2432                         } else {
2433                             scope = l[EU.ADJ_SCOPE];
2434                         }
2435                     }
2436                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2437                     unloadListeners[i] = null;
2438                     l = null;
2439                     scope = null;
2440                 }
2441             }
2442
2443             unloadListeners = null;
2444
2445             if (listeners && listeners.length > 0) {
2446                 j = listeners.length;
2447                 while (j) {
2448                     index = j - 1;
2449                     l = listeners[index];
2450                     if (l) {
2451                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2452                                 l[EU.FN], index);
2453                     }
2454                     j = j - 1;
2455                 }
2456                 l = null;
2457
2458                 EU.clearCache();
2459             }
2460
2461             EU.doRemove(window, "unload", EU._unload);
2462
2463         },
2464
2465
2466         getScroll: function() {
2467             var dd = document.documentElement, db = document.body;
2468             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2469                 return [dd.scrollTop, dd.scrollLeft];
2470             } else if (db) {
2471                 return [db.scrollTop, db.scrollLeft];
2472             } else {
2473                 return [0, 0];
2474             }
2475         },
2476
2477
2478         doAdd: function () {
2479             if (window.addEventListener) {
2480                 return function(el, eventName, fn, capture) {
2481                     el.addEventListener(eventName, fn, (capture));
2482                 };
2483             } else if (window.attachEvent) {
2484                 return function(el, eventName, fn, capture) {
2485                     el.attachEvent("on" + eventName, fn);
2486                 };
2487             } else {
2488                 return function() {
2489                 };
2490             }
2491         }(),
2492
2493
2494         doRemove: function() {
2495             if (window.removeEventListener) {
2496                 return function (el, eventName, fn, capture) {
2497                     el.removeEventListener(eventName, fn, (capture));
2498                 };
2499             } else if (window.detachEvent) {
2500                 return function (el, eventName, fn) {
2501                     el.detachEvent("on" + eventName, fn);
2502                 };
2503             } else {
2504                 return function() {
2505                 };
2506             }
2507         }()
2508     };
2509     
2510 }();
2511 (function() {     
2512    
2513     var E = Roo.lib.Event;
2514     E.on = E.addListener;
2515     E.un = E.removeListener;
2516
2517     if (document && document.body) {
2518         E._load();
2519     } else {
2520         E.doAdd(window, "load", E._load);
2521     }
2522     E.doAdd(window, "unload", E._unload);
2523     E._tryPreloadAttach();
2524 })();
2525
2526 /*
2527  * Portions of this file are based on pieces of Yahoo User Interface Library
2528  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2529  * YUI licensed under the BSD License:
2530  * http://developer.yahoo.net/yui/license.txt
2531  * <script type="text/javascript">
2532  *
2533  */
2534
2535 (function() {
2536     /**
2537      * @class Roo.lib.Ajax
2538      *
2539      */
2540     Roo.lib.Ajax = {
2541         /**
2542          * @static 
2543          */
2544         request : function(method, uri, cb, data, options) {
2545             if(options){
2546                 var hs = options.headers;
2547                 if(hs){
2548                     for(var h in hs){
2549                         if(hs.hasOwnProperty(h)){
2550                             this.initHeader(h, hs[h], false);
2551                         }
2552                     }
2553                 }
2554                 if(options.xmlData){
2555                     this.initHeader('Content-Type', 'text/xml', false);
2556                     method = 'POST';
2557                     data = options.xmlData;
2558                 }
2559             }
2560
2561             return this.asyncRequest(method, uri, cb, data);
2562         },
2563
2564         serializeForm : function(form) {
2565             if(typeof form == 'string') {
2566                 form = (document.getElementById(form) || document.forms[form]);
2567             }
2568
2569             var el, name, val, disabled, data = '', hasSubmit = false;
2570             for (var i = 0; i < form.elements.length; i++) {
2571                 el = form.elements[i];
2572                 disabled = form.elements[i].disabled;
2573                 name = form.elements[i].name;
2574                 val = form.elements[i].value;
2575
2576                 if (!disabled && name){
2577                     switch (el.type)
2578                             {
2579                         case 'select-one':
2580                         case 'select-multiple':
2581                             for (var j = 0; j < el.options.length; j++) {
2582                                 if (el.options[j].selected) {
2583                                     if (Roo.isIE) {
2584                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2585                                     }
2586                                     else {
2587                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2588                                     }
2589                                 }
2590                             }
2591                             break;
2592                         case 'radio':
2593                         case 'checkbox':
2594                             if (el.checked) {
2595                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2596                             }
2597                             break;
2598                         case 'file':
2599
2600                         case undefined:
2601
2602                         case 'reset':
2603
2604                         case 'button':
2605
2606                             break;
2607                         case 'submit':
2608                             if(hasSubmit == false) {
2609                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2610                                 hasSubmit = true;
2611                             }
2612                             break;
2613                         default:
2614                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2615                             break;
2616                     }
2617                 }
2618             }
2619             data = data.substr(0, data.length - 1);
2620             return data;
2621         },
2622
2623         headers:{},
2624
2625         hasHeaders:false,
2626
2627         useDefaultHeader:true,
2628
2629         defaultPostHeader:'application/x-www-form-urlencoded',
2630
2631         useDefaultXhrHeader:true,
2632
2633         defaultXhrHeader:'XMLHttpRequest',
2634
2635         hasDefaultHeaders:true,
2636
2637         defaultHeaders:{},
2638
2639         poll:{},
2640
2641         timeout:{},
2642
2643         pollInterval:50,
2644
2645         transactionId:0,
2646
2647         setProgId:function(id)
2648         {
2649             this.activeX.unshift(id);
2650         },
2651
2652         setDefaultPostHeader:function(b)
2653         {
2654             this.useDefaultHeader = b;
2655         },
2656
2657         setDefaultXhrHeader:function(b)
2658         {
2659             this.useDefaultXhrHeader = b;
2660         },
2661
2662         setPollingInterval:function(i)
2663         {
2664             if (typeof i == 'number' && isFinite(i)) {
2665                 this.pollInterval = i;
2666             }
2667         },
2668
2669         createXhrObject:function(transactionId)
2670         {
2671             var obj,http;
2672             try
2673             {
2674
2675                 http = new XMLHttpRequest();
2676
2677                 obj = { conn:http, tId:transactionId };
2678             }
2679             catch(e)
2680             {
2681                 for (var i = 0; i < this.activeX.length; ++i) {
2682                     try
2683                     {
2684
2685                         http = new ActiveXObject(this.activeX[i]);
2686
2687                         obj = { conn:http, tId:transactionId };
2688                         break;
2689                     }
2690                     catch(e) {
2691                     }
2692                 }
2693             }
2694             finally
2695             {
2696                 return obj;
2697             }
2698         },
2699
2700         getConnectionObject:function()
2701         {
2702             var o;
2703             var tId = this.transactionId;
2704
2705             try
2706             {
2707                 o = this.createXhrObject(tId);
2708                 if (o) {
2709                     this.transactionId++;
2710                 }
2711             }
2712             catch(e) {
2713             }
2714             finally
2715             {
2716                 return o;
2717             }
2718         },
2719
2720         asyncRequest:function(method, uri, callback, postData)
2721         {
2722             var o = this.getConnectionObject();
2723
2724             if (!o) {
2725                 return null;
2726             }
2727             else {
2728                 o.conn.open(method, uri, true);
2729
2730                 if (this.useDefaultXhrHeader) {
2731                     if (!this.defaultHeaders['X-Requested-With']) {
2732                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2733                     }
2734                 }
2735
2736                 if(postData && this.useDefaultHeader){
2737                     this.initHeader('Content-Type', this.defaultPostHeader);
2738                 }
2739
2740                  if (this.hasDefaultHeaders || this.hasHeaders) {
2741                     this.setHeader(o);
2742                 }
2743
2744                 this.handleReadyState(o, callback);
2745                 o.conn.send(postData || null);
2746
2747                 return o;
2748             }
2749         },
2750
2751         handleReadyState:function(o, callback)
2752         {
2753             var oConn = this;
2754
2755             if (callback && callback.timeout) {
2756                 
2757                 this.timeout[o.tId] = window.setTimeout(function() {
2758                     oConn.abort(o, callback, true);
2759                 }, callback.timeout);
2760             }
2761
2762             this.poll[o.tId] = window.setInterval(
2763                     function() {
2764                         if (o.conn && o.conn.readyState == 4) {
2765                             window.clearInterval(oConn.poll[o.tId]);
2766                             delete oConn.poll[o.tId];
2767
2768                             if(callback && callback.timeout) {
2769                                 window.clearTimeout(oConn.timeout[o.tId]);
2770                                 delete oConn.timeout[o.tId];
2771                             }
2772
2773                             oConn.handleTransactionResponse(o, callback);
2774                         }
2775                     }
2776                     , this.pollInterval);
2777         },
2778
2779         handleTransactionResponse:function(o, callback, isAbort)
2780         {
2781
2782             if (!callback) {
2783                 this.releaseObject(o);
2784                 return;
2785             }
2786
2787             var httpStatus, responseObject;
2788
2789             try
2790             {
2791                 if (o.conn.status !== undefined && o.conn.status != 0) {
2792                     httpStatus = o.conn.status;
2793                 }
2794                 else {
2795                     httpStatus = 13030;
2796                 }
2797             }
2798             catch(e) {
2799
2800
2801                 httpStatus = 13030;
2802             }
2803
2804             if (httpStatus >= 200 && httpStatus < 300) {
2805                 responseObject = this.createResponseObject(o, callback.argument);
2806                 if (callback.success) {
2807                     if (!callback.scope) {
2808                         callback.success(responseObject);
2809                     }
2810                     else {
2811
2812
2813                         callback.success.apply(callback.scope, [responseObject]);
2814                     }
2815                 }
2816             }
2817             else {
2818                 switch (httpStatus) {
2819
2820                     case 12002:
2821                     case 12029:
2822                     case 12030:
2823                     case 12031:
2824                     case 12152:
2825                     case 13030:
2826                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2827                         if (callback.failure) {
2828                             if (!callback.scope) {
2829                                 callback.failure(responseObject);
2830                             }
2831                             else {
2832                                 callback.failure.apply(callback.scope, [responseObject]);
2833                             }
2834                         }
2835                         break;
2836                     default:
2837                         responseObject = this.createResponseObject(o, callback.argument);
2838                         if (callback.failure) {
2839                             if (!callback.scope) {
2840                                 callback.failure(responseObject);
2841                             }
2842                             else {
2843                                 callback.failure.apply(callback.scope, [responseObject]);
2844                             }
2845                         }
2846                 }
2847             }
2848
2849             this.releaseObject(o);
2850             responseObject = null;
2851         },
2852
2853         createResponseObject:function(o, callbackArg)
2854         {
2855             var obj = {};
2856             var headerObj = {};
2857
2858             try
2859             {
2860                 var headerStr = o.conn.getAllResponseHeaders();
2861                 var header = headerStr.split('\n');
2862                 for (var i = 0; i < header.length; i++) {
2863                     var delimitPos = header[i].indexOf(':');
2864                     if (delimitPos != -1) {
2865                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2866                     }
2867                 }
2868             }
2869             catch(e) {
2870             }
2871
2872             obj.tId = o.tId;
2873             obj.status = o.conn.status;
2874             obj.statusText = o.conn.statusText;
2875             obj.getResponseHeader = headerObj;
2876             obj.getAllResponseHeaders = headerStr;
2877             obj.responseText = o.conn.responseText;
2878             obj.responseXML = o.conn.responseXML;
2879
2880             if (typeof callbackArg !== undefined) {
2881                 obj.argument = callbackArg;
2882             }
2883
2884             return obj;
2885         },
2886
2887         createExceptionObject:function(tId, callbackArg, isAbort)
2888         {
2889             var COMM_CODE = 0;
2890             var COMM_ERROR = 'communication failure';
2891             var ABORT_CODE = -1;
2892             var ABORT_ERROR = 'transaction aborted';
2893
2894             var obj = {};
2895
2896             obj.tId = tId;
2897             if (isAbort) {
2898                 obj.status = ABORT_CODE;
2899                 obj.statusText = ABORT_ERROR;
2900             }
2901             else {
2902                 obj.status = COMM_CODE;
2903                 obj.statusText = COMM_ERROR;
2904             }
2905
2906             if (callbackArg) {
2907                 obj.argument = callbackArg;
2908             }
2909
2910             return obj;
2911         },
2912
2913         initHeader:function(label, value, isDefault)
2914         {
2915             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2916
2917             if (headerObj[label] === undefined) {
2918                 headerObj[label] = value;
2919             }
2920             else {
2921
2922
2923                 headerObj[label] = value + "," + headerObj[label];
2924             }
2925
2926             if (isDefault) {
2927                 this.hasDefaultHeaders = true;
2928             }
2929             else {
2930                 this.hasHeaders = true;
2931             }
2932         },
2933
2934
2935         setHeader:function(o)
2936         {
2937             if (this.hasDefaultHeaders) {
2938                 for (var prop in this.defaultHeaders) {
2939                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2940                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2941                     }
2942                 }
2943             }
2944
2945             if (this.hasHeaders) {
2946                 for (var prop in this.headers) {
2947                     if (this.headers.hasOwnProperty(prop)) {
2948                         o.conn.setRequestHeader(prop, this.headers[prop]);
2949                     }
2950                 }
2951                 this.headers = {};
2952                 this.hasHeaders = false;
2953             }
2954         },
2955
2956         resetDefaultHeaders:function() {
2957             delete this.defaultHeaders;
2958             this.defaultHeaders = {};
2959             this.hasDefaultHeaders = false;
2960         },
2961
2962         abort:function(o, callback, isTimeout)
2963         {
2964             if(this.isCallInProgress(o)) {
2965                 o.conn.abort();
2966                 window.clearInterval(this.poll[o.tId]);
2967                 delete this.poll[o.tId];
2968                 if (isTimeout) {
2969                     delete this.timeout[o.tId];
2970                 }
2971
2972                 this.handleTransactionResponse(o, callback, true);
2973
2974                 return true;
2975             }
2976             else {
2977                 return false;
2978             }
2979         },
2980
2981
2982         isCallInProgress:function(o)
2983         {
2984             if (o && o.conn) {
2985                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2986             }
2987             else {
2988
2989                 return false;
2990             }
2991         },
2992
2993
2994         releaseObject:function(o)
2995         {
2996
2997             o.conn = null;
2998
2999             o = null;
3000         },
3001
3002         activeX:[
3003         'MSXML2.XMLHTTP.3.0',
3004         'MSXML2.XMLHTTP',
3005         'Microsoft.XMLHTTP'
3006         ]
3007
3008
3009     };
3010 })();/*
3011  * Portions of this file are based on pieces of Yahoo User Interface Library
3012  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3013  * YUI licensed under the BSD License:
3014  * http://developer.yahoo.net/yui/license.txt
3015  * <script type="text/javascript">
3016  *
3017  */
3018
3019 Roo.lib.Region = function(t, r, b, l) {
3020     this.top = t;
3021     this[1] = t;
3022     this.right = r;
3023     this.bottom = b;
3024     this.left = l;
3025     this[0] = l;
3026 };
3027
3028
3029 Roo.lib.Region.prototype = {
3030     contains : function(region) {
3031         return ( region.left >= this.left &&
3032                  region.right <= this.right &&
3033                  region.top >= this.top &&
3034                  region.bottom <= this.bottom    );
3035
3036     },
3037
3038     getArea : function() {
3039         return ( (this.bottom - this.top) * (this.right - this.left) );
3040     },
3041
3042     intersect : function(region) {
3043         var t = Math.max(this.top, region.top);
3044         var r = Math.min(this.right, region.right);
3045         var b = Math.min(this.bottom, region.bottom);
3046         var l = Math.max(this.left, region.left);
3047
3048         if (b >= t && r >= l) {
3049             return new Roo.lib.Region(t, r, b, l);
3050         } else {
3051             return null;
3052         }
3053     },
3054     union : function(region) {
3055         var t = Math.min(this.top, region.top);
3056         var r = Math.max(this.right, region.right);
3057         var b = Math.max(this.bottom, region.bottom);
3058         var l = Math.min(this.left, region.left);
3059
3060         return new Roo.lib.Region(t, r, b, l);
3061     },
3062
3063     adjust : function(t, l, b, r) {
3064         this.top += t;
3065         this.left += l;
3066         this.right += r;
3067         this.bottom += b;
3068         return this;
3069     }
3070 };
3071
3072 Roo.lib.Region.getRegion = function(el) {
3073     var p = Roo.lib.Dom.getXY(el);
3074
3075     var t = p[1];
3076     var r = p[0] + el.offsetWidth;
3077     var b = p[1] + el.offsetHeight;
3078     var l = p[0];
3079
3080     return new Roo.lib.Region(t, r, b, l);
3081 };
3082 /*
3083  * Portions of this file are based on pieces of Yahoo User Interface Library
3084  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3085  * YUI licensed under the BSD License:
3086  * http://developer.yahoo.net/yui/license.txt
3087  * <script type="text/javascript">
3088  *
3089  */
3090 //@@dep Roo.lib.Region
3091
3092
3093 Roo.lib.Point = function(x, y) {
3094     if (x instanceof Array) {
3095         y = x[1];
3096         x = x[0];
3097     }
3098     this.x = this.right = this.left = this[0] = x;
3099     this.y = this.top = this.bottom = this[1] = y;
3100 };
3101
3102 Roo.lib.Point.prototype = new Roo.lib.Region();
3103 /*
3104  * Portions of this file are based on pieces of Yahoo User Interface Library
3105  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3106  * YUI licensed under the BSD License:
3107  * http://developer.yahoo.net/yui/license.txt
3108  * <script type="text/javascript">
3109  *
3110  */
3111  
3112 (function() {   
3113
3114     Roo.lib.Anim = {
3115         scroll : function(el, args, duration, easing, cb, scope) {
3116             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3117         },
3118
3119         motion : function(el, args, duration, easing, cb, scope) {
3120             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3121         },
3122
3123         color : function(el, args, duration, easing, cb, scope) {
3124             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3125         },
3126
3127         run : function(el, args, duration, easing, cb, scope, type) {
3128             type = type || Roo.lib.AnimBase;
3129             if (typeof easing == "string") {
3130                 easing = Roo.lib.Easing[easing];
3131             }
3132             var anim = new type(el, args, duration, easing);
3133             anim.animateX(function() {
3134                 Roo.callback(cb, scope);
3135             });
3136             return anim;
3137         }
3138     };
3139 })();/*
3140  * Portions of this file are based on pieces of Yahoo User Interface Library
3141  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3142  * YUI licensed under the BSD License:
3143  * http://developer.yahoo.net/yui/license.txt
3144  * <script type="text/javascript">
3145  *
3146  */
3147
3148 (function() {    
3149     var libFlyweight;
3150     
3151     function fly(el) {
3152         if (!libFlyweight) {
3153             libFlyweight = new Roo.Element.Flyweight();
3154         }
3155         libFlyweight.dom = el;
3156         return libFlyweight;
3157     }
3158
3159     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3160     
3161    
3162     
3163     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3164         if (el) {
3165             this.init(el, attributes, duration, method);
3166         }
3167     };
3168
3169     Roo.lib.AnimBase.fly = fly;
3170     
3171     
3172     
3173     Roo.lib.AnimBase.prototype = {
3174
3175         toString: function() {
3176             var el = this.getEl();
3177             var id = el.id || el.tagName;
3178             return ("Anim " + id);
3179         },
3180
3181         patterns: {
3182             noNegatives:        /width|height|opacity|padding/i,
3183             offsetAttribute:  /^((width|height)|(top|left))$/,
3184             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3185             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3186         },
3187
3188
3189         doMethod: function(attr, start, end) {
3190             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3191         },
3192
3193
3194         setAttribute: function(attr, val, unit) {
3195             if (this.patterns.noNegatives.test(attr)) {
3196                 val = (val > 0) ? val : 0;
3197             }
3198
3199             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3200         },
3201
3202
3203         getAttribute: function(attr) {
3204             var el = this.getEl();
3205             var val = fly(el).getStyle(attr);
3206
3207             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3208                 return parseFloat(val);
3209             }
3210
3211             var a = this.patterns.offsetAttribute.exec(attr) || [];
3212             var pos = !!( a[3] );
3213             var box = !!( a[2] );
3214
3215
3216             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3217                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3218             } else {
3219                 val = 0;
3220             }
3221
3222             return val;
3223         },
3224
3225
3226         getDefaultUnit: function(attr) {
3227             if (this.patterns.defaultUnit.test(attr)) {
3228                 return 'px';
3229             }
3230
3231             return '';
3232         },
3233
3234         animateX : function(callback, scope) {
3235             var f = function() {
3236                 this.onComplete.removeListener(f);
3237                 if (typeof callback == "function") {
3238                     callback.call(scope || this, this);
3239                 }
3240             };
3241             this.onComplete.addListener(f, this);
3242             this.animate();
3243         },
3244
3245
3246         setRuntimeAttribute: function(attr) {
3247             var start;
3248             var end;
3249             var attributes = this.attributes;
3250
3251             this.runtimeAttributes[attr] = {};
3252
3253             var isset = function(prop) {
3254                 return (typeof prop !== 'undefined');
3255             };
3256
3257             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3258                 return false;
3259             }
3260
3261             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3262
3263
3264             if (isset(attributes[attr]['to'])) {
3265                 end = attributes[attr]['to'];
3266             } else if (isset(attributes[attr]['by'])) {
3267                 if (start.constructor == Array) {
3268                     end = [];
3269                     for (var i = 0, len = start.length; i < len; ++i) {
3270                         end[i] = start[i] + attributes[attr]['by'][i];
3271                     }
3272                 } else {
3273                     end = start + attributes[attr]['by'];
3274                 }
3275             }
3276
3277             this.runtimeAttributes[attr].start = start;
3278             this.runtimeAttributes[attr].end = end;
3279
3280
3281             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3282         },
3283
3284
3285         init: function(el, attributes, duration, method) {
3286
3287             var isAnimated = false;
3288
3289
3290             var startTime = null;
3291
3292
3293             var actualFrames = 0;
3294
3295
3296             el = Roo.getDom(el);
3297
3298
3299             this.attributes = attributes || {};
3300
3301
3302             this.duration = duration || 1;
3303
3304
3305             this.method = method || Roo.lib.Easing.easeNone;
3306
3307
3308             this.useSeconds = true;
3309
3310
3311             this.currentFrame = 0;
3312
3313
3314             this.totalFrames = Roo.lib.AnimMgr.fps;
3315
3316
3317             this.getEl = function() {
3318                 return el;
3319             };
3320
3321
3322             this.isAnimated = function() {
3323                 return isAnimated;
3324             };
3325
3326
3327             this.getStartTime = function() {
3328                 return startTime;
3329             };
3330
3331             this.runtimeAttributes = {};
3332
3333
3334             this.animate = function() {
3335                 if (this.isAnimated()) {
3336                     return false;
3337                 }
3338
3339                 this.currentFrame = 0;
3340
3341                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3342
3343                 Roo.lib.AnimMgr.registerElement(this);
3344             };
3345
3346
3347             this.stop = function(finish) {
3348                 if (finish) {
3349                     this.currentFrame = this.totalFrames;
3350                     this._onTween.fire();
3351                 }
3352                 Roo.lib.AnimMgr.stop(this);
3353             };
3354
3355             var onStart = function() {
3356                 this.onStart.fire();
3357
3358                 this.runtimeAttributes = {};
3359                 for (var attr in this.attributes) {
3360                     this.setRuntimeAttribute(attr);
3361                 }
3362
3363                 isAnimated = true;
3364                 actualFrames = 0;
3365                 startTime = new Date();
3366             };
3367
3368
3369             var onTween = function() {
3370                 var data = {
3371                     duration: new Date() - this.getStartTime(),
3372                     currentFrame: this.currentFrame
3373                 };
3374
3375                 data.toString = function() {
3376                     return (
3377                             'duration: ' + data.duration +
3378                             ', currentFrame: ' + data.currentFrame
3379                             );
3380                 };
3381
3382                 this.onTween.fire(data);
3383
3384                 var runtimeAttributes = this.runtimeAttributes;
3385
3386                 for (var attr in runtimeAttributes) {
3387                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3388                 }
3389
3390                 actualFrames += 1;
3391             };
3392
3393             var onComplete = function() {
3394                 var actual_duration = (new Date() - startTime) / 1000 ;
3395
3396                 var data = {
3397                     duration: actual_duration,
3398                     frames: actualFrames,
3399                     fps: actualFrames / actual_duration
3400                 };
3401
3402                 data.toString = function() {
3403                     return (
3404                             'duration: ' + data.duration +
3405                             ', frames: ' + data.frames +
3406                             ', fps: ' + data.fps
3407                             );
3408                 };
3409
3410                 isAnimated = false;
3411                 actualFrames = 0;
3412                 this.onComplete.fire(data);
3413             };
3414
3415
3416             this._onStart = new Roo.util.Event(this);
3417             this.onStart = new Roo.util.Event(this);
3418             this.onTween = new Roo.util.Event(this);
3419             this._onTween = new Roo.util.Event(this);
3420             this.onComplete = new Roo.util.Event(this);
3421             this._onComplete = new Roo.util.Event(this);
3422             this._onStart.addListener(onStart);
3423             this._onTween.addListener(onTween);
3424             this._onComplete.addListener(onComplete);
3425         }
3426     };
3427 })();
3428 /*
3429  * Portions of this file are based on pieces of Yahoo User Interface Library
3430  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3431  * YUI licensed under the BSD License:
3432  * http://developer.yahoo.net/yui/license.txt
3433  * <script type="text/javascript">
3434  *
3435  */
3436
3437 Roo.lib.AnimMgr = new function() {
3438
3439     var thread = null;
3440
3441
3442     var queue = [];
3443
3444
3445     var tweenCount = 0;
3446
3447
3448     this.fps = 1000;
3449
3450
3451     this.delay = 1;
3452
3453
3454     this.registerElement = function(tween) {
3455         queue[queue.length] = tween;
3456         tweenCount += 1;
3457         tween._onStart.fire();
3458         this.start();
3459     };
3460
3461
3462     this.unRegister = function(tween, index) {
3463         tween._onComplete.fire();
3464         index = index || getIndex(tween);
3465         if (index != -1) {
3466             queue.splice(index, 1);
3467         }
3468
3469         tweenCount -= 1;
3470         if (tweenCount <= 0) {
3471             this.stop();
3472         }
3473     };
3474
3475
3476     this.start = function() {
3477         if (thread === null) {
3478             thread = setInterval(this.run, this.delay);
3479         }
3480     };
3481
3482
3483     this.stop = function(tween) {
3484         if (!tween) {
3485             clearInterval(thread);
3486
3487             for (var i = 0, len = queue.length; i < len; ++i) {
3488                 if (queue[0].isAnimated()) {
3489                     this.unRegister(queue[0], 0);
3490                 }
3491             }
3492
3493             queue = [];
3494             thread = null;
3495             tweenCount = 0;
3496         }
3497         else {
3498             this.unRegister(tween);
3499         }
3500     };
3501
3502
3503     this.run = function() {
3504         for (var i = 0, len = queue.length; i < len; ++i) {
3505             var tween = queue[i];
3506             if (!tween || !tween.isAnimated()) {
3507                 continue;
3508             }
3509
3510             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3511             {
3512                 tween.currentFrame += 1;
3513
3514                 if (tween.useSeconds) {
3515                     correctFrame(tween);
3516                 }
3517                 tween._onTween.fire();
3518             }
3519             else {
3520                 Roo.lib.AnimMgr.stop(tween, i);
3521             }
3522         }
3523     };
3524
3525     var getIndex = function(anim) {
3526         for (var i = 0, len = queue.length; i < len; ++i) {
3527             if (queue[i] == anim) {
3528                 return i;
3529             }
3530         }
3531         return -1;
3532     };
3533
3534
3535     var correctFrame = function(tween) {
3536         var frames = tween.totalFrames;
3537         var frame = tween.currentFrame;
3538         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3539         var elapsed = (new Date() - tween.getStartTime());
3540         var tweak = 0;
3541
3542         if (elapsed < tween.duration * 1000) {
3543             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3544         } else {
3545             tweak = frames - (frame + 1);
3546         }
3547         if (tweak > 0 && isFinite(tweak)) {
3548             if (tween.currentFrame + tweak >= frames) {
3549                 tweak = frames - (frame + 1);
3550             }
3551
3552             tween.currentFrame += tweak;
3553         }
3554     };
3555 };
3556
3557     /*
3558  * Portions of this file are based on pieces of Yahoo User Interface Library
3559  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3560  * YUI licensed under the BSD License:
3561  * http://developer.yahoo.net/yui/license.txt
3562  * <script type="text/javascript">
3563  *
3564  */
3565 Roo.lib.Bezier = new function() {
3566
3567         this.getPosition = function(points, t) {
3568             var n = points.length;
3569             var tmp = [];
3570
3571             for (var i = 0; i < n; ++i) {
3572                 tmp[i] = [points[i][0], points[i][1]];
3573             }
3574
3575             for (var j = 1; j < n; ++j) {
3576                 for (i = 0; i < n - j; ++i) {
3577                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3578                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3579                 }
3580             }
3581
3582             return [ tmp[0][0], tmp[0][1] ];
3583
3584         };
3585     };/*
3586  * Portions of this file are based on pieces of Yahoo User Interface Library
3587  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3588  * YUI licensed under the BSD License:
3589  * http://developer.yahoo.net/yui/license.txt
3590  * <script type="text/javascript">
3591  *
3592  */
3593 (function() {
3594
3595     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3596         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3597     };
3598
3599     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3600
3601     var fly = Roo.lib.AnimBase.fly;
3602     var Y = Roo.lib;
3603     var superclass = Y.ColorAnim.superclass;
3604     var proto = Y.ColorAnim.prototype;
3605
3606     proto.toString = function() {
3607         var el = this.getEl();
3608         var id = el.id || el.tagName;
3609         return ("ColorAnim " + id);
3610     };
3611
3612     proto.patterns.color = /color$/i;
3613     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3614     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3615     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3616     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3617
3618
3619     proto.parseColor = function(s) {
3620         if (s.length == 3) {
3621             return s;
3622         }
3623
3624         var c = this.patterns.hex.exec(s);
3625         if (c && c.length == 4) {
3626             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3627         }
3628
3629         c = this.patterns.rgb.exec(s);
3630         if (c && c.length == 4) {
3631             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3632         }
3633
3634         c = this.patterns.hex3.exec(s);
3635         if (c && c.length == 4) {
3636             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3637         }
3638
3639         return null;
3640     };
3641     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3642     proto.getAttribute = function(attr) {
3643         var el = this.getEl();
3644         if (this.patterns.color.test(attr)) {
3645             var val = fly(el).getStyle(attr);
3646
3647             if (this.patterns.transparent.test(val)) {
3648                 var parent = el.parentNode;
3649                 val = fly(parent).getStyle(attr);
3650
3651                 while (parent && this.patterns.transparent.test(val)) {
3652                     parent = parent.parentNode;
3653                     val = fly(parent).getStyle(attr);
3654                     if (parent.tagName.toUpperCase() == 'HTML') {
3655                         val = '#fff';
3656                     }
3657                 }
3658             }
3659         } else {
3660             val = superclass.getAttribute.call(this, attr);
3661         }
3662
3663         return val;
3664     };
3665     proto.getAttribute = function(attr) {
3666         var el = this.getEl();
3667         if (this.patterns.color.test(attr)) {
3668             var val = fly(el).getStyle(attr);
3669
3670             if (this.patterns.transparent.test(val)) {
3671                 var parent = el.parentNode;
3672                 val = fly(parent).getStyle(attr);
3673
3674                 while (parent && this.patterns.transparent.test(val)) {
3675                     parent = parent.parentNode;
3676                     val = fly(parent).getStyle(attr);
3677                     if (parent.tagName.toUpperCase() == 'HTML') {
3678                         val = '#fff';
3679                     }
3680                 }
3681             }
3682         } else {
3683             val = superclass.getAttribute.call(this, attr);
3684         }
3685
3686         return val;
3687     };
3688
3689     proto.doMethod = function(attr, start, end) {
3690         var val;
3691
3692         if (this.patterns.color.test(attr)) {
3693             val = [];
3694             for (var i = 0, len = start.length; i < len; ++i) {
3695                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3696             }
3697
3698             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3699         }
3700         else {
3701             val = superclass.doMethod.call(this, attr, start, end);
3702         }
3703
3704         return val;
3705     };
3706
3707     proto.setRuntimeAttribute = function(attr) {
3708         superclass.setRuntimeAttribute.call(this, attr);
3709
3710         if (this.patterns.color.test(attr)) {
3711             var attributes = this.attributes;
3712             var start = this.parseColor(this.runtimeAttributes[attr].start);
3713             var end = this.parseColor(this.runtimeAttributes[attr].end);
3714
3715             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3716                 end = this.parseColor(attributes[attr].by);
3717
3718                 for (var i = 0, len = start.length; i < len; ++i) {
3719                     end[i] = start[i] + end[i];
3720                 }
3721             }
3722
3723             this.runtimeAttributes[attr].start = start;
3724             this.runtimeAttributes[attr].end = end;
3725         }
3726     };
3727 })();
3728
3729 /*
3730  * Portions of this file are based on pieces of Yahoo User Interface Library
3731  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3732  * YUI licensed under the BSD License:
3733  * http://developer.yahoo.net/yui/license.txt
3734  * <script type="text/javascript">
3735  *
3736  */
3737 Roo.lib.Easing = {
3738
3739
3740     easeNone: function (t, b, c, d) {
3741         return c * t / d + b;
3742     },
3743
3744
3745     easeIn: function (t, b, c, d) {
3746         return c * (t /= d) * t + b;
3747     },
3748
3749
3750     easeOut: function (t, b, c, d) {
3751         return -c * (t /= d) * (t - 2) + b;
3752     },
3753
3754
3755     easeBoth: function (t, b, c, d) {
3756         if ((t /= d / 2) < 1) {
3757             return c / 2 * t * t + b;
3758         }
3759
3760         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3761     },
3762
3763
3764     easeInStrong: function (t, b, c, d) {
3765         return c * (t /= d) * t * t * t + b;
3766     },
3767
3768
3769     easeOutStrong: function (t, b, c, d) {
3770         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3771     },
3772
3773
3774     easeBothStrong: function (t, b, c, d) {
3775         if ((t /= d / 2) < 1) {
3776             return c / 2 * t * t * t * t + b;
3777         }
3778
3779         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3780     },
3781
3782
3783
3784     elasticIn: function (t, b, c, d, a, p) {
3785         if (t == 0) {
3786             return b;
3787         }
3788         if ((t /= d) == 1) {
3789             return b + c;
3790         }
3791         if (!p) {
3792             p = d * .3;
3793         }
3794
3795         if (!a || a < Math.abs(c)) {
3796             a = c;
3797             var s = p / 4;
3798         }
3799         else {
3800             var s = p / (2 * Math.PI) * Math.asin(c / a);
3801         }
3802
3803         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3804     },
3805
3806
3807     elasticOut: function (t, b, c, d, a, p) {
3808         if (t == 0) {
3809             return b;
3810         }
3811         if ((t /= d) == 1) {
3812             return b + c;
3813         }
3814         if (!p) {
3815             p = d * .3;
3816         }
3817
3818         if (!a || a < Math.abs(c)) {
3819             a = c;
3820             var s = p / 4;
3821         }
3822         else {
3823             var s = p / (2 * Math.PI) * Math.asin(c / a);
3824         }
3825
3826         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3827     },
3828
3829
3830     elasticBoth: function (t, b, c, d, a, p) {
3831         if (t == 0) {
3832             return b;
3833         }
3834
3835         if ((t /= d / 2) == 2) {
3836             return b + c;
3837         }
3838
3839         if (!p) {
3840             p = d * (.3 * 1.5);
3841         }
3842
3843         if (!a || a < Math.abs(c)) {
3844             a = c;
3845             var s = p / 4;
3846         }
3847         else {
3848             var s = p / (2 * Math.PI) * Math.asin(c / a);
3849         }
3850
3851         if (t < 1) {
3852             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3853                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3854         }
3855         return a * Math.pow(2, -10 * (t -= 1)) *
3856                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3857     },
3858
3859
3860
3861     backIn: function (t, b, c, d, s) {
3862         if (typeof s == 'undefined') {
3863             s = 1.70158;
3864         }
3865         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3866     },
3867
3868
3869     backOut: function (t, b, c, d, s) {
3870         if (typeof s == 'undefined') {
3871             s = 1.70158;
3872         }
3873         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3874     },
3875
3876
3877     backBoth: function (t, b, c, d, s) {
3878         if (typeof s == 'undefined') {
3879             s = 1.70158;
3880         }
3881
3882         if ((t /= d / 2 ) < 1) {
3883             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3884         }
3885         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3886     },
3887
3888
3889     bounceIn: function (t, b, c, d) {
3890         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3891     },
3892
3893
3894     bounceOut: function (t, b, c, d) {
3895         if ((t /= d) < (1 / 2.75)) {
3896             return c * (7.5625 * t * t) + b;
3897         } else if (t < (2 / 2.75)) {
3898             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3899         } else if (t < (2.5 / 2.75)) {
3900             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3901         }
3902         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3903     },
3904
3905
3906     bounceBoth: function (t, b, c, d) {
3907         if (t < d / 2) {
3908             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3909         }
3910         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3911     }
3912 };/*
3913  * Portions of this file are based on pieces of Yahoo User Interface Library
3914  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3915  * YUI licensed under the BSD License:
3916  * http://developer.yahoo.net/yui/license.txt
3917  * <script type="text/javascript">
3918  *
3919  */
3920     (function() {
3921         Roo.lib.Motion = function(el, attributes, duration, method) {
3922             if (el) {
3923                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3924             }
3925         };
3926
3927         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3928
3929
3930         var Y = Roo.lib;
3931         var superclass = Y.Motion.superclass;
3932         var proto = Y.Motion.prototype;
3933
3934         proto.toString = function() {
3935             var el = this.getEl();
3936             var id = el.id || el.tagName;
3937             return ("Motion " + id);
3938         };
3939
3940         proto.patterns.points = /^points$/i;
3941
3942         proto.setAttribute = function(attr, val, unit) {
3943             if (this.patterns.points.test(attr)) {
3944                 unit = unit || 'px';
3945                 superclass.setAttribute.call(this, 'left', val[0], unit);
3946                 superclass.setAttribute.call(this, 'top', val[1], unit);
3947             } else {
3948                 superclass.setAttribute.call(this, attr, val, unit);
3949             }
3950         };
3951
3952         proto.getAttribute = function(attr) {
3953             if (this.patterns.points.test(attr)) {
3954                 var val = [
3955                         superclass.getAttribute.call(this, 'left'),
3956                         superclass.getAttribute.call(this, 'top')
3957                         ];
3958             } else {
3959                 val = superclass.getAttribute.call(this, attr);
3960             }
3961
3962             return val;
3963         };
3964
3965         proto.doMethod = function(attr, start, end) {
3966             var val = null;
3967
3968             if (this.patterns.points.test(attr)) {
3969                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3970                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3971             } else {
3972                 val = superclass.doMethod.call(this, attr, start, end);
3973             }
3974             return val;
3975         };
3976
3977         proto.setRuntimeAttribute = function(attr) {
3978             if (this.patterns.points.test(attr)) {
3979                 var el = this.getEl();
3980                 var attributes = this.attributes;
3981                 var start;
3982                 var control = attributes['points']['control'] || [];
3983                 var end;
3984                 var i, len;
3985
3986                 if (control.length > 0 && !(control[0] instanceof Array)) {
3987                     control = [control];
3988                 } else {
3989                     var tmp = [];
3990                     for (i = 0,len = control.length; i < len; ++i) {
3991                         tmp[i] = control[i];
3992                     }
3993                     control = tmp;
3994                 }
3995
3996                 Roo.fly(el).position();
3997
3998                 if (isset(attributes['points']['from'])) {
3999                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4000                 }
4001                 else {
4002                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4003                 }
4004
4005                 start = this.getAttribute('points');
4006
4007
4008                 if (isset(attributes['points']['to'])) {
4009                     end = translateValues.call(this, attributes['points']['to'], start);
4010
4011                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4012                     for (i = 0,len = control.length; i < len; ++i) {
4013                         control[i] = translateValues.call(this, control[i], start);
4014                     }
4015
4016
4017                 } else if (isset(attributes['points']['by'])) {
4018                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4019
4020                     for (i = 0,len = control.length; i < len; ++i) {
4021                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4022                     }
4023                 }
4024
4025                 this.runtimeAttributes[attr] = [start];
4026
4027                 if (control.length > 0) {
4028                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4029                 }
4030
4031                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4032             }
4033             else {
4034                 superclass.setRuntimeAttribute.call(this, attr);
4035             }
4036         };
4037
4038         var translateValues = function(val, start) {
4039             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4040             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4041
4042             return val;
4043         };
4044
4045         var isset = function(prop) {
4046             return (typeof prop !== 'undefined');
4047         };
4048     })();
4049 /*
4050  * Portions of this file are based on pieces of Yahoo User Interface Library
4051  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4052  * YUI licensed under the BSD License:
4053  * http://developer.yahoo.net/yui/license.txt
4054  * <script type="text/javascript">
4055  *
4056  */
4057     (function() {
4058         Roo.lib.Scroll = function(el, attributes, duration, method) {
4059             if (el) {
4060                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4061             }
4062         };
4063
4064         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4065
4066
4067         var Y = Roo.lib;
4068         var superclass = Y.Scroll.superclass;
4069         var proto = Y.Scroll.prototype;
4070
4071         proto.toString = function() {
4072             var el = this.getEl();
4073             var id = el.id || el.tagName;
4074             return ("Scroll " + id);
4075         };
4076
4077         proto.doMethod = function(attr, start, end) {
4078             var val = null;
4079
4080             if (attr == 'scroll') {
4081                 val = [
4082                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4083                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4084                         ];
4085
4086             } else {
4087                 val = superclass.doMethod.call(this, attr, start, end);
4088             }
4089             return val;
4090         };
4091
4092         proto.getAttribute = function(attr) {
4093             var val = null;
4094             var el = this.getEl();
4095
4096             if (attr == 'scroll') {
4097                 val = [ el.scrollLeft, el.scrollTop ];
4098             } else {
4099                 val = superclass.getAttribute.call(this, attr);
4100             }
4101
4102             return val;
4103         };
4104
4105         proto.setAttribute = function(attr, val, unit) {
4106             var el = this.getEl();
4107
4108             if (attr == 'scroll') {
4109                 el.scrollLeft = val[0];
4110                 el.scrollTop = val[1];
4111             } else {
4112                 superclass.setAttribute.call(this, attr, val, unit);
4113             }
4114         };
4115     })();
4116 /*
4117  * Based on:
4118  * Ext JS Library 1.1.1
4119  * Copyright(c) 2006-2007, Ext JS, LLC.
4120  *
4121  * Originally Released Under LGPL - original licence link has changed is not relivant.
4122  *
4123  * Fork - LGPL
4124  * <script type="text/javascript">
4125  */
4126
4127
4128 // nasty IE9 hack - what a pile of crap that is..
4129
4130  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4131     Range.prototype.createContextualFragment = function (html) {
4132         var doc = window.document;
4133         var container = doc.createElement("div");
4134         container.innerHTML = html;
4135         var frag = doc.createDocumentFragment(), n;
4136         while ((n = container.firstChild)) {
4137             frag.appendChild(n);
4138         }
4139         return frag;
4140     };
4141 }
4142
4143 /**
4144  * @class Roo.DomHelper
4145  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4146  * 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>.
4147  * @singleton
4148  */
4149 Roo.DomHelper = function(){
4150     var tempTableEl = null;
4151     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4152     var tableRe = /^table|tbody|tr|td$/i;
4153     var xmlns = {};
4154     // build as innerHTML where available
4155     /** @ignore */
4156     var createHtml = function(o){
4157         if(typeof o == 'string'){
4158             return o;
4159         }
4160         var b = "";
4161         if(!o.tag){
4162             o.tag = "div";
4163         }
4164         b += "<" + o.tag;
4165         for(var attr in o){
4166             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4167             if(attr == "style"){
4168                 var s = o["style"];
4169                 if(typeof s == "function"){
4170                     s = s.call();
4171                 }
4172                 if(typeof s == "string"){
4173                     b += ' style="' + s + '"';
4174                 }else if(typeof s == "object"){
4175                     b += ' style="';
4176                     for(var key in s){
4177                         if(typeof s[key] != "function"){
4178                             b += key + ":" + s[key] + ";";
4179                         }
4180                     }
4181                     b += '"';
4182                 }
4183             }else{
4184                 if(attr == "cls"){
4185                     b += ' class="' + o["cls"] + '"';
4186                 }else if(attr == "htmlFor"){
4187                     b += ' for="' + o["htmlFor"] + '"';
4188                 }else{
4189                     b += " " + attr + '="' + o[attr] + '"';
4190                 }
4191             }
4192         }
4193         if(emptyTags.test(o.tag)){
4194             b += "/>";
4195         }else{
4196             b += ">";
4197             var cn = o.children || o.cn;
4198             if(cn){
4199                 //http://bugs.kde.org/show_bug.cgi?id=71506
4200                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4201                     for(var i = 0, len = cn.length; i < len; i++) {
4202                         b += createHtml(cn[i], b);
4203                     }
4204                 }else{
4205                     b += createHtml(cn, b);
4206                 }
4207             }
4208             if(o.html){
4209                 b += o.html;
4210             }
4211             b += "</" + o.tag + ">";
4212         }
4213         return b;
4214     };
4215
4216     // build as dom
4217     /** @ignore */
4218     var createDom = function(o, parentNode){
4219          
4220         // defininition craeted..
4221         var ns = false;
4222         if (o.ns && o.ns != 'html') {
4223                
4224             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4225                 xmlns[o.ns] = o.xmlns;
4226                 ns = o.xmlns;
4227             }
4228             if (typeof(xmlns[o.ns]) == 'undefined') {
4229                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4230             }
4231             ns = xmlns[o.ns];
4232         }
4233         
4234         
4235         if (typeof(o) == 'string') {
4236             return parentNode.appendChild(document.createTextNode(o));
4237         }
4238         o.tag = o.tag || div;
4239         if (o.ns && Roo.isIE) {
4240             ns = false;
4241             o.tag = o.ns + ':' + o.tag;
4242             
4243         }
4244         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4245         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4246         for(var attr in o){
4247             
4248             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4249                     attr == "style" || typeof o[attr] == "function") { continue; }
4250                     
4251             if(attr=="cls" && Roo.isIE){
4252                 el.className = o["cls"];
4253             }else{
4254                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4255                 else { 
4256                     el[attr] = o[attr];
4257                 }
4258             }
4259         }
4260         Roo.DomHelper.applyStyles(el, o.style);
4261         var cn = o.children || o.cn;
4262         if(cn){
4263             //http://bugs.kde.org/show_bug.cgi?id=71506
4264              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4265                 for(var i = 0, len = cn.length; i < len; i++) {
4266                     createDom(cn[i], el);
4267                 }
4268             }else{
4269                 createDom(cn, el);
4270             }
4271         }
4272         if(o.html){
4273             el.innerHTML = o.html;
4274         }
4275         if(parentNode){
4276            parentNode.appendChild(el);
4277         }
4278         return el;
4279     };
4280
4281     var ieTable = function(depth, s, h, e){
4282         tempTableEl.innerHTML = [s, h, e].join('');
4283         var i = -1, el = tempTableEl;
4284         while(++i < depth){
4285             el = el.firstChild;
4286         }
4287         return el;
4288     };
4289
4290     // kill repeat to save bytes
4291     var ts = '<table>',
4292         te = '</table>',
4293         tbs = ts+'<tbody>',
4294         tbe = '</tbody>'+te,
4295         trs = tbs + '<tr>',
4296         tre = '</tr>'+tbe;
4297
4298     /**
4299      * @ignore
4300      * Nasty code for IE's broken table implementation
4301      */
4302     var insertIntoTable = function(tag, where, el, html){
4303         if(!tempTableEl){
4304             tempTableEl = document.createElement('div');
4305         }
4306         var node;
4307         var before = null;
4308         if(tag == 'td'){
4309             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4310                 return;
4311             }
4312             if(where == 'beforebegin'){
4313                 before = el;
4314                 el = el.parentNode;
4315             } else{
4316                 before = el.nextSibling;
4317                 el = el.parentNode;
4318             }
4319             node = ieTable(4, trs, html, tre);
4320         }
4321         else if(tag == 'tr'){
4322             if(where == 'beforebegin'){
4323                 before = el;
4324                 el = el.parentNode;
4325                 node = ieTable(3, tbs, html, tbe);
4326             } else if(where == 'afterend'){
4327                 before = el.nextSibling;
4328                 el = el.parentNode;
4329                 node = ieTable(3, tbs, html, tbe);
4330             } else{ // INTO a TR
4331                 if(where == 'afterbegin'){
4332                     before = el.firstChild;
4333                 }
4334                 node = ieTable(4, trs, html, tre);
4335             }
4336         } else if(tag == 'tbody'){
4337             if(where == 'beforebegin'){
4338                 before = el;
4339                 el = el.parentNode;
4340                 node = ieTable(2, ts, html, te);
4341             } else if(where == 'afterend'){
4342                 before = el.nextSibling;
4343                 el = el.parentNode;
4344                 node = ieTable(2, ts, html, te);
4345             } else{
4346                 if(where == 'afterbegin'){
4347                     before = el.firstChild;
4348                 }
4349                 node = ieTable(3, tbs, html, tbe);
4350             }
4351         } else{ // TABLE
4352             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4353                 return;
4354             }
4355             if(where == 'afterbegin'){
4356                 before = el.firstChild;
4357             }
4358             node = ieTable(2, ts, html, te);
4359         }
4360         el.insertBefore(node, before);
4361         return node;
4362     };
4363
4364     return {
4365     /** True to force the use of DOM instead of html fragments @type Boolean */
4366     useDom : false,
4367
4368     /**
4369      * Returns the markup for the passed Element(s) config
4370      * @param {Object} o The Dom object spec (and children)
4371      * @return {String}
4372      */
4373     markup : function(o){
4374         return createHtml(o);
4375     },
4376
4377     /**
4378      * Applies a style specification to an element
4379      * @param {String/HTMLElement} el The element to apply styles to
4380      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4381      * a function which returns such a specification.
4382      */
4383     applyStyles : function(el, styles){
4384         if(styles){
4385            el = Roo.fly(el);
4386            if(typeof styles == "string"){
4387                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4388                var matches;
4389                while ((matches = re.exec(styles)) != null){
4390                    el.setStyle(matches[1], matches[2]);
4391                }
4392            }else if (typeof styles == "object"){
4393                for (var style in styles){
4394                   el.setStyle(style, styles[style]);
4395                }
4396            }else if (typeof styles == "function"){
4397                 Roo.DomHelper.applyStyles(el, styles.call());
4398            }
4399         }
4400     },
4401
4402     /**
4403      * Inserts an HTML fragment into the Dom
4404      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4405      * @param {HTMLElement} el The context element
4406      * @param {String} html The HTML fragmenet
4407      * @return {HTMLElement} The new node
4408      */
4409     insertHtml : function(where, el, html){
4410         where = where.toLowerCase();
4411         if(el.insertAdjacentHTML){
4412             if(tableRe.test(el.tagName)){
4413                 var rs;
4414                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4415                     return rs;
4416                 }
4417             }
4418             switch(where){
4419                 case "beforebegin":
4420                     el.insertAdjacentHTML('BeforeBegin', html);
4421                     return el.previousSibling;
4422                 case "afterbegin":
4423                     el.insertAdjacentHTML('AfterBegin', html);
4424                     return el.firstChild;
4425                 case "beforeend":
4426                     el.insertAdjacentHTML('BeforeEnd', html);
4427                     return el.lastChild;
4428                 case "afterend":
4429                     el.insertAdjacentHTML('AfterEnd', html);
4430                     return el.nextSibling;
4431             }
4432             throw 'Illegal insertion point -> "' + where + '"';
4433         }
4434         var range = el.ownerDocument.createRange();
4435         var frag;
4436         switch(where){
4437              case "beforebegin":
4438                 range.setStartBefore(el);
4439                 frag = range.createContextualFragment(html);
4440                 el.parentNode.insertBefore(frag, el);
4441                 return el.previousSibling;
4442              case "afterbegin":
4443                 if(el.firstChild){
4444                     range.setStartBefore(el.firstChild);
4445                     frag = range.createContextualFragment(html);
4446                     el.insertBefore(frag, el.firstChild);
4447                     return el.firstChild;
4448                 }else{
4449                     el.innerHTML = html;
4450                     return el.firstChild;
4451                 }
4452             case "beforeend":
4453                 if(el.lastChild){
4454                     range.setStartAfter(el.lastChild);
4455                     frag = range.createContextualFragment(html);
4456                     el.appendChild(frag);
4457                     return el.lastChild;
4458                 }else{
4459                     el.innerHTML = html;
4460                     return el.lastChild;
4461                 }
4462             case "afterend":
4463                 range.setStartAfter(el);
4464                 frag = range.createContextualFragment(html);
4465                 el.parentNode.insertBefore(frag, el.nextSibling);
4466                 return el.nextSibling;
4467             }
4468             throw 'Illegal insertion point -> "' + where + '"';
4469     },
4470
4471     /**
4472      * Creates new Dom element(s) and inserts them before el
4473      * @param {String/HTMLElement/Element} el The context element
4474      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4475      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4476      * @return {HTMLElement/Roo.Element} The new node
4477      */
4478     insertBefore : function(el, o, returnElement){
4479         return this.doInsert(el, o, returnElement, "beforeBegin");
4480     },
4481
4482     /**
4483      * Creates new Dom element(s) and inserts them after el
4484      * @param {String/HTMLElement/Element} el The context element
4485      * @param {Object} o The Dom object spec (and children)
4486      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4487      * @return {HTMLElement/Roo.Element} The new node
4488      */
4489     insertAfter : function(el, o, returnElement){
4490         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4491     },
4492
4493     /**
4494      * Creates new Dom element(s) and inserts them as the first child of el
4495      * @param {String/HTMLElement/Element} el The context element
4496      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4497      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4498      * @return {HTMLElement/Roo.Element} The new node
4499      */
4500     insertFirst : function(el, o, returnElement){
4501         return this.doInsert(el, o, returnElement, "afterBegin");
4502     },
4503
4504     // private
4505     doInsert : function(el, o, returnElement, pos, sibling){
4506         el = Roo.getDom(el);
4507         var newNode;
4508         if(this.useDom || o.ns){
4509             newNode = createDom(o, null);
4510             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4511         }else{
4512             var html = createHtml(o);
4513             newNode = this.insertHtml(pos, el, html);
4514         }
4515         return returnElement ? Roo.get(newNode, true) : newNode;
4516     },
4517
4518     /**
4519      * Creates new Dom element(s) and appends them to el
4520      * @param {String/HTMLElement/Element} el The context element
4521      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4522      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4523      * @return {HTMLElement/Roo.Element} The new node
4524      */
4525     append : function(el, o, returnElement){
4526         el = Roo.getDom(el);
4527         var newNode;
4528         if(this.useDom || o.ns){
4529             newNode = createDom(o, null);
4530             el.appendChild(newNode);
4531         }else{
4532             var html = createHtml(o);
4533             newNode = this.insertHtml("beforeEnd", el, html);
4534         }
4535         return returnElement ? Roo.get(newNode, true) : newNode;
4536     },
4537
4538     /**
4539      * Creates new Dom element(s) and overwrites the contents of el with them
4540      * @param {String/HTMLElement/Element} el The context element
4541      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4542      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4543      * @return {HTMLElement/Roo.Element} The new node
4544      */
4545     overwrite : function(el, o, returnElement){
4546         el = Roo.getDom(el);
4547         if (o.ns) {
4548           
4549             while (el.childNodes.length) {
4550                 el.removeChild(el.firstChild);
4551             }
4552             createDom(o, el);
4553         } else {
4554             el.innerHTML = createHtml(o);   
4555         }
4556         
4557         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4558     },
4559
4560     /**
4561      * Creates a new Roo.DomHelper.Template from the Dom object spec
4562      * @param {Object} o The Dom object spec (and children)
4563      * @return {Roo.DomHelper.Template} The new template
4564      */
4565     createTemplate : function(o){
4566         var html = createHtml(o);
4567         return new Roo.Template(html);
4568     }
4569     };
4570 }();
4571 /*
4572  * Based on:
4573  * Ext JS Library 1.1.1
4574  * Copyright(c) 2006-2007, Ext JS, LLC.
4575  *
4576  * Originally Released Under LGPL - original licence link has changed is not relivant.
4577  *
4578  * Fork - LGPL
4579  * <script type="text/javascript">
4580  */
4581  
4582 /**
4583 * @class Roo.Template
4584 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4585 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4586 * Usage:
4587 <pre><code>
4588 var t = new Roo.Template({
4589     html :  '&lt;div name="{id}"&gt;' + 
4590         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4591         '&lt;/div&gt;',
4592     myformat: function (value, allValues) {
4593         return 'XX' + value;
4594     }
4595 });
4596 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4597 </code></pre>
4598 * For more information see this blog post with examples:
4599 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4600      - Create Elements using DOM, HTML fragments and Templates</a>. 
4601 * @constructor
4602 * @param {Object} cfg - Configuration object.
4603 */
4604 Roo.Template = function(cfg){
4605     // BC!
4606     if(cfg instanceof Array){
4607         cfg = cfg.join("");
4608     }else if(arguments.length > 1){
4609         cfg = Array.prototype.join.call(arguments, "");
4610     }
4611     
4612     
4613     if (typeof(cfg) == 'object') {
4614         Roo.apply(this,cfg)
4615     } else {
4616         // bc
4617         this.html = cfg;
4618     }
4619     if (this.url) {
4620         this.load();
4621     }
4622     
4623 };
4624 Roo.Template.prototype = {
4625     
4626     /**
4627      * @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..
4628      *                    it should be fixed so that template is observable...
4629      */
4630     url : false,
4631     /**
4632      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4633      */
4634     html : '',
4635     /**
4636      * Returns an HTML fragment of this template with the specified values applied.
4637      * @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'})
4638      * @return {String} The HTML fragment
4639      */
4640     applyTemplate : function(values){
4641         try {
4642            
4643             if(this.compiled){
4644                 return this.compiled(values);
4645             }
4646             var useF = this.disableFormats !== true;
4647             var fm = Roo.util.Format, tpl = this;
4648             var fn = function(m, name, format, args){
4649                 if(format && useF){
4650                     if(format.substr(0, 5) == "this."){
4651                         return tpl.call(format.substr(5), values[name], values);
4652                     }else{
4653                         if(args){
4654                             // quoted values are required for strings in compiled templates, 
4655                             // but for non compiled we need to strip them
4656                             // quoted reversed for jsmin
4657                             var re = /^\s*['"](.*)["']\s*$/;
4658                             args = args.split(',');
4659                             for(var i = 0, len = args.length; i < len; i++){
4660                                 args[i] = args[i].replace(re, "$1");
4661                             }
4662                             args = [values[name]].concat(args);
4663                         }else{
4664                             args = [values[name]];
4665                         }
4666                         return fm[format].apply(fm, args);
4667                     }
4668                 }else{
4669                     return values[name] !== undefined ? values[name] : "";
4670                 }
4671             };
4672             return this.html.replace(this.re, fn);
4673         } catch (e) {
4674             Roo.log(e);
4675             throw e;
4676         }
4677          
4678     },
4679     
4680     loading : false,
4681       
4682     load : function ()
4683     {
4684          
4685         if (this.loading) {
4686             return;
4687         }
4688         var _t = this;
4689         
4690         this.loading = true;
4691         this.compiled = false;
4692         
4693         var cx = new Roo.data.Connection();
4694         cx.request({
4695             url : this.url,
4696             method : 'GET',
4697             success : function (response) {
4698                 _t.loading = false;
4699                 _t.html = response.responseText;
4700                 _t.url = false;
4701                 _t.compile();
4702              },
4703             failure : function(response) {
4704                 Roo.log("Template failed to load from " + _t.url);
4705                 _t.loading = false;
4706             }
4707         });
4708     },
4709
4710     /**
4711      * Sets the HTML used as the template and optionally compiles it.
4712      * @param {String} html
4713      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4714      * @return {Roo.Template} this
4715      */
4716     set : function(html, compile){
4717         this.html = html;
4718         this.compiled = null;
4719         if(compile){
4720             this.compile();
4721         }
4722         return this;
4723     },
4724     
4725     /**
4726      * True to disable format functions (defaults to false)
4727      * @type Boolean
4728      */
4729     disableFormats : false,
4730     
4731     /**
4732     * The regular expression used to match template variables 
4733     * @type RegExp
4734     * @property 
4735     */
4736     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4737     
4738     /**
4739      * Compiles the template into an internal function, eliminating the RegEx overhead.
4740      * @return {Roo.Template} this
4741      */
4742     compile : function(){
4743         var fm = Roo.util.Format;
4744         var useF = this.disableFormats !== true;
4745         var sep = Roo.isGecko ? "+" : ",";
4746         var fn = function(m, name, format, args){
4747             if(format && useF){
4748                 args = args ? ',' + args : "";
4749                 if(format.substr(0, 5) != "this."){
4750                     format = "fm." + format + '(';
4751                 }else{
4752                     format = 'this.call("'+ format.substr(5) + '", ';
4753                     args = ", values";
4754                 }
4755             }else{
4756                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4757             }
4758             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4759         };
4760         var body;
4761         // branched to use + in gecko and [].join() in others
4762         if(Roo.isGecko){
4763             body = "this.compiled = function(values){ return '" +
4764                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4765                     "';};";
4766         }else{
4767             body = ["this.compiled = function(values){ return ['"];
4768             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4769             body.push("'].join('');};");
4770             body = body.join('');
4771         }
4772         /**
4773          * eval:var:values
4774          * eval:var:fm
4775          */
4776         eval(body);
4777         return this;
4778     },
4779     
4780     // private function used to call members
4781     call : function(fnName, value, allValues){
4782         return this[fnName](value, allValues);
4783     },
4784     
4785     /**
4786      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4787      * @param {String/HTMLElement/Roo.Element} el The context element
4788      * @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'})
4789      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4790      * @return {HTMLElement/Roo.Element} The new node or Element
4791      */
4792     insertFirst: function(el, values, returnElement){
4793         return this.doInsert('afterBegin', el, values, returnElement);
4794     },
4795
4796     /**
4797      * Applies the supplied values to the template and inserts the new node(s) before el.
4798      * @param {String/HTMLElement/Roo.Element} el The context element
4799      * @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'})
4800      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4801      * @return {HTMLElement/Roo.Element} The new node or Element
4802      */
4803     insertBefore: function(el, values, returnElement){
4804         return this.doInsert('beforeBegin', el, values, returnElement);
4805     },
4806
4807     /**
4808      * Applies the supplied values to the template and inserts the new node(s) after el.
4809      * @param {String/HTMLElement/Roo.Element} el The context element
4810      * @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'})
4811      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4812      * @return {HTMLElement/Roo.Element} The new node or Element
4813      */
4814     insertAfter : function(el, values, returnElement){
4815         return this.doInsert('afterEnd', el, values, returnElement);
4816     },
4817     
4818     /**
4819      * Applies the supplied values to the template and appends the new node(s) to el.
4820      * @param {String/HTMLElement/Roo.Element} el The context element
4821      * @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'})
4822      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4823      * @return {HTMLElement/Roo.Element} The new node or Element
4824      */
4825     append : function(el, values, returnElement){
4826         return this.doInsert('beforeEnd', el, values, returnElement);
4827     },
4828
4829     doInsert : function(where, el, values, returnEl){
4830         el = Roo.getDom(el);
4831         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4832         return returnEl ? Roo.get(newNode, true) : newNode;
4833     },
4834
4835     /**
4836      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4837      * @param {String/HTMLElement/Roo.Element} el The context element
4838      * @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'})
4839      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4840      * @return {HTMLElement/Roo.Element} The new node or Element
4841      */
4842     overwrite : function(el, values, returnElement){
4843         el = Roo.getDom(el);
4844         el.innerHTML = this.applyTemplate(values);
4845         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4846     }
4847 };
4848 /**
4849  * Alias for {@link #applyTemplate}
4850  * @method
4851  */
4852 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4853
4854 // backwards compat
4855 Roo.DomHelper.Template = Roo.Template;
4856
4857 /**
4858  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4859  * @param {String/HTMLElement} el A DOM element or its id
4860  * @returns {Roo.Template} The created template
4861  * @static
4862  */
4863 Roo.Template.from = function(el){
4864     el = Roo.getDom(el);
4865     return new Roo.Template(el.value || el.innerHTML);
4866 };/*
4867  * Based on:
4868  * Ext JS Library 1.1.1
4869  * Copyright(c) 2006-2007, Ext JS, LLC.
4870  *
4871  * Originally Released Under LGPL - original licence link has changed is not relivant.
4872  *
4873  * Fork - LGPL
4874  * <script type="text/javascript">
4875  */
4876  
4877
4878 /*
4879  * This is code is also distributed under MIT license for use
4880  * with jQuery and prototype JavaScript libraries.
4881  */
4882 /**
4883  * @class Roo.DomQuery
4884 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).
4885 <p>
4886 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>
4887
4888 <p>
4889 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.
4890 </p>
4891 <h4>Element Selectors:</h4>
4892 <ul class="list">
4893     <li> <b>*</b> any element</li>
4894     <li> <b>E</b> an element with the tag E</li>
4895     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4896     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4897     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4898     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4899 </ul>
4900 <h4>Attribute Selectors:</h4>
4901 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4902 <ul class="list">
4903     <li> <b>E[foo]</b> has an attribute "foo"</li>
4904     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4905     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4906     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4907     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4908     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4909     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4910 </ul>
4911 <h4>Pseudo Classes:</h4>
4912 <ul class="list">
4913     <li> <b>E:first-child</b> E is the first child of its parent</li>
4914     <li> <b>E:last-child</b> E is the last child of its parent</li>
4915     <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>
4916     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4917     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4918     <li> <b>E:only-child</b> E is the only child of its parent</li>
4919     <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>
4920     <li> <b>E:first</b> the first E in the resultset</li>
4921     <li> <b>E:last</b> the last E in the resultset</li>
4922     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4923     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4924     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4925     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4926     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4927     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4928     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4929     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4930     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4931 </ul>
4932 <h4>CSS Value Selectors:</h4>
4933 <ul class="list">
4934     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4935     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4936     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4937     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4938     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4939     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4940 </ul>
4941  * @singleton
4942  */
4943 Roo.DomQuery = function(){
4944     var cache = {}, simpleCache = {}, valueCache = {};
4945     var nonSpace = /\S/;
4946     var trimRe = /^\s+|\s+$/g;
4947     var tplRe = /\{(\d+)\}/g;
4948     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4949     var tagTokenRe = /^(#)?([\w-\*]+)/;
4950     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4951
4952     function child(p, index){
4953         var i = 0;
4954         var n = p.firstChild;
4955         while(n){
4956             if(n.nodeType == 1){
4957                if(++i == index){
4958                    return n;
4959                }
4960             }
4961             n = n.nextSibling;
4962         }
4963         return null;
4964     };
4965
4966     function next(n){
4967         while((n = n.nextSibling) && n.nodeType != 1);
4968         return n;
4969     };
4970
4971     function prev(n){
4972         while((n = n.previousSibling) && n.nodeType != 1);
4973         return n;
4974     };
4975
4976     function children(d){
4977         var n = d.firstChild, ni = -1;
4978             while(n){
4979                 var nx = n.nextSibling;
4980                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4981                     d.removeChild(n);
4982                 }else{
4983                     n.nodeIndex = ++ni;
4984                 }
4985                 n = nx;
4986             }
4987             return this;
4988         };
4989
4990     function byClassName(c, a, v){
4991         if(!v){
4992             return c;
4993         }
4994         var r = [], ri = -1, cn;
4995         for(var i = 0, ci; ci = c[i]; i++){
4996             if((' '+ci.className+' ').indexOf(v) != -1){
4997                 r[++ri] = ci;
4998             }
4999         }
5000         return r;
5001     };
5002
5003     function attrValue(n, attr){
5004         if(!n.tagName && typeof n.length != "undefined"){
5005             n = n[0];
5006         }
5007         if(!n){
5008             return null;
5009         }
5010         if(attr == "for"){
5011             return n.htmlFor;
5012         }
5013         if(attr == "class" || attr == "className"){
5014             return n.className;
5015         }
5016         return n.getAttribute(attr) || n[attr];
5017
5018     };
5019
5020     function getNodes(ns, mode, tagName){
5021         var result = [], ri = -1, cs;
5022         if(!ns){
5023             return result;
5024         }
5025         tagName = tagName || "*";
5026         if(typeof ns.getElementsByTagName != "undefined"){
5027             ns = [ns];
5028         }
5029         if(!mode){
5030             for(var i = 0, ni; ni = ns[i]; i++){
5031                 cs = ni.getElementsByTagName(tagName);
5032                 for(var j = 0, ci; ci = cs[j]; j++){
5033                     result[++ri] = ci;
5034                 }
5035             }
5036         }else if(mode == "/" || mode == ">"){
5037             var utag = tagName.toUpperCase();
5038             for(var i = 0, ni, cn; ni = ns[i]; i++){
5039                 cn = ni.children || ni.childNodes;
5040                 for(var j = 0, cj; cj = cn[j]; j++){
5041                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5042                         result[++ri] = cj;
5043                     }
5044                 }
5045             }
5046         }else if(mode == "+"){
5047             var utag = tagName.toUpperCase();
5048             for(var i = 0, n; n = ns[i]; i++){
5049                 while((n = n.nextSibling) && n.nodeType != 1);
5050                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5051                     result[++ri] = n;
5052                 }
5053             }
5054         }else if(mode == "~"){
5055             for(var i = 0, n; n = ns[i]; i++){
5056                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5057                 if(n){
5058                     result[++ri] = n;
5059                 }
5060             }
5061         }
5062         return result;
5063     };
5064
5065     function concat(a, b){
5066         if(b.slice){
5067             return a.concat(b);
5068         }
5069         for(var i = 0, l = b.length; i < l; i++){
5070             a[a.length] = b[i];
5071         }
5072         return a;
5073     }
5074
5075     function byTag(cs, tagName){
5076         if(cs.tagName || cs == document){
5077             cs = [cs];
5078         }
5079         if(!tagName){
5080             return cs;
5081         }
5082         var r = [], ri = -1;
5083         tagName = tagName.toLowerCase();
5084         for(var i = 0, ci; ci = cs[i]; i++){
5085             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5086                 r[++ri] = ci;
5087             }
5088         }
5089         return r;
5090     };
5091
5092     function byId(cs, attr, id){
5093         if(cs.tagName || cs == document){
5094             cs = [cs];
5095         }
5096         if(!id){
5097             return cs;
5098         }
5099         var r = [], ri = -1;
5100         for(var i = 0,ci; ci = cs[i]; i++){
5101             if(ci && ci.id == id){
5102                 r[++ri] = ci;
5103                 return r;
5104             }
5105         }
5106         return r;
5107     };
5108
5109     function byAttribute(cs, attr, value, op, custom){
5110         var r = [], ri = -1, st = custom=="{";
5111         var f = Roo.DomQuery.operators[op];
5112         for(var i = 0, ci; ci = cs[i]; i++){
5113             var a;
5114             if(st){
5115                 a = Roo.DomQuery.getStyle(ci, attr);
5116             }
5117             else if(attr == "class" || attr == "className"){
5118                 a = ci.className;
5119             }else if(attr == "for"){
5120                 a = ci.htmlFor;
5121             }else if(attr == "href"){
5122                 a = ci.getAttribute("href", 2);
5123             }else{
5124                 a = ci.getAttribute(attr);
5125             }
5126             if((f && f(a, value)) || (!f && a)){
5127                 r[++ri] = ci;
5128             }
5129         }
5130         return r;
5131     };
5132
5133     function byPseudo(cs, name, value){
5134         return Roo.DomQuery.pseudos[name](cs, value);
5135     };
5136
5137     // This is for IE MSXML which does not support expandos.
5138     // IE runs the same speed using setAttribute, however FF slows way down
5139     // and Safari completely fails so they need to continue to use expandos.
5140     var isIE = window.ActiveXObject ? true : false;
5141
5142     // this eval is stop the compressor from
5143     // renaming the variable to something shorter
5144     
5145     /** eval:var:batch */
5146     var batch = 30803; 
5147
5148     var key = 30803;
5149
5150     function nodupIEXml(cs){
5151         var d = ++key;
5152         cs[0].setAttribute("_nodup", d);
5153         var r = [cs[0]];
5154         for(var i = 1, len = cs.length; i < len; i++){
5155             var c = cs[i];
5156             if(!c.getAttribute("_nodup") != d){
5157                 c.setAttribute("_nodup", d);
5158                 r[r.length] = c;
5159             }
5160         }
5161         for(var i = 0, len = cs.length; i < len; i++){
5162             cs[i].removeAttribute("_nodup");
5163         }
5164         return r;
5165     }
5166
5167     function nodup(cs){
5168         if(!cs){
5169             return [];
5170         }
5171         var len = cs.length, c, i, r = cs, cj, ri = -1;
5172         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5173             return cs;
5174         }
5175         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5176             return nodupIEXml(cs);
5177         }
5178         var d = ++key;
5179         cs[0]._nodup = d;
5180         for(i = 1; c = cs[i]; i++){
5181             if(c._nodup != d){
5182                 c._nodup = d;
5183             }else{
5184                 r = [];
5185                 for(var j = 0; j < i; j++){
5186                     r[++ri] = cs[j];
5187                 }
5188                 for(j = i+1; cj = cs[j]; j++){
5189                     if(cj._nodup != d){
5190                         cj._nodup = d;
5191                         r[++ri] = cj;
5192                     }
5193                 }
5194                 return r;
5195             }
5196         }
5197         return r;
5198     }
5199
5200     function quickDiffIEXml(c1, c2){
5201         var d = ++key;
5202         for(var i = 0, len = c1.length; i < len; i++){
5203             c1[i].setAttribute("_qdiff", d);
5204         }
5205         var r = [];
5206         for(var i = 0, len = c2.length; i < len; i++){
5207             if(c2[i].getAttribute("_qdiff") != d){
5208                 r[r.length] = c2[i];
5209             }
5210         }
5211         for(var i = 0, len = c1.length; i < len; i++){
5212            c1[i].removeAttribute("_qdiff");
5213         }
5214         return r;
5215     }
5216
5217     function quickDiff(c1, c2){
5218         var len1 = c1.length;
5219         if(!len1){
5220             return c2;
5221         }
5222         if(isIE && c1[0].selectSingleNode){
5223             return quickDiffIEXml(c1, c2);
5224         }
5225         var d = ++key;
5226         for(var i = 0; i < len1; i++){
5227             c1[i]._qdiff = d;
5228         }
5229         var r = [];
5230         for(var i = 0, len = c2.length; i < len; i++){
5231             if(c2[i]._qdiff != d){
5232                 r[r.length] = c2[i];
5233             }
5234         }
5235         return r;
5236     }
5237
5238     function quickId(ns, mode, root, id){
5239         if(ns == root){
5240            var d = root.ownerDocument || root;
5241            return d.getElementById(id);
5242         }
5243         ns = getNodes(ns, mode, "*");
5244         return byId(ns, null, id);
5245     }
5246
5247     return {
5248         getStyle : function(el, name){
5249             return Roo.fly(el).getStyle(name);
5250         },
5251         /**
5252          * Compiles a selector/xpath query into a reusable function. The returned function
5253          * takes one parameter "root" (optional), which is the context node from where the query should start.
5254          * @param {String} selector The selector/xpath query
5255          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5256          * @return {Function}
5257          */
5258         compile : function(path, type){
5259             type = type || "select";
5260             
5261             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5262             var q = path, mode, lq;
5263             var tk = Roo.DomQuery.matchers;
5264             var tklen = tk.length;
5265             var mm;
5266
5267             // accept leading mode switch
5268             var lmode = q.match(modeRe);
5269             if(lmode && lmode[1]){
5270                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5271                 q = q.replace(lmode[1], "");
5272             }
5273             // strip leading slashes
5274             while(path.substr(0, 1)=="/"){
5275                 path = path.substr(1);
5276             }
5277
5278             while(q && lq != q){
5279                 lq = q;
5280                 var tm = q.match(tagTokenRe);
5281                 if(type == "select"){
5282                     if(tm){
5283                         if(tm[1] == "#"){
5284                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5285                         }else{
5286                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5287                         }
5288                         q = q.replace(tm[0], "");
5289                     }else if(q.substr(0, 1) != '@'){
5290                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5291                     }
5292                 }else{
5293                     if(tm){
5294                         if(tm[1] == "#"){
5295                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5296                         }else{
5297                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5298                         }
5299                         q = q.replace(tm[0], "");
5300                     }
5301                 }
5302                 while(!(mm = q.match(modeRe))){
5303                     var matched = false;
5304                     for(var j = 0; j < tklen; j++){
5305                         var t = tk[j];
5306                         var m = q.match(t.re);
5307                         if(m){
5308                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5309                                                     return m[i];
5310                                                 });
5311                             q = q.replace(m[0], "");
5312                             matched = true;
5313                             break;
5314                         }
5315                     }
5316                     // prevent infinite loop on bad selector
5317                     if(!matched){
5318                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5319                     }
5320                 }
5321                 if(mm[1]){
5322                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5323                     q = q.replace(mm[1], "");
5324                 }
5325             }
5326             fn[fn.length] = "return nodup(n);\n}";
5327             
5328              /** 
5329               * list of variables that need from compression as they are used by eval.
5330              *  eval:var:batch 
5331              *  eval:var:nodup
5332              *  eval:var:byTag
5333              *  eval:var:ById
5334              *  eval:var:getNodes
5335              *  eval:var:quickId
5336              *  eval:var:mode
5337              *  eval:var:root
5338              *  eval:var:n
5339              *  eval:var:byClassName
5340              *  eval:var:byPseudo
5341              *  eval:var:byAttribute
5342              *  eval:var:attrValue
5343              * 
5344              **/ 
5345             eval(fn.join(""));
5346             return f;
5347         },
5348
5349         /**
5350          * Selects a group of elements.
5351          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5352          * @param {Node} root (optional) The start of the query (defaults to document).
5353          * @return {Array}
5354          */
5355         select : function(path, root, type){
5356             if(!root || root == document){
5357                 root = document;
5358             }
5359             if(typeof root == "string"){
5360                 root = document.getElementById(root);
5361             }
5362             var paths = path.split(",");
5363             var results = [];
5364             for(var i = 0, len = paths.length; i < len; i++){
5365                 var p = paths[i].replace(trimRe, "");
5366                 if(!cache[p]){
5367                     cache[p] = Roo.DomQuery.compile(p);
5368                     if(!cache[p]){
5369                         throw p + " is not a valid selector";
5370                     }
5371                 }
5372                 var result = cache[p](root);
5373                 if(result && result != document){
5374                     results = results.concat(result);
5375                 }
5376             }
5377             if(paths.length > 1){
5378                 return nodup(results);
5379             }
5380             return results;
5381         },
5382
5383         /**
5384          * Selects a single element.
5385          * @param {String} selector The selector/xpath query
5386          * @param {Node} root (optional) The start of the query (defaults to document).
5387          * @return {Element}
5388          */
5389         selectNode : function(path, root){
5390             return Roo.DomQuery.select(path, root)[0];
5391         },
5392
5393         /**
5394          * Selects the value of a node, optionally replacing null with the defaultValue.
5395          * @param {String} selector The selector/xpath query
5396          * @param {Node} root (optional) The start of the query (defaults to document).
5397          * @param {String} defaultValue
5398          */
5399         selectValue : function(path, root, defaultValue){
5400             path = path.replace(trimRe, "");
5401             if(!valueCache[path]){
5402                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5403             }
5404             var n = valueCache[path](root);
5405             n = n[0] ? n[0] : n;
5406             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5407             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5408         },
5409
5410         /**
5411          * Selects the value of a node, parsing integers and floats.
5412          * @param {String} selector The selector/xpath query
5413          * @param {Node} root (optional) The start of the query (defaults to document).
5414          * @param {Number} defaultValue
5415          * @return {Number}
5416          */
5417         selectNumber : function(path, root, defaultValue){
5418             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5419             return parseFloat(v);
5420         },
5421
5422         /**
5423          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5424          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5425          * @param {String} selector The simple selector to test
5426          * @return {Boolean}
5427          */
5428         is : function(el, ss){
5429             if(typeof el == "string"){
5430                 el = document.getElementById(el);
5431             }
5432             var isArray = (el instanceof Array);
5433             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5434             return isArray ? (result.length == el.length) : (result.length > 0);
5435         },
5436
5437         /**
5438          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5439          * @param {Array} el An array of elements to filter
5440          * @param {String} selector The simple selector to test
5441          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5442          * the selector instead of the ones that match
5443          * @return {Array}
5444          */
5445         filter : function(els, ss, nonMatches){
5446             ss = ss.replace(trimRe, "");
5447             if(!simpleCache[ss]){
5448                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5449             }
5450             var result = simpleCache[ss](els);
5451             return nonMatches ? quickDiff(result, els) : result;
5452         },
5453
5454         /**
5455          * Collection of matching regular expressions and code snippets.
5456          */
5457         matchers : [{
5458                 re: /^\.([\w-]+)/,
5459                 select: 'n = byClassName(n, null, " {1} ");'
5460             }, {
5461                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5462                 select: 'n = byPseudo(n, "{1}", "{2}");'
5463             },{
5464                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5465                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5466             }, {
5467                 re: /^#([\w-]+)/,
5468                 select: 'n = byId(n, null, "{1}");'
5469             },{
5470                 re: /^@([\w-]+)/,
5471                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5472             }
5473         ],
5474
5475         /**
5476          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5477          * 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;.
5478          */
5479         operators : {
5480             "=" : function(a, v){
5481                 return a == v;
5482             },
5483             "!=" : function(a, v){
5484                 return a != v;
5485             },
5486             "^=" : function(a, v){
5487                 return a && a.substr(0, v.length) == v;
5488             },
5489             "$=" : function(a, v){
5490                 return a && a.substr(a.length-v.length) == v;
5491             },
5492             "*=" : function(a, v){
5493                 return a && a.indexOf(v) !== -1;
5494             },
5495             "%=" : function(a, v){
5496                 return (a % v) == 0;
5497             },
5498             "|=" : function(a, v){
5499                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5500             },
5501             "~=" : function(a, v){
5502                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5503             }
5504         },
5505
5506         /**
5507          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5508          * and the argument (if any) supplied in the selector.
5509          */
5510         pseudos : {
5511             "first-child" : function(c){
5512                 var r = [], ri = -1, n;
5513                 for(var i = 0, ci; ci = n = c[i]; i++){
5514                     while((n = n.previousSibling) && n.nodeType != 1);
5515                     if(!n){
5516                         r[++ri] = ci;
5517                     }
5518                 }
5519                 return r;
5520             },
5521
5522             "last-child" : function(c){
5523                 var r = [], ri = -1, n;
5524                 for(var i = 0, ci; ci = n = c[i]; i++){
5525                     while((n = n.nextSibling) && n.nodeType != 1);
5526                     if(!n){
5527                         r[++ri] = ci;
5528                     }
5529                 }
5530                 return r;
5531             },
5532
5533             "nth-child" : function(c, a) {
5534                 var r = [], ri = -1;
5535                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5536                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5537                 for(var i = 0, n; n = c[i]; i++){
5538                     var pn = n.parentNode;
5539                     if (batch != pn._batch) {
5540                         var j = 0;
5541                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5542                             if(cn.nodeType == 1){
5543                                cn.nodeIndex = ++j;
5544                             }
5545                         }
5546                         pn._batch = batch;
5547                     }
5548                     if (f == 1) {
5549                         if (l == 0 || n.nodeIndex == l){
5550                             r[++ri] = n;
5551                         }
5552                     } else if ((n.nodeIndex + l) % f == 0){
5553                         r[++ri] = n;
5554                     }
5555                 }
5556
5557                 return r;
5558             },
5559
5560             "only-child" : function(c){
5561                 var r = [], ri = -1;;
5562                 for(var i = 0, ci; ci = c[i]; i++){
5563                     if(!prev(ci) && !next(ci)){
5564                         r[++ri] = ci;
5565                     }
5566                 }
5567                 return r;
5568             },
5569
5570             "empty" : function(c){
5571                 var r = [], ri = -1;
5572                 for(var i = 0, ci; ci = c[i]; i++){
5573                     var cns = ci.childNodes, j = 0, cn, empty = true;
5574                     while(cn = cns[j]){
5575                         ++j;
5576                         if(cn.nodeType == 1 || cn.nodeType == 3){
5577                             empty = false;
5578                             break;
5579                         }
5580                     }
5581                     if(empty){
5582                         r[++ri] = ci;
5583                     }
5584                 }
5585                 return r;
5586             },
5587
5588             "contains" : function(c, v){
5589                 var r = [], ri = -1;
5590                 for(var i = 0, ci; ci = c[i]; i++){
5591                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5592                         r[++ri] = ci;
5593                     }
5594                 }
5595                 return r;
5596             },
5597
5598             "nodeValue" : function(c, v){
5599                 var r = [], ri = -1;
5600                 for(var i = 0, ci; ci = c[i]; i++){
5601                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5602                         r[++ri] = ci;
5603                     }
5604                 }
5605                 return r;
5606             },
5607
5608             "checked" : function(c){
5609                 var r = [], ri = -1;
5610                 for(var i = 0, ci; ci = c[i]; i++){
5611                     if(ci.checked == true){
5612                         r[++ri] = ci;
5613                     }
5614                 }
5615                 return r;
5616             },
5617
5618             "not" : function(c, ss){
5619                 return Roo.DomQuery.filter(c, ss, true);
5620             },
5621
5622             "odd" : function(c){
5623                 return this["nth-child"](c, "odd");
5624             },
5625
5626             "even" : function(c){
5627                 return this["nth-child"](c, "even");
5628             },
5629
5630             "nth" : function(c, a){
5631                 return c[a-1] || [];
5632             },
5633
5634             "first" : function(c){
5635                 return c[0] || [];
5636             },
5637
5638             "last" : function(c){
5639                 return c[c.length-1] || [];
5640             },
5641
5642             "has" : function(c, ss){
5643                 var s = Roo.DomQuery.select;
5644                 var r = [], ri = -1;
5645                 for(var i = 0, ci; ci = c[i]; i++){
5646                     if(s(ss, ci).length > 0){
5647                         r[++ri] = ci;
5648                     }
5649                 }
5650                 return r;
5651             },
5652
5653             "next" : function(c, ss){
5654                 var is = Roo.DomQuery.is;
5655                 var r = [], ri = -1;
5656                 for(var i = 0, ci; ci = c[i]; i++){
5657                     var n = next(ci);
5658                     if(n && is(n, ss)){
5659                         r[++ri] = ci;
5660                     }
5661                 }
5662                 return r;
5663             },
5664
5665             "prev" : function(c, ss){
5666                 var is = Roo.DomQuery.is;
5667                 var r = [], ri = -1;
5668                 for(var i = 0, ci; ci = c[i]; i++){
5669                     var n = prev(ci);
5670                     if(n && is(n, ss)){
5671                         r[++ri] = ci;
5672                     }
5673                 }
5674                 return r;
5675             }
5676         }
5677     };
5678 }();
5679
5680 /**
5681  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5682  * @param {String} path The selector/xpath query
5683  * @param {Node} root (optional) The start of the query (defaults to document).
5684  * @return {Array}
5685  * @member Roo
5686  * @method query
5687  */
5688 Roo.query = Roo.DomQuery.select;
5689 /*
5690  * Based on:
5691  * Ext JS Library 1.1.1
5692  * Copyright(c) 2006-2007, Ext JS, LLC.
5693  *
5694  * Originally Released Under LGPL - original licence link has changed is not relivant.
5695  *
5696  * Fork - LGPL
5697  * <script type="text/javascript">
5698  */
5699
5700 /**
5701  * @class Roo.util.Observable
5702  * Base class that provides a common interface for publishing events. Subclasses are expected to
5703  * to have a property "events" with all the events defined.<br>
5704  * For example:
5705  * <pre><code>
5706  Employee = function(name){
5707     this.name = name;
5708     this.addEvents({
5709         "fired" : true,
5710         "quit" : true
5711     });
5712  }
5713  Roo.extend(Employee, Roo.util.Observable);
5714 </code></pre>
5715  * @param {Object} config properties to use (incuding events / listeners)
5716  */
5717
5718 Roo.util.Observable = function(cfg){
5719     
5720     cfg = cfg|| {};
5721     this.addEvents(cfg.events || {});
5722     if (cfg.events) {
5723         delete cfg.events; // make sure
5724     }
5725      
5726     Roo.apply(this, cfg);
5727     
5728     if(this.listeners){
5729         this.on(this.listeners);
5730         delete this.listeners;
5731     }
5732 };
5733 Roo.util.Observable.prototype = {
5734     /** 
5735  * @cfg {Object} listeners  list of events and functions to call for this object, 
5736  * For example :
5737  * <pre><code>
5738     listeners :  { 
5739        'click' : function(e) {
5740            ..... 
5741         } ,
5742         .... 
5743     } 
5744   </code></pre>
5745  */
5746     
5747     
5748     /**
5749      * Fires the specified event with the passed parameters (minus the event name).
5750      * @param {String} eventName
5751      * @param {Object...} args Variable number of parameters are passed to handlers
5752      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5753      */
5754     fireEvent : function(){
5755         var ce = this.events[arguments[0].toLowerCase()];
5756         if(typeof ce == "object"){
5757             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5758         }else{
5759             return true;
5760         }
5761     },
5762
5763     // private
5764     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5765
5766     /**
5767      * Appends an event handler to this component
5768      * @param {String}   eventName The type of event to listen for
5769      * @param {Function} handler The method the event invokes
5770      * @param {Object}   scope (optional) The scope in which to execute the handler
5771      * function. The handler function's "this" context.
5772      * @param {Object}   options (optional) An object containing handler configuration
5773      * properties. This may contain any of the following properties:<ul>
5774      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5775      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5776      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5777      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5778      * by the specified number of milliseconds. If the event fires again within that time, the original
5779      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5780      * </ul><br>
5781      * <p>
5782      * <b>Combining Options</b><br>
5783      * Using the options argument, it is possible to combine different types of listeners:<br>
5784      * <br>
5785      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5786                 <pre><code>
5787                 el.on('click', this.onClick, this, {
5788                         single: true,
5789                 delay: 100,
5790                 forumId: 4
5791                 });
5792                 </code></pre>
5793      * <p>
5794      * <b>Attaching multiple handlers in 1 call</b><br>
5795      * The method also allows for a single argument to be passed which is a config object containing properties
5796      * which specify multiple handlers.
5797      * <pre><code>
5798                 el.on({
5799                         'click': {
5800                         fn: this.onClick,
5801                         scope: this,
5802                         delay: 100
5803                 }, 
5804                 'mouseover': {
5805                         fn: this.onMouseOver,
5806                         scope: this
5807                 },
5808                 'mouseout': {
5809                         fn: this.onMouseOut,
5810                         scope: this
5811                 }
5812                 });
5813                 </code></pre>
5814      * <p>
5815      * Or a shorthand syntax which passes the same scope object to all handlers:
5816         <pre><code>
5817                 el.on({
5818                         'click': this.onClick,
5819                 'mouseover': this.onMouseOver,
5820                 'mouseout': this.onMouseOut,
5821                 scope: this
5822                 });
5823                 </code></pre>
5824      */
5825     addListener : function(eventName, fn, scope, o){
5826         if(typeof eventName == "object"){
5827             o = eventName;
5828             for(var e in o){
5829                 if(this.filterOptRe.test(e)){
5830                     continue;
5831                 }
5832                 if(typeof o[e] == "function"){
5833                     // shared options
5834                     this.addListener(e, o[e], o.scope,  o);
5835                 }else{
5836                     // individual options
5837                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5838                 }
5839             }
5840             return;
5841         }
5842         o = (!o || typeof o == "boolean") ? {} : o;
5843         eventName = eventName.toLowerCase();
5844         var ce = this.events[eventName] || true;
5845         if(typeof ce == "boolean"){
5846             ce = new Roo.util.Event(this, eventName);
5847             this.events[eventName] = ce;
5848         }
5849         ce.addListener(fn, scope, o);
5850     },
5851
5852     /**
5853      * Removes a listener
5854      * @param {String}   eventName     The type of event to listen for
5855      * @param {Function} handler        The handler to remove
5856      * @param {Object}   scope  (optional) The scope (this object) for the handler
5857      */
5858     removeListener : function(eventName, fn, scope){
5859         var ce = this.events[eventName.toLowerCase()];
5860         if(typeof ce == "object"){
5861             ce.removeListener(fn, scope);
5862         }
5863     },
5864
5865     /**
5866      * Removes all listeners for this object
5867      */
5868     purgeListeners : function(){
5869         for(var evt in this.events){
5870             if(typeof this.events[evt] == "object"){
5871                  this.events[evt].clearListeners();
5872             }
5873         }
5874     },
5875
5876     relayEvents : function(o, events){
5877         var createHandler = function(ename){
5878             return function(){
5879                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5880             };
5881         };
5882         for(var i = 0, len = events.length; i < len; i++){
5883             var ename = events[i];
5884             if(!this.events[ename]){ this.events[ename] = true; };
5885             o.on(ename, createHandler(ename), this);
5886         }
5887     },
5888
5889     /**
5890      * Used to define events on this Observable
5891      * @param {Object} object The object with the events defined
5892      */
5893     addEvents : function(o){
5894         if(!this.events){
5895             this.events = {};
5896         }
5897         Roo.applyIf(this.events, o);
5898     },
5899
5900     /**
5901      * Checks to see if this object has any listeners for a specified event
5902      * @param {String} eventName The name of the event to check for
5903      * @return {Boolean} True if the event is being listened for, else false
5904      */
5905     hasListener : function(eventName){
5906         var e = this.events[eventName];
5907         return typeof e == "object" && e.listeners.length > 0;
5908     }
5909 };
5910 /**
5911  * Appends an event handler to this element (shorthand for addListener)
5912  * @param {String}   eventName     The type of event to listen for
5913  * @param {Function} handler        The method the event invokes
5914  * @param {Object}   scope (optional) The scope in which to execute the handler
5915  * function. The handler function's "this" context.
5916  * @param {Object}   options  (optional)
5917  * @method
5918  */
5919 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5920 /**
5921  * Removes a listener (shorthand for removeListener)
5922  * @param {String}   eventName     The type of event to listen for
5923  * @param {Function} handler        The handler to remove
5924  * @param {Object}   scope  (optional) The scope (this object) for the handler
5925  * @method
5926  */
5927 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5928
5929 /**
5930  * Starts capture on the specified Observable. All events will be passed
5931  * to the supplied function with the event name + standard signature of the event
5932  * <b>before</b> the event is fired. If the supplied function returns false,
5933  * the event will not fire.
5934  * @param {Observable} o The Observable to capture
5935  * @param {Function} fn The function to call
5936  * @param {Object} scope (optional) The scope (this object) for the fn
5937  * @static
5938  */
5939 Roo.util.Observable.capture = function(o, fn, scope){
5940     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5941 };
5942
5943 /**
5944  * Removes <b>all</b> added captures from the Observable.
5945  * @param {Observable} o The Observable to release
5946  * @static
5947  */
5948 Roo.util.Observable.releaseCapture = function(o){
5949     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5950 };
5951
5952 (function(){
5953
5954     var createBuffered = function(h, o, scope){
5955         var task = new Roo.util.DelayedTask();
5956         return function(){
5957             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5958         };
5959     };
5960
5961     var createSingle = function(h, e, fn, scope){
5962         return function(){
5963             e.removeListener(fn, scope);
5964             return h.apply(scope, arguments);
5965         };
5966     };
5967
5968     var createDelayed = function(h, o, scope){
5969         return function(){
5970             var args = Array.prototype.slice.call(arguments, 0);
5971             setTimeout(function(){
5972                 h.apply(scope, args);
5973             }, o.delay || 10);
5974         };
5975     };
5976
5977     Roo.util.Event = function(obj, name){
5978         this.name = name;
5979         this.obj = obj;
5980         this.listeners = [];
5981     };
5982
5983     Roo.util.Event.prototype = {
5984         addListener : function(fn, scope, options){
5985             var o = options || {};
5986             scope = scope || this.obj;
5987             if(!this.isListening(fn, scope)){
5988                 var l = {fn: fn, scope: scope, options: o};
5989                 var h = fn;
5990                 if(o.delay){
5991                     h = createDelayed(h, o, scope);
5992                 }
5993                 if(o.single){
5994                     h = createSingle(h, this, fn, scope);
5995                 }
5996                 if(o.buffer){
5997                     h = createBuffered(h, o, scope);
5998                 }
5999                 l.fireFn = h;
6000                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6001                     this.listeners.push(l);
6002                 }else{
6003                     this.listeners = this.listeners.slice(0);
6004                     this.listeners.push(l);
6005                 }
6006             }
6007         },
6008
6009         findListener : function(fn, scope){
6010             scope = scope || this.obj;
6011             var ls = this.listeners;
6012             for(var i = 0, len = ls.length; i < len; i++){
6013                 var l = ls[i];
6014                 if(l.fn == fn && l.scope == scope){
6015                     return i;
6016                 }
6017             }
6018             return -1;
6019         },
6020
6021         isListening : function(fn, scope){
6022             return this.findListener(fn, scope) != -1;
6023         },
6024
6025         removeListener : function(fn, scope){
6026             var index;
6027             if((index = this.findListener(fn, scope)) != -1){
6028                 if(!this.firing){
6029                     this.listeners.splice(index, 1);
6030                 }else{
6031                     this.listeners = this.listeners.slice(0);
6032                     this.listeners.splice(index, 1);
6033                 }
6034                 return true;
6035             }
6036             return false;
6037         },
6038
6039         clearListeners : function(){
6040             this.listeners = [];
6041         },
6042
6043         fire : function(){
6044             var ls = this.listeners, scope, len = ls.length;
6045             if(len > 0){
6046                 this.firing = true;
6047                 var args = Array.prototype.slice.call(arguments, 0);
6048                 for(var i = 0; i < len; i++){
6049                     var l = ls[i];
6050                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6051                         this.firing = false;
6052                         return false;
6053                     }
6054                 }
6055                 this.firing = false;
6056             }
6057             return true;
6058         }
6059     };
6060 })();/*
6061  * RooJS Library 
6062  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6063  *
6064  * Licence LGPL 
6065  *
6066  */
6067  
6068 /**
6069  * @class Roo.Document
6070  * @extends Roo.util.Observable
6071  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6072  * 
6073  * @param {Object} config the methods and properties of the 'base' class for the application.
6074  * 
6075  *  Generic Page handler - implement this to start your app..
6076  * 
6077  * eg.
6078  *  MyProject = new Roo.Document({
6079         events : {
6080             'load' : true // your events..
6081         },
6082         listeners : {
6083             'ready' : function() {
6084                 // fired on Roo.onReady()
6085             }
6086         }
6087  * 
6088  */
6089 Roo.Document = function(cfg) {
6090      
6091     this.addEvents({ 
6092         'ready' : true
6093     });
6094     Roo.util.Observable.call(this,cfg);
6095     
6096     var _this = this;
6097     
6098     Roo.onReady(function() {
6099         _this.fireEvent('ready');
6100     },null,false);
6101     
6102     
6103 }
6104
6105 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6106  * Based on:
6107  * Ext JS Library 1.1.1
6108  * Copyright(c) 2006-2007, Ext JS, LLC.
6109  *
6110  * Originally Released Under LGPL - original licence link has changed is not relivant.
6111  *
6112  * Fork - LGPL
6113  * <script type="text/javascript">
6114  */
6115
6116 /**
6117  * @class Roo.EventManager
6118  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6119  * several useful events directly.
6120  * See {@link Roo.EventObject} for more details on normalized event objects.
6121  * @singleton
6122  */
6123 Roo.EventManager = function(){
6124     var docReadyEvent, docReadyProcId, docReadyState = false;
6125     var resizeEvent, resizeTask, textEvent, textSize;
6126     var E = Roo.lib.Event;
6127     var D = Roo.lib.Dom;
6128
6129     
6130     
6131
6132     var fireDocReady = function(){
6133         if(!docReadyState){
6134             docReadyState = true;
6135             Roo.isReady = true;
6136             if(docReadyProcId){
6137                 clearInterval(docReadyProcId);
6138             }
6139             if(Roo.isGecko || Roo.isOpera) {
6140                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6141             }
6142             if(Roo.isIE){
6143                 var defer = document.getElementById("ie-deferred-loader");
6144                 if(defer){
6145                     defer.onreadystatechange = null;
6146                     defer.parentNode.removeChild(defer);
6147                 }
6148             }
6149             if(docReadyEvent){
6150                 docReadyEvent.fire();
6151                 docReadyEvent.clearListeners();
6152             }
6153         }
6154     };
6155     
6156     var initDocReady = function(){
6157         docReadyEvent = new Roo.util.Event();
6158         if(Roo.isGecko || Roo.isOpera) {
6159             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6160         }else if(Roo.isIE){
6161             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6162             var defer = document.getElementById("ie-deferred-loader");
6163             defer.onreadystatechange = function(){
6164                 if(this.readyState == "complete"){
6165                     fireDocReady();
6166                 }
6167             };
6168         }else if(Roo.isSafari){ 
6169             docReadyProcId = setInterval(function(){
6170                 var rs = document.readyState;
6171                 if(rs == "complete") {
6172                     fireDocReady();     
6173                  }
6174             }, 10);
6175         }
6176         // no matter what, make sure it fires on load
6177         E.on(window, "load", fireDocReady);
6178     };
6179
6180     var createBuffered = function(h, o){
6181         var task = new Roo.util.DelayedTask(h);
6182         return function(e){
6183             // create new event object impl so new events don't wipe out properties
6184             e = new Roo.EventObjectImpl(e);
6185             task.delay(o.buffer, h, null, [e]);
6186         };
6187     };
6188
6189     var createSingle = function(h, el, ename, fn){
6190         return function(e){
6191             Roo.EventManager.removeListener(el, ename, fn);
6192             h(e);
6193         };
6194     };
6195
6196     var createDelayed = function(h, o){
6197         return function(e){
6198             // create new event object impl so new events don't wipe out properties
6199             e = new Roo.EventObjectImpl(e);
6200             setTimeout(function(){
6201                 h(e);
6202             }, o.delay || 10);
6203         };
6204     };
6205     var transitionEndVal = false;
6206     
6207     var transitionEnd = function()
6208     {
6209         if (transitionEndVal) {
6210             return transitionEndVal;
6211         }
6212         var el = document.createElement('div');
6213
6214         var transEndEventNames = {
6215             WebkitTransition : 'webkitTransitionEnd',
6216             MozTransition    : 'transitionend',
6217             OTransition      : 'oTransitionEnd otransitionend',
6218             transition       : 'transitionend'
6219         };
6220     
6221         for (var name in transEndEventNames) {
6222             if (el.style[name] !== undefined) {
6223                 transitionEndVal = transEndEventNames[name];
6224                 return  transitionEndVal ;
6225             }
6226         }
6227     }
6228     
6229
6230     var listen = function(element, ename, opt, fn, scope){
6231         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6232         fn = fn || o.fn; scope = scope || o.scope;
6233         var el = Roo.getDom(element);
6234         
6235         
6236         if(!el){
6237             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6238         }
6239         
6240         if (ename == 'transitionend') {
6241             ename = transitionEnd();
6242         }
6243         var h = function(e){
6244             e = Roo.EventObject.setEvent(e);
6245             var t;
6246             if(o.delegate){
6247                 t = e.getTarget(o.delegate, el);
6248                 if(!t){
6249                     return;
6250                 }
6251             }else{
6252                 t = e.target;
6253             }
6254             if(o.stopEvent === true){
6255                 e.stopEvent();
6256             }
6257             if(o.preventDefault === true){
6258                e.preventDefault();
6259             }
6260             if(o.stopPropagation === true){
6261                 e.stopPropagation();
6262             }
6263
6264             if(o.normalized === false){
6265                 e = e.browserEvent;
6266             }
6267
6268             fn.call(scope || el, e, t, o);
6269         };
6270         if(o.delay){
6271             h = createDelayed(h, o);
6272         }
6273         if(o.single){
6274             h = createSingle(h, el, ename, fn);
6275         }
6276         if(o.buffer){
6277             h = createBuffered(h, o);
6278         }
6279         fn._handlers = fn._handlers || [];
6280         
6281         
6282         fn._handlers.push([Roo.id(el), ename, h]);
6283         
6284         
6285          
6286         E.on(el, ename, h);
6287         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6288             el.addEventListener("DOMMouseScroll", h, false);
6289             E.on(window, 'unload', function(){
6290                 el.removeEventListener("DOMMouseScroll", h, false);
6291             });
6292         }
6293         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6294             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6295         }
6296         return h;
6297     };
6298
6299     var stopListening = function(el, ename, fn){
6300         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6301         if(hds){
6302             for(var i = 0, len = hds.length; i < len; i++){
6303                 var h = hds[i];
6304                 if(h[0] == id && h[1] == ename){
6305                     hd = h[2];
6306                     hds.splice(i, 1);
6307                     break;
6308                 }
6309             }
6310         }
6311         E.un(el, ename, hd);
6312         el = Roo.getDom(el);
6313         if(ename == "mousewheel" && el.addEventListener){
6314             el.removeEventListener("DOMMouseScroll", hd, false);
6315         }
6316         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6317             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6318         }
6319     };
6320
6321     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6322     
6323     var pub = {
6324         
6325         
6326         /** 
6327          * Fix for doc tools
6328          * @scope Roo.EventManager
6329          */
6330         
6331         
6332         /** 
6333          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6334          * object with a Roo.EventObject
6335          * @param {Function} fn        The method the event invokes
6336          * @param {Object}   scope    An object that becomes the scope of the handler
6337          * @param {boolean}  override If true, the obj passed in becomes
6338          *                             the execution scope of the listener
6339          * @return {Function} The wrapped function
6340          * @deprecated
6341          */
6342         wrap : function(fn, scope, override){
6343             return function(e){
6344                 Roo.EventObject.setEvent(e);
6345                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6346             };
6347         },
6348         
6349         /**
6350      * Appends an event handler to an element (shorthand for addListener)
6351      * @param {String/HTMLElement}   element        The html element or id to assign the
6352      * @param {String}   eventName The type of event to listen for
6353      * @param {Function} handler The method the event invokes
6354      * @param {Object}   scope (optional) The scope in which to execute the handler
6355      * function. The handler function's "this" context.
6356      * @param {Object}   options (optional) An object containing handler configuration
6357      * properties. This may contain any of the following properties:<ul>
6358      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6359      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6360      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6361      * <li>preventDefault {Boolean} True to prevent the default action</li>
6362      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6363      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6364      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6365      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6366      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6367      * by the specified number of milliseconds. If the event fires again within that time, the original
6368      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6369      * </ul><br>
6370      * <p>
6371      * <b>Combining Options</b><br>
6372      * Using the options argument, it is possible to combine different types of listeners:<br>
6373      * <br>
6374      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6375      * Code:<pre><code>
6376 el.on('click', this.onClick, this, {
6377     single: true,
6378     delay: 100,
6379     stopEvent : true,
6380     forumId: 4
6381 });</code></pre>
6382      * <p>
6383      * <b>Attaching multiple handlers in 1 call</b><br>
6384       * The method also allows for a single argument to be passed which is a config object containing properties
6385      * which specify multiple handlers.
6386      * <p>
6387      * Code:<pre><code>
6388 el.on({
6389     'click' : {
6390         fn: this.onClick
6391         scope: this,
6392         delay: 100
6393     },
6394     'mouseover' : {
6395         fn: this.onMouseOver
6396         scope: this
6397     },
6398     'mouseout' : {
6399         fn: this.onMouseOut
6400         scope: this
6401     }
6402 });</code></pre>
6403      * <p>
6404      * Or a shorthand syntax:<br>
6405      * Code:<pre><code>
6406 el.on({
6407     'click' : this.onClick,
6408     'mouseover' : this.onMouseOver,
6409     'mouseout' : this.onMouseOut
6410     scope: this
6411 });</code></pre>
6412      */
6413         addListener : function(element, eventName, fn, scope, options){
6414             if(typeof eventName == "object"){
6415                 var o = eventName;
6416                 for(var e in o){
6417                     if(propRe.test(e)){
6418                         continue;
6419                     }
6420                     if(typeof o[e] == "function"){
6421                         // shared options
6422                         listen(element, e, o, o[e], o.scope);
6423                     }else{
6424                         // individual options
6425                         listen(element, e, o[e]);
6426                     }
6427                 }
6428                 return;
6429             }
6430             return listen(element, eventName, options, fn, scope);
6431         },
6432         
6433         /**
6434          * Removes an event handler
6435          *
6436          * @param {String/HTMLElement}   element        The id or html element to remove the 
6437          *                             event from
6438          * @param {String}   eventName     The type of event
6439          * @param {Function} fn
6440          * @return {Boolean} True if a listener was actually removed
6441          */
6442         removeListener : function(element, eventName, fn){
6443             return stopListening(element, eventName, fn);
6444         },
6445         
6446         /**
6447          * Fires when the document is ready (before onload and before images are loaded). Can be 
6448          * accessed shorthanded Roo.onReady().
6449          * @param {Function} fn        The method the event invokes
6450          * @param {Object}   scope    An  object that becomes the scope of the handler
6451          * @param {boolean}  options
6452          */
6453         onDocumentReady : function(fn, scope, options){
6454             if(docReadyState){ // if it already fired
6455                 docReadyEvent.addListener(fn, scope, options);
6456                 docReadyEvent.fire();
6457                 docReadyEvent.clearListeners();
6458                 return;
6459             }
6460             if(!docReadyEvent){
6461                 initDocReady();
6462             }
6463             docReadyEvent.addListener(fn, scope, options);
6464         },
6465         
6466         /**
6467          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6468          * @param {Function} fn        The method the event invokes
6469          * @param {Object}   scope    An object that becomes the scope of the handler
6470          * @param {boolean}  options
6471          */
6472         onWindowResize : function(fn, scope, options){
6473             if(!resizeEvent){
6474                 resizeEvent = new Roo.util.Event();
6475                 resizeTask = new Roo.util.DelayedTask(function(){
6476                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6477                 });
6478                 E.on(window, "resize", function(){
6479                     if(Roo.isIE){
6480                         resizeTask.delay(50);
6481                     }else{
6482                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6483                     }
6484                 });
6485             }
6486             resizeEvent.addListener(fn, scope, options);
6487         },
6488
6489         /**
6490          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6491          * @param {Function} fn        The method the event invokes
6492          * @param {Object}   scope    An object that becomes the scope of the handler
6493          * @param {boolean}  options
6494          */
6495         onTextResize : function(fn, scope, options){
6496             if(!textEvent){
6497                 textEvent = new Roo.util.Event();
6498                 var textEl = new Roo.Element(document.createElement('div'));
6499                 textEl.dom.className = 'x-text-resize';
6500                 textEl.dom.innerHTML = 'X';
6501                 textEl.appendTo(document.body);
6502                 textSize = textEl.dom.offsetHeight;
6503                 setInterval(function(){
6504                     if(textEl.dom.offsetHeight != textSize){
6505                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6506                     }
6507                 }, this.textResizeInterval);
6508             }
6509             textEvent.addListener(fn, scope, options);
6510         },
6511
6512         /**
6513          * Removes the passed window resize listener.
6514          * @param {Function} fn        The method the event invokes
6515          * @param {Object}   scope    The scope of handler
6516          */
6517         removeResizeListener : function(fn, scope){
6518             if(resizeEvent){
6519                 resizeEvent.removeListener(fn, scope);
6520             }
6521         },
6522
6523         // private
6524         fireResize : function(){
6525             if(resizeEvent){
6526                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6527             }   
6528         },
6529         /**
6530          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6531          */
6532         ieDeferSrc : false,
6533         /**
6534          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6535          */
6536         textResizeInterval : 50
6537     };
6538     
6539     /**
6540      * Fix for doc tools
6541      * @scopeAlias pub=Roo.EventManager
6542      */
6543     
6544      /**
6545      * Appends an event handler to an element (shorthand for addListener)
6546      * @param {String/HTMLElement}   element        The html element or id to assign the
6547      * @param {String}   eventName The type of event to listen for
6548      * @param {Function} handler The method the event invokes
6549      * @param {Object}   scope (optional) The scope in which to execute the handler
6550      * function. The handler function's "this" context.
6551      * @param {Object}   options (optional) An object containing handler configuration
6552      * properties. This may contain any of the following properties:<ul>
6553      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6554      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6555      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6556      * <li>preventDefault {Boolean} True to prevent the default action</li>
6557      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6558      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6559      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6560      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6561      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6562      * by the specified number of milliseconds. If the event fires again within that time, the original
6563      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6564      * </ul><br>
6565      * <p>
6566      * <b>Combining Options</b><br>
6567      * Using the options argument, it is possible to combine different types of listeners:<br>
6568      * <br>
6569      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6570      * Code:<pre><code>
6571 el.on('click', this.onClick, this, {
6572     single: true,
6573     delay: 100,
6574     stopEvent : true,
6575     forumId: 4
6576 });</code></pre>
6577      * <p>
6578      * <b>Attaching multiple handlers in 1 call</b><br>
6579       * The method also allows for a single argument to be passed which is a config object containing properties
6580      * which specify multiple handlers.
6581      * <p>
6582      * Code:<pre><code>
6583 el.on({
6584     'click' : {
6585         fn: this.onClick
6586         scope: this,
6587         delay: 100
6588     },
6589     'mouseover' : {
6590         fn: this.onMouseOver
6591         scope: this
6592     },
6593     'mouseout' : {
6594         fn: this.onMouseOut
6595         scope: this
6596     }
6597 });</code></pre>
6598      * <p>
6599      * Or a shorthand syntax:<br>
6600      * Code:<pre><code>
6601 el.on({
6602     'click' : this.onClick,
6603     'mouseover' : this.onMouseOver,
6604     'mouseout' : this.onMouseOut
6605     scope: this
6606 });</code></pre>
6607      */
6608     pub.on = pub.addListener;
6609     pub.un = pub.removeListener;
6610
6611     pub.stoppedMouseDownEvent = new Roo.util.Event();
6612     return pub;
6613 }();
6614 /**
6615   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6616   * @param {Function} fn        The method the event invokes
6617   * @param {Object}   scope    An  object that becomes the scope of the handler
6618   * @param {boolean}  override If true, the obj passed in becomes
6619   *                             the execution scope of the listener
6620   * @member Roo
6621   * @method onReady
6622  */
6623 Roo.onReady = Roo.EventManager.onDocumentReady;
6624
6625 Roo.onReady(function(){
6626     var bd = Roo.get(document.body);
6627     if(!bd){ return; }
6628
6629     var cls = [
6630             Roo.isIE ? "roo-ie"
6631             : Roo.isGecko ? "roo-gecko"
6632             : Roo.isOpera ? "roo-opera"
6633             : Roo.isSafari ? "roo-safari" : ""];
6634
6635     if(Roo.isMac){
6636         cls.push("roo-mac");
6637     }
6638     if(Roo.isLinux){
6639         cls.push("roo-linux");
6640     }
6641     if(Roo.isIOS){
6642         cls.push("roo-ios");
6643     }
6644     if(Roo.isTouch){
6645         cls.push("roo-touch");
6646     }
6647     if(Roo.isBorderBox){
6648         cls.push('roo-border-box');
6649     }
6650     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6651         var p = bd.dom.parentNode;
6652         if(p){
6653             p.className += ' roo-strict';
6654         }
6655     }
6656     bd.addClass(cls.join(' '));
6657 });
6658
6659 /**
6660  * @class Roo.EventObject
6661  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6662  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6663  * Example:
6664  * <pre><code>
6665  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6666     e.preventDefault();
6667     var target = e.getTarget();
6668     ...
6669  }
6670  var myDiv = Roo.get("myDiv");
6671  myDiv.on("click", handleClick);
6672  //or
6673  Roo.EventManager.on("myDiv", 'click', handleClick);
6674  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6675  </code></pre>
6676  * @singleton
6677  */
6678 Roo.EventObject = function(){
6679     
6680     var E = Roo.lib.Event;
6681     
6682     // safari keypress events for special keys return bad keycodes
6683     var safariKeys = {
6684         63234 : 37, // left
6685         63235 : 39, // right
6686         63232 : 38, // up
6687         63233 : 40, // down
6688         63276 : 33, // page up
6689         63277 : 34, // page down
6690         63272 : 46, // delete
6691         63273 : 36, // home
6692         63275 : 35  // end
6693     };
6694
6695     // normalize button clicks
6696     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6697                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6698
6699     Roo.EventObjectImpl = function(e){
6700         if(e){
6701             this.setEvent(e.browserEvent || e);
6702         }
6703     };
6704     Roo.EventObjectImpl.prototype = {
6705         /**
6706          * Used to fix doc tools.
6707          * @scope Roo.EventObject.prototype
6708          */
6709             
6710
6711         
6712         
6713         /** The normal browser event */
6714         browserEvent : null,
6715         /** The button pressed in a mouse event */
6716         button : -1,
6717         /** True if the shift key was down during the event */
6718         shiftKey : false,
6719         /** True if the control key was down during the event */
6720         ctrlKey : false,
6721         /** True if the alt key was down during the event */
6722         altKey : false,
6723
6724         /** Key constant 
6725         * @type Number */
6726         BACKSPACE : 8,
6727         /** Key constant 
6728         * @type Number */
6729         TAB : 9,
6730         /** Key constant 
6731         * @type Number */
6732         RETURN : 13,
6733         /** Key constant 
6734         * @type Number */
6735         ENTER : 13,
6736         /** Key constant 
6737         * @type Number */
6738         SHIFT : 16,
6739         /** Key constant 
6740         * @type Number */
6741         CONTROL : 17,
6742         /** Key constant 
6743         * @type Number */
6744         ESC : 27,
6745         /** Key constant 
6746         * @type Number */
6747         SPACE : 32,
6748         /** Key constant 
6749         * @type Number */
6750         PAGEUP : 33,
6751         /** Key constant 
6752         * @type Number */
6753         PAGEDOWN : 34,
6754         /** Key constant 
6755         * @type Number */
6756         END : 35,
6757         /** Key constant 
6758         * @type Number */
6759         HOME : 36,
6760         /** Key constant 
6761         * @type Number */
6762         LEFT : 37,
6763         /** Key constant 
6764         * @type Number */
6765         UP : 38,
6766         /** Key constant 
6767         * @type Number */
6768         RIGHT : 39,
6769         /** Key constant 
6770         * @type Number */
6771         DOWN : 40,
6772         /** Key constant 
6773         * @type Number */
6774         DELETE : 46,
6775         /** Key constant 
6776         * @type Number */
6777         F5 : 116,
6778
6779            /** @private */
6780         setEvent : function(e){
6781             if(e == this || (e && e.browserEvent)){ // already wrapped
6782                 return e;
6783             }
6784             this.browserEvent = e;
6785             if(e){
6786                 // normalize buttons
6787                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6788                 if(e.type == 'click' && this.button == -1){
6789                     this.button = 0;
6790                 }
6791                 this.type = e.type;
6792                 this.shiftKey = e.shiftKey;
6793                 // mac metaKey behaves like ctrlKey
6794                 this.ctrlKey = e.ctrlKey || e.metaKey;
6795                 this.altKey = e.altKey;
6796                 // in getKey these will be normalized for the mac
6797                 this.keyCode = e.keyCode;
6798                 // keyup warnings on firefox.
6799                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6800                 // cache the target for the delayed and or buffered events
6801                 this.target = E.getTarget(e);
6802                 // same for XY
6803                 this.xy = E.getXY(e);
6804             }else{
6805                 this.button = -1;
6806                 this.shiftKey = false;
6807                 this.ctrlKey = false;
6808                 this.altKey = false;
6809                 this.keyCode = 0;
6810                 this.charCode =0;
6811                 this.target = null;
6812                 this.xy = [0, 0];
6813             }
6814             return this;
6815         },
6816
6817         /**
6818          * Stop the event (preventDefault and stopPropagation)
6819          */
6820         stopEvent : function(){
6821             if(this.browserEvent){
6822                 if(this.browserEvent.type == 'mousedown'){
6823                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6824                 }
6825                 E.stopEvent(this.browserEvent);
6826             }
6827         },
6828
6829         /**
6830          * Prevents the browsers default handling of the event.
6831          */
6832         preventDefault : function(){
6833             if(this.browserEvent){
6834                 E.preventDefault(this.browserEvent);
6835             }
6836         },
6837
6838         /** @private */
6839         isNavKeyPress : function(){
6840             var k = this.keyCode;
6841             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6842             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6843         },
6844
6845         isSpecialKey : function(){
6846             var k = this.keyCode;
6847             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6848             (k == 16) || (k == 17) ||
6849             (k >= 18 && k <= 20) ||
6850             (k >= 33 && k <= 35) ||
6851             (k >= 36 && k <= 39) ||
6852             (k >= 44 && k <= 45);
6853         },
6854         /**
6855          * Cancels bubbling of the event.
6856          */
6857         stopPropagation : function(){
6858             if(this.browserEvent){
6859                 if(this.type == 'mousedown'){
6860                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6861                 }
6862                 E.stopPropagation(this.browserEvent);
6863             }
6864         },
6865
6866         /**
6867          * Gets the key code for the event.
6868          * @return {Number}
6869          */
6870         getCharCode : function(){
6871             return this.charCode || this.keyCode;
6872         },
6873
6874         /**
6875          * Returns a normalized keyCode for the event.
6876          * @return {Number} The key code
6877          */
6878         getKey : function(){
6879             var k = this.keyCode || this.charCode;
6880             return Roo.isSafari ? (safariKeys[k] || k) : k;
6881         },
6882
6883         /**
6884          * Gets the x coordinate of the event.
6885          * @return {Number}
6886          */
6887         getPageX : function(){
6888             return this.xy[0];
6889         },
6890
6891         /**
6892          * Gets the y coordinate of the event.
6893          * @return {Number}
6894          */
6895         getPageY : function(){
6896             return this.xy[1];
6897         },
6898
6899         /**
6900          * Gets the time of the event.
6901          * @return {Number}
6902          */
6903         getTime : function(){
6904             if(this.browserEvent){
6905                 return E.getTime(this.browserEvent);
6906             }
6907             return null;
6908         },
6909
6910         /**
6911          * Gets the page coordinates of the event.
6912          * @return {Array} The xy values like [x, y]
6913          */
6914         getXY : function(){
6915             return this.xy;
6916         },
6917
6918         /**
6919          * Gets the target for the event.
6920          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6921          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6922                 search as a number or element (defaults to 10 || document.body)
6923          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6924          * @return {HTMLelement}
6925          */
6926         getTarget : function(selector, maxDepth, returnEl){
6927             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6928         },
6929         /**
6930          * Gets the related target.
6931          * @return {HTMLElement}
6932          */
6933         getRelatedTarget : function(){
6934             if(this.browserEvent){
6935                 return E.getRelatedTarget(this.browserEvent);
6936             }
6937             return null;
6938         },
6939
6940         /**
6941          * Normalizes mouse wheel delta across browsers
6942          * @return {Number} The delta
6943          */
6944         getWheelDelta : function(){
6945             var e = this.browserEvent;
6946             var delta = 0;
6947             if(e.wheelDelta){ /* IE/Opera. */
6948                 delta = e.wheelDelta/120;
6949             }else if(e.detail){ /* Mozilla case. */
6950                 delta = -e.detail/3;
6951             }
6952             return delta;
6953         },
6954
6955         /**
6956          * Returns true if the control, meta, shift or alt key was pressed during this event.
6957          * @return {Boolean}
6958          */
6959         hasModifier : function(){
6960             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6961         },
6962
6963         /**
6964          * Returns true if the target of this event equals el or is a child of el
6965          * @param {String/HTMLElement/Element} el
6966          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6967          * @return {Boolean}
6968          */
6969         within : function(el, related){
6970             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6971             return t && Roo.fly(el).contains(t);
6972         },
6973
6974         getPoint : function(){
6975             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6976         }
6977     };
6978
6979     return new Roo.EventObjectImpl();
6980 }();
6981             
6982     /*
6983  * Based on:
6984  * Ext JS Library 1.1.1
6985  * Copyright(c) 2006-2007, Ext JS, LLC.
6986  *
6987  * Originally Released Under LGPL - original licence link has changed is not relivant.
6988  *
6989  * Fork - LGPL
6990  * <script type="text/javascript">
6991  */
6992
6993  
6994 // was in Composite Element!??!?!
6995  
6996 (function(){
6997     var D = Roo.lib.Dom;
6998     var E = Roo.lib.Event;
6999     var A = Roo.lib.Anim;
7000
7001     // local style camelizing for speed
7002     var propCache = {};
7003     var camelRe = /(-[a-z])/gi;
7004     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7005     var view = document.defaultView;
7006
7007 /**
7008  * @class Roo.Element
7009  * Represents an Element in the DOM.<br><br>
7010  * Usage:<br>
7011 <pre><code>
7012 var el = Roo.get("my-div");
7013
7014 // or with getEl
7015 var el = getEl("my-div");
7016
7017 // or with a DOM element
7018 var el = Roo.get(myDivElement);
7019 </code></pre>
7020  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7021  * each call instead of constructing a new one.<br><br>
7022  * <b>Animations</b><br />
7023  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7024  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7025 <pre>
7026 Option    Default   Description
7027 --------- --------  ---------------------------------------------
7028 duration  .35       The duration of the animation in seconds
7029 easing    easeOut   The YUI easing method
7030 callback  none      A function to execute when the anim completes
7031 scope     this      The scope (this) of the callback function
7032 </pre>
7033 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7034 * manipulate the animation. Here's an example:
7035 <pre><code>
7036 var el = Roo.get("my-div");
7037
7038 // no animation
7039 el.setWidth(100);
7040
7041 // default animation
7042 el.setWidth(100, true);
7043
7044 // animation with some options set
7045 el.setWidth(100, {
7046     duration: 1,
7047     callback: this.foo,
7048     scope: this
7049 });
7050
7051 // using the "anim" property to get the Anim object
7052 var opt = {
7053     duration: 1,
7054     callback: this.foo,
7055     scope: this
7056 };
7057 el.setWidth(100, opt);
7058 ...
7059 if(opt.anim.isAnimated()){
7060     opt.anim.stop();
7061 }
7062 </code></pre>
7063 * <b> Composite (Collections of) Elements</b><br />
7064  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7065  * @constructor Create a new Element directly.
7066  * @param {String/HTMLElement} element
7067  * @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).
7068  */
7069     Roo.Element = function(element, forceNew){
7070         var dom = typeof element == "string" ?
7071                 document.getElementById(element) : element;
7072         if(!dom){ // invalid id/element
7073             return null;
7074         }
7075         var id = dom.id;
7076         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7077             return Roo.Element.cache[id];
7078         }
7079
7080         /**
7081          * The DOM element
7082          * @type HTMLElement
7083          */
7084         this.dom = dom;
7085
7086         /**
7087          * The DOM element ID
7088          * @type String
7089          */
7090         this.id = id || Roo.id(dom);
7091     };
7092
7093     var El = Roo.Element;
7094
7095     El.prototype = {
7096         /**
7097          * The element's default display mode  (defaults to "")
7098          * @type String
7099          */
7100         originalDisplay : "",
7101
7102         visibilityMode : 1,
7103         /**
7104          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7105          * @type String
7106          */
7107         defaultUnit : "px",
7108         
7109         /**
7110          * Sets the element's visibility mode. When setVisible() is called it
7111          * will use this to determine whether to set the visibility or the display property.
7112          * @param visMode Element.VISIBILITY or Element.DISPLAY
7113          * @return {Roo.Element} this
7114          */
7115         setVisibilityMode : function(visMode){
7116             this.visibilityMode = visMode;
7117             return this;
7118         },
7119         /**
7120          * Convenience method for setVisibilityMode(Element.DISPLAY)
7121          * @param {String} display (optional) What to set display to when visible
7122          * @return {Roo.Element} this
7123          */
7124         enableDisplayMode : function(display){
7125             this.setVisibilityMode(El.DISPLAY);
7126             if(typeof display != "undefined") { this.originalDisplay = display; }
7127             return this;
7128         },
7129
7130         /**
7131          * 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)
7132          * @param {String} selector The simple selector to test
7133          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7134                 search as a number or element (defaults to 10 || document.body)
7135          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7136          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7137          */
7138         findParent : function(simpleSelector, maxDepth, returnEl){
7139             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7140             maxDepth = maxDepth || 50;
7141             if(typeof maxDepth != "number"){
7142                 stopEl = Roo.getDom(maxDepth);
7143                 maxDepth = 10;
7144             }
7145             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7146                 if(dq.is(p, simpleSelector)){
7147                     return returnEl ? Roo.get(p) : p;
7148                 }
7149                 depth++;
7150                 p = p.parentNode;
7151             }
7152             return null;
7153         },
7154
7155
7156         /**
7157          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7158          * @param {String} selector The simple selector to test
7159          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7160                 search as a number or element (defaults to 10 || document.body)
7161          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7162          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7163          */
7164         findParentNode : function(simpleSelector, maxDepth, returnEl){
7165             var p = Roo.fly(this.dom.parentNode, '_internal');
7166             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7167         },
7168         
7169         /**
7170          * Looks at  the scrollable parent element
7171          */
7172         findScrollableParent : function()
7173         {
7174             var overflowRegex = /(auto|scroll)/;
7175             
7176             if(this.getStyle('position') === 'fixed'){
7177                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7178             }
7179             
7180             var excludeStaticParent = this.getStyle('position') === "absolute";
7181             
7182             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7183                 
7184                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7185                     continue;
7186                 }
7187                 
7188                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7189                     return parent;
7190                 }
7191                 
7192                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7193                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7194                 }
7195             }
7196             
7197             alert(Roo.isAndroid);
7198             
7199             if(Roo.isAndroid){
7200                 alert('Is Android');
7201                 return Roo.get(document.documentElement);
7202             }
7203             
7204             if(!Roo.isAndroid){
7205                 alert('not android');
7206             }
7207             
7208             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7209         },
7210
7211         /**
7212          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7213          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7214          * @param {String} selector The simple selector to test
7215          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7216                 search as a number or element (defaults to 10 || document.body)
7217          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7218          */
7219         up : function(simpleSelector, maxDepth){
7220             return this.findParentNode(simpleSelector, maxDepth, true);
7221         },
7222
7223
7224
7225         /**
7226          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7227          * @param {String} selector The simple selector to test
7228          * @return {Boolean} True if this element matches the selector, else false
7229          */
7230         is : function(simpleSelector){
7231             return Roo.DomQuery.is(this.dom, simpleSelector);
7232         },
7233
7234         /**
7235          * Perform animation on this element.
7236          * @param {Object} args The YUI animation control args
7237          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7238          * @param {Function} onComplete (optional) Function to call when animation completes
7239          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7240          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7241          * @return {Roo.Element} this
7242          */
7243         animate : function(args, duration, onComplete, easing, animType){
7244             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7245             return this;
7246         },
7247
7248         /*
7249          * @private Internal animation call
7250          */
7251         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7252             animType = animType || 'run';
7253             opt = opt || {};
7254             var anim = Roo.lib.Anim[animType](
7255                 this.dom, args,
7256                 (opt.duration || defaultDur) || .35,
7257                 (opt.easing || defaultEase) || 'easeOut',
7258                 function(){
7259                     Roo.callback(cb, this);
7260                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7261                 },
7262                 this
7263             );
7264             opt.anim = anim;
7265             return anim;
7266         },
7267
7268         // private legacy anim prep
7269         preanim : function(a, i){
7270             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7271         },
7272
7273         /**
7274          * Removes worthless text nodes
7275          * @param {Boolean} forceReclean (optional) By default the element
7276          * keeps track if it has been cleaned already so
7277          * you can call this over and over. However, if you update the element and
7278          * need to force a reclean, you can pass true.
7279          */
7280         clean : function(forceReclean){
7281             if(this.isCleaned && forceReclean !== true){
7282                 return this;
7283             }
7284             var ns = /\S/;
7285             var d = this.dom, n = d.firstChild, ni = -1;
7286             while(n){
7287                 var nx = n.nextSibling;
7288                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7289                     d.removeChild(n);
7290                 }else{
7291                     n.nodeIndex = ++ni;
7292                 }
7293                 n = nx;
7294             }
7295             this.isCleaned = true;
7296             return this;
7297         },
7298
7299         // private
7300         calcOffsetsTo : function(el){
7301             el = Roo.get(el);
7302             var d = el.dom;
7303             var restorePos = false;
7304             if(el.getStyle('position') == 'static'){
7305                 el.position('relative');
7306                 restorePos = true;
7307             }
7308             var x = 0, y =0;
7309             var op = this.dom;
7310             while(op && op != d && op.tagName != 'HTML'){
7311                 x+= op.offsetLeft;
7312                 y+= op.offsetTop;
7313                 op = op.offsetParent;
7314             }
7315             if(restorePos){
7316                 el.position('static');
7317             }
7318             return [x, y];
7319         },
7320
7321         /**
7322          * Scrolls this element into view within the passed container.
7323          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7324          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7325          * @return {Roo.Element} this
7326          */
7327         scrollIntoView : function(container, hscroll){
7328             var c = Roo.getDom(container) || document.body;
7329             var el = this.dom;
7330
7331             var o = this.calcOffsetsTo(c),
7332                 l = o[0],
7333                 t = o[1],
7334                 b = t+el.offsetHeight,
7335                 r = l+el.offsetWidth;
7336
7337             var ch = c.clientHeight;
7338             var ct = parseInt(c.scrollTop, 10);
7339             var cl = parseInt(c.scrollLeft, 10);
7340             var cb = ct + ch;
7341             var cr = cl + c.clientWidth;
7342
7343             if(t < ct){
7344                 c.scrollTop = t;
7345             }else if(b > cb){
7346                 c.scrollTop = b-ch;
7347             }
7348
7349             if(hscroll !== false){
7350                 if(l < cl){
7351                     c.scrollLeft = l;
7352                 }else if(r > cr){
7353                     c.scrollLeft = r-c.clientWidth;
7354                 }
7355             }
7356             return this;
7357         },
7358
7359         // private
7360         scrollChildIntoView : function(child, hscroll){
7361             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7362         },
7363
7364         /**
7365          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7366          * the new height may not be available immediately.
7367          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7368          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7369          * @param {Function} onComplete (optional) Function to call when animation completes
7370          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7371          * @return {Roo.Element} this
7372          */
7373         autoHeight : function(animate, duration, onComplete, easing){
7374             var oldHeight = this.getHeight();
7375             this.clip();
7376             this.setHeight(1); // force clipping
7377             setTimeout(function(){
7378                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7379                 if(!animate){
7380                     this.setHeight(height);
7381                     this.unclip();
7382                     if(typeof onComplete == "function"){
7383                         onComplete();
7384                     }
7385                 }else{
7386                     this.setHeight(oldHeight); // restore original height
7387                     this.setHeight(height, animate, duration, function(){
7388                         this.unclip();
7389                         if(typeof onComplete == "function") { onComplete(); }
7390                     }.createDelegate(this), easing);
7391                 }
7392             }.createDelegate(this), 0);
7393             return this;
7394         },
7395
7396         /**
7397          * Returns true if this element is an ancestor of the passed element
7398          * @param {HTMLElement/String} el The element to check
7399          * @return {Boolean} True if this element is an ancestor of el, else false
7400          */
7401         contains : function(el){
7402             if(!el){return false;}
7403             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7404         },
7405
7406         /**
7407          * Checks whether the element is currently visible using both visibility and display properties.
7408          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7409          * @return {Boolean} True if the element is currently visible, else false
7410          */
7411         isVisible : function(deep) {
7412             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7413             if(deep !== true || !vis){
7414                 return vis;
7415             }
7416             var p = this.dom.parentNode;
7417             while(p && p.tagName.toLowerCase() != "body"){
7418                 if(!Roo.fly(p, '_isVisible').isVisible()){
7419                     return false;
7420                 }
7421                 p = p.parentNode;
7422             }
7423             return true;
7424         },
7425
7426         /**
7427          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7428          * @param {String} selector The CSS selector
7429          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7430          * @return {CompositeElement/CompositeElementLite} The composite element
7431          */
7432         select : function(selector, unique){
7433             return El.select(selector, unique, this.dom);
7434         },
7435
7436         /**
7437          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7438          * @param {String} selector The CSS selector
7439          * @return {Array} An array of the matched nodes
7440          */
7441         query : function(selector, unique){
7442             return Roo.DomQuery.select(selector, this.dom);
7443         },
7444
7445         /**
7446          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7447          * @param {String} selector The CSS selector
7448          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7449          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7450          */
7451         child : function(selector, returnDom){
7452             var n = Roo.DomQuery.selectNode(selector, this.dom);
7453             return returnDom ? n : Roo.get(n);
7454         },
7455
7456         /**
7457          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7458          * @param {String} selector The CSS selector
7459          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7460          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7461          */
7462         down : function(selector, returnDom){
7463             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7464             return returnDom ? n : Roo.get(n);
7465         },
7466
7467         /**
7468          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7469          * @param {String} group The group the DD object is member of
7470          * @param {Object} config The DD config object
7471          * @param {Object} overrides An object containing methods to override/implement on the DD object
7472          * @return {Roo.dd.DD} The DD object
7473          */
7474         initDD : function(group, config, overrides){
7475             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7476             return Roo.apply(dd, overrides);
7477         },
7478
7479         /**
7480          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7481          * @param {String} group The group the DDProxy object is member of
7482          * @param {Object} config The DDProxy config object
7483          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7484          * @return {Roo.dd.DDProxy} The DDProxy object
7485          */
7486         initDDProxy : function(group, config, overrides){
7487             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7488             return Roo.apply(dd, overrides);
7489         },
7490
7491         /**
7492          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7493          * @param {String} group The group the DDTarget object is member of
7494          * @param {Object} config The DDTarget config object
7495          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7496          * @return {Roo.dd.DDTarget} The DDTarget object
7497          */
7498         initDDTarget : function(group, config, overrides){
7499             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7500             return Roo.apply(dd, overrides);
7501         },
7502
7503         /**
7504          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7505          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7506          * @param {Boolean} visible Whether the element is visible
7507          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7508          * @return {Roo.Element} this
7509          */
7510          setVisible : function(visible, animate){
7511             if(!animate || !A){
7512                 if(this.visibilityMode == El.DISPLAY){
7513                     this.setDisplayed(visible);
7514                 }else{
7515                     this.fixDisplay();
7516                     this.dom.style.visibility = visible ? "visible" : "hidden";
7517                 }
7518             }else{
7519                 // closure for composites
7520                 var dom = this.dom;
7521                 var visMode = this.visibilityMode;
7522                 if(visible){
7523                     this.setOpacity(.01);
7524                     this.setVisible(true);
7525                 }
7526                 this.anim({opacity: { to: (visible?1:0) }},
7527                       this.preanim(arguments, 1),
7528                       null, .35, 'easeIn', function(){
7529                          if(!visible){
7530                              if(visMode == El.DISPLAY){
7531                                  dom.style.display = "none";
7532                              }else{
7533                                  dom.style.visibility = "hidden";
7534                              }
7535                              Roo.get(dom).setOpacity(1);
7536                          }
7537                      });
7538             }
7539             return this;
7540         },
7541
7542         /**
7543          * Returns true if display is not "none"
7544          * @return {Boolean}
7545          */
7546         isDisplayed : function() {
7547             return this.getStyle("display") != "none";
7548         },
7549
7550         /**
7551          * Toggles the element's visibility or display, depending on visibility mode.
7552          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7553          * @return {Roo.Element} this
7554          */
7555         toggle : function(animate){
7556             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7557             return this;
7558         },
7559
7560         /**
7561          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7562          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7563          * @return {Roo.Element} this
7564          */
7565         setDisplayed : function(value) {
7566             if(typeof value == "boolean"){
7567                value = value ? this.originalDisplay : "none";
7568             }
7569             this.setStyle("display", value);
7570             return this;
7571         },
7572
7573         /**
7574          * Tries to focus the element. Any exceptions are caught and ignored.
7575          * @return {Roo.Element} this
7576          */
7577         focus : function() {
7578             try{
7579                 this.dom.focus();
7580             }catch(e){}
7581             return this;
7582         },
7583
7584         /**
7585          * Tries to blur the element. Any exceptions are caught and ignored.
7586          * @return {Roo.Element} this
7587          */
7588         blur : function() {
7589             try{
7590                 this.dom.blur();
7591             }catch(e){}
7592             return this;
7593         },
7594
7595         /**
7596          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7597          * @param {String/Array} className The CSS class to add, or an array of classes
7598          * @return {Roo.Element} this
7599          */
7600         addClass : function(className){
7601             if(className instanceof Array){
7602                 for(var i = 0, len = className.length; i < len; i++) {
7603                     this.addClass(className[i]);
7604                 }
7605             }else{
7606                 if(className && !this.hasClass(className)){
7607                     this.dom.className = this.dom.className + " " + className;
7608                 }
7609             }
7610             return this;
7611         },
7612
7613         /**
7614          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7615          * @param {String/Array} className The CSS class to add, or an array of classes
7616          * @return {Roo.Element} this
7617          */
7618         radioClass : function(className){
7619             var siblings = this.dom.parentNode.childNodes;
7620             for(var i = 0; i < siblings.length; i++) {
7621                 var s = siblings[i];
7622                 if(s.nodeType == 1){
7623                     Roo.get(s).removeClass(className);
7624                 }
7625             }
7626             this.addClass(className);
7627             return this;
7628         },
7629
7630         /**
7631          * Removes one or more CSS classes from the element.
7632          * @param {String/Array} className The CSS class to remove, or an array of classes
7633          * @return {Roo.Element} this
7634          */
7635         removeClass : function(className){
7636             if(!className || !this.dom.className){
7637                 return this;
7638             }
7639             if(className instanceof Array){
7640                 for(var i = 0, len = className.length; i < len; i++) {
7641                     this.removeClass(className[i]);
7642                 }
7643             }else{
7644                 if(this.hasClass(className)){
7645                     var re = this.classReCache[className];
7646                     if (!re) {
7647                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7648                        this.classReCache[className] = re;
7649                     }
7650                     this.dom.className =
7651                         this.dom.className.replace(re, " ");
7652                 }
7653             }
7654             return this;
7655         },
7656
7657         // private
7658         classReCache: {},
7659
7660         /**
7661          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7662          * @param {String} className The CSS class to toggle
7663          * @return {Roo.Element} this
7664          */
7665         toggleClass : function(className){
7666             if(this.hasClass(className)){
7667                 this.removeClass(className);
7668             }else{
7669                 this.addClass(className);
7670             }
7671             return this;
7672         },
7673
7674         /**
7675          * Checks if the specified CSS class exists on this element's DOM node.
7676          * @param {String} className The CSS class to check for
7677          * @return {Boolean} True if the class exists, else false
7678          */
7679         hasClass : function(className){
7680             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7681         },
7682
7683         /**
7684          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7685          * @param {String} oldClassName The CSS class to replace
7686          * @param {String} newClassName The replacement CSS class
7687          * @return {Roo.Element} this
7688          */
7689         replaceClass : function(oldClassName, newClassName){
7690             this.removeClass(oldClassName);
7691             this.addClass(newClassName);
7692             return this;
7693         },
7694
7695         /**
7696          * Returns an object with properties matching the styles requested.
7697          * For example, el.getStyles('color', 'font-size', 'width') might return
7698          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7699          * @param {String} style1 A style name
7700          * @param {String} style2 A style name
7701          * @param {String} etc.
7702          * @return {Object} The style object
7703          */
7704         getStyles : function(){
7705             var a = arguments, len = a.length, r = {};
7706             for(var i = 0; i < len; i++){
7707                 r[a[i]] = this.getStyle(a[i]);
7708             }
7709             return r;
7710         },
7711
7712         /**
7713          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7714          * @param {String} property The style property whose value is returned.
7715          * @return {String} The current value of the style property for this element.
7716          */
7717         getStyle : function(){
7718             return view && view.getComputedStyle ?
7719                 function(prop){
7720                     var el = this.dom, v, cs, camel;
7721                     if(prop == 'float'){
7722                         prop = "cssFloat";
7723                     }
7724                     if(el.style && (v = el.style[prop])){
7725                         return v;
7726                     }
7727                     if(cs = view.getComputedStyle(el, "")){
7728                         if(!(camel = propCache[prop])){
7729                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7730                         }
7731                         return cs[camel];
7732                     }
7733                     return null;
7734                 } :
7735                 function(prop){
7736                     var el = this.dom, v, cs, camel;
7737                     if(prop == 'opacity'){
7738                         if(typeof el.style.filter == 'string'){
7739                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7740                             if(m){
7741                                 var fv = parseFloat(m[1]);
7742                                 if(!isNaN(fv)){
7743                                     return fv ? fv / 100 : 0;
7744                                 }
7745                             }
7746                         }
7747                         return 1;
7748                     }else if(prop == 'float'){
7749                         prop = "styleFloat";
7750                     }
7751                     if(!(camel = propCache[prop])){
7752                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7753                     }
7754                     if(v = el.style[camel]){
7755                         return v;
7756                     }
7757                     if(cs = el.currentStyle){
7758                         return cs[camel];
7759                     }
7760                     return null;
7761                 };
7762         }(),
7763
7764         /**
7765          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7766          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7767          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7768          * @return {Roo.Element} this
7769          */
7770         setStyle : function(prop, value){
7771             if(typeof prop == "string"){
7772                 
7773                 if (prop == 'float') {
7774                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7775                     return this;
7776                 }
7777                 
7778                 var camel;
7779                 if(!(camel = propCache[prop])){
7780                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7781                 }
7782                 
7783                 if(camel == 'opacity') {
7784                     this.setOpacity(value);
7785                 }else{
7786                     this.dom.style[camel] = value;
7787                 }
7788             }else{
7789                 for(var style in prop){
7790                     if(typeof prop[style] != "function"){
7791                        this.setStyle(style, prop[style]);
7792                     }
7793                 }
7794             }
7795             return this;
7796         },
7797
7798         /**
7799          * More flexible version of {@link #setStyle} for setting style properties.
7800          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7801          * a function which returns such a specification.
7802          * @return {Roo.Element} this
7803          */
7804         applyStyles : function(style){
7805             Roo.DomHelper.applyStyles(this.dom, style);
7806             return this;
7807         },
7808
7809         /**
7810           * 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).
7811           * @return {Number} The X position of the element
7812           */
7813         getX : function(){
7814             return D.getX(this.dom);
7815         },
7816
7817         /**
7818           * 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).
7819           * @return {Number} The Y position of the element
7820           */
7821         getY : function(){
7822             return D.getY(this.dom);
7823         },
7824
7825         /**
7826           * 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).
7827           * @return {Array} The XY position of the element
7828           */
7829         getXY : function(){
7830             return D.getXY(this.dom);
7831         },
7832
7833         /**
7834          * 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).
7835          * @param {Number} The X position of the element
7836          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7837          * @return {Roo.Element} this
7838          */
7839         setX : function(x, animate){
7840             if(!animate || !A){
7841                 D.setX(this.dom, x);
7842             }else{
7843                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7844             }
7845             return this;
7846         },
7847
7848         /**
7849          * 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).
7850          * @param {Number} The Y position of the element
7851          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7852          * @return {Roo.Element} this
7853          */
7854         setY : function(y, animate){
7855             if(!animate || !A){
7856                 D.setY(this.dom, y);
7857             }else{
7858                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7859             }
7860             return this;
7861         },
7862
7863         /**
7864          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7865          * @param {String} left The left CSS property value
7866          * @return {Roo.Element} this
7867          */
7868         setLeft : function(left){
7869             this.setStyle("left", this.addUnits(left));
7870             return this;
7871         },
7872
7873         /**
7874          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7875          * @param {String} top The top CSS property value
7876          * @return {Roo.Element} this
7877          */
7878         setTop : function(top){
7879             this.setStyle("top", this.addUnits(top));
7880             return this;
7881         },
7882
7883         /**
7884          * Sets the element's CSS right style.
7885          * @param {String} right The right CSS property value
7886          * @return {Roo.Element} this
7887          */
7888         setRight : function(right){
7889             this.setStyle("right", this.addUnits(right));
7890             return this;
7891         },
7892
7893         /**
7894          * Sets the element's CSS bottom style.
7895          * @param {String} bottom The bottom CSS property value
7896          * @return {Roo.Element} this
7897          */
7898         setBottom : function(bottom){
7899             this.setStyle("bottom", this.addUnits(bottom));
7900             return this;
7901         },
7902
7903         /**
7904          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7905          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7906          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7907          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7908          * @return {Roo.Element} this
7909          */
7910         setXY : function(pos, animate){
7911             if(!animate || !A){
7912                 D.setXY(this.dom, pos);
7913             }else{
7914                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7915             }
7916             return this;
7917         },
7918
7919         /**
7920          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7921          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7922          * @param {Number} x X value for new position (coordinates are page-based)
7923          * @param {Number} y Y value for new position (coordinates are page-based)
7924          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7925          * @return {Roo.Element} this
7926          */
7927         setLocation : function(x, y, animate){
7928             this.setXY([x, y], this.preanim(arguments, 2));
7929             return this;
7930         },
7931
7932         /**
7933          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7934          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7935          * @param {Number} x X value for new position (coordinates are page-based)
7936          * @param {Number} y Y value for new position (coordinates are page-based)
7937          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7938          * @return {Roo.Element} this
7939          */
7940         moveTo : function(x, y, animate){
7941             this.setXY([x, y], this.preanim(arguments, 2));
7942             return this;
7943         },
7944
7945         /**
7946          * Returns the region of the given element.
7947          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7948          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7949          */
7950         getRegion : function(){
7951             return D.getRegion(this.dom);
7952         },
7953
7954         /**
7955          * Returns the offset height of the element
7956          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7957          * @return {Number} The element's height
7958          */
7959         getHeight : function(contentHeight){
7960             var h = this.dom.offsetHeight || 0;
7961             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7962         },
7963
7964         /**
7965          * Returns the offset width of the element
7966          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7967          * @return {Number} The element's width
7968          */
7969         getWidth : function(contentWidth){
7970             var w = this.dom.offsetWidth || 0;
7971             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7972         },
7973
7974         /**
7975          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7976          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7977          * if a height has not been set using CSS.
7978          * @return {Number}
7979          */
7980         getComputedHeight : function(){
7981             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7982             if(!h){
7983                 h = parseInt(this.getStyle('height'), 10) || 0;
7984                 if(!this.isBorderBox()){
7985                     h += this.getFrameWidth('tb');
7986                 }
7987             }
7988             return h;
7989         },
7990
7991         /**
7992          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7993          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7994          * if a width has not been set using CSS.
7995          * @return {Number}
7996          */
7997         getComputedWidth : function(){
7998             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7999             if(!w){
8000                 w = parseInt(this.getStyle('width'), 10) || 0;
8001                 if(!this.isBorderBox()){
8002                     w += this.getFrameWidth('lr');
8003                 }
8004             }
8005             return w;
8006         },
8007
8008         /**
8009          * Returns the size of the element.
8010          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8011          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8012          */
8013         getSize : function(contentSize){
8014             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8015         },
8016
8017         /**
8018          * Returns the width and height of the viewport.
8019          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8020          */
8021         getViewSize : function(){
8022             var d = this.dom, doc = document, aw = 0, ah = 0;
8023             if(d == doc || d == doc.body){
8024                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8025             }else{
8026                 return {
8027                     width : d.clientWidth,
8028                     height: d.clientHeight
8029                 };
8030             }
8031         },
8032
8033         /**
8034          * Returns the value of the "value" attribute
8035          * @param {Boolean} asNumber true to parse the value as a number
8036          * @return {String/Number}
8037          */
8038         getValue : function(asNumber){
8039             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8040         },
8041
8042         // private
8043         adjustWidth : function(width){
8044             if(typeof width == "number"){
8045                 if(this.autoBoxAdjust && !this.isBorderBox()){
8046                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8047                 }
8048                 if(width < 0){
8049                     width = 0;
8050                 }
8051             }
8052             return width;
8053         },
8054
8055         // private
8056         adjustHeight : function(height){
8057             if(typeof height == "number"){
8058                if(this.autoBoxAdjust && !this.isBorderBox()){
8059                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8060                }
8061                if(height < 0){
8062                    height = 0;
8063                }
8064             }
8065             return height;
8066         },
8067
8068         /**
8069          * Set the width of the element
8070          * @param {Number} width The new width
8071          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8072          * @return {Roo.Element} this
8073          */
8074         setWidth : function(width, animate){
8075             width = this.adjustWidth(width);
8076             if(!animate || !A){
8077                 this.dom.style.width = this.addUnits(width);
8078             }else{
8079                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8080             }
8081             return this;
8082         },
8083
8084         /**
8085          * Set the height of the element
8086          * @param {Number} height The new height
8087          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8088          * @return {Roo.Element} this
8089          */
8090          setHeight : function(height, animate){
8091             height = this.adjustHeight(height);
8092             if(!animate || !A){
8093                 this.dom.style.height = this.addUnits(height);
8094             }else{
8095                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8096             }
8097             return this;
8098         },
8099
8100         /**
8101          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8102          * @param {Number} width The new width
8103          * @param {Number} height The new height
8104          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8105          * @return {Roo.Element} this
8106          */
8107          setSize : function(width, height, animate){
8108             if(typeof width == "object"){ // in case of object from getSize()
8109                 height = width.height; width = width.width;
8110             }
8111             width = this.adjustWidth(width); height = this.adjustHeight(height);
8112             if(!animate || !A){
8113                 this.dom.style.width = this.addUnits(width);
8114                 this.dom.style.height = this.addUnits(height);
8115             }else{
8116                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8117             }
8118             return this;
8119         },
8120
8121         /**
8122          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8123          * @param {Number} x X value for new position (coordinates are page-based)
8124          * @param {Number} y Y value for new position (coordinates are page-based)
8125          * @param {Number} width The new width
8126          * @param {Number} height The new height
8127          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8128          * @return {Roo.Element} this
8129          */
8130         setBounds : function(x, y, width, height, animate){
8131             if(!animate || !A){
8132                 this.setSize(width, height);
8133                 this.setLocation(x, y);
8134             }else{
8135                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8136                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8137                               this.preanim(arguments, 4), 'motion');
8138             }
8139             return this;
8140         },
8141
8142         /**
8143          * 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.
8144          * @param {Roo.lib.Region} region The region to fill
8145          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8146          * @return {Roo.Element} this
8147          */
8148         setRegion : function(region, animate){
8149             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8150             return this;
8151         },
8152
8153         /**
8154          * Appends an event handler
8155          *
8156          * @param {String}   eventName     The type of event to append
8157          * @param {Function} fn        The method the event invokes
8158          * @param {Object} scope       (optional) The scope (this object) of the fn
8159          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8160          */
8161         addListener : function(eventName, fn, scope, options){
8162             if (this.dom) {
8163                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8164             }
8165         },
8166
8167         /**
8168          * Removes an event handler from this element
8169          * @param {String} eventName the type of event to remove
8170          * @param {Function} fn the method the event invokes
8171          * @return {Roo.Element} this
8172          */
8173         removeListener : function(eventName, fn){
8174             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8175             return this;
8176         },
8177
8178         /**
8179          * Removes all previous added listeners from this element
8180          * @return {Roo.Element} this
8181          */
8182         removeAllListeners : function(){
8183             E.purgeElement(this.dom);
8184             return this;
8185         },
8186
8187         relayEvent : function(eventName, observable){
8188             this.on(eventName, function(e){
8189                 observable.fireEvent(eventName, e);
8190             });
8191         },
8192
8193         /**
8194          * Set the opacity of the element
8195          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8196          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8197          * @return {Roo.Element} this
8198          */
8199          setOpacity : function(opacity, animate){
8200             if(!animate || !A){
8201                 var s = this.dom.style;
8202                 if(Roo.isIE){
8203                     s.zoom = 1;
8204                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8205                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8206                 }else{
8207                     s.opacity = opacity;
8208                 }
8209             }else{
8210                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8211             }
8212             return this;
8213         },
8214
8215         /**
8216          * Gets the left X coordinate
8217          * @param {Boolean} local True to get the local css position instead of page coordinate
8218          * @return {Number}
8219          */
8220         getLeft : function(local){
8221             if(!local){
8222                 return this.getX();
8223             }else{
8224                 return parseInt(this.getStyle("left"), 10) || 0;
8225             }
8226         },
8227
8228         /**
8229          * Gets the right X coordinate of the element (element X position + element width)
8230          * @param {Boolean} local True to get the local css position instead of page coordinate
8231          * @return {Number}
8232          */
8233         getRight : function(local){
8234             if(!local){
8235                 return this.getX() + this.getWidth();
8236             }else{
8237                 return (this.getLeft(true) + this.getWidth()) || 0;
8238             }
8239         },
8240
8241         /**
8242          * Gets the top Y coordinate
8243          * @param {Boolean} local True to get the local css position instead of page coordinate
8244          * @return {Number}
8245          */
8246         getTop : function(local) {
8247             if(!local){
8248                 return this.getY();
8249             }else{
8250                 return parseInt(this.getStyle("top"), 10) || 0;
8251             }
8252         },
8253
8254         /**
8255          * Gets the bottom Y coordinate of the element (element Y position + element height)
8256          * @param {Boolean} local True to get the local css position instead of page coordinate
8257          * @return {Number}
8258          */
8259         getBottom : function(local){
8260             if(!local){
8261                 return this.getY() + this.getHeight();
8262             }else{
8263                 return (this.getTop(true) + this.getHeight()) || 0;
8264             }
8265         },
8266
8267         /**
8268         * Initializes positioning on this element. If a desired position is not passed, it will make the
8269         * the element positioned relative IF it is not already positioned.
8270         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8271         * @param {Number} zIndex (optional) The zIndex to apply
8272         * @param {Number} x (optional) Set the page X position
8273         * @param {Number} y (optional) Set the page Y position
8274         */
8275         position : function(pos, zIndex, x, y){
8276             if(!pos){
8277                if(this.getStyle('position') == 'static'){
8278                    this.setStyle('position', 'relative');
8279                }
8280             }else{
8281                 this.setStyle("position", pos);
8282             }
8283             if(zIndex){
8284                 this.setStyle("z-index", zIndex);
8285             }
8286             if(x !== undefined && y !== undefined){
8287                 this.setXY([x, y]);
8288             }else if(x !== undefined){
8289                 this.setX(x);
8290             }else if(y !== undefined){
8291                 this.setY(y);
8292             }
8293         },
8294
8295         /**
8296         * Clear positioning back to the default when the document was loaded
8297         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8298         * @return {Roo.Element} this
8299          */
8300         clearPositioning : function(value){
8301             value = value ||'';
8302             this.setStyle({
8303                 "left": value,
8304                 "right": value,
8305                 "top": value,
8306                 "bottom": value,
8307                 "z-index": "",
8308                 "position" : "static"
8309             });
8310             return this;
8311         },
8312
8313         /**
8314         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8315         * snapshot before performing an update and then restoring the element.
8316         * @return {Object}
8317         */
8318         getPositioning : function(){
8319             var l = this.getStyle("left");
8320             var t = this.getStyle("top");
8321             return {
8322                 "position" : this.getStyle("position"),
8323                 "left" : l,
8324                 "right" : l ? "" : this.getStyle("right"),
8325                 "top" : t,
8326                 "bottom" : t ? "" : this.getStyle("bottom"),
8327                 "z-index" : this.getStyle("z-index")
8328             };
8329         },
8330
8331         /**
8332          * Gets the width of the border(s) for the specified side(s)
8333          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8334          * passing lr would get the border (l)eft width + the border (r)ight width.
8335          * @return {Number} The width of the sides passed added together
8336          */
8337         getBorderWidth : function(side){
8338             return this.addStyles(side, El.borders);
8339         },
8340
8341         /**
8342          * Gets the width of the padding(s) for the specified side(s)
8343          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8344          * passing lr would get the padding (l)eft + the padding (r)ight.
8345          * @return {Number} The padding of the sides passed added together
8346          */
8347         getPadding : function(side){
8348             return this.addStyles(side, El.paddings);
8349         },
8350
8351         /**
8352         * Set positioning with an object returned by getPositioning().
8353         * @param {Object} posCfg
8354         * @return {Roo.Element} this
8355          */
8356         setPositioning : function(pc){
8357             this.applyStyles(pc);
8358             if(pc.right == "auto"){
8359                 this.dom.style.right = "";
8360             }
8361             if(pc.bottom == "auto"){
8362                 this.dom.style.bottom = "";
8363             }
8364             return this;
8365         },
8366
8367         // private
8368         fixDisplay : function(){
8369             if(this.getStyle("display") == "none"){
8370                 this.setStyle("visibility", "hidden");
8371                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8372                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8373                     this.setStyle("display", "block");
8374                 }
8375             }
8376         },
8377
8378         /**
8379          * Quick set left and top adding default units
8380          * @param {String} left The left CSS property value
8381          * @param {String} top The top CSS property value
8382          * @return {Roo.Element} this
8383          */
8384          setLeftTop : function(left, top){
8385             this.dom.style.left = this.addUnits(left);
8386             this.dom.style.top = this.addUnits(top);
8387             return this;
8388         },
8389
8390         /**
8391          * Move this element relative to its current position.
8392          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8393          * @param {Number} distance How far to move the element in pixels
8394          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8395          * @return {Roo.Element} this
8396          */
8397          move : function(direction, distance, animate){
8398             var xy = this.getXY();
8399             direction = direction.toLowerCase();
8400             switch(direction){
8401                 case "l":
8402                 case "left":
8403                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8404                     break;
8405                case "r":
8406                case "right":
8407                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8408                     break;
8409                case "t":
8410                case "top":
8411                case "up":
8412                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8413                     break;
8414                case "b":
8415                case "bottom":
8416                case "down":
8417                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8418                     break;
8419             }
8420             return this;
8421         },
8422
8423         /**
8424          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8425          * @return {Roo.Element} this
8426          */
8427         clip : function(){
8428             if(!this.isClipped){
8429                this.isClipped = true;
8430                this.originalClip = {
8431                    "o": this.getStyle("overflow"),
8432                    "x": this.getStyle("overflow-x"),
8433                    "y": this.getStyle("overflow-y")
8434                };
8435                this.setStyle("overflow", "hidden");
8436                this.setStyle("overflow-x", "hidden");
8437                this.setStyle("overflow-y", "hidden");
8438             }
8439             return this;
8440         },
8441
8442         /**
8443          *  Return clipping (overflow) to original clipping before clip() was called
8444          * @return {Roo.Element} this
8445          */
8446         unclip : function(){
8447             if(this.isClipped){
8448                 this.isClipped = false;
8449                 var o = this.originalClip;
8450                 if(o.o){this.setStyle("overflow", o.o);}
8451                 if(o.x){this.setStyle("overflow-x", o.x);}
8452                 if(o.y){this.setStyle("overflow-y", o.y);}
8453             }
8454             return this;
8455         },
8456
8457
8458         /**
8459          * Gets the x,y coordinates specified by the anchor position on the element.
8460          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8461          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8462          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8463          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8464          * @return {Array} [x, y] An array containing the element's x and y coordinates
8465          */
8466         getAnchorXY : function(anchor, local, s){
8467             //Passing a different size is useful for pre-calculating anchors,
8468             //especially for anchored animations that change the el size.
8469
8470             var w, h, vp = false;
8471             if(!s){
8472                 var d = this.dom;
8473                 if(d == document.body || d == document){
8474                     vp = true;
8475                     w = D.getViewWidth(); h = D.getViewHeight();
8476                 }else{
8477                     w = this.getWidth(); h = this.getHeight();
8478                 }
8479             }else{
8480                 w = s.width;  h = s.height;
8481             }
8482             var x = 0, y = 0, r = Math.round;
8483             switch((anchor || "tl").toLowerCase()){
8484                 case "c":
8485                     x = r(w*.5);
8486                     y = r(h*.5);
8487                 break;
8488                 case "t":
8489                     x = r(w*.5);
8490                     y = 0;
8491                 break;
8492                 case "l":
8493                     x = 0;
8494                     y = r(h*.5);
8495                 break;
8496                 case "r":
8497                     x = w;
8498                     y = r(h*.5);
8499                 break;
8500                 case "b":
8501                     x = r(w*.5);
8502                     y = h;
8503                 break;
8504                 case "tl":
8505                     x = 0;
8506                     y = 0;
8507                 break;
8508                 case "bl":
8509                     x = 0;
8510                     y = h;
8511                 break;
8512                 case "br":
8513                     x = w;
8514                     y = h;
8515                 break;
8516                 case "tr":
8517                     x = w;
8518                     y = 0;
8519                 break;
8520             }
8521             if(local === true){
8522                 return [x, y];
8523             }
8524             if(vp){
8525                 var sc = this.getScroll();
8526                 return [x + sc.left, y + sc.top];
8527             }
8528             //Add the element's offset xy
8529             var o = this.getXY();
8530             return [x+o[0], y+o[1]];
8531         },
8532
8533         /**
8534          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8535          * supported position values.
8536          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8537          * @param {String} position The position to align to.
8538          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8539          * @return {Array} [x, y]
8540          */
8541         getAlignToXY : function(el, p, o){
8542             el = Roo.get(el);
8543             var d = this.dom;
8544             if(!el.dom){
8545                 throw "Element.alignTo with an element that doesn't exist";
8546             }
8547             var c = false; //constrain to viewport
8548             var p1 = "", p2 = "";
8549             o = o || [0,0];
8550
8551             if(!p){
8552                 p = "tl-bl";
8553             }else if(p == "?"){
8554                 p = "tl-bl?";
8555             }else if(p.indexOf("-") == -1){
8556                 p = "tl-" + p;
8557             }
8558             p = p.toLowerCase();
8559             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8560             if(!m){
8561                throw "Element.alignTo with an invalid alignment " + p;
8562             }
8563             p1 = m[1]; p2 = m[2]; c = !!m[3];
8564
8565             //Subtract the aligned el's internal xy from the target's offset xy
8566             //plus custom offset to get the aligned el's new offset xy
8567             var a1 = this.getAnchorXY(p1, true);
8568             var a2 = el.getAnchorXY(p2, false);
8569             var x = a2[0] - a1[0] + o[0];
8570             var y = a2[1] - a1[1] + o[1];
8571             if(c){
8572                 //constrain the aligned el to viewport if necessary
8573                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8574                 // 5px of margin for ie
8575                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8576
8577                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8578                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8579                 //otherwise swap the aligned el to the opposite border of the target.
8580                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8581                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8582                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8583                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8584
8585                var doc = document;
8586                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8587                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8588
8589                if((x+w) > dw + scrollX){
8590                     x = swapX ? r.left-w : dw+scrollX-w;
8591                 }
8592                if(x < scrollX){
8593                    x = swapX ? r.right : scrollX;
8594                }
8595                if((y+h) > dh + scrollY){
8596                     y = swapY ? r.top-h : dh+scrollY-h;
8597                 }
8598                if (y < scrollY){
8599                    y = swapY ? r.bottom : scrollY;
8600                }
8601             }
8602             return [x,y];
8603         },
8604
8605         // private
8606         getConstrainToXY : function(){
8607             var os = {top:0, left:0, bottom:0, right: 0};
8608
8609             return function(el, local, offsets, proposedXY){
8610                 el = Roo.get(el);
8611                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8612
8613                 var vw, vh, vx = 0, vy = 0;
8614                 if(el.dom == document.body || el.dom == document){
8615                     vw = Roo.lib.Dom.getViewWidth();
8616                     vh = Roo.lib.Dom.getViewHeight();
8617                 }else{
8618                     vw = el.dom.clientWidth;
8619                     vh = el.dom.clientHeight;
8620                     if(!local){
8621                         var vxy = el.getXY();
8622                         vx = vxy[0];
8623                         vy = vxy[1];
8624                     }
8625                 }
8626
8627                 var s = el.getScroll();
8628
8629                 vx += offsets.left + s.left;
8630                 vy += offsets.top + s.top;
8631
8632                 vw -= offsets.right;
8633                 vh -= offsets.bottom;
8634
8635                 var vr = vx+vw;
8636                 var vb = vy+vh;
8637
8638                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8639                 var x = xy[0], y = xy[1];
8640                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8641
8642                 // only move it if it needs it
8643                 var moved = false;
8644
8645                 // first validate right/bottom
8646                 if((x + w) > vr){
8647                     x = vr - w;
8648                     moved = true;
8649                 }
8650                 if((y + h) > vb){
8651                     y = vb - h;
8652                     moved = true;
8653                 }
8654                 // then make sure top/left isn't negative
8655                 if(x < vx){
8656                     x = vx;
8657                     moved = true;
8658                 }
8659                 if(y < vy){
8660                     y = vy;
8661                     moved = true;
8662                 }
8663                 return moved ? [x, y] : false;
8664             };
8665         }(),
8666
8667         // private
8668         adjustForConstraints : function(xy, parent, offsets){
8669             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8670         },
8671
8672         /**
8673          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8674          * document it aligns it to the viewport.
8675          * The position parameter is optional, and can be specified in any one of the following formats:
8676          * <ul>
8677          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8678          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8679          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8680          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8681          *   <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
8682          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8683          * </ul>
8684          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8685          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8686          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8687          * that specified in order to enforce the viewport constraints.
8688          * Following are all of the supported anchor positions:
8689     <pre>
8690     Value  Description
8691     -----  -----------------------------
8692     tl     The top left corner (default)
8693     t      The center of the top edge
8694     tr     The top right corner
8695     l      The center of the left edge
8696     c      In the center of the element
8697     r      The center of the right edge
8698     bl     The bottom left corner
8699     b      The center of the bottom edge
8700     br     The bottom right corner
8701     </pre>
8702     Example Usage:
8703     <pre><code>
8704     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8705     el.alignTo("other-el");
8706
8707     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8708     el.alignTo("other-el", "tr?");
8709
8710     // align the bottom right corner of el with the center left edge of other-el
8711     el.alignTo("other-el", "br-l?");
8712
8713     // align the center of el with the bottom left corner of other-el and
8714     // adjust the x position by -6 pixels (and the y position by 0)
8715     el.alignTo("other-el", "c-bl", [-6, 0]);
8716     </code></pre>
8717          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8718          * @param {String} position The position to align to.
8719          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8720          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8721          * @return {Roo.Element} this
8722          */
8723         alignTo : function(element, position, offsets, animate){
8724             var xy = this.getAlignToXY(element, position, offsets);
8725             this.setXY(xy, this.preanim(arguments, 3));
8726             return this;
8727         },
8728
8729         /**
8730          * Anchors an element to another element and realigns it when the window is resized.
8731          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8732          * @param {String} position The position to align to.
8733          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8734          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8735          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8736          * is a number, it is used as the buffer delay (defaults to 50ms).
8737          * @param {Function} callback The function to call after the animation finishes
8738          * @return {Roo.Element} this
8739          */
8740         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8741             var action = function(){
8742                 this.alignTo(el, alignment, offsets, animate);
8743                 Roo.callback(callback, this);
8744             };
8745             Roo.EventManager.onWindowResize(action, this);
8746             var tm = typeof monitorScroll;
8747             if(tm != 'undefined'){
8748                 Roo.EventManager.on(window, 'scroll', action, this,
8749                     {buffer: tm == 'number' ? monitorScroll : 50});
8750             }
8751             action.call(this); // align immediately
8752             return this;
8753         },
8754         /**
8755          * Clears any opacity settings from this element. Required in some cases for IE.
8756          * @return {Roo.Element} this
8757          */
8758         clearOpacity : function(){
8759             if (window.ActiveXObject) {
8760                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8761                     this.dom.style.filter = "";
8762                 }
8763             } else {
8764                 this.dom.style.opacity = "";
8765                 this.dom.style["-moz-opacity"] = "";
8766                 this.dom.style["-khtml-opacity"] = "";
8767             }
8768             return this;
8769         },
8770
8771         /**
8772          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8773          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8774          * @return {Roo.Element} this
8775          */
8776         hide : function(animate){
8777             this.setVisible(false, this.preanim(arguments, 0));
8778             return this;
8779         },
8780
8781         /**
8782         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8783         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8784          * @return {Roo.Element} this
8785          */
8786         show : function(animate){
8787             this.setVisible(true, this.preanim(arguments, 0));
8788             return this;
8789         },
8790
8791         /**
8792          * @private Test if size has a unit, otherwise appends the default
8793          */
8794         addUnits : function(size){
8795             return Roo.Element.addUnits(size, this.defaultUnit);
8796         },
8797
8798         /**
8799          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8800          * @return {Roo.Element} this
8801          */
8802         beginMeasure : function(){
8803             var el = this.dom;
8804             if(el.offsetWidth || el.offsetHeight){
8805                 return this; // offsets work already
8806             }
8807             var changed = [];
8808             var p = this.dom, b = document.body; // start with this element
8809             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8810                 var pe = Roo.get(p);
8811                 if(pe.getStyle('display') == 'none'){
8812                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8813                     p.style.visibility = "hidden";
8814                     p.style.display = "block";
8815                 }
8816                 p = p.parentNode;
8817             }
8818             this._measureChanged = changed;
8819             return this;
8820
8821         },
8822
8823         /**
8824          * Restores displays to before beginMeasure was called
8825          * @return {Roo.Element} this
8826          */
8827         endMeasure : function(){
8828             var changed = this._measureChanged;
8829             if(changed){
8830                 for(var i = 0, len = changed.length; i < len; i++) {
8831                     var r = changed[i];
8832                     r.el.style.visibility = r.visibility;
8833                     r.el.style.display = "none";
8834                 }
8835                 this._measureChanged = null;
8836             }
8837             return this;
8838         },
8839
8840         /**
8841         * Update the innerHTML of this element, optionally searching for and processing scripts
8842         * @param {String} html The new HTML
8843         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8844         * @param {Function} callback For async script loading you can be noticed when the update completes
8845         * @return {Roo.Element} this
8846          */
8847         update : function(html, loadScripts, callback){
8848             if(typeof html == "undefined"){
8849                 html = "";
8850             }
8851             if(loadScripts !== true){
8852                 this.dom.innerHTML = html;
8853                 if(typeof callback == "function"){
8854                     callback();
8855                 }
8856                 return this;
8857             }
8858             var id = Roo.id();
8859             var dom = this.dom;
8860
8861             html += '<span id="' + id + '"></span>';
8862
8863             E.onAvailable(id, function(){
8864                 var hd = document.getElementsByTagName("head")[0];
8865                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8866                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8867                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8868
8869                 var match;
8870                 while(match = re.exec(html)){
8871                     var attrs = match[1];
8872                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8873                     if(srcMatch && srcMatch[2]){
8874                        var s = document.createElement("script");
8875                        s.src = srcMatch[2];
8876                        var typeMatch = attrs.match(typeRe);
8877                        if(typeMatch && typeMatch[2]){
8878                            s.type = typeMatch[2];
8879                        }
8880                        hd.appendChild(s);
8881                     }else if(match[2] && match[2].length > 0){
8882                         if(window.execScript) {
8883                            window.execScript(match[2]);
8884                         } else {
8885                             /**
8886                              * eval:var:id
8887                              * eval:var:dom
8888                              * eval:var:html
8889                              * 
8890                              */
8891                            window.eval(match[2]);
8892                         }
8893                     }
8894                 }
8895                 var el = document.getElementById(id);
8896                 if(el){el.parentNode.removeChild(el);}
8897                 if(typeof callback == "function"){
8898                     callback();
8899                 }
8900             });
8901             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8902             return this;
8903         },
8904
8905         /**
8906          * Direct access to the UpdateManager update() method (takes the same parameters).
8907          * @param {String/Function} url The url for this request or a function to call to get the url
8908          * @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}
8909          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8910          * @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.
8911          * @return {Roo.Element} this
8912          */
8913         load : function(){
8914             var um = this.getUpdateManager();
8915             um.update.apply(um, arguments);
8916             return this;
8917         },
8918
8919         /**
8920         * Gets this element's UpdateManager
8921         * @return {Roo.UpdateManager} The UpdateManager
8922         */
8923         getUpdateManager : function(){
8924             if(!this.updateManager){
8925                 this.updateManager = new Roo.UpdateManager(this);
8926             }
8927             return this.updateManager;
8928         },
8929
8930         /**
8931          * Disables text selection for this element (normalized across browsers)
8932          * @return {Roo.Element} this
8933          */
8934         unselectable : function(){
8935             this.dom.unselectable = "on";
8936             this.swallowEvent("selectstart", true);
8937             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8938             this.addClass("x-unselectable");
8939             return this;
8940         },
8941
8942         /**
8943         * Calculates the x, y to center this element on the screen
8944         * @return {Array} The x, y values [x, y]
8945         */
8946         getCenterXY : function(){
8947             return this.getAlignToXY(document, 'c-c');
8948         },
8949
8950         /**
8951         * Centers the Element in either the viewport, or another Element.
8952         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8953         */
8954         center : function(centerIn){
8955             this.alignTo(centerIn || document, 'c-c');
8956             return this;
8957         },
8958
8959         /**
8960          * Tests various css rules/browsers to determine if this element uses a border box
8961          * @return {Boolean}
8962          */
8963         isBorderBox : function(){
8964             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8965         },
8966
8967         /**
8968          * Return a box {x, y, width, height} that can be used to set another elements
8969          * size/location to match this element.
8970          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8971          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8972          * @return {Object} box An object in the format {x, y, width, height}
8973          */
8974         getBox : function(contentBox, local){
8975             var xy;
8976             if(!local){
8977                 xy = this.getXY();
8978             }else{
8979                 var left = parseInt(this.getStyle("left"), 10) || 0;
8980                 var top = parseInt(this.getStyle("top"), 10) || 0;
8981                 xy = [left, top];
8982             }
8983             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8984             if(!contentBox){
8985                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8986             }else{
8987                 var l = this.getBorderWidth("l")+this.getPadding("l");
8988                 var r = this.getBorderWidth("r")+this.getPadding("r");
8989                 var t = this.getBorderWidth("t")+this.getPadding("t");
8990                 var b = this.getBorderWidth("b")+this.getPadding("b");
8991                 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)};
8992             }
8993             bx.right = bx.x + bx.width;
8994             bx.bottom = bx.y + bx.height;
8995             return bx;
8996         },
8997
8998         /**
8999          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9000          for more information about the sides.
9001          * @param {String} sides
9002          * @return {Number}
9003          */
9004         getFrameWidth : function(sides, onlyContentBox){
9005             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9006         },
9007
9008         /**
9009          * 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.
9010          * @param {Object} box The box to fill {x, y, width, height}
9011          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9012          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9013          * @return {Roo.Element} this
9014          */
9015         setBox : function(box, adjust, animate){
9016             var w = box.width, h = box.height;
9017             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9018                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9019                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9020             }
9021             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9022             return this;
9023         },
9024
9025         /**
9026          * Forces the browser to repaint this element
9027          * @return {Roo.Element} this
9028          */
9029          repaint : function(){
9030             var dom = this.dom;
9031             this.addClass("x-repaint");
9032             setTimeout(function(){
9033                 Roo.get(dom).removeClass("x-repaint");
9034             }, 1);
9035             return this;
9036         },
9037
9038         /**
9039          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9040          * then it returns the calculated width of the sides (see getPadding)
9041          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9042          * @return {Object/Number}
9043          */
9044         getMargins : function(side){
9045             if(!side){
9046                 return {
9047                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9048                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9049                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9050                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9051                 };
9052             }else{
9053                 return this.addStyles(side, El.margins);
9054              }
9055         },
9056
9057         // private
9058         addStyles : function(sides, styles){
9059             var val = 0, v, w;
9060             for(var i = 0, len = sides.length; i < len; i++){
9061                 v = this.getStyle(styles[sides.charAt(i)]);
9062                 if(v){
9063                      w = parseInt(v, 10);
9064                      if(w){ val += w; }
9065                 }
9066             }
9067             return val;
9068         },
9069
9070         /**
9071          * Creates a proxy element of this element
9072          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9073          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9074          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9075          * @return {Roo.Element} The new proxy element
9076          */
9077         createProxy : function(config, renderTo, matchBox){
9078             if(renderTo){
9079                 renderTo = Roo.getDom(renderTo);
9080             }else{
9081                 renderTo = document.body;
9082             }
9083             config = typeof config == "object" ?
9084                 config : {tag : "div", cls: config};
9085             var proxy = Roo.DomHelper.append(renderTo, config, true);
9086             if(matchBox){
9087                proxy.setBox(this.getBox());
9088             }
9089             return proxy;
9090         },
9091
9092         /**
9093          * Puts a mask over this element to disable user interaction. Requires core.css.
9094          * This method can only be applied to elements which accept child nodes.
9095          * @param {String} msg (optional) A message to display in the mask
9096          * @param {String} msgCls (optional) A css class to apply to the msg element
9097          * @return {Element} The mask  element
9098          */
9099         mask : function(msg, msgCls)
9100         {
9101             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9102                 this.setStyle("position", "relative");
9103             }
9104             if(!this._mask){
9105                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9106             }
9107             this.addClass("x-masked");
9108             this._mask.setDisplayed(true);
9109             
9110             // we wander
9111             var z = 0;
9112             var dom = this.dom;
9113             while (dom && dom.style) {
9114                 if (!isNaN(parseInt(dom.style.zIndex))) {
9115                     z = Math.max(z, parseInt(dom.style.zIndex));
9116                 }
9117                 dom = dom.parentNode;
9118             }
9119             // if we are masking the body - then it hides everything..
9120             if (this.dom == document.body) {
9121                 z = 1000000;
9122                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9123                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9124             }
9125            
9126             if(typeof msg == 'string'){
9127                 if(!this._maskMsg){
9128                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9129                 }
9130                 var mm = this._maskMsg;
9131                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9132                 if (mm.dom.firstChild) { // weird IE issue?
9133                     mm.dom.firstChild.innerHTML = msg;
9134                 }
9135                 mm.setDisplayed(true);
9136                 mm.center(this);
9137                 mm.setStyle('z-index', z + 102);
9138             }
9139             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9140                 this._mask.setHeight(this.getHeight());
9141             }
9142             this._mask.setStyle('z-index', z + 100);
9143             
9144             return this._mask;
9145         },
9146
9147         /**
9148          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9149          * it is cached for reuse.
9150          */
9151         unmask : function(removeEl){
9152             if(this._mask){
9153                 if(removeEl === true){
9154                     this._mask.remove();
9155                     delete this._mask;
9156                     if(this._maskMsg){
9157                         this._maskMsg.remove();
9158                         delete this._maskMsg;
9159                     }
9160                 }else{
9161                     this._mask.setDisplayed(false);
9162                     if(this._maskMsg){
9163                         this._maskMsg.setDisplayed(false);
9164                     }
9165                 }
9166             }
9167             this.removeClass("x-masked");
9168         },
9169
9170         /**
9171          * Returns true if this element is masked
9172          * @return {Boolean}
9173          */
9174         isMasked : function(){
9175             return this._mask && this._mask.isVisible();
9176         },
9177
9178         /**
9179          * Creates an iframe shim for this element to keep selects and other windowed objects from
9180          * showing through.
9181          * @return {Roo.Element} The new shim element
9182          */
9183         createShim : function(){
9184             var el = document.createElement('iframe');
9185             el.frameBorder = 'no';
9186             el.className = 'roo-shim';
9187             if(Roo.isIE && Roo.isSecure){
9188                 el.src = Roo.SSL_SECURE_URL;
9189             }
9190             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9191             shim.autoBoxAdjust = false;
9192             return shim;
9193         },
9194
9195         /**
9196          * Removes this element from the DOM and deletes it from the cache
9197          */
9198         remove : function(){
9199             if(this.dom.parentNode){
9200                 this.dom.parentNode.removeChild(this.dom);
9201             }
9202             delete El.cache[this.dom.id];
9203         },
9204
9205         /**
9206          * Sets up event handlers to add and remove a css class when the mouse is over this element
9207          * @param {String} className
9208          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9209          * mouseout events for children elements
9210          * @return {Roo.Element} this
9211          */
9212         addClassOnOver : function(className, preventFlicker){
9213             this.on("mouseover", function(){
9214                 Roo.fly(this, '_internal').addClass(className);
9215             }, this.dom);
9216             var removeFn = function(e){
9217                 if(preventFlicker !== true || !e.within(this, true)){
9218                     Roo.fly(this, '_internal').removeClass(className);
9219                 }
9220             };
9221             this.on("mouseout", removeFn, this.dom);
9222             return this;
9223         },
9224
9225         /**
9226          * Sets up event handlers to add and remove a css class when this element has the focus
9227          * @param {String} className
9228          * @return {Roo.Element} this
9229          */
9230         addClassOnFocus : function(className){
9231             this.on("focus", function(){
9232                 Roo.fly(this, '_internal').addClass(className);
9233             }, this.dom);
9234             this.on("blur", function(){
9235                 Roo.fly(this, '_internal').removeClass(className);
9236             }, this.dom);
9237             return this;
9238         },
9239         /**
9240          * 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)
9241          * @param {String} className
9242          * @return {Roo.Element} this
9243          */
9244         addClassOnClick : function(className){
9245             var dom = this.dom;
9246             this.on("mousedown", function(){
9247                 Roo.fly(dom, '_internal').addClass(className);
9248                 var d = Roo.get(document);
9249                 var fn = function(){
9250                     Roo.fly(dom, '_internal').removeClass(className);
9251                     d.removeListener("mouseup", fn);
9252                 };
9253                 d.on("mouseup", fn);
9254             });
9255             return this;
9256         },
9257
9258         /**
9259          * Stops the specified event from bubbling and optionally prevents the default action
9260          * @param {String} eventName
9261          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9262          * @return {Roo.Element} this
9263          */
9264         swallowEvent : function(eventName, preventDefault){
9265             var fn = function(e){
9266                 e.stopPropagation();
9267                 if(preventDefault){
9268                     e.preventDefault();
9269                 }
9270             };
9271             if(eventName instanceof Array){
9272                 for(var i = 0, len = eventName.length; i < len; i++){
9273                      this.on(eventName[i], fn);
9274                 }
9275                 return this;
9276             }
9277             this.on(eventName, fn);
9278             return this;
9279         },
9280
9281         /**
9282          * @private
9283          */
9284       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9285
9286         /**
9287          * Sizes this element to its parent element's dimensions performing
9288          * neccessary box adjustments.
9289          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9290          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9291          * @return {Roo.Element} this
9292          */
9293         fitToParent : function(monitorResize, targetParent) {
9294           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9295           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9296           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9297             return;
9298           }
9299           var p = Roo.get(targetParent || this.dom.parentNode);
9300           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9301           if (monitorResize === true) {
9302             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9303             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9304           }
9305           return this;
9306         },
9307
9308         /**
9309          * Gets the next sibling, skipping text nodes
9310          * @return {HTMLElement} The next sibling or null
9311          */
9312         getNextSibling : function(){
9313             var n = this.dom.nextSibling;
9314             while(n && n.nodeType != 1){
9315                 n = n.nextSibling;
9316             }
9317             return n;
9318         },
9319
9320         /**
9321          * Gets the previous sibling, skipping text nodes
9322          * @return {HTMLElement} The previous sibling or null
9323          */
9324         getPrevSibling : function(){
9325             var n = this.dom.previousSibling;
9326             while(n && n.nodeType != 1){
9327                 n = n.previousSibling;
9328             }
9329             return n;
9330         },
9331
9332
9333         /**
9334          * Appends the passed element(s) to this element
9335          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9336          * @return {Roo.Element} this
9337          */
9338         appendChild: function(el){
9339             el = Roo.get(el);
9340             el.appendTo(this);
9341             return this;
9342         },
9343
9344         /**
9345          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9346          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9347          * automatically generated with the specified attributes.
9348          * @param {HTMLElement} insertBefore (optional) a child element of this element
9349          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9350          * @return {Roo.Element} The new child element
9351          */
9352         createChild: function(config, insertBefore, returnDom){
9353             config = config || {tag:'div'};
9354             if(insertBefore){
9355                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9356             }
9357             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9358         },
9359
9360         /**
9361          * Appends this element to the passed element
9362          * @param {String/HTMLElement/Element} el The new parent element
9363          * @return {Roo.Element} this
9364          */
9365         appendTo: function(el){
9366             el = Roo.getDom(el);
9367             el.appendChild(this.dom);
9368             return this;
9369         },
9370
9371         /**
9372          * Inserts this element before the passed element in the DOM
9373          * @param {String/HTMLElement/Element} el The element to insert before
9374          * @return {Roo.Element} this
9375          */
9376         insertBefore: function(el){
9377             el = Roo.getDom(el);
9378             el.parentNode.insertBefore(this.dom, el);
9379             return this;
9380         },
9381
9382         /**
9383          * Inserts this element after the passed element in the DOM
9384          * @param {String/HTMLElement/Element} el The element to insert after
9385          * @return {Roo.Element} this
9386          */
9387         insertAfter: function(el){
9388             el = Roo.getDom(el);
9389             el.parentNode.insertBefore(this.dom, el.nextSibling);
9390             return this;
9391         },
9392
9393         /**
9394          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9395          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9396          * @return {Roo.Element} The new child
9397          */
9398         insertFirst: function(el, returnDom){
9399             el = el || {};
9400             if(typeof el == 'object' && !el.nodeType){ // dh config
9401                 return this.createChild(el, this.dom.firstChild, returnDom);
9402             }else{
9403                 el = Roo.getDom(el);
9404                 this.dom.insertBefore(el, this.dom.firstChild);
9405                 return !returnDom ? Roo.get(el) : el;
9406             }
9407         },
9408
9409         /**
9410          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9411          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9412          * @param {String} where (optional) 'before' or 'after' defaults to before
9413          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9414          * @return {Roo.Element} the inserted Element
9415          */
9416         insertSibling: function(el, where, returnDom){
9417             where = where ? where.toLowerCase() : 'before';
9418             el = el || {};
9419             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9420
9421             if(typeof el == 'object' && !el.nodeType){ // dh config
9422                 if(where == 'after' && !this.dom.nextSibling){
9423                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9424                 }else{
9425                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9426                 }
9427
9428             }else{
9429                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9430                             where == 'before' ? this.dom : this.dom.nextSibling);
9431                 if(!returnDom){
9432                     rt = Roo.get(rt);
9433                 }
9434             }
9435             return rt;
9436         },
9437
9438         /**
9439          * Creates and wraps this element with another element
9440          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9441          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9442          * @return {HTMLElement/Element} The newly created wrapper element
9443          */
9444         wrap: function(config, returnDom){
9445             if(!config){
9446                 config = {tag: "div"};
9447             }
9448             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9449             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9450             return newEl;
9451         },
9452
9453         /**
9454          * Replaces the passed element with this element
9455          * @param {String/HTMLElement/Element} el The element to replace
9456          * @return {Roo.Element} this
9457          */
9458         replace: function(el){
9459             el = Roo.get(el);
9460             this.insertBefore(el);
9461             el.remove();
9462             return this;
9463         },
9464
9465         /**
9466          * Inserts an html fragment into this element
9467          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9468          * @param {String} html The HTML fragment
9469          * @param {Boolean} returnEl True to return an Roo.Element
9470          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9471          */
9472         insertHtml : function(where, html, returnEl){
9473             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9474             return returnEl ? Roo.get(el) : el;
9475         },
9476
9477         /**
9478          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9479          * @param {Object} o The object with the attributes
9480          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9481          * @return {Roo.Element} this
9482          */
9483         set : function(o, useSet){
9484             var el = this.dom;
9485             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9486             for(var attr in o){
9487                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9488                 if(attr=="cls"){
9489                     el.className = o["cls"];
9490                 }else{
9491                     if(useSet) {
9492                         el.setAttribute(attr, o[attr]);
9493                     } else {
9494                         el[attr] = o[attr];
9495                     }
9496                 }
9497             }
9498             if(o.style){
9499                 Roo.DomHelper.applyStyles(el, o.style);
9500             }
9501             return this;
9502         },
9503
9504         /**
9505          * Convenience method for constructing a KeyMap
9506          * @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:
9507          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9508          * @param {Function} fn The function to call
9509          * @param {Object} scope (optional) The scope of the function
9510          * @return {Roo.KeyMap} The KeyMap created
9511          */
9512         addKeyListener : function(key, fn, scope){
9513             var config;
9514             if(typeof key != "object" || key instanceof Array){
9515                 config = {
9516                     key: key,
9517                     fn: fn,
9518                     scope: scope
9519                 };
9520             }else{
9521                 config = {
9522                     key : key.key,
9523                     shift : key.shift,
9524                     ctrl : key.ctrl,
9525                     alt : key.alt,
9526                     fn: fn,
9527                     scope: scope
9528                 };
9529             }
9530             return new Roo.KeyMap(this, config);
9531         },
9532
9533         /**
9534          * Creates a KeyMap for this element
9535          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9536          * @return {Roo.KeyMap} The KeyMap created
9537          */
9538         addKeyMap : function(config){
9539             return new Roo.KeyMap(this, config);
9540         },
9541
9542         /**
9543          * Returns true if this element is scrollable.
9544          * @return {Boolean}
9545          */
9546          isScrollable : function(){
9547             var dom = this.dom;
9548             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9549         },
9550
9551         /**
9552          * 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().
9553          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9554          * @param {Number} value The new scroll value
9555          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9556          * @return {Element} this
9557          */
9558
9559         scrollTo : function(side, value, animate){
9560             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9561             if(!animate || !A){
9562                 this.dom[prop] = value;
9563             }else{
9564                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9565                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9566             }
9567             return this;
9568         },
9569
9570         /**
9571          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9572          * within this element's scrollable range.
9573          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9574          * @param {Number} distance How far to scroll the element in pixels
9575          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9576          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9577          * was scrolled as far as it could go.
9578          */
9579          scroll : function(direction, distance, animate){
9580              if(!this.isScrollable()){
9581                  return;
9582              }
9583              var el = this.dom;
9584              var l = el.scrollLeft, t = el.scrollTop;
9585              var w = el.scrollWidth, h = el.scrollHeight;
9586              var cw = el.clientWidth, ch = el.clientHeight;
9587              direction = direction.toLowerCase();
9588              var scrolled = false;
9589              var a = this.preanim(arguments, 2);
9590              switch(direction){
9591                  case "l":
9592                  case "left":
9593                      if(w - l > cw){
9594                          var v = Math.min(l + distance, w-cw);
9595                          this.scrollTo("left", v, a);
9596                          scrolled = true;
9597                      }
9598                      break;
9599                 case "r":
9600                 case "right":
9601                      if(l > 0){
9602                          var v = Math.max(l - distance, 0);
9603                          this.scrollTo("left", v, a);
9604                          scrolled = true;
9605                      }
9606                      break;
9607                 case "t":
9608                 case "top":
9609                 case "up":
9610                      if(t > 0){
9611                          var v = Math.max(t - distance, 0);
9612                          this.scrollTo("top", v, a);
9613                          scrolled = true;
9614                      }
9615                      break;
9616                 case "b":
9617                 case "bottom":
9618                 case "down":
9619                      if(h - t > ch){
9620                          var v = Math.min(t + distance, h-ch);
9621                          this.scrollTo("top", v, a);
9622                          scrolled = true;
9623                      }
9624                      break;
9625              }
9626              return scrolled;
9627         },
9628
9629         /**
9630          * Translates the passed page coordinates into left/top css values for this element
9631          * @param {Number/Array} x The page x or an array containing [x, y]
9632          * @param {Number} y The page y
9633          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9634          */
9635         translatePoints : function(x, y){
9636             if(typeof x == 'object' || x instanceof Array){
9637                 y = x[1]; x = x[0];
9638             }
9639             var p = this.getStyle('position');
9640             var o = this.getXY();
9641
9642             var l = parseInt(this.getStyle('left'), 10);
9643             var t = parseInt(this.getStyle('top'), 10);
9644
9645             if(isNaN(l)){
9646                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9647             }
9648             if(isNaN(t)){
9649                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9650             }
9651
9652             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9653         },
9654
9655         /**
9656          * Returns the current scroll position of the element.
9657          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9658          */
9659         getScroll : function(){
9660             var d = this.dom, doc = document;
9661             if(d == doc || d == doc.body){
9662                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9663                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9664                 return {left: l, top: t};
9665             }else{
9666                 return {left: d.scrollLeft, top: d.scrollTop};
9667             }
9668         },
9669
9670         /**
9671          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9672          * are convert to standard 6 digit hex color.
9673          * @param {String} attr The css attribute
9674          * @param {String} defaultValue The default value to use when a valid color isn't found
9675          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9676          * YUI color anims.
9677          */
9678         getColor : function(attr, defaultValue, prefix){
9679             var v = this.getStyle(attr);
9680             if(!v || v == "transparent" || v == "inherit") {
9681                 return defaultValue;
9682             }
9683             var color = typeof prefix == "undefined" ? "#" : prefix;
9684             if(v.substr(0, 4) == "rgb("){
9685                 var rvs = v.slice(4, v.length -1).split(",");
9686                 for(var i = 0; i < 3; i++){
9687                     var h = parseInt(rvs[i]).toString(16);
9688                     if(h < 16){
9689                         h = "0" + h;
9690                     }
9691                     color += h;
9692                 }
9693             } else {
9694                 if(v.substr(0, 1) == "#"){
9695                     if(v.length == 4) {
9696                         for(var i = 1; i < 4; i++){
9697                             var c = v.charAt(i);
9698                             color +=  c + c;
9699                         }
9700                     }else if(v.length == 7){
9701                         color += v.substr(1);
9702                     }
9703                 }
9704             }
9705             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9706         },
9707
9708         /**
9709          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9710          * gradient background, rounded corners and a 4-way shadow.
9711          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9712          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9713          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9714          * @return {Roo.Element} this
9715          */
9716         boxWrap : function(cls){
9717             cls = cls || 'x-box';
9718             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9719             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9720             return el;
9721         },
9722
9723         /**
9724          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9725          * @param {String} namespace The namespace in which to look for the attribute
9726          * @param {String} name The attribute name
9727          * @return {String} The attribute value
9728          */
9729         getAttributeNS : Roo.isIE ? function(ns, name){
9730             var d = this.dom;
9731             var type = typeof d[ns+":"+name];
9732             if(type != 'undefined' && type != 'unknown'){
9733                 return d[ns+":"+name];
9734             }
9735             return d[name];
9736         } : function(ns, name){
9737             var d = this.dom;
9738             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9739         },
9740         
9741         
9742         /**
9743          * Sets or Returns the value the dom attribute value
9744          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9745          * @param {String} value (optional) The value to set the attribute to
9746          * @return {String} The attribute value
9747          */
9748         attr : function(name){
9749             if (arguments.length > 1) {
9750                 this.dom.setAttribute(name, arguments[1]);
9751                 return arguments[1];
9752             }
9753             if (typeof(name) == 'object') {
9754                 for(var i in name) {
9755                     this.attr(i, name[i]);
9756                 }
9757                 return name;
9758             }
9759             
9760             
9761             if (!this.dom.hasAttribute(name)) {
9762                 return undefined;
9763             }
9764             return this.dom.getAttribute(name);
9765         }
9766         
9767         
9768         
9769     };
9770
9771     var ep = El.prototype;
9772
9773     /**
9774      * Appends an event handler (Shorthand for addListener)
9775      * @param {String}   eventName     The type of event to append
9776      * @param {Function} fn        The method the event invokes
9777      * @param {Object} scope       (optional) The scope (this object) of the fn
9778      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9779      * @method
9780      */
9781     ep.on = ep.addListener;
9782         // backwards compat
9783     ep.mon = ep.addListener;
9784
9785     /**
9786      * Removes an event handler from this element (shorthand for removeListener)
9787      * @param {String} eventName the type of event to remove
9788      * @param {Function} fn the method the event invokes
9789      * @return {Roo.Element} this
9790      * @method
9791      */
9792     ep.un = ep.removeListener;
9793
9794     /**
9795      * true to automatically adjust width and height settings for box-model issues (default to true)
9796      */
9797     ep.autoBoxAdjust = true;
9798
9799     // private
9800     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9801
9802     // private
9803     El.addUnits = function(v, defaultUnit){
9804         if(v === "" || v == "auto"){
9805             return v;
9806         }
9807         if(v === undefined){
9808             return '';
9809         }
9810         if(typeof v == "number" || !El.unitPattern.test(v)){
9811             return v + (defaultUnit || 'px');
9812         }
9813         return v;
9814     };
9815
9816     // special markup used throughout Roo when box wrapping elements
9817     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>';
9818     /**
9819      * Visibility mode constant - Use visibility to hide element
9820      * @static
9821      * @type Number
9822      */
9823     El.VISIBILITY = 1;
9824     /**
9825      * Visibility mode constant - Use display to hide element
9826      * @static
9827      * @type Number
9828      */
9829     El.DISPLAY = 2;
9830
9831     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9832     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9833     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9834
9835
9836
9837     /**
9838      * @private
9839      */
9840     El.cache = {};
9841
9842     var docEl;
9843
9844     /**
9845      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9846      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9847      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9848      * @return {Element} The Element object
9849      * @static
9850      */
9851     El.get = function(el){
9852         var ex, elm, id;
9853         if(!el){ return null; }
9854         if(typeof el == "string"){ // element id
9855             if(!(elm = document.getElementById(el))){
9856                 return null;
9857             }
9858             if(ex = El.cache[el]){
9859                 ex.dom = elm;
9860             }else{
9861                 ex = El.cache[el] = new El(elm);
9862             }
9863             return ex;
9864         }else if(el.tagName){ // dom element
9865             if(!(id = el.id)){
9866                 id = Roo.id(el);
9867             }
9868             if(ex = El.cache[id]){
9869                 ex.dom = el;
9870             }else{
9871                 ex = El.cache[id] = new El(el);
9872             }
9873             return ex;
9874         }else if(el instanceof El){
9875             if(el != docEl){
9876                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9877                                                               // catch case where it hasn't been appended
9878                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9879             }
9880             return el;
9881         }else if(el.isComposite){
9882             return el;
9883         }else if(el instanceof Array){
9884             return El.select(el);
9885         }else if(el == document){
9886             // create a bogus element object representing the document object
9887             if(!docEl){
9888                 var f = function(){};
9889                 f.prototype = El.prototype;
9890                 docEl = new f();
9891                 docEl.dom = document;
9892             }
9893             return docEl;
9894         }
9895         return null;
9896     };
9897
9898     // private
9899     El.uncache = function(el){
9900         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9901             if(a[i]){
9902                 delete El.cache[a[i].id || a[i]];
9903             }
9904         }
9905     };
9906
9907     // private
9908     // Garbage collection - uncache elements/purge listeners on orphaned elements
9909     // so we don't hold a reference and cause the browser to retain them
9910     El.garbageCollect = function(){
9911         if(!Roo.enableGarbageCollector){
9912             clearInterval(El.collectorThread);
9913             return;
9914         }
9915         for(var eid in El.cache){
9916             var el = El.cache[eid], d = el.dom;
9917             // -------------------------------------------------------
9918             // Determining what is garbage:
9919             // -------------------------------------------------------
9920             // !d
9921             // dom node is null, definitely garbage
9922             // -------------------------------------------------------
9923             // !d.parentNode
9924             // no parentNode == direct orphan, definitely garbage
9925             // -------------------------------------------------------
9926             // !d.offsetParent && !document.getElementById(eid)
9927             // display none elements have no offsetParent so we will
9928             // also try to look it up by it's id. However, check
9929             // offsetParent first so we don't do unneeded lookups.
9930             // This enables collection of elements that are not orphans
9931             // directly, but somewhere up the line they have an orphan
9932             // parent.
9933             // -------------------------------------------------------
9934             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9935                 delete El.cache[eid];
9936                 if(d && Roo.enableListenerCollection){
9937                     E.purgeElement(d);
9938                 }
9939             }
9940         }
9941     }
9942     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9943
9944
9945     // dom is optional
9946     El.Flyweight = function(dom){
9947         this.dom = dom;
9948     };
9949     El.Flyweight.prototype = El.prototype;
9950
9951     El._flyweights = {};
9952     /**
9953      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9954      * the dom node can be overwritten by other code.
9955      * @param {String/HTMLElement} el The dom node or id
9956      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9957      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9958      * @static
9959      * @return {Element} The shared Element object
9960      */
9961     El.fly = function(el, named){
9962         named = named || '_global';
9963         el = Roo.getDom(el);
9964         if(!el){
9965             return null;
9966         }
9967         if(!El._flyweights[named]){
9968             El._flyweights[named] = new El.Flyweight();
9969         }
9970         El._flyweights[named].dom = el;
9971         return El._flyweights[named];
9972     };
9973
9974     /**
9975      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9976      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9977      * Shorthand of {@link Roo.Element#get}
9978      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9979      * @return {Element} The Element object
9980      * @member Roo
9981      * @method get
9982      */
9983     Roo.get = El.get;
9984     /**
9985      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9986      * the dom node can be overwritten by other code.
9987      * Shorthand of {@link Roo.Element#fly}
9988      * @param {String/HTMLElement} el The dom node or id
9989      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9990      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9991      * @static
9992      * @return {Element} The shared Element object
9993      * @member Roo
9994      * @method fly
9995      */
9996     Roo.fly = El.fly;
9997
9998     // speedy lookup for elements never to box adjust
9999     var noBoxAdjust = Roo.isStrict ? {
10000         select:1
10001     } : {
10002         input:1, select:1, textarea:1
10003     };
10004     if(Roo.isIE || Roo.isGecko){
10005         noBoxAdjust['button'] = 1;
10006     }
10007
10008
10009     Roo.EventManager.on(window, 'unload', function(){
10010         delete El.cache;
10011         delete El._flyweights;
10012     });
10013 })();
10014
10015
10016
10017
10018 if(Roo.DomQuery){
10019     Roo.Element.selectorFunction = Roo.DomQuery.select;
10020 }
10021
10022 Roo.Element.select = function(selector, unique, root){
10023     var els;
10024     if(typeof selector == "string"){
10025         els = Roo.Element.selectorFunction(selector, root);
10026     }else if(selector.length !== undefined){
10027         els = selector;
10028     }else{
10029         throw "Invalid selector";
10030     }
10031     if(unique === true){
10032         return new Roo.CompositeElement(els);
10033     }else{
10034         return new Roo.CompositeElementLite(els);
10035     }
10036 };
10037 /**
10038  * Selects elements based on the passed CSS selector to enable working on them as 1.
10039  * @param {String/Array} selector The CSS selector or an array of elements
10040  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10041  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10042  * @return {CompositeElementLite/CompositeElement}
10043  * @member Roo
10044  * @method select
10045  */
10046 Roo.select = Roo.Element.select;
10047
10048
10049
10050
10051
10052
10053
10054
10055
10056
10057
10058
10059
10060
10061 /*
10062  * Based on:
10063  * Ext JS Library 1.1.1
10064  * Copyright(c) 2006-2007, Ext JS, LLC.
10065  *
10066  * Originally Released Under LGPL - original licence link has changed is not relivant.
10067  *
10068  * Fork - LGPL
10069  * <script type="text/javascript">
10070  */
10071
10072
10073
10074 //Notifies Element that fx methods are available
10075 Roo.enableFx = true;
10076
10077 /**
10078  * @class Roo.Fx
10079  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10080  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10081  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10082  * Element effects to work.</p><br/>
10083  *
10084  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10085  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10086  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10087  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10088  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10089  * expected results and should be done with care.</p><br/>
10090  *
10091  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10092  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10093 <pre>
10094 Value  Description
10095 -----  -----------------------------
10096 tl     The top left corner
10097 t      The center of the top edge
10098 tr     The top right corner
10099 l      The center of the left edge
10100 r      The center of the right edge
10101 bl     The bottom left corner
10102 b      The center of the bottom edge
10103 br     The bottom right corner
10104 </pre>
10105  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10106  * below are common options that can be passed to any Fx method.</b>
10107  * @cfg {Function} callback A function called when the effect is finished
10108  * @cfg {Object} scope The scope of the effect function
10109  * @cfg {String} easing A valid Easing value for the effect
10110  * @cfg {String} afterCls A css class to apply after the effect
10111  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10112  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10113  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10114  * effects that end with the element being visually hidden, ignored otherwise)
10115  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10116  * a function which returns such a specification that will be applied to the Element after the effect finishes
10117  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10118  * @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
10119  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10120  */
10121 Roo.Fx = {
10122         /**
10123          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10124          * origin for the slide effect.  This function automatically handles wrapping the element with
10125          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10126          * Usage:
10127          *<pre><code>
10128 // default: slide the element in from the top
10129 el.slideIn();
10130
10131 // custom: slide the element in from the right with a 2-second duration
10132 el.slideIn('r', { duration: 2 });
10133
10134 // common config options shown with default values
10135 el.slideIn('t', {
10136     easing: 'easeOut',
10137     duration: .5
10138 });
10139 </code></pre>
10140          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10141          * @param {Object} options (optional) Object literal with any of the Fx config options
10142          * @return {Roo.Element} The Element
10143          */
10144     slideIn : function(anchor, o){
10145         var el = this.getFxEl();
10146         o = o || {};
10147
10148         el.queueFx(o, function(){
10149
10150             anchor = anchor || "t";
10151
10152             // fix display to visibility
10153             this.fixDisplay();
10154
10155             // restore values after effect
10156             var r = this.getFxRestore();
10157             var b = this.getBox();
10158             // fixed size for slide
10159             this.setSize(b);
10160
10161             // wrap if needed
10162             var wrap = this.fxWrap(r.pos, o, "hidden");
10163
10164             var st = this.dom.style;
10165             st.visibility = "visible";
10166             st.position = "absolute";
10167
10168             // clear out temp styles after slide and unwrap
10169             var after = function(){
10170                 el.fxUnwrap(wrap, r.pos, o);
10171                 st.width = r.width;
10172                 st.height = r.height;
10173                 el.afterFx(o);
10174             };
10175             // time to calc the positions
10176             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10177
10178             switch(anchor.toLowerCase()){
10179                 case "t":
10180                     wrap.setSize(b.width, 0);
10181                     st.left = st.bottom = "0";
10182                     a = {height: bh};
10183                 break;
10184                 case "l":
10185                     wrap.setSize(0, b.height);
10186                     st.right = st.top = "0";
10187                     a = {width: bw};
10188                 break;
10189                 case "r":
10190                     wrap.setSize(0, b.height);
10191                     wrap.setX(b.right);
10192                     st.left = st.top = "0";
10193                     a = {width: bw, points: pt};
10194                 break;
10195                 case "b":
10196                     wrap.setSize(b.width, 0);
10197                     wrap.setY(b.bottom);
10198                     st.left = st.top = "0";
10199                     a = {height: bh, points: pt};
10200                 break;
10201                 case "tl":
10202                     wrap.setSize(0, 0);
10203                     st.right = st.bottom = "0";
10204                     a = {width: bw, height: bh};
10205                 break;
10206                 case "bl":
10207                     wrap.setSize(0, 0);
10208                     wrap.setY(b.y+b.height);
10209                     st.right = st.top = "0";
10210                     a = {width: bw, height: bh, points: pt};
10211                 break;
10212                 case "br":
10213                     wrap.setSize(0, 0);
10214                     wrap.setXY([b.right, b.bottom]);
10215                     st.left = st.top = "0";
10216                     a = {width: bw, height: bh, points: pt};
10217                 break;
10218                 case "tr":
10219                     wrap.setSize(0, 0);
10220                     wrap.setX(b.x+b.width);
10221                     st.left = st.bottom = "0";
10222                     a = {width: bw, height: bh, points: pt};
10223                 break;
10224             }
10225             this.dom.style.visibility = "visible";
10226             wrap.show();
10227
10228             arguments.callee.anim = wrap.fxanim(a,
10229                 o,
10230                 'motion',
10231                 .5,
10232                 'easeOut', after);
10233         });
10234         return this;
10235     },
10236     
10237         /**
10238          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10239          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10240          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10241          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10242          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10243          * Usage:
10244          *<pre><code>
10245 // default: slide the element out to the top
10246 el.slideOut();
10247
10248 // custom: slide the element out to the right with a 2-second duration
10249 el.slideOut('r', { duration: 2 });
10250
10251 // common config options shown with default values
10252 el.slideOut('t', {
10253     easing: 'easeOut',
10254     duration: .5,
10255     remove: false,
10256     useDisplay: false
10257 });
10258 </code></pre>
10259          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10260          * @param {Object} options (optional) Object literal with any of the Fx config options
10261          * @return {Roo.Element} The Element
10262          */
10263     slideOut : function(anchor, o){
10264         var el = this.getFxEl();
10265         o = o || {};
10266
10267         el.queueFx(o, function(){
10268
10269             anchor = anchor || "t";
10270
10271             // restore values after effect
10272             var r = this.getFxRestore();
10273             
10274             var b = this.getBox();
10275             // fixed size for slide
10276             this.setSize(b);
10277
10278             // wrap if needed
10279             var wrap = this.fxWrap(r.pos, o, "visible");
10280
10281             var st = this.dom.style;
10282             st.visibility = "visible";
10283             st.position = "absolute";
10284
10285             wrap.setSize(b);
10286
10287             var after = function(){
10288                 if(o.useDisplay){
10289                     el.setDisplayed(false);
10290                 }else{
10291                     el.hide();
10292                 }
10293
10294                 el.fxUnwrap(wrap, r.pos, o);
10295
10296                 st.width = r.width;
10297                 st.height = r.height;
10298
10299                 el.afterFx(o);
10300             };
10301
10302             var a, zero = {to: 0};
10303             switch(anchor.toLowerCase()){
10304                 case "t":
10305                     st.left = st.bottom = "0";
10306                     a = {height: zero};
10307                 break;
10308                 case "l":
10309                     st.right = st.top = "0";
10310                     a = {width: zero};
10311                 break;
10312                 case "r":
10313                     st.left = st.top = "0";
10314                     a = {width: zero, points: {to:[b.right, b.y]}};
10315                 break;
10316                 case "b":
10317                     st.left = st.top = "0";
10318                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10319                 break;
10320                 case "tl":
10321                     st.right = st.bottom = "0";
10322                     a = {width: zero, height: zero};
10323                 break;
10324                 case "bl":
10325                     st.right = st.top = "0";
10326                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10327                 break;
10328                 case "br":
10329                     st.left = st.top = "0";
10330                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10331                 break;
10332                 case "tr":
10333                     st.left = st.bottom = "0";
10334                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10335                 break;
10336             }
10337
10338             arguments.callee.anim = wrap.fxanim(a,
10339                 o,
10340                 'motion',
10341                 .5,
10342                 "easeOut", after);
10343         });
10344         return this;
10345     },
10346
10347         /**
10348          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10349          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10350          * The element must be removed from the DOM using the 'remove' config option if desired.
10351          * Usage:
10352          *<pre><code>
10353 // default
10354 el.puff();
10355
10356 // common config options shown with default values
10357 el.puff({
10358     easing: 'easeOut',
10359     duration: .5,
10360     remove: false,
10361     useDisplay: false
10362 });
10363 </code></pre>
10364          * @param {Object} options (optional) Object literal with any of the Fx config options
10365          * @return {Roo.Element} The Element
10366          */
10367     puff : function(o){
10368         var el = this.getFxEl();
10369         o = o || {};
10370
10371         el.queueFx(o, function(){
10372             this.clearOpacity();
10373             this.show();
10374
10375             // restore values after effect
10376             var r = this.getFxRestore();
10377             var st = this.dom.style;
10378
10379             var after = function(){
10380                 if(o.useDisplay){
10381                     el.setDisplayed(false);
10382                 }else{
10383                     el.hide();
10384                 }
10385
10386                 el.clearOpacity();
10387
10388                 el.setPositioning(r.pos);
10389                 st.width = r.width;
10390                 st.height = r.height;
10391                 st.fontSize = '';
10392                 el.afterFx(o);
10393             };
10394
10395             var width = this.getWidth();
10396             var height = this.getHeight();
10397
10398             arguments.callee.anim = this.fxanim({
10399                     width : {to: this.adjustWidth(width * 2)},
10400                     height : {to: this.adjustHeight(height * 2)},
10401                     points : {by: [-(width * .5), -(height * .5)]},
10402                     opacity : {to: 0},
10403                     fontSize: {to:200, unit: "%"}
10404                 },
10405                 o,
10406                 'motion',
10407                 .5,
10408                 "easeOut", after);
10409         });
10410         return this;
10411     },
10412
10413         /**
10414          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10415          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10416          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10417          * Usage:
10418          *<pre><code>
10419 // default
10420 el.switchOff();
10421
10422 // all config options shown with default values
10423 el.switchOff({
10424     easing: 'easeIn',
10425     duration: .3,
10426     remove: false,
10427     useDisplay: false
10428 });
10429 </code></pre>
10430          * @param {Object} options (optional) Object literal with any of the Fx config options
10431          * @return {Roo.Element} The Element
10432          */
10433     switchOff : function(o){
10434         var el = this.getFxEl();
10435         o = o || {};
10436
10437         el.queueFx(o, function(){
10438             this.clearOpacity();
10439             this.clip();
10440
10441             // restore values after effect
10442             var r = this.getFxRestore();
10443             var st = this.dom.style;
10444
10445             var after = function(){
10446                 if(o.useDisplay){
10447                     el.setDisplayed(false);
10448                 }else{
10449                     el.hide();
10450                 }
10451
10452                 el.clearOpacity();
10453                 el.setPositioning(r.pos);
10454                 st.width = r.width;
10455                 st.height = r.height;
10456
10457                 el.afterFx(o);
10458             };
10459
10460             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10461                 this.clearOpacity();
10462                 (function(){
10463                     this.fxanim({
10464                         height:{to:1},
10465                         points:{by:[0, this.getHeight() * .5]}
10466                     }, o, 'motion', 0.3, 'easeIn', after);
10467                 }).defer(100, this);
10468             });
10469         });
10470         return this;
10471     },
10472
10473     /**
10474      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10475      * changed using the "attr" config option) and then fading back to the original color. If no original
10476      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10477      * Usage:
10478 <pre><code>
10479 // default: highlight background to yellow
10480 el.highlight();
10481
10482 // custom: highlight foreground text to blue for 2 seconds
10483 el.highlight("0000ff", { attr: 'color', duration: 2 });
10484
10485 // common config options shown with default values
10486 el.highlight("ffff9c", {
10487     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10488     endColor: (current color) or "ffffff",
10489     easing: 'easeIn',
10490     duration: 1
10491 });
10492 </code></pre>
10493      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10494      * @param {Object} options (optional) Object literal with any of the Fx config options
10495      * @return {Roo.Element} The Element
10496      */ 
10497     highlight : function(color, o){
10498         var el = this.getFxEl();
10499         o = o || {};
10500
10501         el.queueFx(o, function(){
10502             color = color || "ffff9c";
10503             attr = o.attr || "backgroundColor";
10504
10505             this.clearOpacity();
10506             this.show();
10507
10508             var origColor = this.getColor(attr);
10509             var restoreColor = this.dom.style[attr];
10510             endColor = (o.endColor || origColor) || "ffffff";
10511
10512             var after = function(){
10513                 el.dom.style[attr] = restoreColor;
10514                 el.afterFx(o);
10515             };
10516
10517             var a = {};
10518             a[attr] = {from: color, to: endColor};
10519             arguments.callee.anim = this.fxanim(a,
10520                 o,
10521                 'color',
10522                 1,
10523                 'easeIn', after);
10524         });
10525         return this;
10526     },
10527
10528    /**
10529     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10530     * Usage:
10531 <pre><code>
10532 // default: a single light blue ripple
10533 el.frame();
10534
10535 // custom: 3 red ripples lasting 3 seconds total
10536 el.frame("ff0000", 3, { duration: 3 });
10537
10538 // common config options shown with default values
10539 el.frame("C3DAF9", 1, {
10540     duration: 1 //duration of entire animation (not each individual ripple)
10541     // Note: Easing is not configurable and will be ignored if included
10542 });
10543 </code></pre>
10544     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10545     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10546     * @param {Object} options (optional) Object literal with any of the Fx config options
10547     * @return {Roo.Element} The Element
10548     */
10549     frame : function(color, count, o){
10550         var el = this.getFxEl();
10551         o = o || {};
10552
10553         el.queueFx(o, function(){
10554             color = color || "#C3DAF9";
10555             if(color.length == 6){
10556                 color = "#" + color;
10557             }
10558             count = count || 1;
10559             duration = o.duration || 1;
10560             this.show();
10561
10562             var b = this.getBox();
10563             var animFn = function(){
10564                 var proxy = this.createProxy({
10565
10566                      style:{
10567                         visbility:"hidden",
10568                         position:"absolute",
10569                         "z-index":"35000", // yee haw
10570                         border:"0px solid " + color
10571                      }
10572                   });
10573                 var scale = Roo.isBorderBox ? 2 : 1;
10574                 proxy.animate({
10575                     top:{from:b.y, to:b.y - 20},
10576                     left:{from:b.x, to:b.x - 20},
10577                     borderWidth:{from:0, to:10},
10578                     opacity:{from:1, to:0},
10579                     height:{from:b.height, to:(b.height + (20*scale))},
10580                     width:{from:b.width, to:(b.width + (20*scale))}
10581                 }, duration, function(){
10582                     proxy.remove();
10583                 });
10584                 if(--count > 0){
10585                      animFn.defer((duration/2)*1000, this);
10586                 }else{
10587                     el.afterFx(o);
10588                 }
10589             };
10590             animFn.call(this);
10591         });
10592         return this;
10593     },
10594
10595    /**
10596     * Creates a pause before any subsequent queued effects begin.  If there are
10597     * no effects queued after the pause it will have no effect.
10598     * Usage:
10599 <pre><code>
10600 el.pause(1);
10601 </code></pre>
10602     * @param {Number} seconds The length of time to pause (in seconds)
10603     * @return {Roo.Element} The Element
10604     */
10605     pause : function(seconds){
10606         var el = this.getFxEl();
10607         var o = {};
10608
10609         el.queueFx(o, function(){
10610             setTimeout(function(){
10611                 el.afterFx(o);
10612             }, seconds * 1000);
10613         });
10614         return this;
10615     },
10616
10617    /**
10618     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10619     * using the "endOpacity" config option.
10620     * Usage:
10621 <pre><code>
10622 // default: fade in from opacity 0 to 100%
10623 el.fadeIn();
10624
10625 // custom: fade in from opacity 0 to 75% over 2 seconds
10626 el.fadeIn({ endOpacity: .75, duration: 2});
10627
10628 // common config options shown with default values
10629 el.fadeIn({
10630     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10631     easing: 'easeOut',
10632     duration: .5
10633 });
10634 </code></pre>
10635     * @param {Object} options (optional) Object literal with any of the Fx config options
10636     * @return {Roo.Element} The Element
10637     */
10638     fadeIn : function(o){
10639         var el = this.getFxEl();
10640         o = o || {};
10641         el.queueFx(o, function(){
10642             this.setOpacity(0);
10643             this.fixDisplay();
10644             this.dom.style.visibility = 'visible';
10645             var to = o.endOpacity || 1;
10646             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10647                 o, null, .5, "easeOut", function(){
10648                 if(to == 1){
10649                     this.clearOpacity();
10650                 }
10651                 el.afterFx(o);
10652             });
10653         });
10654         return this;
10655     },
10656
10657    /**
10658     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10659     * using the "endOpacity" config option.
10660     * Usage:
10661 <pre><code>
10662 // default: fade out from the element's current opacity to 0
10663 el.fadeOut();
10664
10665 // custom: fade out from the element's current opacity to 25% over 2 seconds
10666 el.fadeOut({ endOpacity: .25, duration: 2});
10667
10668 // common config options shown with default values
10669 el.fadeOut({
10670     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10671     easing: 'easeOut',
10672     duration: .5
10673     remove: false,
10674     useDisplay: false
10675 });
10676 </code></pre>
10677     * @param {Object} options (optional) Object literal with any of the Fx config options
10678     * @return {Roo.Element} The Element
10679     */
10680     fadeOut : function(o){
10681         var el = this.getFxEl();
10682         o = o || {};
10683         el.queueFx(o, function(){
10684             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10685                 o, null, .5, "easeOut", function(){
10686                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10687                      this.dom.style.display = "none";
10688                 }else{
10689                      this.dom.style.visibility = "hidden";
10690                 }
10691                 this.clearOpacity();
10692                 el.afterFx(o);
10693             });
10694         });
10695         return this;
10696     },
10697
10698    /**
10699     * Animates the transition of an element's dimensions from a starting height/width
10700     * to an ending height/width.
10701     * Usage:
10702 <pre><code>
10703 // change height and width to 100x100 pixels
10704 el.scale(100, 100);
10705
10706 // common config options shown with default values.  The height and width will default to
10707 // the element's existing values if passed as null.
10708 el.scale(
10709     [element's width],
10710     [element's height], {
10711     easing: 'easeOut',
10712     duration: .35
10713 });
10714 </code></pre>
10715     * @param {Number} width  The new width (pass undefined to keep the original width)
10716     * @param {Number} height  The new height (pass undefined to keep the original height)
10717     * @param {Object} options (optional) Object literal with any of the Fx config options
10718     * @return {Roo.Element} The Element
10719     */
10720     scale : function(w, h, o){
10721         this.shift(Roo.apply({}, o, {
10722             width: w,
10723             height: h
10724         }));
10725         return this;
10726     },
10727
10728    /**
10729     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10730     * Any of these properties not specified in the config object will not be changed.  This effect 
10731     * requires that at least one new dimension, position or opacity setting must be passed in on
10732     * the config object in order for the function to have any effect.
10733     * Usage:
10734 <pre><code>
10735 // slide the element horizontally to x position 200 while changing the height and opacity
10736 el.shift({ x: 200, height: 50, opacity: .8 });
10737
10738 // common config options shown with default values.
10739 el.shift({
10740     width: [element's width],
10741     height: [element's height],
10742     x: [element's x position],
10743     y: [element's y position],
10744     opacity: [element's opacity],
10745     easing: 'easeOut',
10746     duration: .35
10747 });
10748 </code></pre>
10749     * @param {Object} options  Object literal with any of the Fx config options
10750     * @return {Roo.Element} The Element
10751     */
10752     shift : function(o){
10753         var el = this.getFxEl();
10754         o = o || {};
10755         el.queueFx(o, function(){
10756             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10757             if(w !== undefined){
10758                 a.width = {to: this.adjustWidth(w)};
10759             }
10760             if(h !== undefined){
10761                 a.height = {to: this.adjustHeight(h)};
10762             }
10763             if(x !== undefined || y !== undefined){
10764                 a.points = {to: [
10765                     x !== undefined ? x : this.getX(),
10766                     y !== undefined ? y : this.getY()
10767                 ]};
10768             }
10769             if(op !== undefined){
10770                 a.opacity = {to: op};
10771             }
10772             if(o.xy !== undefined){
10773                 a.points = {to: o.xy};
10774             }
10775             arguments.callee.anim = this.fxanim(a,
10776                 o, 'motion', .35, "easeOut", function(){
10777                 el.afterFx(o);
10778             });
10779         });
10780         return this;
10781     },
10782
10783         /**
10784          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10785          * ending point of the effect.
10786          * Usage:
10787          *<pre><code>
10788 // default: slide the element downward while fading out
10789 el.ghost();
10790
10791 // custom: slide the element out to the right with a 2-second duration
10792 el.ghost('r', { duration: 2 });
10793
10794 // common config options shown with default values
10795 el.ghost('b', {
10796     easing: 'easeOut',
10797     duration: .5
10798     remove: false,
10799     useDisplay: false
10800 });
10801 </code></pre>
10802          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10803          * @param {Object} options (optional) Object literal with any of the Fx config options
10804          * @return {Roo.Element} The Element
10805          */
10806     ghost : function(anchor, o){
10807         var el = this.getFxEl();
10808         o = o || {};
10809
10810         el.queueFx(o, function(){
10811             anchor = anchor || "b";
10812
10813             // restore values after effect
10814             var r = this.getFxRestore();
10815             var w = this.getWidth(),
10816                 h = this.getHeight();
10817
10818             var st = this.dom.style;
10819
10820             var after = function(){
10821                 if(o.useDisplay){
10822                     el.setDisplayed(false);
10823                 }else{
10824                     el.hide();
10825                 }
10826
10827                 el.clearOpacity();
10828                 el.setPositioning(r.pos);
10829                 st.width = r.width;
10830                 st.height = r.height;
10831
10832                 el.afterFx(o);
10833             };
10834
10835             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10836             switch(anchor.toLowerCase()){
10837                 case "t":
10838                     pt.by = [0, -h];
10839                 break;
10840                 case "l":
10841                     pt.by = [-w, 0];
10842                 break;
10843                 case "r":
10844                     pt.by = [w, 0];
10845                 break;
10846                 case "b":
10847                     pt.by = [0, h];
10848                 break;
10849                 case "tl":
10850                     pt.by = [-w, -h];
10851                 break;
10852                 case "bl":
10853                     pt.by = [-w, h];
10854                 break;
10855                 case "br":
10856                     pt.by = [w, h];
10857                 break;
10858                 case "tr":
10859                     pt.by = [w, -h];
10860                 break;
10861             }
10862
10863             arguments.callee.anim = this.fxanim(a,
10864                 o,
10865                 'motion',
10866                 .5,
10867                 "easeOut", after);
10868         });
10869         return this;
10870     },
10871
10872         /**
10873          * Ensures that all effects queued after syncFx is called on the element are
10874          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10875          * @return {Roo.Element} The Element
10876          */
10877     syncFx : function(){
10878         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10879             block : false,
10880             concurrent : true,
10881             stopFx : false
10882         });
10883         return this;
10884     },
10885
10886         /**
10887          * Ensures that all effects queued after sequenceFx is called on the element are
10888          * run in sequence.  This is the opposite of {@link #syncFx}.
10889          * @return {Roo.Element} The Element
10890          */
10891     sequenceFx : function(){
10892         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10893             block : false,
10894             concurrent : false,
10895             stopFx : false
10896         });
10897         return this;
10898     },
10899
10900         /* @private */
10901     nextFx : function(){
10902         var ef = this.fxQueue[0];
10903         if(ef){
10904             ef.call(this);
10905         }
10906     },
10907
10908         /**
10909          * Returns true if the element has any effects actively running or queued, else returns false.
10910          * @return {Boolean} True if element has active effects, else false
10911          */
10912     hasActiveFx : function(){
10913         return this.fxQueue && this.fxQueue[0];
10914     },
10915
10916         /**
10917          * Stops any running effects and clears the element's internal effects queue if it contains
10918          * any additional effects that haven't started yet.
10919          * @return {Roo.Element} The Element
10920          */
10921     stopFx : function(){
10922         if(this.hasActiveFx()){
10923             var cur = this.fxQueue[0];
10924             if(cur && cur.anim && cur.anim.isAnimated()){
10925                 this.fxQueue = [cur]; // clear out others
10926                 cur.anim.stop(true);
10927             }
10928         }
10929         return this;
10930     },
10931
10932         /* @private */
10933     beforeFx : function(o){
10934         if(this.hasActiveFx() && !o.concurrent){
10935            if(o.stopFx){
10936                this.stopFx();
10937                return true;
10938            }
10939            return false;
10940         }
10941         return true;
10942     },
10943
10944         /**
10945          * Returns true if the element is currently blocking so that no other effect can be queued
10946          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10947          * used to ensure that an effect initiated by a user action runs to completion prior to the
10948          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10949          * @return {Boolean} True if blocking, else false
10950          */
10951     hasFxBlock : function(){
10952         var q = this.fxQueue;
10953         return q && q[0] && q[0].block;
10954     },
10955
10956         /* @private */
10957     queueFx : function(o, fn){
10958         if(!this.fxQueue){
10959             this.fxQueue = [];
10960         }
10961         if(!this.hasFxBlock()){
10962             Roo.applyIf(o, this.fxDefaults);
10963             if(!o.concurrent){
10964                 var run = this.beforeFx(o);
10965                 fn.block = o.block;
10966                 this.fxQueue.push(fn);
10967                 if(run){
10968                     this.nextFx();
10969                 }
10970             }else{
10971                 fn.call(this);
10972             }
10973         }
10974         return this;
10975     },
10976
10977         /* @private */
10978     fxWrap : function(pos, o, vis){
10979         var wrap;
10980         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10981             var wrapXY;
10982             if(o.fixPosition){
10983                 wrapXY = this.getXY();
10984             }
10985             var div = document.createElement("div");
10986             div.style.visibility = vis;
10987             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10988             wrap.setPositioning(pos);
10989             if(wrap.getStyle("position") == "static"){
10990                 wrap.position("relative");
10991             }
10992             this.clearPositioning('auto');
10993             wrap.clip();
10994             wrap.dom.appendChild(this.dom);
10995             if(wrapXY){
10996                 wrap.setXY(wrapXY);
10997             }
10998         }
10999         return wrap;
11000     },
11001
11002         /* @private */
11003     fxUnwrap : function(wrap, pos, o){
11004         this.clearPositioning();
11005         this.setPositioning(pos);
11006         if(!o.wrap){
11007             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11008             wrap.remove();
11009         }
11010     },
11011
11012         /* @private */
11013     getFxRestore : function(){
11014         var st = this.dom.style;
11015         return {pos: this.getPositioning(), width: st.width, height : st.height};
11016     },
11017
11018         /* @private */
11019     afterFx : function(o){
11020         if(o.afterStyle){
11021             this.applyStyles(o.afterStyle);
11022         }
11023         if(o.afterCls){
11024             this.addClass(o.afterCls);
11025         }
11026         if(o.remove === true){
11027             this.remove();
11028         }
11029         Roo.callback(o.callback, o.scope, [this]);
11030         if(!o.concurrent){
11031             this.fxQueue.shift();
11032             this.nextFx();
11033         }
11034     },
11035
11036         /* @private */
11037     getFxEl : function(){ // support for composite element fx
11038         return Roo.get(this.dom);
11039     },
11040
11041         /* @private */
11042     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11043         animType = animType || 'run';
11044         opt = opt || {};
11045         var anim = Roo.lib.Anim[animType](
11046             this.dom, args,
11047             (opt.duration || defaultDur) || .35,
11048             (opt.easing || defaultEase) || 'easeOut',
11049             function(){
11050                 Roo.callback(cb, this);
11051             },
11052             this
11053         );
11054         opt.anim = anim;
11055         return anim;
11056     }
11057 };
11058
11059 // backwords compat
11060 Roo.Fx.resize = Roo.Fx.scale;
11061
11062 //When included, Roo.Fx is automatically applied to Element so that all basic
11063 //effects are available directly via the Element API
11064 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11065  * Based on:
11066  * Ext JS Library 1.1.1
11067  * Copyright(c) 2006-2007, Ext JS, LLC.
11068  *
11069  * Originally Released Under LGPL - original licence link has changed is not relivant.
11070  *
11071  * Fork - LGPL
11072  * <script type="text/javascript">
11073  */
11074
11075
11076 /**
11077  * @class Roo.CompositeElement
11078  * Standard composite class. Creates a Roo.Element for every element in the collection.
11079  * <br><br>
11080  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11081  * actions will be performed on all the elements in this collection.</b>
11082  * <br><br>
11083  * All methods return <i>this</i> and can be chained.
11084  <pre><code>
11085  var els = Roo.select("#some-el div.some-class", true);
11086  // or select directly from an existing element
11087  var el = Roo.get('some-el');
11088  el.select('div.some-class', true);
11089
11090  els.setWidth(100); // all elements become 100 width
11091  els.hide(true); // all elements fade out and hide
11092  // or
11093  els.setWidth(100).hide(true);
11094  </code></pre>
11095  */
11096 Roo.CompositeElement = function(els){
11097     this.elements = [];
11098     this.addElements(els);
11099 };
11100 Roo.CompositeElement.prototype = {
11101     isComposite: true,
11102     addElements : function(els){
11103         if(!els) {
11104             return this;
11105         }
11106         if(typeof els == "string"){
11107             els = Roo.Element.selectorFunction(els);
11108         }
11109         var yels = this.elements;
11110         var index = yels.length-1;
11111         for(var i = 0, len = els.length; i < len; i++) {
11112                 yels[++index] = Roo.get(els[i]);
11113         }
11114         return this;
11115     },
11116
11117     /**
11118     * Clears this composite and adds the elements returned by the passed selector.
11119     * @param {String/Array} els A string CSS selector, an array of elements or an element
11120     * @return {CompositeElement} this
11121     */
11122     fill : function(els){
11123         this.elements = [];
11124         this.add(els);
11125         return this;
11126     },
11127
11128     /**
11129     * Filters this composite to only elements that match the passed selector.
11130     * @param {String} selector A string CSS selector
11131     * @param {Boolean} inverse return inverse filter (not matches)
11132     * @return {CompositeElement} this
11133     */
11134     filter : function(selector, inverse){
11135         var els = [];
11136         inverse = inverse || false;
11137         this.each(function(el){
11138             var match = inverse ? !el.is(selector) : el.is(selector);
11139             if(match){
11140                 els[els.length] = el.dom;
11141             }
11142         });
11143         this.fill(els);
11144         return this;
11145     },
11146
11147     invoke : function(fn, args){
11148         var els = this.elements;
11149         for(var i = 0, len = els.length; i < len; i++) {
11150                 Roo.Element.prototype[fn].apply(els[i], args);
11151         }
11152         return this;
11153     },
11154     /**
11155     * Adds elements to this composite.
11156     * @param {String/Array} els A string CSS selector, an array of elements or an element
11157     * @return {CompositeElement} this
11158     */
11159     add : function(els){
11160         if(typeof els == "string"){
11161             this.addElements(Roo.Element.selectorFunction(els));
11162         }else if(els.length !== undefined){
11163             this.addElements(els);
11164         }else{
11165             this.addElements([els]);
11166         }
11167         return this;
11168     },
11169     /**
11170     * Calls the passed function passing (el, this, index) for each element in this composite.
11171     * @param {Function} fn The function to call
11172     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11173     * @return {CompositeElement} this
11174     */
11175     each : function(fn, scope){
11176         var els = this.elements;
11177         for(var i = 0, len = els.length; i < len; i++){
11178             if(fn.call(scope || els[i], els[i], this, i) === false) {
11179                 break;
11180             }
11181         }
11182         return this;
11183     },
11184
11185     /**
11186      * Returns the Element object at the specified index
11187      * @param {Number} index
11188      * @return {Roo.Element}
11189      */
11190     item : function(index){
11191         return this.elements[index] || null;
11192     },
11193
11194     /**
11195      * Returns the first Element
11196      * @return {Roo.Element}
11197      */
11198     first : function(){
11199         return this.item(0);
11200     },
11201
11202     /**
11203      * Returns the last Element
11204      * @return {Roo.Element}
11205      */
11206     last : function(){
11207         return this.item(this.elements.length-1);
11208     },
11209
11210     /**
11211      * Returns the number of elements in this composite
11212      * @return Number
11213      */
11214     getCount : function(){
11215         return this.elements.length;
11216     },
11217
11218     /**
11219      * Returns true if this composite contains the passed element
11220      * @return Boolean
11221      */
11222     contains : function(el){
11223         return this.indexOf(el) !== -1;
11224     },
11225
11226     /**
11227      * Returns true if this composite contains the passed element
11228      * @return Boolean
11229      */
11230     indexOf : function(el){
11231         return this.elements.indexOf(Roo.get(el));
11232     },
11233
11234
11235     /**
11236     * Removes the specified element(s).
11237     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11238     * or an array of any of those.
11239     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11240     * @return {CompositeElement} this
11241     */
11242     removeElement : function(el, removeDom){
11243         if(el instanceof Array){
11244             for(var i = 0, len = el.length; i < len; i++){
11245                 this.removeElement(el[i]);
11246             }
11247             return this;
11248         }
11249         var index = typeof el == 'number' ? el : this.indexOf(el);
11250         if(index !== -1){
11251             if(removeDom){
11252                 var d = this.elements[index];
11253                 if(d.dom){
11254                     d.remove();
11255                 }else{
11256                     d.parentNode.removeChild(d);
11257                 }
11258             }
11259             this.elements.splice(index, 1);
11260         }
11261         return this;
11262     },
11263
11264     /**
11265     * Replaces the specified element with the passed element.
11266     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11267     * to replace.
11268     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11269     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11270     * @return {CompositeElement} this
11271     */
11272     replaceElement : function(el, replacement, domReplace){
11273         var index = typeof el == 'number' ? el : this.indexOf(el);
11274         if(index !== -1){
11275             if(domReplace){
11276                 this.elements[index].replaceWith(replacement);
11277             }else{
11278                 this.elements.splice(index, 1, Roo.get(replacement))
11279             }
11280         }
11281         return this;
11282     },
11283
11284     /**
11285      * Removes all elements.
11286      */
11287     clear : function(){
11288         this.elements = [];
11289     }
11290 };
11291 (function(){
11292     Roo.CompositeElement.createCall = function(proto, fnName){
11293         if(!proto[fnName]){
11294             proto[fnName] = function(){
11295                 return this.invoke(fnName, arguments);
11296             };
11297         }
11298     };
11299     for(var fnName in Roo.Element.prototype){
11300         if(typeof Roo.Element.prototype[fnName] == "function"){
11301             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11302         }
11303     };
11304 })();
11305 /*
11306  * Based on:
11307  * Ext JS Library 1.1.1
11308  * Copyright(c) 2006-2007, Ext JS, LLC.
11309  *
11310  * Originally Released Under LGPL - original licence link has changed is not relivant.
11311  *
11312  * Fork - LGPL
11313  * <script type="text/javascript">
11314  */
11315
11316 /**
11317  * @class Roo.CompositeElementLite
11318  * @extends Roo.CompositeElement
11319  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11320  <pre><code>
11321  var els = Roo.select("#some-el div.some-class");
11322  // or select directly from an existing element
11323  var el = Roo.get('some-el');
11324  el.select('div.some-class');
11325
11326  els.setWidth(100); // all elements become 100 width
11327  els.hide(true); // all elements fade out and hide
11328  // or
11329  els.setWidth(100).hide(true);
11330  </code></pre><br><br>
11331  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11332  * actions will be performed on all the elements in this collection.</b>
11333  */
11334 Roo.CompositeElementLite = function(els){
11335     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11336     this.el = new Roo.Element.Flyweight();
11337 };
11338 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11339     addElements : function(els){
11340         if(els){
11341             if(els instanceof Array){
11342                 this.elements = this.elements.concat(els);
11343             }else{
11344                 var yels = this.elements;
11345                 var index = yels.length-1;
11346                 for(var i = 0, len = els.length; i < len; i++) {
11347                     yels[++index] = els[i];
11348                 }
11349             }
11350         }
11351         return this;
11352     },
11353     invoke : function(fn, args){
11354         var els = this.elements;
11355         var el = this.el;
11356         for(var i = 0, len = els.length; i < len; i++) {
11357             el.dom = els[i];
11358                 Roo.Element.prototype[fn].apply(el, args);
11359         }
11360         return this;
11361     },
11362     /**
11363      * Returns a flyweight Element of the dom element object at the specified index
11364      * @param {Number} index
11365      * @return {Roo.Element}
11366      */
11367     item : function(index){
11368         if(!this.elements[index]){
11369             return null;
11370         }
11371         this.el.dom = this.elements[index];
11372         return this.el;
11373     },
11374
11375     // fixes scope with flyweight
11376     addListener : function(eventName, handler, scope, opt){
11377         var els = this.elements;
11378         for(var i = 0, len = els.length; i < len; i++) {
11379             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11380         }
11381         return this;
11382     },
11383
11384     /**
11385     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11386     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11387     * a reference to the dom node, use el.dom.</b>
11388     * @param {Function} fn The function to call
11389     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11390     * @return {CompositeElement} this
11391     */
11392     each : function(fn, scope){
11393         var els = this.elements;
11394         var el = this.el;
11395         for(var i = 0, len = els.length; i < len; i++){
11396             el.dom = els[i];
11397                 if(fn.call(scope || el, el, this, i) === false){
11398                 break;
11399             }
11400         }
11401         return this;
11402     },
11403
11404     indexOf : function(el){
11405         return this.elements.indexOf(Roo.getDom(el));
11406     },
11407
11408     replaceElement : function(el, replacement, domReplace){
11409         var index = typeof el == 'number' ? el : this.indexOf(el);
11410         if(index !== -1){
11411             replacement = Roo.getDom(replacement);
11412             if(domReplace){
11413                 var d = this.elements[index];
11414                 d.parentNode.insertBefore(replacement, d);
11415                 d.parentNode.removeChild(d);
11416             }
11417             this.elements.splice(index, 1, replacement);
11418         }
11419         return this;
11420     }
11421 });
11422 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11423
11424 /*
11425  * Based on:
11426  * Ext JS Library 1.1.1
11427  * Copyright(c) 2006-2007, Ext JS, LLC.
11428  *
11429  * Originally Released Under LGPL - original licence link has changed is not relivant.
11430  *
11431  * Fork - LGPL
11432  * <script type="text/javascript">
11433  */
11434
11435  
11436
11437 /**
11438  * @class Roo.data.Connection
11439  * @extends Roo.util.Observable
11440  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11441  * either to a configured URL, or to a URL specified at request time.<br><br>
11442  * <p>
11443  * Requests made by this class are asynchronous, and will return immediately. No data from
11444  * the server will be available to the statement immediately following the {@link #request} call.
11445  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11446  * <p>
11447  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11448  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11449  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11450  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11451  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11452  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11453  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11454  * standard DOM methods.
11455  * @constructor
11456  * @param {Object} config a configuration object.
11457  */
11458 Roo.data.Connection = function(config){
11459     Roo.apply(this, config);
11460     this.addEvents({
11461         /**
11462          * @event beforerequest
11463          * Fires before a network request is made to retrieve a data object.
11464          * @param {Connection} conn This Connection object.
11465          * @param {Object} options The options config object passed to the {@link #request} method.
11466          */
11467         "beforerequest" : true,
11468         /**
11469          * @event requestcomplete
11470          * Fires if the request was successfully completed.
11471          * @param {Connection} conn This Connection object.
11472          * @param {Object} response The XHR object containing the response data.
11473          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11474          * @param {Object} options The options config object passed to the {@link #request} method.
11475          */
11476         "requestcomplete" : true,
11477         /**
11478          * @event requestexception
11479          * Fires if an error HTTP status was returned from the server.
11480          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11481          * @param {Connection} conn This Connection object.
11482          * @param {Object} response The XHR object containing the response data.
11483          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11484          * @param {Object} options The options config object passed to the {@link #request} method.
11485          */
11486         "requestexception" : true
11487     });
11488     Roo.data.Connection.superclass.constructor.call(this);
11489 };
11490
11491 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11492     /**
11493      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11494      */
11495     /**
11496      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11497      * extra parameters to each request made by this object. (defaults to undefined)
11498      */
11499     /**
11500      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11501      *  to each request made by this object. (defaults to undefined)
11502      */
11503     /**
11504      * @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)
11505      */
11506     /**
11507      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11508      */
11509     timeout : 30000,
11510     /**
11511      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11512      * @type Boolean
11513      */
11514     autoAbort:false,
11515
11516     /**
11517      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11518      * @type Boolean
11519      */
11520     disableCaching: true,
11521
11522     /**
11523      * Sends an HTTP request to a remote server.
11524      * @param {Object} options An object which may contain the following properties:<ul>
11525      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11526      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11527      * request, a url encoded string or a function to call to get either.</li>
11528      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11529      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11530      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11531      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11532      * <li>options {Object} The parameter to the request call.</li>
11533      * <li>success {Boolean} True if the request succeeded.</li>
11534      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11535      * </ul></li>
11536      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11537      * The callback is passed the following parameters:<ul>
11538      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11539      * <li>options {Object} The parameter to the request call.</li>
11540      * </ul></li>
11541      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11542      * The callback is passed the following parameters:<ul>
11543      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11544      * <li>options {Object} The parameter to the request call.</li>
11545      * </ul></li>
11546      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11547      * for the callback function. Defaults to the browser window.</li>
11548      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11549      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11550      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11551      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11552      * params for the post data. Any params will be appended to the URL.</li>
11553      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11554      * </ul>
11555      * @return {Number} transactionId
11556      */
11557     request : function(o){
11558         if(this.fireEvent("beforerequest", this, o) !== false){
11559             var p = o.params;
11560
11561             if(typeof p == "function"){
11562                 p = p.call(o.scope||window, o);
11563             }
11564             if(typeof p == "object"){
11565                 p = Roo.urlEncode(o.params);
11566             }
11567             if(this.extraParams){
11568                 var extras = Roo.urlEncode(this.extraParams);
11569                 p = p ? (p + '&' + extras) : extras;
11570             }
11571
11572             var url = o.url || this.url;
11573             if(typeof url == 'function'){
11574                 url = url.call(o.scope||window, o);
11575             }
11576
11577             if(o.form){
11578                 var form = Roo.getDom(o.form);
11579                 url = url || form.action;
11580
11581                 var enctype = form.getAttribute("enctype");
11582                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11583                     return this.doFormUpload(o, p, url);
11584                 }
11585                 var f = Roo.lib.Ajax.serializeForm(form);
11586                 p = p ? (p + '&' + f) : f;
11587             }
11588
11589             var hs = o.headers;
11590             if(this.defaultHeaders){
11591                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11592                 if(!o.headers){
11593                     o.headers = hs;
11594                 }
11595             }
11596
11597             var cb = {
11598                 success: this.handleResponse,
11599                 failure: this.handleFailure,
11600                 scope: this,
11601                 argument: {options: o},
11602                 timeout : o.timeout || this.timeout
11603             };
11604
11605             var method = o.method||this.method||(p ? "POST" : "GET");
11606
11607             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11608                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11609             }
11610
11611             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11612                 if(o.autoAbort){
11613                     this.abort();
11614                 }
11615             }else if(this.autoAbort !== false){
11616                 this.abort();
11617             }
11618
11619             if((method == 'GET' && p) || o.xmlData){
11620                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11621                 p = '';
11622             }
11623             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11624             return this.transId;
11625         }else{
11626             Roo.callback(o.callback, o.scope, [o, null, null]);
11627             return null;
11628         }
11629     },
11630
11631     /**
11632      * Determine whether this object has a request outstanding.
11633      * @param {Number} transactionId (Optional) defaults to the last transaction
11634      * @return {Boolean} True if there is an outstanding request.
11635      */
11636     isLoading : function(transId){
11637         if(transId){
11638             return Roo.lib.Ajax.isCallInProgress(transId);
11639         }else{
11640             return this.transId ? true : false;
11641         }
11642     },
11643
11644     /**
11645      * Aborts any outstanding request.
11646      * @param {Number} transactionId (Optional) defaults to the last transaction
11647      */
11648     abort : function(transId){
11649         if(transId || this.isLoading()){
11650             Roo.lib.Ajax.abort(transId || this.transId);
11651         }
11652     },
11653
11654     // private
11655     handleResponse : function(response){
11656         this.transId = false;
11657         var options = response.argument.options;
11658         response.argument = options ? options.argument : null;
11659         this.fireEvent("requestcomplete", this, response, options);
11660         Roo.callback(options.success, options.scope, [response, options]);
11661         Roo.callback(options.callback, options.scope, [options, true, response]);
11662     },
11663
11664     // private
11665     handleFailure : function(response, e){
11666         this.transId = false;
11667         var options = response.argument.options;
11668         response.argument = options ? options.argument : null;
11669         this.fireEvent("requestexception", this, response, options, e);
11670         Roo.callback(options.failure, options.scope, [response, options]);
11671         Roo.callback(options.callback, options.scope, [options, false, response]);
11672     },
11673
11674     // private
11675     doFormUpload : function(o, ps, url){
11676         var id = Roo.id();
11677         var frame = document.createElement('iframe');
11678         frame.id = id;
11679         frame.name = id;
11680         frame.className = 'x-hidden';
11681         if(Roo.isIE){
11682             frame.src = Roo.SSL_SECURE_URL;
11683         }
11684         document.body.appendChild(frame);
11685
11686         if(Roo.isIE){
11687            document.frames[id].name = id;
11688         }
11689
11690         var form = Roo.getDom(o.form);
11691         form.target = id;
11692         form.method = 'POST';
11693         form.enctype = form.encoding = 'multipart/form-data';
11694         if(url){
11695             form.action = url;
11696         }
11697
11698         var hiddens, hd;
11699         if(ps){ // add dynamic params
11700             hiddens = [];
11701             ps = Roo.urlDecode(ps, false);
11702             for(var k in ps){
11703                 if(ps.hasOwnProperty(k)){
11704                     hd = document.createElement('input');
11705                     hd.type = 'hidden';
11706                     hd.name = k;
11707                     hd.value = ps[k];
11708                     form.appendChild(hd);
11709                     hiddens.push(hd);
11710                 }
11711             }
11712         }
11713
11714         function cb(){
11715             var r = {  // bogus response object
11716                 responseText : '',
11717                 responseXML : null
11718             };
11719
11720             r.argument = o ? o.argument : null;
11721
11722             try { //
11723                 var doc;
11724                 if(Roo.isIE){
11725                     doc = frame.contentWindow.document;
11726                 }else {
11727                     doc = (frame.contentDocument || window.frames[id].document);
11728                 }
11729                 if(doc && doc.body){
11730                     r.responseText = doc.body.innerHTML;
11731                 }
11732                 if(doc && doc.XMLDocument){
11733                     r.responseXML = doc.XMLDocument;
11734                 }else {
11735                     r.responseXML = doc;
11736                 }
11737             }
11738             catch(e) {
11739                 // ignore
11740             }
11741
11742             Roo.EventManager.removeListener(frame, 'load', cb, this);
11743
11744             this.fireEvent("requestcomplete", this, r, o);
11745             Roo.callback(o.success, o.scope, [r, o]);
11746             Roo.callback(o.callback, o.scope, [o, true, r]);
11747
11748             setTimeout(function(){document.body.removeChild(frame);}, 100);
11749         }
11750
11751         Roo.EventManager.on(frame, 'load', cb, this);
11752         form.submit();
11753
11754         if(hiddens){ // remove dynamic params
11755             for(var i = 0, len = hiddens.length; i < len; i++){
11756                 form.removeChild(hiddens[i]);
11757             }
11758         }
11759     }
11760 });
11761 /*
11762  * Based on:
11763  * Ext JS Library 1.1.1
11764  * Copyright(c) 2006-2007, Ext JS, LLC.
11765  *
11766  * Originally Released Under LGPL - original licence link has changed is not relivant.
11767  *
11768  * Fork - LGPL
11769  * <script type="text/javascript">
11770  */
11771  
11772 /**
11773  * Global Ajax request class.
11774  * 
11775  * @class Roo.Ajax
11776  * @extends Roo.data.Connection
11777  * @static
11778  * 
11779  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11780  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11781  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11782  * @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)
11783  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11784  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11785  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11786  */
11787 Roo.Ajax = new Roo.data.Connection({
11788     // fix up the docs
11789     /**
11790      * @scope Roo.Ajax
11791      * @type {Boolear} 
11792      */
11793     autoAbort : false,
11794
11795     /**
11796      * Serialize the passed form into a url encoded string
11797      * @scope Roo.Ajax
11798      * @param {String/HTMLElement} form
11799      * @return {String}
11800      */
11801     serializeForm : function(form){
11802         return Roo.lib.Ajax.serializeForm(form);
11803     }
11804 });/*
11805  * Based on:
11806  * Ext JS Library 1.1.1
11807  * Copyright(c) 2006-2007, Ext JS, LLC.
11808  *
11809  * Originally Released Under LGPL - original licence link has changed is not relivant.
11810  *
11811  * Fork - LGPL
11812  * <script type="text/javascript">
11813  */
11814
11815  
11816 /**
11817  * @class Roo.UpdateManager
11818  * @extends Roo.util.Observable
11819  * Provides AJAX-style update for Element object.<br><br>
11820  * Usage:<br>
11821  * <pre><code>
11822  * // Get it from a Roo.Element object
11823  * var el = Roo.get("foo");
11824  * var mgr = el.getUpdateManager();
11825  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11826  * ...
11827  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11828  * <br>
11829  * // or directly (returns the same UpdateManager instance)
11830  * var mgr = new Roo.UpdateManager("myElementId");
11831  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11832  * mgr.on("update", myFcnNeedsToKnow);
11833  * <br>
11834    // short handed call directly from the element object
11835    Roo.get("foo").load({
11836         url: "bar.php",
11837         scripts:true,
11838         params: "for=bar",
11839         text: "Loading Foo..."
11840    });
11841  * </code></pre>
11842  * @constructor
11843  * Create new UpdateManager directly.
11844  * @param {String/HTMLElement/Roo.Element} el The element to update
11845  * @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).
11846  */
11847 Roo.UpdateManager = function(el, forceNew){
11848     el = Roo.get(el);
11849     if(!forceNew && el.updateManager){
11850         return el.updateManager;
11851     }
11852     /**
11853      * The Element object
11854      * @type Roo.Element
11855      */
11856     this.el = el;
11857     /**
11858      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11859      * @type String
11860      */
11861     this.defaultUrl = null;
11862
11863     this.addEvents({
11864         /**
11865          * @event beforeupdate
11866          * Fired before an update is made, return false from your handler and the update is cancelled.
11867          * @param {Roo.Element} el
11868          * @param {String/Object/Function} url
11869          * @param {String/Object} params
11870          */
11871         "beforeupdate": true,
11872         /**
11873          * @event update
11874          * Fired after successful update is made.
11875          * @param {Roo.Element} el
11876          * @param {Object} oResponseObject The response Object
11877          */
11878         "update": true,
11879         /**
11880          * @event failure
11881          * Fired on update failure.
11882          * @param {Roo.Element} el
11883          * @param {Object} oResponseObject The response Object
11884          */
11885         "failure": true
11886     });
11887     var d = Roo.UpdateManager.defaults;
11888     /**
11889      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11890      * @type String
11891      */
11892     this.sslBlankUrl = d.sslBlankUrl;
11893     /**
11894      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11895      * @type Boolean
11896      */
11897     this.disableCaching = d.disableCaching;
11898     /**
11899      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11900      * @type String
11901      */
11902     this.indicatorText = d.indicatorText;
11903     /**
11904      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11905      * @type String
11906      */
11907     this.showLoadIndicator = d.showLoadIndicator;
11908     /**
11909      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11910      * @type Number
11911      */
11912     this.timeout = d.timeout;
11913
11914     /**
11915      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11916      * @type Boolean
11917      */
11918     this.loadScripts = d.loadScripts;
11919
11920     /**
11921      * Transaction object of current executing transaction
11922      */
11923     this.transaction = null;
11924
11925     /**
11926      * @private
11927      */
11928     this.autoRefreshProcId = null;
11929     /**
11930      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11931      * @type Function
11932      */
11933     this.refreshDelegate = this.refresh.createDelegate(this);
11934     /**
11935      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11936      * @type Function
11937      */
11938     this.updateDelegate = this.update.createDelegate(this);
11939     /**
11940      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11941      * @type Function
11942      */
11943     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11944     /**
11945      * @private
11946      */
11947     this.successDelegate = this.processSuccess.createDelegate(this);
11948     /**
11949      * @private
11950      */
11951     this.failureDelegate = this.processFailure.createDelegate(this);
11952
11953     if(!this.renderer){
11954      /**
11955       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11956       */
11957     this.renderer = new Roo.UpdateManager.BasicRenderer();
11958     }
11959     
11960     Roo.UpdateManager.superclass.constructor.call(this);
11961 };
11962
11963 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11964     /**
11965      * Get the Element this UpdateManager is bound to
11966      * @return {Roo.Element} The element
11967      */
11968     getEl : function(){
11969         return this.el;
11970     },
11971     /**
11972      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11973      * @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:
11974 <pre><code>
11975 um.update({<br/>
11976     url: "your-url.php",<br/>
11977     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11978     callback: yourFunction,<br/>
11979     scope: yourObject, //(optional scope)  <br/>
11980     discardUrl: false, <br/>
11981     nocache: false,<br/>
11982     text: "Loading...",<br/>
11983     timeout: 30,<br/>
11984     scripts: false<br/>
11985 });
11986 </code></pre>
11987      * The only required property is url. The optional properties nocache, text and scripts
11988      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11989      * @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}
11990      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11991      * @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.
11992      */
11993     update : function(url, params, callback, discardUrl){
11994         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11995             var method = this.method,
11996                 cfg;
11997             if(typeof url == "object"){ // must be config object
11998                 cfg = url;
11999                 url = cfg.url;
12000                 params = params || cfg.params;
12001                 callback = callback || cfg.callback;
12002                 discardUrl = discardUrl || cfg.discardUrl;
12003                 if(callback && cfg.scope){
12004                     callback = callback.createDelegate(cfg.scope);
12005                 }
12006                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12007                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12008                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12009                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12010                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12011             }
12012             this.showLoading();
12013             if(!discardUrl){
12014                 this.defaultUrl = url;
12015             }
12016             if(typeof url == "function"){
12017                 url = url.call(this);
12018             }
12019
12020             method = method || (params ? "POST" : "GET");
12021             if(method == "GET"){
12022                 url = this.prepareUrl(url);
12023             }
12024
12025             var o = Roo.apply(cfg ||{}, {
12026                 url : url,
12027                 params: params,
12028                 success: this.successDelegate,
12029                 failure: this.failureDelegate,
12030                 callback: undefined,
12031                 timeout: (this.timeout*1000),
12032                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12033             });
12034             Roo.log("updated manager called with timeout of " + o.timeout);
12035             this.transaction = Roo.Ajax.request(o);
12036         }
12037     },
12038
12039     /**
12040      * 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.
12041      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12042      * @param {String/HTMLElement} form The form Id or form element
12043      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12044      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12045      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12046      */
12047     formUpdate : function(form, url, reset, callback){
12048         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12049             if(typeof url == "function"){
12050                 url = url.call(this);
12051             }
12052             form = Roo.getDom(form);
12053             this.transaction = Roo.Ajax.request({
12054                 form: form,
12055                 url:url,
12056                 success: this.successDelegate,
12057                 failure: this.failureDelegate,
12058                 timeout: (this.timeout*1000),
12059                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12060             });
12061             this.showLoading.defer(1, this);
12062         }
12063     },
12064
12065     /**
12066      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12067      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12068      */
12069     refresh : function(callback){
12070         if(this.defaultUrl == null){
12071             return;
12072         }
12073         this.update(this.defaultUrl, null, callback, true);
12074     },
12075
12076     /**
12077      * Set this element to auto refresh.
12078      * @param {Number} interval How often to update (in seconds).
12079      * @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)
12080      * @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}
12081      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12082      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12083      */
12084     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12085         if(refreshNow){
12086             this.update(url || this.defaultUrl, params, callback, true);
12087         }
12088         if(this.autoRefreshProcId){
12089             clearInterval(this.autoRefreshProcId);
12090         }
12091         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12092     },
12093
12094     /**
12095      * Stop auto refresh on this element.
12096      */
12097      stopAutoRefresh : function(){
12098         if(this.autoRefreshProcId){
12099             clearInterval(this.autoRefreshProcId);
12100             delete this.autoRefreshProcId;
12101         }
12102     },
12103
12104     isAutoRefreshing : function(){
12105        return this.autoRefreshProcId ? true : false;
12106     },
12107     /**
12108      * Called to update the element to "Loading" state. Override to perform custom action.
12109      */
12110     showLoading : function(){
12111         if(this.showLoadIndicator){
12112             this.el.update(this.indicatorText);
12113         }
12114     },
12115
12116     /**
12117      * Adds unique parameter to query string if disableCaching = true
12118      * @private
12119      */
12120     prepareUrl : function(url){
12121         if(this.disableCaching){
12122             var append = "_dc=" + (new Date().getTime());
12123             if(url.indexOf("?") !== -1){
12124                 url += "&" + append;
12125             }else{
12126                 url += "?" + append;
12127             }
12128         }
12129         return url;
12130     },
12131
12132     /**
12133      * @private
12134      */
12135     processSuccess : function(response){
12136         this.transaction = null;
12137         if(response.argument.form && response.argument.reset){
12138             try{ // put in try/catch since some older FF releases had problems with this
12139                 response.argument.form.reset();
12140             }catch(e){}
12141         }
12142         if(this.loadScripts){
12143             this.renderer.render(this.el, response, this,
12144                 this.updateComplete.createDelegate(this, [response]));
12145         }else{
12146             this.renderer.render(this.el, response, this);
12147             this.updateComplete(response);
12148         }
12149     },
12150
12151     updateComplete : function(response){
12152         this.fireEvent("update", this.el, response);
12153         if(typeof response.argument.callback == "function"){
12154             response.argument.callback(this.el, true, response);
12155         }
12156     },
12157
12158     /**
12159      * @private
12160      */
12161     processFailure : function(response){
12162         this.transaction = null;
12163         this.fireEvent("failure", this.el, response);
12164         if(typeof response.argument.callback == "function"){
12165             response.argument.callback(this.el, false, response);
12166         }
12167     },
12168
12169     /**
12170      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12171      * @param {Object} renderer The object implementing the render() method
12172      */
12173     setRenderer : function(renderer){
12174         this.renderer = renderer;
12175     },
12176
12177     getRenderer : function(){
12178        return this.renderer;
12179     },
12180
12181     /**
12182      * Set the defaultUrl used for updates
12183      * @param {String/Function} defaultUrl The url or a function to call to get the url
12184      */
12185     setDefaultUrl : function(defaultUrl){
12186         this.defaultUrl = defaultUrl;
12187     },
12188
12189     /**
12190      * Aborts the executing transaction
12191      */
12192     abort : function(){
12193         if(this.transaction){
12194             Roo.Ajax.abort(this.transaction);
12195         }
12196     },
12197
12198     /**
12199      * Returns true if an update is in progress
12200      * @return {Boolean}
12201      */
12202     isUpdating : function(){
12203         if(this.transaction){
12204             return Roo.Ajax.isLoading(this.transaction);
12205         }
12206         return false;
12207     }
12208 });
12209
12210 /**
12211  * @class Roo.UpdateManager.defaults
12212  * @static (not really - but it helps the doc tool)
12213  * The defaults collection enables customizing the default properties of UpdateManager
12214  */
12215    Roo.UpdateManager.defaults = {
12216        /**
12217          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12218          * @type Number
12219          */
12220          timeout : 30,
12221
12222          /**
12223          * True to process scripts by default (Defaults to false).
12224          * @type Boolean
12225          */
12226         loadScripts : false,
12227
12228         /**
12229         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12230         * @type String
12231         */
12232         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12233         /**
12234          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12235          * @type Boolean
12236          */
12237         disableCaching : false,
12238         /**
12239          * Whether to show indicatorText when loading (Defaults to true).
12240          * @type Boolean
12241          */
12242         showLoadIndicator : true,
12243         /**
12244          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12245          * @type String
12246          */
12247         indicatorText : '<div class="loading-indicator">Loading...</div>'
12248    };
12249
12250 /**
12251  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12252  *Usage:
12253  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12254  * @param {String/HTMLElement/Roo.Element} el The element to update
12255  * @param {String} url The url
12256  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12257  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12258  * @static
12259  * @deprecated
12260  * @member Roo.UpdateManager
12261  */
12262 Roo.UpdateManager.updateElement = function(el, url, params, options){
12263     var um = Roo.get(el, true).getUpdateManager();
12264     Roo.apply(um, options);
12265     um.update(url, params, options ? options.callback : null);
12266 };
12267 // alias for backwards compat
12268 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12269 /**
12270  * @class Roo.UpdateManager.BasicRenderer
12271  * Default Content renderer. Updates the elements innerHTML with the responseText.
12272  */
12273 Roo.UpdateManager.BasicRenderer = function(){};
12274
12275 Roo.UpdateManager.BasicRenderer.prototype = {
12276     /**
12277      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12278      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12279      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12280      * @param {Roo.Element} el The element being rendered
12281      * @param {Object} response The YUI Connect response object
12282      * @param {UpdateManager} updateManager The calling update manager
12283      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12284      */
12285      render : function(el, response, updateManager, callback){
12286         el.update(response.responseText, updateManager.loadScripts, callback);
12287     }
12288 };
12289 /*
12290  * Based on:
12291  * Roo JS
12292  * (c)) Alan Knowles
12293  * Licence : LGPL
12294  */
12295
12296
12297 /**
12298  * @class Roo.DomTemplate
12299  * @extends Roo.Template
12300  * An effort at a dom based template engine..
12301  *
12302  * Similar to XTemplate, except it uses dom parsing to create the template..
12303  *
12304  * Supported features:
12305  *
12306  *  Tags:
12307
12308 <pre><code>
12309       {a_variable} - output encoded.
12310       {a_variable.format:("Y-m-d")} - call a method on the variable
12311       {a_variable:raw} - unencoded output
12312       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12313       {a_variable:this.method_on_template(...)} - call a method on the template object.
12314  
12315 </code></pre>
12316  *  The tpl tag:
12317 <pre><code>
12318         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12319         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12320         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12321         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12322   
12323 </code></pre>
12324  *      
12325  */
12326 Roo.DomTemplate = function()
12327 {
12328      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12329      if (this.html) {
12330         this.compile();
12331      }
12332 };
12333
12334
12335 Roo.extend(Roo.DomTemplate, Roo.Template, {
12336     /**
12337      * id counter for sub templates.
12338      */
12339     id : 0,
12340     /**
12341      * flag to indicate if dom parser is inside a pre,
12342      * it will strip whitespace if not.
12343      */
12344     inPre : false,
12345     
12346     /**
12347      * The various sub templates
12348      */
12349     tpls : false,
12350     
12351     
12352     
12353     /**
12354      *
12355      * basic tag replacing syntax
12356      * WORD:WORD()
12357      *
12358      * // you can fake an object call by doing this
12359      *  x.t:(test,tesT) 
12360      * 
12361      */
12362     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12363     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12364     
12365     iterChild : function (node, method) {
12366         
12367         var oldPre = this.inPre;
12368         if (node.tagName == 'PRE') {
12369             this.inPre = true;
12370         }
12371         for( var i = 0; i < node.childNodes.length; i++) {
12372             method.call(this, node.childNodes[i]);
12373         }
12374         this.inPre = oldPre;
12375     },
12376     
12377     
12378     
12379     /**
12380      * compile the template
12381      *
12382      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12383      *
12384      */
12385     compile: function()
12386     {
12387         var s = this.html;
12388         
12389         // covert the html into DOM...
12390         var doc = false;
12391         var div =false;
12392         try {
12393             doc = document.implementation.createHTMLDocument("");
12394             doc.documentElement.innerHTML =   this.html  ;
12395             div = doc.documentElement;
12396         } catch (e) {
12397             // old IE... - nasty -- it causes all sorts of issues.. with
12398             // images getting pulled from server..
12399             div = document.createElement('div');
12400             div.innerHTML = this.html;
12401         }
12402         //doc.documentElement.innerHTML = htmlBody
12403          
12404         
12405         
12406         this.tpls = [];
12407         var _t = this;
12408         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12409         
12410         var tpls = this.tpls;
12411         
12412         // create a top level template from the snippet..
12413         
12414         //Roo.log(div.innerHTML);
12415         
12416         var tpl = {
12417             uid : 'master',
12418             id : this.id++,
12419             attr : false,
12420             value : false,
12421             body : div.innerHTML,
12422             
12423             forCall : false,
12424             execCall : false,
12425             dom : div,
12426             isTop : true
12427             
12428         };
12429         tpls.unshift(tpl);
12430         
12431         
12432         // compile them...
12433         this.tpls = [];
12434         Roo.each(tpls, function(tp){
12435             this.compileTpl(tp);
12436             this.tpls[tp.id] = tp;
12437         }, this);
12438         
12439         this.master = tpls[0];
12440         return this;
12441         
12442         
12443     },
12444     
12445     compileNode : function(node, istop) {
12446         // test for
12447         //Roo.log(node);
12448         
12449         
12450         // skip anything not a tag..
12451         if (node.nodeType != 1) {
12452             if (node.nodeType == 3 && !this.inPre) {
12453                 // reduce white space..
12454                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12455                 
12456             }
12457             return;
12458         }
12459         
12460         var tpl = {
12461             uid : false,
12462             id : false,
12463             attr : false,
12464             value : false,
12465             body : '',
12466             
12467             forCall : false,
12468             execCall : false,
12469             dom : false,
12470             isTop : istop
12471             
12472             
12473         };
12474         
12475         
12476         switch(true) {
12477             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12478             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12479             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12480             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12481             // no default..
12482         }
12483         
12484         
12485         if (!tpl.attr) {
12486             // just itterate children..
12487             this.iterChild(node,this.compileNode);
12488             return;
12489         }
12490         tpl.uid = this.id++;
12491         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12492         node.removeAttribute('roo-'+ tpl.attr);
12493         if (tpl.attr != 'name') {
12494             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12495             node.parentNode.replaceChild(placeholder,  node);
12496         } else {
12497             
12498             var placeholder =  document.createElement('span');
12499             placeholder.className = 'roo-tpl-' + tpl.value;
12500             node.parentNode.replaceChild(placeholder,  node);
12501         }
12502         
12503         // parent now sees '{domtplXXXX}
12504         this.iterChild(node,this.compileNode);
12505         
12506         // we should now have node body...
12507         var div = document.createElement('div');
12508         div.appendChild(node);
12509         tpl.dom = node;
12510         // this has the unfortunate side effect of converting tagged attributes
12511         // eg. href="{...}" into %7C...%7D
12512         // this has been fixed by searching for those combo's although it's a bit hacky..
12513         
12514         
12515         tpl.body = div.innerHTML;
12516         
12517         
12518          
12519         tpl.id = tpl.uid;
12520         switch(tpl.attr) {
12521             case 'for' :
12522                 switch (tpl.value) {
12523                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12524                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12525                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12526                 }
12527                 break;
12528             
12529             case 'exec':
12530                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12531                 break;
12532             
12533             case 'if':     
12534                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12535                 break;
12536             
12537             case 'name':
12538                 tpl.id  = tpl.value; // replace non characters???
12539                 break;
12540             
12541         }
12542         
12543         
12544         this.tpls.push(tpl);
12545         
12546         
12547         
12548     },
12549     
12550     
12551     
12552     
12553     /**
12554      * Compile a segment of the template into a 'sub-template'
12555      *
12556      * 
12557      * 
12558      *
12559      */
12560     compileTpl : function(tpl)
12561     {
12562         var fm = Roo.util.Format;
12563         var useF = this.disableFormats !== true;
12564         
12565         var sep = Roo.isGecko ? "+\n" : ",\n";
12566         
12567         var undef = function(str) {
12568             Roo.debug && Roo.log("Property not found :"  + str);
12569             return '';
12570         };
12571           
12572         //Roo.log(tpl.body);
12573         
12574         
12575         
12576         var fn = function(m, lbrace, name, format, args)
12577         {
12578             //Roo.log("ARGS");
12579             //Roo.log(arguments);
12580             args = args ? args.replace(/\\'/g,"'") : args;
12581             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12582             if (typeof(format) == 'undefined') {
12583                 format =  'htmlEncode'; 
12584             }
12585             if (format == 'raw' ) {
12586                 format = false;
12587             }
12588             
12589             if(name.substr(0, 6) == 'domtpl'){
12590                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12591             }
12592             
12593             // build an array of options to determine if value is undefined..
12594             
12595             // basically get 'xxxx.yyyy' then do
12596             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12597             //    (function () { Roo.log("Property not found"); return ''; })() :
12598             //    ......
12599             
12600             var udef_ar = [];
12601             var lookfor = '';
12602             Roo.each(name.split('.'), function(st) {
12603                 lookfor += (lookfor.length ? '.': '') + st;
12604                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12605             });
12606             
12607             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12608             
12609             
12610             if(format && useF){
12611                 
12612                 args = args ? ',' + args : "";
12613                  
12614                 if(format.substr(0, 5) != "this."){
12615                     format = "fm." + format + '(';
12616                 }else{
12617                     format = 'this.call("'+ format.substr(5) + '", ';
12618                     args = ", values";
12619                 }
12620                 
12621                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12622             }
12623              
12624             if (args && args.length) {
12625                 // called with xxyx.yuu:(test,test)
12626                 // change to ()
12627                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12628             }
12629             // raw.. - :raw modifier..
12630             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12631             
12632         };
12633         var body;
12634         // branched to use + in gecko and [].join() in others
12635         if(Roo.isGecko){
12636             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12637                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12638                     "';};};";
12639         }else{
12640             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12641             body.push(tpl.body.replace(/(\r\n|\n)/g,
12642                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12643             body.push("'].join('');};};");
12644             body = body.join('');
12645         }
12646         
12647         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12648        
12649         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12650         eval(body);
12651         
12652         return this;
12653     },
12654      
12655     /**
12656      * same as applyTemplate, except it's done to one of the subTemplates
12657      * when using named templates, you can do:
12658      *
12659      * var str = pl.applySubTemplate('your-name', values);
12660      *
12661      * 
12662      * @param {Number} id of the template
12663      * @param {Object} values to apply to template
12664      * @param {Object} parent (normaly the instance of this object)
12665      */
12666     applySubTemplate : function(id, values, parent)
12667     {
12668         
12669         
12670         var t = this.tpls[id];
12671         
12672         
12673         try { 
12674             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12675                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12676                 return '';
12677             }
12678         } catch(e) {
12679             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12680             Roo.log(values);
12681           
12682             return '';
12683         }
12684         try { 
12685             
12686             if(t.execCall && t.execCall.call(this, values, parent)){
12687                 return '';
12688             }
12689         } catch(e) {
12690             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12691             Roo.log(values);
12692             return '';
12693         }
12694         
12695         try {
12696             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12697             parent = t.target ? values : parent;
12698             if(t.forCall && vs instanceof Array){
12699                 var buf = [];
12700                 for(var i = 0, len = vs.length; i < len; i++){
12701                     try {
12702                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12703                     } catch (e) {
12704                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12705                         Roo.log(e.body);
12706                         //Roo.log(t.compiled);
12707                         Roo.log(vs[i]);
12708                     }   
12709                 }
12710                 return buf.join('');
12711             }
12712         } catch (e) {
12713             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12714             Roo.log(values);
12715             return '';
12716         }
12717         try {
12718             return t.compiled.call(this, vs, parent);
12719         } catch (e) {
12720             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12721             Roo.log(e.body);
12722             //Roo.log(t.compiled);
12723             Roo.log(values);
12724             return '';
12725         }
12726     },
12727
12728    
12729
12730     applyTemplate : function(values){
12731         return this.master.compiled.call(this, values, {});
12732         //var s = this.subs;
12733     },
12734
12735     apply : function(){
12736         return this.applyTemplate.apply(this, arguments);
12737     }
12738
12739  });
12740
12741 Roo.DomTemplate.from = function(el){
12742     el = Roo.getDom(el);
12743     return new Roo.Domtemplate(el.value || el.innerHTML);
12744 };/*
12745  * Based on:
12746  * Ext JS Library 1.1.1
12747  * Copyright(c) 2006-2007, Ext JS, LLC.
12748  *
12749  * Originally Released Under LGPL - original licence link has changed is not relivant.
12750  *
12751  * Fork - LGPL
12752  * <script type="text/javascript">
12753  */
12754
12755 /**
12756  * @class Roo.util.DelayedTask
12757  * Provides a convenient method of performing setTimeout where a new
12758  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12759  * You can use this class to buffer
12760  * the keypress events for a certain number of milliseconds, and perform only if they stop
12761  * for that amount of time.
12762  * @constructor The parameters to this constructor serve as defaults and are not required.
12763  * @param {Function} fn (optional) The default function to timeout
12764  * @param {Object} scope (optional) The default scope of that timeout
12765  * @param {Array} args (optional) The default Array of arguments
12766  */
12767 Roo.util.DelayedTask = function(fn, scope, args){
12768     var id = null, d, t;
12769
12770     var call = function(){
12771         var now = new Date().getTime();
12772         if(now - t >= d){
12773             clearInterval(id);
12774             id = null;
12775             fn.apply(scope, args || []);
12776         }
12777     };
12778     /**
12779      * Cancels any pending timeout and queues a new one
12780      * @param {Number} delay The milliseconds to delay
12781      * @param {Function} newFn (optional) Overrides function passed to constructor
12782      * @param {Object} newScope (optional) Overrides scope passed to constructor
12783      * @param {Array} newArgs (optional) Overrides args passed to constructor
12784      */
12785     this.delay = function(delay, newFn, newScope, newArgs){
12786         if(id && delay != d){
12787             this.cancel();
12788         }
12789         d = delay;
12790         t = new Date().getTime();
12791         fn = newFn || fn;
12792         scope = newScope || scope;
12793         args = newArgs || args;
12794         if(!id){
12795             id = setInterval(call, d);
12796         }
12797     };
12798
12799     /**
12800      * Cancel the last queued timeout
12801      */
12802     this.cancel = function(){
12803         if(id){
12804             clearInterval(id);
12805             id = null;
12806         }
12807     };
12808 };/*
12809  * Based on:
12810  * Ext JS Library 1.1.1
12811  * Copyright(c) 2006-2007, Ext JS, LLC.
12812  *
12813  * Originally Released Under LGPL - original licence link has changed is not relivant.
12814  *
12815  * Fork - LGPL
12816  * <script type="text/javascript">
12817  */
12818  
12819  
12820 Roo.util.TaskRunner = function(interval){
12821     interval = interval || 10;
12822     var tasks = [], removeQueue = [];
12823     var id = 0;
12824     var running = false;
12825
12826     var stopThread = function(){
12827         running = false;
12828         clearInterval(id);
12829         id = 0;
12830     };
12831
12832     var startThread = function(){
12833         if(!running){
12834             running = true;
12835             id = setInterval(runTasks, interval);
12836         }
12837     };
12838
12839     var removeTask = function(task){
12840         removeQueue.push(task);
12841         if(task.onStop){
12842             task.onStop();
12843         }
12844     };
12845
12846     var runTasks = function(){
12847         if(removeQueue.length > 0){
12848             for(var i = 0, len = removeQueue.length; i < len; i++){
12849                 tasks.remove(removeQueue[i]);
12850             }
12851             removeQueue = [];
12852             if(tasks.length < 1){
12853                 stopThread();
12854                 return;
12855             }
12856         }
12857         var now = new Date().getTime();
12858         for(var i = 0, len = tasks.length; i < len; ++i){
12859             var t = tasks[i];
12860             var itime = now - t.taskRunTime;
12861             if(t.interval <= itime){
12862                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12863                 t.taskRunTime = now;
12864                 if(rt === false || t.taskRunCount === t.repeat){
12865                     removeTask(t);
12866                     return;
12867                 }
12868             }
12869             if(t.duration && t.duration <= (now - t.taskStartTime)){
12870                 removeTask(t);
12871             }
12872         }
12873     };
12874
12875     /**
12876      * Queues a new task.
12877      * @param {Object} task
12878      */
12879     this.start = function(task){
12880         tasks.push(task);
12881         task.taskStartTime = new Date().getTime();
12882         task.taskRunTime = 0;
12883         task.taskRunCount = 0;
12884         startThread();
12885         return task;
12886     };
12887
12888     this.stop = function(task){
12889         removeTask(task);
12890         return task;
12891     };
12892
12893     this.stopAll = function(){
12894         stopThread();
12895         for(var i = 0, len = tasks.length; i < len; i++){
12896             if(tasks[i].onStop){
12897                 tasks[i].onStop();
12898             }
12899         }
12900         tasks = [];
12901         removeQueue = [];
12902     };
12903 };
12904
12905 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12906  * Based on:
12907  * Ext JS Library 1.1.1
12908  * Copyright(c) 2006-2007, Ext JS, LLC.
12909  *
12910  * Originally Released Under LGPL - original licence link has changed is not relivant.
12911  *
12912  * Fork - LGPL
12913  * <script type="text/javascript">
12914  */
12915
12916  
12917 /**
12918  * @class Roo.util.MixedCollection
12919  * @extends Roo.util.Observable
12920  * A Collection class that maintains both numeric indexes and keys and exposes events.
12921  * @constructor
12922  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12923  * collection (defaults to false)
12924  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12925  * and return the key value for that item.  This is used when available to look up the key on items that
12926  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12927  * equivalent to providing an implementation for the {@link #getKey} method.
12928  */
12929 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12930     this.items = [];
12931     this.map = {};
12932     this.keys = [];
12933     this.length = 0;
12934     this.addEvents({
12935         /**
12936          * @event clear
12937          * Fires when the collection is cleared.
12938          */
12939         "clear" : true,
12940         /**
12941          * @event add
12942          * Fires when an item is added to the collection.
12943          * @param {Number} index The index at which the item was added.
12944          * @param {Object} o The item added.
12945          * @param {String} key The key associated with the added item.
12946          */
12947         "add" : true,
12948         /**
12949          * @event replace
12950          * Fires when an item is replaced in the collection.
12951          * @param {String} key he key associated with the new added.
12952          * @param {Object} old The item being replaced.
12953          * @param {Object} new The new item.
12954          */
12955         "replace" : true,
12956         /**
12957          * @event remove
12958          * Fires when an item is removed from the collection.
12959          * @param {Object} o The item being removed.
12960          * @param {String} key (optional) The key associated with the removed item.
12961          */
12962         "remove" : true,
12963         "sort" : true
12964     });
12965     this.allowFunctions = allowFunctions === true;
12966     if(keyFn){
12967         this.getKey = keyFn;
12968     }
12969     Roo.util.MixedCollection.superclass.constructor.call(this);
12970 };
12971
12972 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12973     allowFunctions : false,
12974     
12975 /**
12976  * Adds an item to the collection.
12977  * @param {String} key The key to associate with the item
12978  * @param {Object} o The item to add.
12979  * @return {Object} The item added.
12980  */
12981     add : function(key, o){
12982         if(arguments.length == 1){
12983             o = arguments[0];
12984             key = this.getKey(o);
12985         }
12986         if(typeof key == "undefined" || key === null){
12987             this.length++;
12988             this.items.push(o);
12989             this.keys.push(null);
12990         }else{
12991             var old = this.map[key];
12992             if(old){
12993                 return this.replace(key, o);
12994             }
12995             this.length++;
12996             this.items.push(o);
12997             this.map[key] = o;
12998             this.keys.push(key);
12999         }
13000         this.fireEvent("add", this.length-1, o, key);
13001         return o;
13002     },
13003        
13004 /**
13005   * MixedCollection has a generic way to fetch keys if you implement getKey.
13006 <pre><code>
13007 // normal way
13008 var mc = new Roo.util.MixedCollection();
13009 mc.add(someEl.dom.id, someEl);
13010 mc.add(otherEl.dom.id, otherEl);
13011 //and so on
13012
13013 // using getKey
13014 var mc = new Roo.util.MixedCollection();
13015 mc.getKey = function(el){
13016    return el.dom.id;
13017 };
13018 mc.add(someEl);
13019 mc.add(otherEl);
13020
13021 // or via the constructor
13022 var mc = new Roo.util.MixedCollection(false, function(el){
13023    return el.dom.id;
13024 });
13025 mc.add(someEl);
13026 mc.add(otherEl);
13027 </code></pre>
13028  * @param o {Object} The item for which to find the key.
13029  * @return {Object} The key for the passed item.
13030  */
13031     getKey : function(o){
13032          return o.id; 
13033     },
13034    
13035 /**
13036  * Replaces an item in the collection.
13037  * @param {String} key The key associated with the item to replace, or the item to replace.
13038  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13039  * @return {Object}  The new item.
13040  */
13041     replace : function(key, o){
13042         if(arguments.length == 1){
13043             o = arguments[0];
13044             key = this.getKey(o);
13045         }
13046         var old = this.item(key);
13047         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13048              return this.add(key, o);
13049         }
13050         var index = this.indexOfKey(key);
13051         this.items[index] = o;
13052         this.map[key] = o;
13053         this.fireEvent("replace", key, old, o);
13054         return o;
13055     },
13056    
13057 /**
13058  * Adds all elements of an Array or an Object to the collection.
13059  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13060  * an Array of values, each of which are added to the collection.
13061  */
13062     addAll : function(objs){
13063         if(arguments.length > 1 || objs instanceof Array){
13064             var args = arguments.length > 1 ? arguments : objs;
13065             for(var i = 0, len = args.length; i < len; i++){
13066                 this.add(args[i]);
13067             }
13068         }else{
13069             for(var key in objs){
13070                 if(this.allowFunctions || typeof objs[key] != "function"){
13071                     this.add(key, objs[key]);
13072                 }
13073             }
13074         }
13075     },
13076    
13077 /**
13078  * Executes the specified function once for every item in the collection, passing each
13079  * item as the first and only parameter. returning false from the function will stop the iteration.
13080  * @param {Function} fn The function to execute for each item.
13081  * @param {Object} scope (optional) The scope in which to execute the function.
13082  */
13083     each : function(fn, scope){
13084         var items = [].concat(this.items); // each safe for removal
13085         for(var i = 0, len = items.length; i < len; i++){
13086             if(fn.call(scope || items[i], items[i], i, len) === false){
13087                 break;
13088             }
13089         }
13090     },
13091    
13092 /**
13093  * Executes the specified function once for every key in the collection, passing each
13094  * key, and its associated item as the first two parameters.
13095  * @param {Function} fn The function to execute for each item.
13096  * @param {Object} scope (optional) The scope in which to execute the function.
13097  */
13098     eachKey : function(fn, scope){
13099         for(var i = 0, len = this.keys.length; i < len; i++){
13100             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13101         }
13102     },
13103    
13104 /**
13105  * Returns the first item in the collection which elicits a true return value from the
13106  * passed selection function.
13107  * @param {Function} fn The selection function to execute for each item.
13108  * @param {Object} scope (optional) The scope in which to execute the function.
13109  * @return {Object} The first item in the collection which returned true from the selection function.
13110  */
13111     find : function(fn, scope){
13112         for(var i = 0, len = this.items.length; i < len; i++){
13113             if(fn.call(scope || window, this.items[i], this.keys[i])){
13114                 return this.items[i];
13115             }
13116         }
13117         return null;
13118     },
13119    
13120 /**
13121  * Inserts an item at the specified index in the collection.
13122  * @param {Number} index The index to insert the item at.
13123  * @param {String} key The key to associate with the new item, or the item itself.
13124  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13125  * @return {Object} The item inserted.
13126  */
13127     insert : function(index, key, o){
13128         if(arguments.length == 2){
13129             o = arguments[1];
13130             key = this.getKey(o);
13131         }
13132         if(index >= this.length){
13133             return this.add(key, o);
13134         }
13135         this.length++;
13136         this.items.splice(index, 0, o);
13137         if(typeof key != "undefined" && key != null){
13138             this.map[key] = o;
13139         }
13140         this.keys.splice(index, 0, key);
13141         this.fireEvent("add", index, o, key);
13142         return o;
13143     },
13144    
13145 /**
13146  * Removed an item from the collection.
13147  * @param {Object} o The item to remove.
13148  * @return {Object} The item removed.
13149  */
13150     remove : function(o){
13151         return this.removeAt(this.indexOf(o));
13152     },
13153    
13154 /**
13155  * Remove an item from a specified index in the collection.
13156  * @param {Number} index The index within the collection of the item to remove.
13157  */
13158     removeAt : function(index){
13159         if(index < this.length && index >= 0){
13160             this.length--;
13161             var o = this.items[index];
13162             this.items.splice(index, 1);
13163             var key = this.keys[index];
13164             if(typeof key != "undefined"){
13165                 delete this.map[key];
13166             }
13167             this.keys.splice(index, 1);
13168             this.fireEvent("remove", o, key);
13169         }
13170     },
13171    
13172 /**
13173  * Removed an item associated with the passed key fom the collection.
13174  * @param {String} key The key of the item to remove.
13175  */
13176     removeKey : function(key){
13177         return this.removeAt(this.indexOfKey(key));
13178     },
13179    
13180 /**
13181  * Returns the number of items in the collection.
13182  * @return {Number} the number of items in the collection.
13183  */
13184     getCount : function(){
13185         return this.length; 
13186     },
13187    
13188 /**
13189  * Returns index within the collection of the passed Object.
13190  * @param {Object} o The item to find the index of.
13191  * @return {Number} index of the item.
13192  */
13193     indexOf : function(o){
13194         if(!this.items.indexOf){
13195             for(var i = 0, len = this.items.length; i < len; i++){
13196                 if(this.items[i] == o) {
13197                     return i;
13198                 }
13199             }
13200             return -1;
13201         }else{
13202             return this.items.indexOf(o);
13203         }
13204     },
13205    
13206 /**
13207  * Returns index within the collection of the passed key.
13208  * @param {String} key The key to find the index of.
13209  * @return {Number} index of the key.
13210  */
13211     indexOfKey : function(key){
13212         if(!this.keys.indexOf){
13213             for(var i = 0, len = this.keys.length; i < len; i++){
13214                 if(this.keys[i] == key) {
13215                     return i;
13216                 }
13217             }
13218             return -1;
13219         }else{
13220             return this.keys.indexOf(key);
13221         }
13222     },
13223    
13224 /**
13225  * Returns the item associated with the passed key OR index. Key has priority over index.
13226  * @param {String/Number} key The key or index of the item.
13227  * @return {Object} The item associated with the passed key.
13228  */
13229     item : function(key){
13230         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13231         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13232     },
13233     
13234 /**
13235  * Returns the item at the specified index.
13236  * @param {Number} index The index of the item.
13237  * @return {Object}
13238  */
13239     itemAt : function(index){
13240         return this.items[index];
13241     },
13242     
13243 /**
13244  * Returns the item associated with the passed key.
13245  * @param {String/Number} key The key of the item.
13246  * @return {Object} The item associated with the passed key.
13247  */
13248     key : function(key){
13249         return this.map[key];
13250     },
13251    
13252 /**
13253  * Returns true if the collection contains the passed Object as an item.
13254  * @param {Object} o  The Object to look for in the collection.
13255  * @return {Boolean} True if the collection contains the Object as an item.
13256  */
13257     contains : function(o){
13258         return this.indexOf(o) != -1;
13259     },
13260    
13261 /**
13262  * Returns true if the collection contains the passed Object as a key.
13263  * @param {String} key The key to look for in the collection.
13264  * @return {Boolean} True if the collection contains the Object as a key.
13265  */
13266     containsKey : function(key){
13267         return typeof this.map[key] != "undefined";
13268     },
13269    
13270 /**
13271  * Removes all items from the collection.
13272  */
13273     clear : function(){
13274         this.length = 0;
13275         this.items = [];
13276         this.keys = [];
13277         this.map = {};
13278         this.fireEvent("clear");
13279     },
13280    
13281 /**
13282  * Returns the first item in the collection.
13283  * @return {Object} the first item in the collection..
13284  */
13285     first : function(){
13286         return this.items[0]; 
13287     },
13288    
13289 /**
13290  * Returns the last item in the collection.
13291  * @return {Object} the last item in the collection..
13292  */
13293     last : function(){
13294         return this.items[this.length-1];   
13295     },
13296     
13297     _sort : function(property, dir, fn){
13298         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13299         fn = fn || function(a, b){
13300             return a-b;
13301         };
13302         var c = [], k = this.keys, items = this.items;
13303         for(var i = 0, len = items.length; i < len; i++){
13304             c[c.length] = {key: k[i], value: items[i], index: i};
13305         }
13306         c.sort(function(a, b){
13307             var v = fn(a[property], b[property]) * dsc;
13308             if(v == 0){
13309                 v = (a.index < b.index ? -1 : 1);
13310             }
13311             return v;
13312         });
13313         for(var i = 0, len = c.length; i < len; i++){
13314             items[i] = c[i].value;
13315             k[i] = c[i].key;
13316         }
13317         this.fireEvent("sort", this);
13318     },
13319     
13320     /**
13321      * Sorts this collection with the passed comparison function
13322      * @param {String} direction (optional) "ASC" or "DESC"
13323      * @param {Function} fn (optional) comparison function
13324      */
13325     sort : function(dir, fn){
13326         this._sort("value", dir, fn);
13327     },
13328     
13329     /**
13330      * Sorts this collection by keys
13331      * @param {String} direction (optional) "ASC" or "DESC"
13332      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13333      */
13334     keySort : function(dir, fn){
13335         this._sort("key", dir, fn || function(a, b){
13336             return String(a).toUpperCase()-String(b).toUpperCase();
13337         });
13338     },
13339     
13340     /**
13341      * Returns a range of items in this collection
13342      * @param {Number} startIndex (optional) defaults to 0
13343      * @param {Number} endIndex (optional) default to the last item
13344      * @return {Array} An array of items
13345      */
13346     getRange : function(start, end){
13347         var items = this.items;
13348         if(items.length < 1){
13349             return [];
13350         }
13351         start = start || 0;
13352         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13353         var r = [];
13354         if(start <= end){
13355             for(var i = start; i <= end; i++) {
13356                     r[r.length] = items[i];
13357             }
13358         }else{
13359             for(var i = start; i >= end; i--) {
13360                     r[r.length] = items[i];
13361             }
13362         }
13363         return r;
13364     },
13365         
13366     /**
13367      * Filter the <i>objects</i> in this collection by a specific property. 
13368      * Returns a new collection that has been filtered.
13369      * @param {String} property A property on your objects
13370      * @param {String/RegExp} value Either string that the property values 
13371      * should start with or a RegExp to test against the property
13372      * @return {MixedCollection} The new filtered collection
13373      */
13374     filter : function(property, value){
13375         if(!value.exec){ // not a regex
13376             value = String(value);
13377             if(value.length == 0){
13378                 return this.clone();
13379             }
13380             value = new RegExp("^" + Roo.escapeRe(value), "i");
13381         }
13382         return this.filterBy(function(o){
13383             return o && value.test(o[property]);
13384         });
13385         },
13386     
13387     /**
13388      * Filter by a function. * Returns a new collection that has been filtered.
13389      * The passed function will be called with each 
13390      * object in the collection. If the function returns true, the value is included 
13391      * otherwise it is filtered.
13392      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13393      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13394      * @return {MixedCollection} The new filtered collection
13395      */
13396     filterBy : function(fn, scope){
13397         var r = new Roo.util.MixedCollection();
13398         r.getKey = this.getKey;
13399         var k = this.keys, it = this.items;
13400         for(var i = 0, len = it.length; i < len; i++){
13401             if(fn.call(scope||this, it[i], k[i])){
13402                                 r.add(k[i], it[i]);
13403                         }
13404         }
13405         return r;
13406     },
13407     
13408     /**
13409      * Creates a duplicate of this collection
13410      * @return {MixedCollection}
13411      */
13412     clone : function(){
13413         var r = new Roo.util.MixedCollection();
13414         var k = this.keys, it = this.items;
13415         for(var i = 0, len = it.length; i < len; i++){
13416             r.add(k[i], it[i]);
13417         }
13418         r.getKey = this.getKey;
13419         return r;
13420     }
13421 });
13422 /**
13423  * Returns the item associated with the passed key or index.
13424  * @method
13425  * @param {String/Number} key The key or index of the item.
13426  * @return {Object} The item associated with the passed key.
13427  */
13428 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13429  * Based on:
13430  * Ext JS Library 1.1.1
13431  * Copyright(c) 2006-2007, Ext JS, LLC.
13432  *
13433  * Originally Released Under LGPL - original licence link has changed is not relivant.
13434  *
13435  * Fork - LGPL
13436  * <script type="text/javascript">
13437  */
13438 /**
13439  * @class Roo.util.JSON
13440  * Modified version of Douglas Crockford"s json.js that doesn"t
13441  * mess with the Object prototype 
13442  * http://www.json.org/js.html
13443  * @singleton
13444  */
13445 Roo.util.JSON = new (function(){
13446     var useHasOwn = {}.hasOwnProperty ? true : false;
13447     
13448     // crashes Safari in some instances
13449     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13450     
13451     var pad = function(n) {
13452         return n < 10 ? "0" + n : n;
13453     };
13454     
13455     var m = {
13456         "\b": '\\b',
13457         "\t": '\\t',
13458         "\n": '\\n',
13459         "\f": '\\f',
13460         "\r": '\\r',
13461         '"' : '\\"',
13462         "\\": '\\\\'
13463     };
13464
13465     var encodeString = function(s){
13466         if (/["\\\x00-\x1f]/.test(s)) {
13467             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13468                 var c = m[b];
13469                 if(c){
13470                     return c;
13471                 }
13472                 c = b.charCodeAt();
13473                 return "\\u00" +
13474                     Math.floor(c / 16).toString(16) +
13475                     (c % 16).toString(16);
13476             }) + '"';
13477         }
13478         return '"' + s + '"';
13479     };
13480     
13481     var encodeArray = function(o){
13482         var a = ["["], b, i, l = o.length, v;
13483             for (i = 0; i < l; i += 1) {
13484                 v = o[i];
13485                 switch (typeof v) {
13486                     case "undefined":
13487                     case "function":
13488                     case "unknown":
13489                         break;
13490                     default:
13491                         if (b) {
13492                             a.push(',');
13493                         }
13494                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13495                         b = true;
13496                 }
13497             }
13498             a.push("]");
13499             return a.join("");
13500     };
13501     
13502     var encodeDate = function(o){
13503         return '"' + o.getFullYear() + "-" +
13504                 pad(o.getMonth() + 1) + "-" +
13505                 pad(o.getDate()) + "T" +
13506                 pad(o.getHours()) + ":" +
13507                 pad(o.getMinutes()) + ":" +
13508                 pad(o.getSeconds()) + '"';
13509     };
13510     
13511     /**
13512      * Encodes an Object, Array or other value
13513      * @param {Mixed} o The variable to encode
13514      * @return {String} The JSON string
13515      */
13516     this.encode = function(o)
13517     {
13518         // should this be extended to fully wrap stringify..
13519         
13520         if(typeof o == "undefined" || o === null){
13521             return "null";
13522         }else if(o instanceof Array){
13523             return encodeArray(o);
13524         }else if(o instanceof Date){
13525             return encodeDate(o);
13526         }else if(typeof o == "string"){
13527             return encodeString(o);
13528         }else if(typeof o == "number"){
13529             return isFinite(o) ? String(o) : "null";
13530         }else if(typeof o == "boolean"){
13531             return String(o);
13532         }else {
13533             var a = ["{"], b, i, v;
13534             for (i in o) {
13535                 if(!useHasOwn || o.hasOwnProperty(i)) {
13536                     v = o[i];
13537                     switch (typeof v) {
13538                     case "undefined":
13539                     case "function":
13540                     case "unknown":
13541                         break;
13542                     default:
13543                         if(b){
13544                             a.push(',');
13545                         }
13546                         a.push(this.encode(i), ":",
13547                                 v === null ? "null" : this.encode(v));
13548                         b = true;
13549                     }
13550                 }
13551             }
13552             a.push("}");
13553             return a.join("");
13554         }
13555     };
13556     
13557     /**
13558      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13559      * @param {String} json The JSON string
13560      * @return {Object} The resulting object
13561      */
13562     this.decode = function(json){
13563         
13564         return  /** eval:var:json */ eval("(" + json + ')');
13565     };
13566 })();
13567 /** 
13568  * Shorthand for {@link Roo.util.JSON#encode}
13569  * @member Roo encode 
13570  * @method */
13571 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13572 /** 
13573  * Shorthand for {@link Roo.util.JSON#decode}
13574  * @member Roo decode 
13575  * @method */
13576 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13577 /*
13578  * Based on:
13579  * Ext JS Library 1.1.1
13580  * Copyright(c) 2006-2007, Ext JS, LLC.
13581  *
13582  * Originally Released Under LGPL - original licence link has changed is not relivant.
13583  *
13584  * Fork - LGPL
13585  * <script type="text/javascript">
13586  */
13587  
13588 /**
13589  * @class Roo.util.Format
13590  * Reusable data formatting functions
13591  * @singleton
13592  */
13593 Roo.util.Format = function(){
13594     var trimRe = /^\s+|\s+$/g;
13595     return {
13596         /**
13597          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13598          * @param {String} value The string to truncate
13599          * @param {Number} length The maximum length to allow before truncating
13600          * @return {String} The converted text
13601          */
13602         ellipsis : function(value, len){
13603             if(value && value.length > len){
13604                 return value.substr(0, len-3)+"...";
13605             }
13606             return value;
13607         },
13608
13609         /**
13610          * Checks a reference and converts it to empty string if it is undefined
13611          * @param {Mixed} value Reference to check
13612          * @return {Mixed} Empty string if converted, otherwise the original value
13613          */
13614         undef : function(value){
13615             return typeof value != "undefined" ? value : "";
13616         },
13617
13618         /**
13619          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13620          * @param {String} value The string to encode
13621          * @return {String} The encoded text
13622          */
13623         htmlEncode : function(value){
13624             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13625         },
13626
13627         /**
13628          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13629          * @param {String} value The string to decode
13630          * @return {String} The decoded text
13631          */
13632         htmlDecode : function(value){
13633             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13634         },
13635
13636         /**
13637          * Trims any whitespace from either side of a string
13638          * @param {String} value The text to trim
13639          * @return {String} The trimmed text
13640          */
13641         trim : function(value){
13642             return String(value).replace(trimRe, "");
13643         },
13644
13645         /**
13646          * Returns a substring from within an original string
13647          * @param {String} value The original text
13648          * @param {Number} start The start index of the substring
13649          * @param {Number} length The length of the substring
13650          * @return {String} The substring
13651          */
13652         substr : function(value, start, length){
13653             return String(value).substr(start, length);
13654         },
13655
13656         /**
13657          * Converts a string to all lower case letters
13658          * @param {String} value The text to convert
13659          * @return {String} The converted text
13660          */
13661         lowercase : function(value){
13662             return String(value).toLowerCase();
13663         },
13664
13665         /**
13666          * Converts a string to all upper case letters
13667          * @param {String} value The text to convert
13668          * @return {String} The converted text
13669          */
13670         uppercase : function(value){
13671             return String(value).toUpperCase();
13672         },
13673
13674         /**
13675          * Converts the first character only of a string to upper case
13676          * @param {String} value The text to convert
13677          * @return {String} The converted text
13678          */
13679         capitalize : function(value){
13680             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13681         },
13682
13683         // private
13684         call : function(value, fn){
13685             if(arguments.length > 2){
13686                 var args = Array.prototype.slice.call(arguments, 2);
13687                 args.unshift(value);
13688                  
13689                 return /** eval:var:value */  eval(fn).apply(window, args);
13690             }else{
13691                 /** eval:var:value */
13692                 return /** eval:var:value */ eval(fn).call(window, value);
13693             }
13694         },
13695
13696        
13697         /**
13698          * safer version of Math.toFixed..??/
13699          * @param {Number/String} value The numeric value to format
13700          * @param {Number/String} value Decimal places 
13701          * @return {String} The formatted currency string
13702          */
13703         toFixed : function(v, n)
13704         {
13705             // why not use to fixed - precision is buggered???
13706             if (!n) {
13707                 return Math.round(v-0);
13708             }
13709             var fact = Math.pow(10,n+1);
13710             v = (Math.round((v-0)*fact))/fact;
13711             var z = (''+fact).substring(2);
13712             if (v == Math.floor(v)) {
13713                 return Math.floor(v) + '.' + z;
13714             }
13715             
13716             // now just padd decimals..
13717             var ps = String(v).split('.');
13718             var fd = (ps[1] + z);
13719             var r = fd.substring(0,n); 
13720             var rm = fd.substring(n); 
13721             if (rm < 5) {
13722                 return ps[0] + '.' + r;
13723             }
13724             r*=1; // turn it into a number;
13725             r++;
13726             if (String(r).length != n) {
13727                 ps[0]*=1;
13728                 ps[0]++;
13729                 r = String(r).substring(1); // chop the end off.
13730             }
13731             
13732             return ps[0] + '.' + r;
13733              
13734         },
13735         
13736         /**
13737          * Format a number as US currency
13738          * @param {Number/String} value The numeric value to format
13739          * @return {String} The formatted currency string
13740          */
13741         usMoney : function(v){
13742             return '$' + Roo.util.Format.number(v);
13743         },
13744         
13745         /**
13746          * Format a number
13747          * eventually this should probably emulate php's number_format
13748          * @param {Number/String} value The numeric value to format
13749          * @param {Number} decimals number of decimal places
13750          * @return {String} The formatted currency string
13751          */
13752         number : function(v,decimals)
13753         {
13754             // multiply and round.
13755             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13756             var mul = Math.pow(10, decimals);
13757             var zero = String(mul).substring(1);
13758             v = (Math.round((v-0)*mul))/mul;
13759             
13760             // if it's '0' number.. then
13761             
13762             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13763             v = String(v);
13764             var ps = v.split('.');
13765             var whole = ps[0];
13766             
13767             
13768             var r = /(\d+)(\d{3})/;
13769             // add comma's
13770             while (r.test(whole)) {
13771                 whole = whole.replace(r, '$1' + ',' + '$2');
13772             }
13773             
13774             
13775             var sub = ps[1] ?
13776                     // has decimals..
13777                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13778                     // does not have decimals
13779                     (decimals ? ('.' + zero) : '');
13780             
13781             
13782             return whole + sub ;
13783         },
13784         
13785         /**
13786          * Parse a value into a formatted date using the specified format pattern.
13787          * @param {Mixed} value The value to format
13788          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13789          * @return {String} The formatted date string
13790          */
13791         date : function(v, format){
13792             if(!v){
13793                 return "";
13794             }
13795             if(!(v instanceof Date)){
13796                 v = new Date(Date.parse(v));
13797             }
13798             return v.dateFormat(format || Roo.util.Format.defaults.date);
13799         },
13800
13801         /**
13802          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13803          * @param {String} format Any valid date format string
13804          * @return {Function} The date formatting function
13805          */
13806         dateRenderer : function(format){
13807             return function(v){
13808                 return Roo.util.Format.date(v, format);  
13809             };
13810         },
13811
13812         // private
13813         stripTagsRE : /<\/?[^>]+>/gi,
13814         
13815         /**
13816          * Strips all HTML tags
13817          * @param {Mixed} value The text from which to strip tags
13818          * @return {String} The stripped text
13819          */
13820         stripTags : function(v){
13821             return !v ? v : String(v).replace(this.stripTagsRE, "");
13822         }
13823     };
13824 }();
13825 Roo.util.Format.defaults = {
13826     date : 'd/M/Y'
13827 };/*
13828  * Based on:
13829  * Ext JS Library 1.1.1
13830  * Copyright(c) 2006-2007, Ext JS, LLC.
13831  *
13832  * Originally Released Under LGPL - original licence link has changed is not relivant.
13833  *
13834  * Fork - LGPL
13835  * <script type="text/javascript">
13836  */
13837
13838
13839  
13840
13841 /**
13842  * @class Roo.MasterTemplate
13843  * @extends Roo.Template
13844  * Provides a template that can have child templates. The syntax is:
13845 <pre><code>
13846 var t = new Roo.MasterTemplate(
13847         '&lt;select name="{name}"&gt;',
13848                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13849         '&lt;/select&gt;'
13850 );
13851 t.add('options', {value: 'foo', text: 'bar'});
13852 // or you can add multiple child elements in one shot
13853 t.addAll('options', [
13854     {value: 'foo', text: 'bar'},
13855     {value: 'foo2', text: 'bar2'},
13856     {value: 'foo3', text: 'bar3'}
13857 ]);
13858 // then append, applying the master template values
13859 t.append('my-form', {name: 'my-select'});
13860 </code></pre>
13861 * A name attribute for the child template is not required if you have only one child
13862 * template or you want to refer to them by index.
13863  */
13864 Roo.MasterTemplate = function(){
13865     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13866     this.originalHtml = this.html;
13867     var st = {};
13868     var m, re = this.subTemplateRe;
13869     re.lastIndex = 0;
13870     var subIndex = 0;
13871     while(m = re.exec(this.html)){
13872         var name = m[1], content = m[2];
13873         st[subIndex] = {
13874             name: name,
13875             index: subIndex,
13876             buffer: [],
13877             tpl : new Roo.Template(content)
13878         };
13879         if(name){
13880             st[name] = st[subIndex];
13881         }
13882         st[subIndex].tpl.compile();
13883         st[subIndex].tpl.call = this.call.createDelegate(this);
13884         subIndex++;
13885     }
13886     this.subCount = subIndex;
13887     this.subs = st;
13888 };
13889 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13890     /**
13891     * The regular expression used to match sub templates
13892     * @type RegExp
13893     * @property
13894     */
13895     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13896
13897     /**
13898      * Applies the passed values to a child template.
13899      * @param {String/Number} name (optional) The name or index of the child template
13900      * @param {Array/Object} values The values to be applied to the template
13901      * @return {MasterTemplate} this
13902      */
13903      add : function(name, values){
13904         if(arguments.length == 1){
13905             values = arguments[0];
13906             name = 0;
13907         }
13908         var s = this.subs[name];
13909         s.buffer[s.buffer.length] = s.tpl.apply(values);
13910         return this;
13911     },
13912
13913     /**
13914      * Applies all the passed values to a child template.
13915      * @param {String/Number} name (optional) The name or index of the child template
13916      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13917      * @param {Boolean} reset (optional) True to reset the template first
13918      * @return {MasterTemplate} this
13919      */
13920     fill : function(name, values, reset){
13921         var a = arguments;
13922         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13923             values = a[0];
13924             name = 0;
13925             reset = a[1];
13926         }
13927         if(reset){
13928             this.reset();
13929         }
13930         for(var i = 0, len = values.length; i < len; i++){
13931             this.add(name, values[i]);
13932         }
13933         return this;
13934     },
13935
13936     /**
13937      * Resets the template for reuse
13938      * @return {MasterTemplate} this
13939      */
13940      reset : function(){
13941         var s = this.subs;
13942         for(var i = 0; i < this.subCount; i++){
13943             s[i].buffer = [];
13944         }
13945         return this;
13946     },
13947
13948     applyTemplate : function(values){
13949         var s = this.subs;
13950         var replaceIndex = -1;
13951         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13952             return s[++replaceIndex].buffer.join("");
13953         });
13954         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13955     },
13956
13957     apply : function(){
13958         return this.applyTemplate.apply(this, arguments);
13959     },
13960
13961     compile : function(){return this;}
13962 });
13963
13964 /**
13965  * Alias for fill().
13966  * @method
13967  */
13968 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13969  /**
13970  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13971  * var tpl = Roo.MasterTemplate.from('element-id');
13972  * @param {String/HTMLElement} el
13973  * @param {Object} config
13974  * @static
13975  */
13976 Roo.MasterTemplate.from = function(el, config){
13977     el = Roo.getDom(el);
13978     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13979 };/*
13980  * Based on:
13981  * Ext JS Library 1.1.1
13982  * Copyright(c) 2006-2007, Ext JS, LLC.
13983  *
13984  * Originally Released Under LGPL - original licence link has changed is not relivant.
13985  *
13986  * Fork - LGPL
13987  * <script type="text/javascript">
13988  */
13989
13990  
13991 /**
13992  * @class Roo.util.CSS
13993  * Utility class for manipulating CSS rules
13994  * @singleton
13995  */
13996 Roo.util.CSS = function(){
13997         var rules = null;
13998         var doc = document;
13999
14000     var camelRe = /(-[a-z])/gi;
14001     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14002
14003    return {
14004    /**
14005     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14006     * tag and appended to the HEAD of the document.
14007     * @param {String|Object} cssText The text containing the css rules
14008     * @param {String} id An id to add to the stylesheet for later removal
14009     * @return {StyleSheet}
14010     */
14011     createStyleSheet : function(cssText, id){
14012         var ss;
14013         var head = doc.getElementsByTagName("head")[0];
14014         var nrules = doc.createElement("style");
14015         nrules.setAttribute("type", "text/css");
14016         if(id){
14017             nrules.setAttribute("id", id);
14018         }
14019         if (typeof(cssText) != 'string') {
14020             // support object maps..
14021             // not sure if this a good idea.. 
14022             // perhaps it should be merged with the general css handling
14023             // and handle js style props.
14024             var cssTextNew = [];
14025             for(var n in cssText) {
14026                 var citems = [];
14027                 for(var k in cssText[n]) {
14028                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14029                 }
14030                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14031                 
14032             }
14033             cssText = cssTextNew.join("\n");
14034             
14035         }
14036        
14037        
14038        if(Roo.isIE){
14039            head.appendChild(nrules);
14040            ss = nrules.styleSheet;
14041            ss.cssText = cssText;
14042        }else{
14043            try{
14044                 nrules.appendChild(doc.createTextNode(cssText));
14045            }catch(e){
14046                nrules.cssText = cssText; 
14047            }
14048            head.appendChild(nrules);
14049            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14050        }
14051        this.cacheStyleSheet(ss);
14052        return ss;
14053    },
14054
14055    /**
14056     * Removes a style or link tag by id
14057     * @param {String} id The id of the tag
14058     */
14059    removeStyleSheet : function(id){
14060        var existing = doc.getElementById(id);
14061        if(existing){
14062            existing.parentNode.removeChild(existing);
14063        }
14064    },
14065
14066    /**
14067     * Dynamically swaps an existing stylesheet reference for a new one
14068     * @param {String} id The id of an existing link tag to remove
14069     * @param {String} url The href of the new stylesheet to include
14070     */
14071    swapStyleSheet : function(id, url){
14072        this.removeStyleSheet(id);
14073        var ss = doc.createElement("link");
14074        ss.setAttribute("rel", "stylesheet");
14075        ss.setAttribute("type", "text/css");
14076        ss.setAttribute("id", id);
14077        ss.setAttribute("href", url);
14078        doc.getElementsByTagName("head")[0].appendChild(ss);
14079    },
14080    
14081    /**
14082     * Refresh the rule cache if you have dynamically added stylesheets
14083     * @return {Object} An object (hash) of rules indexed by selector
14084     */
14085    refreshCache : function(){
14086        return this.getRules(true);
14087    },
14088
14089    // private
14090    cacheStyleSheet : function(stylesheet){
14091        if(!rules){
14092            rules = {};
14093        }
14094        try{// try catch for cross domain access issue
14095            var ssRules = stylesheet.cssRules || stylesheet.rules;
14096            for(var j = ssRules.length-1; j >= 0; --j){
14097                rules[ssRules[j].selectorText] = ssRules[j];
14098            }
14099        }catch(e){}
14100    },
14101    
14102    /**
14103     * Gets all css rules for the document
14104     * @param {Boolean} refreshCache true to refresh the internal cache
14105     * @return {Object} An object (hash) of rules indexed by selector
14106     */
14107    getRules : function(refreshCache){
14108                 if(rules == null || refreshCache){
14109                         rules = {};
14110                         var ds = doc.styleSheets;
14111                         for(var i =0, len = ds.length; i < len; i++){
14112                             try{
14113                         this.cacheStyleSheet(ds[i]);
14114                     }catch(e){} 
14115                 }
14116                 }
14117                 return rules;
14118         },
14119         
14120         /**
14121     * Gets an an individual CSS rule by selector(s)
14122     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14123     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14124     * @return {CSSRule} The CSS rule or null if one is not found
14125     */
14126    getRule : function(selector, refreshCache){
14127                 var rs = this.getRules(refreshCache);
14128                 if(!(selector instanceof Array)){
14129                     return rs[selector];
14130                 }
14131                 for(var i = 0; i < selector.length; i++){
14132                         if(rs[selector[i]]){
14133                                 return rs[selector[i]];
14134                         }
14135                 }
14136                 return null;
14137         },
14138         
14139         
14140         /**
14141     * Updates a rule property
14142     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14143     * @param {String} property The css property
14144     * @param {String} value The new value for the property
14145     * @return {Boolean} true If a rule was found and updated
14146     */
14147    updateRule : function(selector, property, value){
14148                 if(!(selector instanceof Array)){
14149                         var rule = this.getRule(selector);
14150                         if(rule){
14151                                 rule.style[property.replace(camelRe, camelFn)] = value;
14152                                 return true;
14153                         }
14154                 }else{
14155                         for(var i = 0; i < selector.length; i++){
14156                                 if(this.updateRule(selector[i], property, value)){
14157                                         return true;
14158                                 }
14159                         }
14160                 }
14161                 return false;
14162         }
14163    };   
14164 }();/*
14165  * Based on:
14166  * Ext JS Library 1.1.1
14167  * Copyright(c) 2006-2007, Ext JS, LLC.
14168  *
14169  * Originally Released Under LGPL - original licence link has changed is not relivant.
14170  *
14171  * Fork - LGPL
14172  * <script type="text/javascript">
14173  */
14174
14175  
14176
14177 /**
14178  * @class Roo.util.ClickRepeater
14179  * @extends Roo.util.Observable
14180  * 
14181  * A wrapper class which can be applied to any element. Fires a "click" event while the
14182  * mouse is pressed. The interval between firings may be specified in the config but
14183  * defaults to 10 milliseconds.
14184  * 
14185  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14186  * 
14187  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14188  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14189  * Similar to an autorepeat key delay.
14190  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14191  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14192  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14193  *           "interval" and "delay" are ignored. "immediate" is honored.
14194  * @cfg {Boolean} preventDefault True to prevent the default click event
14195  * @cfg {Boolean} stopDefault True to stop the default click event
14196  * 
14197  * @history
14198  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14199  *     2007-02-02 jvs Renamed to ClickRepeater
14200  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14201  *
14202  *  @constructor
14203  * @param {String/HTMLElement/Element} el The element to listen on
14204  * @param {Object} config
14205  **/
14206 Roo.util.ClickRepeater = function(el, config)
14207 {
14208     this.el = Roo.get(el);
14209     this.el.unselectable();
14210
14211     Roo.apply(this, config);
14212
14213     this.addEvents({
14214     /**
14215      * @event mousedown
14216      * Fires when the mouse button is depressed.
14217      * @param {Roo.util.ClickRepeater} this
14218      */
14219         "mousedown" : true,
14220     /**
14221      * @event click
14222      * Fires on a specified interval during the time the element is pressed.
14223      * @param {Roo.util.ClickRepeater} this
14224      */
14225         "click" : true,
14226     /**
14227      * @event mouseup
14228      * Fires when the mouse key is released.
14229      * @param {Roo.util.ClickRepeater} this
14230      */
14231         "mouseup" : true
14232     });
14233
14234     this.el.on("mousedown", this.handleMouseDown, this);
14235     if(this.preventDefault || this.stopDefault){
14236         this.el.on("click", function(e){
14237             if(this.preventDefault){
14238                 e.preventDefault();
14239             }
14240             if(this.stopDefault){
14241                 e.stopEvent();
14242             }
14243         }, this);
14244     }
14245
14246     // allow inline handler
14247     if(this.handler){
14248         this.on("click", this.handler,  this.scope || this);
14249     }
14250
14251     Roo.util.ClickRepeater.superclass.constructor.call(this);
14252 };
14253
14254 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14255     interval : 20,
14256     delay: 250,
14257     preventDefault : true,
14258     stopDefault : false,
14259     timer : 0,
14260
14261     // private
14262     handleMouseDown : function(){
14263         clearTimeout(this.timer);
14264         this.el.blur();
14265         if(this.pressClass){
14266             this.el.addClass(this.pressClass);
14267         }
14268         this.mousedownTime = new Date();
14269
14270         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14271         this.el.on("mouseout", this.handleMouseOut, this);
14272
14273         this.fireEvent("mousedown", this);
14274         this.fireEvent("click", this);
14275         
14276         this.timer = this.click.defer(this.delay || this.interval, this);
14277     },
14278
14279     // private
14280     click : function(){
14281         this.fireEvent("click", this);
14282         this.timer = this.click.defer(this.getInterval(), this);
14283     },
14284
14285     // private
14286     getInterval: function(){
14287         if(!this.accelerate){
14288             return this.interval;
14289         }
14290         var pressTime = this.mousedownTime.getElapsed();
14291         if(pressTime < 500){
14292             return 400;
14293         }else if(pressTime < 1700){
14294             return 320;
14295         }else if(pressTime < 2600){
14296             return 250;
14297         }else if(pressTime < 3500){
14298             return 180;
14299         }else if(pressTime < 4400){
14300             return 140;
14301         }else if(pressTime < 5300){
14302             return 80;
14303         }else if(pressTime < 6200){
14304             return 50;
14305         }else{
14306             return 10;
14307         }
14308     },
14309
14310     // private
14311     handleMouseOut : function(){
14312         clearTimeout(this.timer);
14313         if(this.pressClass){
14314             this.el.removeClass(this.pressClass);
14315         }
14316         this.el.on("mouseover", this.handleMouseReturn, this);
14317     },
14318
14319     // private
14320     handleMouseReturn : function(){
14321         this.el.un("mouseover", this.handleMouseReturn);
14322         if(this.pressClass){
14323             this.el.addClass(this.pressClass);
14324         }
14325         this.click();
14326     },
14327
14328     // private
14329     handleMouseUp : function(){
14330         clearTimeout(this.timer);
14331         this.el.un("mouseover", this.handleMouseReturn);
14332         this.el.un("mouseout", this.handleMouseOut);
14333         Roo.get(document).un("mouseup", this.handleMouseUp);
14334         this.el.removeClass(this.pressClass);
14335         this.fireEvent("mouseup", this);
14336     }
14337 });/*
14338  * Based on:
14339  * Ext JS Library 1.1.1
14340  * Copyright(c) 2006-2007, Ext JS, LLC.
14341  *
14342  * Originally Released Under LGPL - original licence link has changed is not relivant.
14343  *
14344  * Fork - LGPL
14345  * <script type="text/javascript">
14346  */
14347
14348  
14349 /**
14350  * @class Roo.KeyNav
14351  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14352  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14353  * way to implement custom navigation schemes for any UI component.</p>
14354  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14355  * pageUp, pageDown, del, home, end.  Usage:</p>
14356  <pre><code>
14357 var nav = new Roo.KeyNav("my-element", {
14358     "left" : function(e){
14359         this.moveLeft(e.ctrlKey);
14360     },
14361     "right" : function(e){
14362         this.moveRight(e.ctrlKey);
14363     },
14364     "enter" : function(e){
14365         this.save();
14366     },
14367     scope : this
14368 });
14369 </code></pre>
14370  * @constructor
14371  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14372  * @param {Object} config The config
14373  */
14374 Roo.KeyNav = function(el, config){
14375     this.el = Roo.get(el);
14376     Roo.apply(this, config);
14377     if(!this.disabled){
14378         this.disabled = true;
14379         this.enable();
14380     }
14381 };
14382
14383 Roo.KeyNav.prototype = {
14384     /**
14385      * @cfg {Boolean} disabled
14386      * True to disable this KeyNav instance (defaults to false)
14387      */
14388     disabled : false,
14389     /**
14390      * @cfg {String} defaultEventAction
14391      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14392      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14393      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14394      */
14395     defaultEventAction: "stopEvent",
14396     /**
14397      * @cfg {Boolean} forceKeyDown
14398      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14399      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14400      * handle keydown instead of keypress.
14401      */
14402     forceKeyDown : false,
14403
14404     // private
14405     prepareEvent : function(e){
14406         var k = e.getKey();
14407         var h = this.keyToHandler[k];
14408         //if(h && this[h]){
14409         //    e.stopPropagation();
14410         //}
14411         if(Roo.isSafari && h && k >= 37 && k <= 40){
14412             e.stopEvent();
14413         }
14414     },
14415
14416     // private
14417     relay : function(e){
14418         var k = e.getKey();
14419         var h = this.keyToHandler[k];
14420         if(h && this[h]){
14421             if(this.doRelay(e, this[h], h) !== true){
14422                 e[this.defaultEventAction]();
14423             }
14424         }
14425     },
14426
14427     // private
14428     doRelay : function(e, h, hname){
14429         return h.call(this.scope || this, e);
14430     },
14431
14432     // possible handlers
14433     enter : false,
14434     left : false,
14435     right : false,
14436     up : false,
14437     down : false,
14438     tab : false,
14439     esc : false,
14440     pageUp : false,
14441     pageDown : false,
14442     del : false,
14443     home : false,
14444     end : false,
14445
14446     // quick lookup hash
14447     keyToHandler : {
14448         37 : "left",
14449         39 : "right",
14450         38 : "up",
14451         40 : "down",
14452         33 : "pageUp",
14453         34 : "pageDown",
14454         46 : "del",
14455         36 : "home",
14456         35 : "end",
14457         13 : "enter",
14458         27 : "esc",
14459         9  : "tab"
14460     },
14461
14462         /**
14463          * Enable this KeyNav
14464          */
14465         enable: function(){
14466                 if(this.disabled){
14467             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14468             // the EventObject will normalize Safari automatically
14469             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14470                 this.el.on("keydown", this.relay,  this);
14471             }else{
14472                 this.el.on("keydown", this.prepareEvent,  this);
14473                 this.el.on("keypress", this.relay,  this);
14474             }
14475                     this.disabled = false;
14476                 }
14477         },
14478
14479         /**
14480          * Disable this KeyNav
14481          */
14482         disable: function(){
14483                 if(!this.disabled){
14484                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14485                 this.el.un("keydown", this.relay);
14486             }else{
14487                 this.el.un("keydown", this.prepareEvent);
14488                 this.el.un("keypress", this.relay);
14489             }
14490                     this.disabled = true;
14491                 }
14492         }
14493 };/*
14494  * Based on:
14495  * Ext JS Library 1.1.1
14496  * Copyright(c) 2006-2007, Ext JS, LLC.
14497  *
14498  * Originally Released Under LGPL - original licence link has changed is not relivant.
14499  *
14500  * Fork - LGPL
14501  * <script type="text/javascript">
14502  */
14503
14504  
14505 /**
14506  * @class Roo.KeyMap
14507  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14508  * The constructor accepts the same config object as defined by {@link #addBinding}.
14509  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14510  * combination it will call the function with this signature (if the match is a multi-key
14511  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14512  * A KeyMap can also handle a string representation of keys.<br />
14513  * Usage:
14514  <pre><code>
14515 // map one key by key code
14516 var map = new Roo.KeyMap("my-element", {
14517     key: 13, // or Roo.EventObject.ENTER
14518     fn: myHandler,
14519     scope: myObject
14520 });
14521
14522 // map multiple keys to one action by string
14523 var map = new Roo.KeyMap("my-element", {
14524     key: "a\r\n\t",
14525     fn: myHandler,
14526     scope: myObject
14527 });
14528
14529 // map multiple keys to multiple actions by strings and array of codes
14530 var map = new Roo.KeyMap("my-element", [
14531     {
14532         key: [10,13],
14533         fn: function(){ alert("Return was pressed"); }
14534     }, {
14535         key: "abc",
14536         fn: function(){ alert('a, b or c was pressed'); }
14537     }, {
14538         key: "\t",
14539         ctrl:true,
14540         shift:true,
14541         fn: function(){ alert('Control + shift + tab was pressed.'); }
14542     }
14543 ]);
14544 </code></pre>
14545  * <b>Note: A KeyMap starts enabled</b>
14546  * @constructor
14547  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14548  * @param {Object} config The config (see {@link #addBinding})
14549  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14550  */
14551 Roo.KeyMap = function(el, config, eventName){
14552     this.el  = Roo.get(el);
14553     this.eventName = eventName || "keydown";
14554     this.bindings = [];
14555     if(config){
14556         this.addBinding(config);
14557     }
14558     this.enable();
14559 };
14560
14561 Roo.KeyMap.prototype = {
14562     /**
14563      * True to stop the event from bubbling and prevent the default browser action if the
14564      * key was handled by the KeyMap (defaults to false)
14565      * @type Boolean
14566      */
14567     stopEvent : false,
14568
14569     /**
14570      * Add a new binding to this KeyMap. The following config object properties are supported:
14571      * <pre>
14572 Property    Type             Description
14573 ----------  ---------------  ----------------------------------------------------------------------
14574 key         String/Array     A single keycode or an array of keycodes to handle
14575 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14576 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14577 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14578 fn          Function         The function to call when KeyMap finds the expected key combination
14579 scope       Object           The scope of the callback function
14580 </pre>
14581      *
14582      * Usage:
14583      * <pre><code>
14584 // Create a KeyMap
14585 var map = new Roo.KeyMap(document, {
14586     key: Roo.EventObject.ENTER,
14587     fn: handleKey,
14588     scope: this
14589 });
14590
14591 //Add a new binding to the existing KeyMap later
14592 map.addBinding({
14593     key: 'abc',
14594     shift: true,
14595     fn: handleKey,
14596     scope: this
14597 });
14598 </code></pre>
14599      * @param {Object/Array} config A single KeyMap config or an array of configs
14600      */
14601         addBinding : function(config){
14602         if(config instanceof Array){
14603             for(var i = 0, len = config.length; i < len; i++){
14604                 this.addBinding(config[i]);
14605             }
14606             return;
14607         }
14608         var keyCode = config.key,
14609             shift = config.shift, 
14610             ctrl = config.ctrl, 
14611             alt = config.alt,
14612             fn = config.fn,
14613             scope = config.scope;
14614         if(typeof keyCode == "string"){
14615             var ks = [];
14616             var keyString = keyCode.toUpperCase();
14617             for(var j = 0, len = keyString.length; j < len; j++){
14618                 ks.push(keyString.charCodeAt(j));
14619             }
14620             keyCode = ks;
14621         }
14622         var keyArray = keyCode instanceof Array;
14623         var handler = function(e){
14624             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14625                 var k = e.getKey();
14626                 if(keyArray){
14627                     for(var i = 0, len = keyCode.length; i < len; i++){
14628                         if(keyCode[i] == k){
14629                           if(this.stopEvent){
14630                               e.stopEvent();
14631                           }
14632                           fn.call(scope || window, k, e);
14633                           return;
14634                         }
14635                     }
14636                 }else{
14637                     if(k == keyCode){
14638                         if(this.stopEvent){
14639                            e.stopEvent();
14640                         }
14641                         fn.call(scope || window, k, e);
14642                     }
14643                 }
14644             }
14645         };
14646         this.bindings.push(handler);  
14647         },
14648
14649     /**
14650      * Shorthand for adding a single key listener
14651      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14652      * following options:
14653      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14654      * @param {Function} fn The function to call
14655      * @param {Object} scope (optional) The scope of the function
14656      */
14657     on : function(key, fn, scope){
14658         var keyCode, shift, ctrl, alt;
14659         if(typeof key == "object" && !(key instanceof Array)){
14660             keyCode = key.key;
14661             shift = key.shift;
14662             ctrl = key.ctrl;
14663             alt = key.alt;
14664         }else{
14665             keyCode = key;
14666         }
14667         this.addBinding({
14668             key: keyCode,
14669             shift: shift,
14670             ctrl: ctrl,
14671             alt: alt,
14672             fn: fn,
14673             scope: scope
14674         })
14675     },
14676
14677     // private
14678     handleKeyDown : function(e){
14679             if(this.enabled){ //just in case
14680             var b = this.bindings;
14681             for(var i = 0, len = b.length; i < len; i++){
14682                 b[i].call(this, e);
14683             }
14684             }
14685         },
14686         
14687         /**
14688          * Returns true if this KeyMap is enabled
14689          * @return {Boolean} 
14690          */
14691         isEnabled : function(){
14692             return this.enabled;  
14693         },
14694         
14695         /**
14696          * Enables this KeyMap
14697          */
14698         enable: function(){
14699                 if(!this.enabled){
14700                     this.el.on(this.eventName, this.handleKeyDown, this);
14701                     this.enabled = true;
14702                 }
14703         },
14704
14705         /**
14706          * Disable this KeyMap
14707          */
14708         disable: function(){
14709                 if(this.enabled){
14710                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14711                     this.enabled = false;
14712                 }
14713         }
14714 };/*
14715  * Based on:
14716  * Ext JS Library 1.1.1
14717  * Copyright(c) 2006-2007, Ext JS, LLC.
14718  *
14719  * Originally Released Under LGPL - original licence link has changed is not relivant.
14720  *
14721  * Fork - LGPL
14722  * <script type="text/javascript">
14723  */
14724
14725  
14726 /**
14727  * @class Roo.util.TextMetrics
14728  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14729  * wide, in pixels, a given block of text will be.
14730  * @singleton
14731  */
14732 Roo.util.TextMetrics = function(){
14733     var shared;
14734     return {
14735         /**
14736          * Measures the size of the specified text
14737          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14738          * that can affect the size of the rendered text
14739          * @param {String} text The text to measure
14740          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14741          * in order to accurately measure the text height
14742          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14743          */
14744         measure : function(el, text, fixedWidth){
14745             if(!shared){
14746                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14747             }
14748             shared.bind(el);
14749             shared.setFixedWidth(fixedWidth || 'auto');
14750             return shared.getSize(text);
14751         },
14752
14753         /**
14754          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14755          * the overhead of multiple calls to initialize the style properties on each measurement.
14756          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14757          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14758          * in order to accurately measure the text height
14759          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14760          */
14761         createInstance : function(el, fixedWidth){
14762             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14763         }
14764     };
14765 }();
14766
14767  
14768
14769 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14770     var ml = new Roo.Element(document.createElement('div'));
14771     document.body.appendChild(ml.dom);
14772     ml.position('absolute');
14773     ml.setLeftTop(-1000, -1000);
14774     ml.hide();
14775
14776     if(fixedWidth){
14777         ml.setWidth(fixedWidth);
14778     }
14779      
14780     var instance = {
14781         /**
14782          * Returns the size of the specified text based on the internal element's style and width properties
14783          * @memberOf Roo.util.TextMetrics.Instance#
14784          * @param {String} text The text to measure
14785          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14786          */
14787         getSize : function(text){
14788             ml.update(text);
14789             var s = ml.getSize();
14790             ml.update('');
14791             return s;
14792         },
14793
14794         /**
14795          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14796          * that can affect the size of the rendered text
14797          * @memberOf Roo.util.TextMetrics.Instance#
14798          * @param {String/HTMLElement} el The element, dom node or id
14799          */
14800         bind : function(el){
14801             ml.setStyle(
14802                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14803             );
14804         },
14805
14806         /**
14807          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14808          * to set a fixed width in order to accurately measure the text height.
14809          * @memberOf Roo.util.TextMetrics.Instance#
14810          * @param {Number} width The width to set on the element
14811          */
14812         setFixedWidth : function(width){
14813             ml.setWidth(width);
14814         },
14815
14816         /**
14817          * Returns the measured width of the specified text
14818          * @memberOf Roo.util.TextMetrics.Instance#
14819          * @param {String} text The text to measure
14820          * @return {Number} width The width in pixels
14821          */
14822         getWidth : function(text){
14823             ml.dom.style.width = 'auto';
14824             return this.getSize(text).width;
14825         },
14826
14827         /**
14828          * Returns the measured height of the specified text.  For multiline text, be sure to call
14829          * {@link #setFixedWidth} if necessary.
14830          * @memberOf Roo.util.TextMetrics.Instance#
14831          * @param {String} text The text to measure
14832          * @return {Number} height The height in pixels
14833          */
14834         getHeight : function(text){
14835             return this.getSize(text).height;
14836         }
14837     };
14838
14839     instance.bind(bindTo);
14840
14841     return instance;
14842 };
14843
14844 // backwards compat
14845 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14846  * Based on:
14847  * Ext JS Library 1.1.1
14848  * Copyright(c) 2006-2007, Ext JS, LLC.
14849  *
14850  * Originally Released Under LGPL - original licence link has changed is not relivant.
14851  *
14852  * Fork - LGPL
14853  * <script type="text/javascript">
14854  */
14855
14856 /**
14857  * @class Roo.state.Provider
14858  * Abstract base class for state provider implementations. This class provides methods
14859  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14860  * Provider interface.
14861  */
14862 Roo.state.Provider = function(){
14863     /**
14864      * @event statechange
14865      * Fires when a state change occurs.
14866      * @param {Provider} this This state provider
14867      * @param {String} key The state key which was changed
14868      * @param {String} value The encoded value for the state
14869      */
14870     this.addEvents({
14871         "statechange": true
14872     });
14873     this.state = {};
14874     Roo.state.Provider.superclass.constructor.call(this);
14875 };
14876 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14877     /**
14878      * Returns the current value for a key
14879      * @param {String} name The key name
14880      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14881      * @return {Mixed} The state data
14882      */
14883     get : function(name, defaultValue){
14884         return typeof this.state[name] == "undefined" ?
14885             defaultValue : this.state[name];
14886     },
14887     
14888     /**
14889      * Clears a value from the state
14890      * @param {String} name The key name
14891      */
14892     clear : function(name){
14893         delete this.state[name];
14894         this.fireEvent("statechange", this, name, null);
14895     },
14896     
14897     /**
14898      * Sets the value for a key
14899      * @param {String} name The key name
14900      * @param {Mixed} value The value to set
14901      */
14902     set : function(name, value){
14903         this.state[name] = value;
14904         this.fireEvent("statechange", this, name, value);
14905     },
14906     
14907     /**
14908      * Decodes a string previously encoded with {@link #encodeValue}.
14909      * @param {String} value The value to decode
14910      * @return {Mixed} The decoded value
14911      */
14912     decodeValue : function(cookie){
14913         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14914         var matches = re.exec(unescape(cookie));
14915         if(!matches || !matches[1]) {
14916             return; // non state cookie
14917         }
14918         var type = matches[1];
14919         var v = matches[2];
14920         switch(type){
14921             case "n":
14922                 return parseFloat(v);
14923             case "d":
14924                 return new Date(Date.parse(v));
14925             case "b":
14926                 return (v == "1");
14927             case "a":
14928                 var all = [];
14929                 var values = v.split("^");
14930                 for(var i = 0, len = values.length; i < len; i++){
14931                     all.push(this.decodeValue(values[i]));
14932                 }
14933                 return all;
14934            case "o":
14935                 var all = {};
14936                 var values = v.split("^");
14937                 for(var i = 0, len = values.length; i < len; i++){
14938                     var kv = values[i].split("=");
14939                     all[kv[0]] = this.decodeValue(kv[1]);
14940                 }
14941                 return all;
14942            default:
14943                 return v;
14944         }
14945     },
14946     
14947     /**
14948      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14949      * @param {Mixed} value The value to encode
14950      * @return {String} The encoded value
14951      */
14952     encodeValue : function(v){
14953         var enc;
14954         if(typeof v == "number"){
14955             enc = "n:" + v;
14956         }else if(typeof v == "boolean"){
14957             enc = "b:" + (v ? "1" : "0");
14958         }else if(v instanceof Date){
14959             enc = "d:" + v.toGMTString();
14960         }else if(v instanceof Array){
14961             var flat = "";
14962             for(var i = 0, len = v.length; i < len; i++){
14963                 flat += this.encodeValue(v[i]);
14964                 if(i != len-1) {
14965                     flat += "^";
14966                 }
14967             }
14968             enc = "a:" + flat;
14969         }else if(typeof v == "object"){
14970             var flat = "";
14971             for(var key in v){
14972                 if(typeof v[key] != "function"){
14973                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14974                 }
14975             }
14976             enc = "o:" + flat.substring(0, flat.length-1);
14977         }else{
14978             enc = "s:" + v;
14979         }
14980         return escape(enc);        
14981     }
14982 });
14983
14984 /*
14985  * Based on:
14986  * Ext JS Library 1.1.1
14987  * Copyright(c) 2006-2007, Ext JS, LLC.
14988  *
14989  * Originally Released Under LGPL - original licence link has changed is not relivant.
14990  *
14991  * Fork - LGPL
14992  * <script type="text/javascript">
14993  */
14994 /**
14995  * @class Roo.state.Manager
14996  * This is the global state manager. By default all components that are "state aware" check this class
14997  * for state information if you don't pass them a custom state provider. In order for this class
14998  * to be useful, it must be initialized with a provider when your application initializes.
14999  <pre><code>
15000 // in your initialization function
15001 init : function(){
15002    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15003    ...
15004    // supposed you have a {@link Roo.BorderLayout}
15005    var layout = new Roo.BorderLayout(...);
15006    layout.restoreState();
15007    // or a {Roo.BasicDialog}
15008    var dialog = new Roo.BasicDialog(...);
15009    dialog.restoreState();
15010  </code></pre>
15011  * @singleton
15012  */
15013 Roo.state.Manager = function(){
15014     var provider = new Roo.state.Provider();
15015     
15016     return {
15017         /**
15018          * Configures the default state provider for your application
15019          * @param {Provider} stateProvider The state provider to set
15020          */
15021         setProvider : function(stateProvider){
15022             provider = stateProvider;
15023         },
15024         
15025         /**
15026          * Returns the current value for a key
15027          * @param {String} name The key name
15028          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15029          * @return {Mixed} The state data
15030          */
15031         get : function(key, defaultValue){
15032             return provider.get(key, defaultValue);
15033         },
15034         
15035         /**
15036          * Sets the value for a key
15037          * @param {String} name The key name
15038          * @param {Mixed} value The state data
15039          */
15040          set : function(key, value){
15041             provider.set(key, value);
15042         },
15043         
15044         /**
15045          * Clears a value from the state
15046          * @param {String} name The key name
15047          */
15048         clear : function(key){
15049             provider.clear(key);
15050         },
15051         
15052         /**
15053          * Gets the currently configured state provider
15054          * @return {Provider} The state provider
15055          */
15056         getProvider : function(){
15057             return provider;
15058         }
15059     };
15060 }();
15061 /*
15062  * Based on:
15063  * Ext JS Library 1.1.1
15064  * Copyright(c) 2006-2007, Ext JS, LLC.
15065  *
15066  * Originally Released Under LGPL - original licence link has changed is not relivant.
15067  *
15068  * Fork - LGPL
15069  * <script type="text/javascript">
15070  */
15071 /**
15072  * @class Roo.state.CookieProvider
15073  * @extends Roo.state.Provider
15074  * The default Provider implementation which saves state via cookies.
15075  * <br />Usage:
15076  <pre><code>
15077    var cp = new Roo.state.CookieProvider({
15078        path: "/cgi-bin/",
15079        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15080        domain: "roojs.com"
15081    })
15082    Roo.state.Manager.setProvider(cp);
15083  </code></pre>
15084  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15085  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15086  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15087  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15088  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15089  * domain the page is running on including the 'www' like 'www.roojs.com')
15090  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15091  * @constructor
15092  * Create a new CookieProvider
15093  * @param {Object} config The configuration object
15094  */
15095 Roo.state.CookieProvider = function(config){
15096     Roo.state.CookieProvider.superclass.constructor.call(this);
15097     this.path = "/";
15098     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15099     this.domain = null;
15100     this.secure = false;
15101     Roo.apply(this, config);
15102     this.state = this.readCookies();
15103 };
15104
15105 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15106     // private
15107     set : function(name, value){
15108         if(typeof value == "undefined" || value === null){
15109             this.clear(name);
15110             return;
15111         }
15112         this.setCookie(name, value);
15113         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15114     },
15115
15116     // private
15117     clear : function(name){
15118         this.clearCookie(name);
15119         Roo.state.CookieProvider.superclass.clear.call(this, name);
15120     },
15121
15122     // private
15123     readCookies : function(){
15124         var cookies = {};
15125         var c = document.cookie + ";";
15126         var re = /\s?(.*?)=(.*?);/g;
15127         var matches;
15128         while((matches = re.exec(c)) != null){
15129             var name = matches[1];
15130             var value = matches[2];
15131             if(name && name.substring(0,3) == "ys-"){
15132                 cookies[name.substr(3)] = this.decodeValue(value);
15133             }
15134         }
15135         return cookies;
15136     },
15137
15138     // private
15139     setCookie : function(name, value){
15140         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15141            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15142            ((this.path == null) ? "" : ("; path=" + this.path)) +
15143            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15144            ((this.secure == true) ? "; secure" : "");
15145     },
15146
15147     // private
15148     clearCookie : function(name){
15149         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15150            ((this.path == null) ? "" : ("; path=" + this.path)) +
15151            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15152            ((this.secure == true) ? "; secure" : "");
15153     }
15154 });/*
15155  * Based on:
15156  * Ext JS Library 1.1.1
15157  * Copyright(c) 2006-2007, Ext JS, LLC.
15158  *
15159  * Originally Released Under LGPL - original licence link has changed is not relivant.
15160  *
15161  * Fork - LGPL
15162  * <script type="text/javascript">
15163  */
15164  
15165
15166 /**
15167  * @class Roo.ComponentMgr
15168  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15169  * @singleton
15170  */
15171 Roo.ComponentMgr = function(){
15172     var all = new Roo.util.MixedCollection();
15173
15174     return {
15175         /**
15176          * Registers a component.
15177          * @param {Roo.Component} c The component
15178          */
15179         register : function(c){
15180             all.add(c);
15181         },
15182
15183         /**
15184          * Unregisters a component.
15185          * @param {Roo.Component} c The component
15186          */
15187         unregister : function(c){
15188             all.remove(c);
15189         },
15190
15191         /**
15192          * Returns a component by id
15193          * @param {String} id The component id
15194          */
15195         get : function(id){
15196             return all.get(id);
15197         },
15198
15199         /**
15200          * Registers a function that will be called when a specified component is added to ComponentMgr
15201          * @param {String} id The component id
15202          * @param {Funtction} fn The callback function
15203          * @param {Object} scope The scope of the callback
15204          */
15205         onAvailable : function(id, fn, scope){
15206             all.on("add", function(index, o){
15207                 if(o.id == id){
15208                     fn.call(scope || o, o);
15209                     all.un("add", fn, scope);
15210                 }
15211             });
15212         }
15213     };
15214 }();/*
15215  * Based on:
15216  * Ext JS Library 1.1.1
15217  * Copyright(c) 2006-2007, Ext JS, LLC.
15218  *
15219  * Originally Released Under LGPL - original licence link has changed is not relivant.
15220  *
15221  * Fork - LGPL
15222  * <script type="text/javascript">
15223  */
15224  
15225 /**
15226  * @class Roo.Component
15227  * @extends Roo.util.Observable
15228  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15229  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15230  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15231  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15232  * All visual components (widgets) that require rendering into a layout should subclass Component.
15233  * @constructor
15234  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15235  * 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
15236  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15237  */
15238 Roo.Component = function(config){
15239     config = config || {};
15240     if(config.tagName || config.dom || typeof config == "string"){ // element object
15241         config = {el: config, id: config.id || config};
15242     }
15243     this.initialConfig = config;
15244
15245     Roo.apply(this, config);
15246     this.addEvents({
15247         /**
15248          * @event disable
15249          * Fires after the component is disabled.
15250              * @param {Roo.Component} this
15251              */
15252         disable : true,
15253         /**
15254          * @event enable
15255          * Fires after the component is enabled.
15256              * @param {Roo.Component} this
15257              */
15258         enable : true,
15259         /**
15260          * @event beforeshow
15261          * Fires before the component is shown.  Return false to stop the show.
15262              * @param {Roo.Component} this
15263              */
15264         beforeshow : true,
15265         /**
15266          * @event show
15267          * Fires after the component is shown.
15268              * @param {Roo.Component} this
15269              */
15270         show : true,
15271         /**
15272          * @event beforehide
15273          * Fires before the component is hidden. Return false to stop the hide.
15274              * @param {Roo.Component} this
15275              */
15276         beforehide : true,
15277         /**
15278          * @event hide
15279          * Fires after the component is hidden.
15280              * @param {Roo.Component} this
15281              */
15282         hide : true,
15283         /**
15284          * @event beforerender
15285          * Fires before the component is rendered. Return false to stop the render.
15286              * @param {Roo.Component} this
15287              */
15288         beforerender : true,
15289         /**
15290          * @event render
15291          * Fires after the component is rendered.
15292              * @param {Roo.Component} this
15293              */
15294         render : true,
15295         /**
15296          * @event beforedestroy
15297          * Fires before the component is destroyed. Return false to stop the destroy.
15298              * @param {Roo.Component} this
15299              */
15300         beforedestroy : true,
15301         /**
15302          * @event destroy
15303          * Fires after the component is destroyed.
15304              * @param {Roo.Component} this
15305              */
15306         destroy : true
15307     });
15308     if(!this.id){
15309         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15310     }
15311     Roo.ComponentMgr.register(this);
15312     Roo.Component.superclass.constructor.call(this);
15313     this.initComponent();
15314     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15315         this.render(this.renderTo);
15316         delete this.renderTo;
15317     }
15318 };
15319
15320 /** @private */
15321 Roo.Component.AUTO_ID = 1000;
15322
15323 Roo.extend(Roo.Component, Roo.util.Observable, {
15324     /**
15325      * @scope Roo.Component.prototype
15326      * @type {Boolean}
15327      * true if this component is hidden. Read-only.
15328      */
15329     hidden : false,
15330     /**
15331      * @type {Boolean}
15332      * true if this component is disabled. Read-only.
15333      */
15334     disabled : false,
15335     /**
15336      * @type {Boolean}
15337      * true if this component has been rendered. Read-only.
15338      */
15339     rendered : false,
15340     
15341     /** @cfg {String} disableClass
15342      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15343      */
15344     disabledClass : "x-item-disabled",
15345         /** @cfg {Boolean} allowDomMove
15346          * Whether the component can move the Dom node when rendering (defaults to true).
15347          */
15348     allowDomMove : true,
15349     /** @cfg {String} hideMode (display|visibility)
15350      * How this component should hidden. Supported values are
15351      * "visibility" (css visibility), "offsets" (negative offset position) and
15352      * "display" (css display) - defaults to "display".
15353      */
15354     hideMode: 'display',
15355
15356     /** @private */
15357     ctype : "Roo.Component",
15358
15359     /**
15360      * @cfg {String} actionMode 
15361      * which property holds the element that used for  hide() / show() / disable() / enable()
15362      * default is 'el' 
15363      */
15364     actionMode : "el",
15365
15366     /** @private */
15367     getActionEl : function(){
15368         return this[this.actionMode];
15369     },
15370
15371     initComponent : Roo.emptyFn,
15372     /**
15373      * If this is a lazy rendering component, render it to its container element.
15374      * @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.
15375      */
15376     render : function(container, position){
15377         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15378             if(!container && this.el){
15379                 this.el = Roo.get(this.el);
15380                 container = this.el.dom.parentNode;
15381                 this.allowDomMove = false;
15382             }
15383             this.container = Roo.get(container);
15384             this.rendered = true;
15385             if(position !== undefined){
15386                 if(typeof position == 'number'){
15387                     position = this.container.dom.childNodes[position];
15388                 }else{
15389                     position = Roo.getDom(position);
15390                 }
15391             }
15392             this.onRender(this.container, position || null);
15393             if(this.cls){
15394                 this.el.addClass(this.cls);
15395                 delete this.cls;
15396             }
15397             if(this.style){
15398                 this.el.applyStyles(this.style);
15399                 delete this.style;
15400             }
15401             this.fireEvent("render", this);
15402             this.afterRender(this.container);
15403             if(this.hidden){
15404                 this.hide();
15405             }
15406             if(this.disabled){
15407                 this.disable();
15408             }
15409         }
15410         return this;
15411     },
15412
15413     /** @private */
15414     // default function is not really useful
15415     onRender : function(ct, position){
15416         if(this.el){
15417             this.el = Roo.get(this.el);
15418             if(this.allowDomMove !== false){
15419                 ct.dom.insertBefore(this.el.dom, position);
15420             }
15421         }
15422     },
15423
15424     /** @private */
15425     getAutoCreate : function(){
15426         var cfg = typeof this.autoCreate == "object" ?
15427                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15428         if(this.id && !cfg.id){
15429             cfg.id = this.id;
15430         }
15431         return cfg;
15432     },
15433
15434     /** @private */
15435     afterRender : Roo.emptyFn,
15436
15437     /**
15438      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15439      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15440      */
15441     destroy : function(){
15442         if(this.fireEvent("beforedestroy", this) !== false){
15443             this.purgeListeners();
15444             this.beforeDestroy();
15445             if(this.rendered){
15446                 this.el.removeAllListeners();
15447                 this.el.remove();
15448                 if(this.actionMode == "container"){
15449                     this.container.remove();
15450                 }
15451             }
15452             this.onDestroy();
15453             Roo.ComponentMgr.unregister(this);
15454             this.fireEvent("destroy", this);
15455         }
15456     },
15457
15458         /** @private */
15459     beforeDestroy : function(){
15460
15461     },
15462
15463         /** @private */
15464         onDestroy : function(){
15465
15466     },
15467
15468     /**
15469      * Returns the underlying {@link Roo.Element}.
15470      * @return {Roo.Element} The element
15471      */
15472     getEl : function(){
15473         return this.el;
15474     },
15475
15476     /**
15477      * Returns the id of this component.
15478      * @return {String}
15479      */
15480     getId : function(){
15481         return this.id;
15482     },
15483
15484     /**
15485      * Try to focus this component.
15486      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15487      * @return {Roo.Component} this
15488      */
15489     focus : function(selectText){
15490         if(this.rendered){
15491             this.el.focus();
15492             if(selectText === true){
15493                 this.el.dom.select();
15494             }
15495         }
15496         return this;
15497     },
15498
15499     /** @private */
15500     blur : function(){
15501         if(this.rendered){
15502             this.el.blur();
15503         }
15504         return this;
15505     },
15506
15507     /**
15508      * Disable this component.
15509      * @return {Roo.Component} this
15510      */
15511     disable : function(){
15512         if(this.rendered){
15513             this.onDisable();
15514         }
15515         this.disabled = true;
15516         this.fireEvent("disable", this);
15517         return this;
15518     },
15519
15520         // private
15521     onDisable : function(){
15522         this.getActionEl().addClass(this.disabledClass);
15523         this.el.dom.disabled = true;
15524     },
15525
15526     /**
15527      * Enable this component.
15528      * @return {Roo.Component} this
15529      */
15530     enable : function(){
15531         if(this.rendered){
15532             this.onEnable();
15533         }
15534         this.disabled = false;
15535         this.fireEvent("enable", this);
15536         return this;
15537     },
15538
15539         // private
15540     onEnable : function(){
15541         this.getActionEl().removeClass(this.disabledClass);
15542         this.el.dom.disabled = false;
15543     },
15544
15545     /**
15546      * Convenience function for setting disabled/enabled by boolean.
15547      * @param {Boolean} disabled
15548      */
15549     setDisabled : function(disabled){
15550         this[disabled ? "disable" : "enable"]();
15551     },
15552
15553     /**
15554      * Show this component.
15555      * @return {Roo.Component} this
15556      */
15557     show: function(){
15558         if(this.fireEvent("beforeshow", this) !== false){
15559             this.hidden = false;
15560             if(this.rendered){
15561                 this.onShow();
15562             }
15563             this.fireEvent("show", this);
15564         }
15565         return this;
15566     },
15567
15568     // private
15569     onShow : function(){
15570         var ae = this.getActionEl();
15571         if(this.hideMode == 'visibility'){
15572             ae.dom.style.visibility = "visible";
15573         }else if(this.hideMode == 'offsets'){
15574             ae.removeClass('x-hidden');
15575         }else{
15576             ae.dom.style.display = "";
15577         }
15578     },
15579
15580     /**
15581      * Hide this component.
15582      * @return {Roo.Component} this
15583      */
15584     hide: function(){
15585         if(this.fireEvent("beforehide", this) !== false){
15586             this.hidden = true;
15587             if(this.rendered){
15588                 this.onHide();
15589             }
15590             this.fireEvent("hide", this);
15591         }
15592         return this;
15593     },
15594
15595     // private
15596     onHide : function(){
15597         var ae = this.getActionEl();
15598         if(this.hideMode == 'visibility'){
15599             ae.dom.style.visibility = "hidden";
15600         }else if(this.hideMode == 'offsets'){
15601             ae.addClass('x-hidden');
15602         }else{
15603             ae.dom.style.display = "none";
15604         }
15605     },
15606
15607     /**
15608      * Convenience function to hide or show this component by boolean.
15609      * @param {Boolean} visible True to show, false to hide
15610      * @return {Roo.Component} this
15611      */
15612     setVisible: function(visible){
15613         if(visible) {
15614             this.show();
15615         }else{
15616             this.hide();
15617         }
15618         return this;
15619     },
15620
15621     /**
15622      * Returns true if this component is visible.
15623      */
15624     isVisible : function(){
15625         return this.getActionEl().isVisible();
15626     },
15627
15628     cloneConfig : function(overrides){
15629         overrides = overrides || {};
15630         var id = overrides.id || Roo.id();
15631         var cfg = Roo.applyIf(overrides, this.initialConfig);
15632         cfg.id = id; // prevent dup id
15633         return new this.constructor(cfg);
15634     }
15635 });/*
15636  * Based on:
15637  * Ext JS Library 1.1.1
15638  * Copyright(c) 2006-2007, Ext JS, LLC.
15639  *
15640  * Originally Released Under LGPL - original licence link has changed is not relivant.
15641  *
15642  * Fork - LGPL
15643  * <script type="text/javascript">
15644  */
15645
15646 /**
15647  * @class Roo.BoxComponent
15648  * @extends Roo.Component
15649  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15650  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15651  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15652  * layout containers.
15653  * @constructor
15654  * @param {Roo.Element/String/Object} config The configuration options.
15655  */
15656 Roo.BoxComponent = function(config){
15657     Roo.Component.call(this, config);
15658     this.addEvents({
15659         /**
15660          * @event resize
15661          * Fires after the component is resized.
15662              * @param {Roo.Component} this
15663              * @param {Number} adjWidth The box-adjusted width that was set
15664              * @param {Number} adjHeight The box-adjusted height that was set
15665              * @param {Number} rawWidth The width that was originally specified
15666              * @param {Number} rawHeight The height that was originally specified
15667              */
15668         resize : true,
15669         /**
15670          * @event move
15671          * Fires after the component is moved.
15672              * @param {Roo.Component} this
15673              * @param {Number} x The new x position
15674              * @param {Number} y The new y position
15675              */
15676         move : true
15677     });
15678 };
15679
15680 Roo.extend(Roo.BoxComponent, Roo.Component, {
15681     // private, set in afterRender to signify that the component has been rendered
15682     boxReady : false,
15683     // private, used to defer height settings to subclasses
15684     deferHeight: false,
15685     /** @cfg {Number} width
15686      * width (optional) size of component
15687      */
15688      /** @cfg {Number} height
15689      * height (optional) size of component
15690      */
15691      
15692     /**
15693      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15694      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15695      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15696      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15697      * @return {Roo.BoxComponent} this
15698      */
15699     setSize : function(w, h){
15700         // support for standard size objects
15701         if(typeof w == 'object'){
15702             h = w.height;
15703             w = w.width;
15704         }
15705         // not rendered
15706         if(!this.boxReady){
15707             this.width = w;
15708             this.height = h;
15709             return this;
15710         }
15711
15712         // prevent recalcs when not needed
15713         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15714             return this;
15715         }
15716         this.lastSize = {width: w, height: h};
15717
15718         var adj = this.adjustSize(w, h);
15719         var aw = adj.width, ah = adj.height;
15720         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15721             var rz = this.getResizeEl();
15722             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15723                 rz.setSize(aw, ah);
15724             }else if(!this.deferHeight && ah !== undefined){
15725                 rz.setHeight(ah);
15726             }else if(aw !== undefined){
15727                 rz.setWidth(aw);
15728             }
15729             this.onResize(aw, ah, w, h);
15730             this.fireEvent('resize', this, aw, ah, w, h);
15731         }
15732         return this;
15733     },
15734
15735     /**
15736      * Gets the current size of the component's underlying element.
15737      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15738      */
15739     getSize : function(){
15740         return this.el.getSize();
15741     },
15742
15743     /**
15744      * Gets the current XY position of the component's underlying element.
15745      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15746      * @return {Array} The XY position of the element (e.g., [100, 200])
15747      */
15748     getPosition : function(local){
15749         if(local === true){
15750             return [this.el.getLeft(true), this.el.getTop(true)];
15751         }
15752         return this.xy || this.el.getXY();
15753     },
15754
15755     /**
15756      * Gets the current box measurements of the component's underlying element.
15757      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15758      * @returns {Object} box An object in the format {x, y, width, height}
15759      */
15760     getBox : function(local){
15761         var s = this.el.getSize();
15762         if(local){
15763             s.x = this.el.getLeft(true);
15764             s.y = this.el.getTop(true);
15765         }else{
15766             var xy = this.xy || this.el.getXY();
15767             s.x = xy[0];
15768             s.y = xy[1];
15769         }
15770         return s;
15771     },
15772
15773     /**
15774      * Sets the current box measurements of the component's underlying element.
15775      * @param {Object} box An object in the format {x, y, width, height}
15776      * @returns {Roo.BoxComponent} this
15777      */
15778     updateBox : function(box){
15779         this.setSize(box.width, box.height);
15780         this.setPagePosition(box.x, box.y);
15781         return this;
15782     },
15783
15784     // protected
15785     getResizeEl : function(){
15786         return this.resizeEl || this.el;
15787     },
15788
15789     // protected
15790     getPositionEl : function(){
15791         return this.positionEl || this.el;
15792     },
15793
15794     /**
15795      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15796      * This method fires the move event.
15797      * @param {Number} left The new left
15798      * @param {Number} top The new top
15799      * @returns {Roo.BoxComponent} this
15800      */
15801     setPosition : function(x, y){
15802         this.x = x;
15803         this.y = y;
15804         if(!this.boxReady){
15805             return this;
15806         }
15807         var adj = this.adjustPosition(x, y);
15808         var ax = adj.x, ay = adj.y;
15809
15810         var el = this.getPositionEl();
15811         if(ax !== undefined || ay !== undefined){
15812             if(ax !== undefined && ay !== undefined){
15813                 el.setLeftTop(ax, ay);
15814             }else if(ax !== undefined){
15815                 el.setLeft(ax);
15816             }else if(ay !== undefined){
15817                 el.setTop(ay);
15818             }
15819             this.onPosition(ax, ay);
15820             this.fireEvent('move', this, ax, ay);
15821         }
15822         return this;
15823     },
15824
15825     /**
15826      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15827      * This method fires the move event.
15828      * @param {Number} x The new x position
15829      * @param {Number} y The new y position
15830      * @returns {Roo.BoxComponent} this
15831      */
15832     setPagePosition : function(x, y){
15833         this.pageX = x;
15834         this.pageY = y;
15835         if(!this.boxReady){
15836             return;
15837         }
15838         if(x === undefined || y === undefined){ // cannot translate undefined points
15839             return;
15840         }
15841         var p = this.el.translatePoints(x, y);
15842         this.setPosition(p.left, p.top);
15843         return this;
15844     },
15845
15846     // private
15847     onRender : function(ct, position){
15848         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15849         if(this.resizeEl){
15850             this.resizeEl = Roo.get(this.resizeEl);
15851         }
15852         if(this.positionEl){
15853             this.positionEl = Roo.get(this.positionEl);
15854         }
15855     },
15856
15857     // private
15858     afterRender : function(){
15859         Roo.BoxComponent.superclass.afterRender.call(this);
15860         this.boxReady = true;
15861         this.setSize(this.width, this.height);
15862         if(this.x || this.y){
15863             this.setPosition(this.x, this.y);
15864         }
15865         if(this.pageX || this.pageY){
15866             this.setPagePosition(this.pageX, this.pageY);
15867         }
15868     },
15869
15870     /**
15871      * Force the component's size to recalculate based on the underlying element's current height and width.
15872      * @returns {Roo.BoxComponent} this
15873      */
15874     syncSize : function(){
15875         delete this.lastSize;
15876         this.setSize(this.el.getWidth(), this.el.getHeight());
15877         return this;
15878     },
15879
15880     /**
15881      * Called after the component is resized, this method is empty by default but can be implemented by any
15882      * subclass that needs to perform custom logic after a resize occurs.
15883      * @param {Number} adjWidth The box-adjusted width that was set
15884      * @param {Number} adjHeight The box-adjusted height that was set
15885      * @param {Number} rawWidth The width that was originally specified
15886      * @param {Number} rawHeight The height that was originally specified
15887      */
15888     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15889
15890     },
15891
15892     /**
15893      * Called after the component is moved, this method is empty by default but can be implemented by any
15894      * subclass that needs to perform custom logic after a move occurs.
15895      * @param {Number} x The new x position
15896      * @param {Number} y The new y position
15897      */
15898     onPosition : function(x, y){
15899
15900     },
15901
15902     // private
15903     adjustSize : function(w, h){
15904         if(this.autoWidth){
15905             w = 'auto';
15906         }
15907         if(this.autoHeight){
15908             h = 'auto';
15909         }
15910         return {width : w, height: h};
15911     },
15912
15913     // private
15914     adjustPosition : function(x, y){
15915         return {x : x, y: y};
15916     }
15917 });/*
15918  * Original code for Roojs - LGPL
15919  * <script type="text/javascript">
15920  */
15921  
15922 /**
15923  * @class Roo.XComponent
15924  * A delayed Element creator...
15925  * Or a way to group chunks of interface together.
15926  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15927  *  used in conjunction with XComponent.build() it will create an instance of each element,
15928  *  then call addxtype() to build the User interface.
15929  * 
15930  * Mypart.xyx = new Roo.XComponent({
15931
15932     parent : 'Mypart.xyz', // empty == document.element.!!
15933     order : '001',
15934     name : 'xxxx'
15935     region : 'xxxx'
15936     disabled : function() {} 
15937      
15938     tree : function() { // return an tree of xtype declared components
15939         var MODULE = this;
15940         return 
15941         {
15942             xtype : 'NestedLayoutPanel',
15943             // technicall
15944         }
15945      ]
15946  *})
15947  *
15948  *
15949  * It can be used to build a big heiracy, with parent etc.
15950  * or you can just use this to render a single compoent to a dom element
15951  * MYPART.render(Roo.Element | String(id) | dom_element )
15952  *
15953  *
15954  * Usage patterns.
15955  *
15956  * Classic Roo
15957  *
15958  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15959  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15960  *
15961  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15962  *
15963  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15964  * - if mulitple topModules exist, the last one is defined as the top module.
15965  *
15966  * Embeded Roo
15967  * 
15968  * When the top level or multiple modules are to embedded into a existing HTML page,
15969  * the parent element can container '#id' of the element where the module will be drawn.
15970  *
15971  * Bootstrap Roo
15972  *
15973  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15974  * it relies more on a include mechanism, where sub modules are included into an outer page.
15975  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15976  * 
15977  * Bootstrap Roo Included elements
15978  *
15979  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15980  * hence confusing the component builder as it thinks there are multiple top level elements. 
15981  *
15982  * 
15983  * 
15984  * @extends Roo.util.Observable
15985  * @constructor
15986  * @param cfg {Object} configuration of component
15987  * 
15988  */
15989 Roo.XComponent = function(cfg) {
15990     Roo.apply(this, cfg);
15991     this.addEvents({ 
15992         /**
15993              * @event built
15994              * Fires when this the componnt is built
15995              * @param {Roo.XComponent} c the component
15996              */
15997         'built' : true
15998         
15999     });
16000     this.region = this.region || 'center'; // default..
16001     Roo.XComponent.register(this);
16002     this.modules = false;
16003     this.el = false; // where the layout goes..
16004     
16005     
16006 }
16007 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16008     /**
16009      * @property el
16010      * The created element (with Roo.factory())
16011      * @type {Roo.Layout}
16012      */
16013     el  : false,
16014     
16015     /**
16016      * @property el
16017      * for BC  - use el in new code
16018      * @type {Roo.Layout}
16019      */
16020     panel : false,
16021     
16022     /**
16023      * @property layout
16024      * for BC  - use el in new code
16025      * @type {Roo.Layout}
16026      */
16027     layout : false,
16028     
16029      /**
16030      * @cfg {Function|boolean} disabled
16031      * If this module is disabled by some rule, return true from the funtion
16032      */
16033     disabled : false,
16034     
16035     /**
16036      * @cfg {String} parent 
16037      * Name of parent element which it get xtype added to..
16038      */
16039     parent: false,
16040     
16041     /**
16042      * @cfg {String} order
16043      * Used to set the order in which elements are created (usefull for multiple tabs)
16044      */
16045     
16046     order : false,
16047     /**
16048      * @cfg {String} name
16049      * String to display while loading.
16050      */
16051     name : false,
16052     /**
16053      * @cfg {String} region
16054      * Region to render component to (defaults to center)
16055      */
16056     region : 'center',
16057     
16058     /**
16059      * @cfg {Array} items
16060      * A single item array - the first element is the root of the tree..
16061      * It's done this way to stay compatible with the Xtype system...
16062      */
16063     items : false,
16064     
16065     /**
16066      * @property _tree
16067      * The method that retuns the tree of parts that make up this compoennt 
16068      * @type {function}
16069      */
16070     _tree  : false,
16071     
16072      /**
16073      * render
16074      * render element to dom or tree
16075      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16076      */
16077     
16078     render : function(el)
16079     {
16080         
16081         el = el || false;
16082         var hp = this.parent ? 1 : 0;
16083         Roo.debug &&  Roo.log(this);
16084         
16085         var tree = this._tree ? this._tree() : this.tree();
16086
16087         
16088         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16089             // if parent is a '#.....' string, then let's use that..
16090             var ename = this.parent.substr(1);
16091             this.parent = false;
16092             Roo.debug && Roo.log(ename);
16093             switch (ename) {
16094                 case 'bootstrap-body':
16095                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16096                         // this is the BorderLayout standard?
16097                        this.parent = { el : true };
16098                        break;
16099                     }
16100                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16101                         // need to insert stuff...
16102                         this.parent =  {
16103                              el : new Roo.bootstrap.layout.Border({
16104                                  el : document.body, 
16105                      
16106                                  center: {
16107                                     titlebar: false,
16108                                     autoScroll:false,
16109                                     closeOnTab: true,
16110                                     tabPosition: 'top',
16111                                       //resizeTabs: true,
16112                                     alwaysShowTabs: true,
16113                                     hideTabs: false
16114                                      //minTabWidth: 140
16115                                  }
16116                              })
16117                         
16118                          };
16119                          break;
16120                     }
16121                          
16122                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16123                         this.parent = { el :  new  Roo.bootstrap.Body() };
16124                         Roo.debug && Roo.log("setting el to doc body");
16125                          
16126                     } else {
16127                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16128                     }
16129                     break;
16130                 case 'bootstrap':
16131                     this.parent = { el : true};
16132                     // fall through
16133                 default:
16134                     el = Roo.get(ename);
16135                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16136                         this.parent = { el : true};
16137                     }
16138                     
16139                     break;
16140             }
16141                 
16142             
16143             if (!el && !this.parent) {
16144                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16145                 return;
16146             }
16147         }
16148         
16149         Roo.debug && Roo.log("EL:");
16150         Roo.debug && Roo.log(el);
16151         Roo.debug && Roo.log("this.parent.el:");
16152         Roo.debug && Roo.log(this.parent.el);
16153         
16154
16155         // altertive root elements ??? - we need a better way to indicate these.
16156         var is_alt = Roo.XComponent.is_alt ||
16157                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16158                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16159                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16160         
16161         
16162         
16163         if (!this.parent && is_alt) {
16164             //el = Roo.get(document.body);
16165             this.parent = { el : true };
16166         }
16167             
16168             
16169         
16170         if (!this.parent) {
16171             
16172             Roo.debug && Roo.log("no parent - creating one");
16173             
16174             el = el ? Roo.get(el) : false;      
16175             
16176             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16177                 
16178                 this.parent =  {
16179                     el : new Roo.bootstrap.layout.Border({
16180                         el: el || document.body,
16181                     
16182                         center: {
16183                             titlebar: false,
16184                             autoScroll:false,
16185                             closeOnTab: true,
16186                             tabPosition: 'top',
16187                              //resizeTabs: true,
16188                             alwaysShowTabs: false,
16189                             hideTabs: true,
16190                             minTabWidth: 140,
16191                             overflow: 'visible'
16192                          }
16193                      })
16194                 };
16195             } else {
16196             
16197                 // it's a top level one..
16198                 this.parent =  {
16199                     el : new Roo.BorderLayout(el || document.body, {
16200                         center: {
16201                             titlebar: false,
16202                             autoScroll:false,
16203                             closeOnTab: true,
16204                             tabPosition: 'top',
16205                              //resizeTabs: true,
16206                             alwaysShowTabs: el && hp? false :  true,
16207                             hideTabs: el || !hp ? true :  false,
16208                             minTabWidth: 140
16209                          }
16210                     })
16211                 };
16212             }
16213         }
16214         
16215         if (!this.parent.el) {
16216                 // probably an old style ctor, which has been disabled.
16217                 return;
16218
16219         }
16220                 // The 'tree' method is  '_tree now' 
16221             
16222         tree.region = tree.region || this.region;
16223         var is_body = false;
16224         if (this.parent.el === true) {
16225             // bootstrap... - body..
16226             if (el) {
16227                 tree.el = el;
16228             }
16229             this.parent.el = Roo.factory(tree);
16230             is_body = true;
16231         }
16232         
16233         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16234         this.fireEvent('built', this);
16235         
16236         this.panel = this.el;
16237         this.layout = this.panel.layout;
16238         this.parentLayout = this.parent.layout  || false;  
16239          
16240     }
16241     
16242 });
16243
16244 Roo.apply(Roo.XComponent, {
16245     /**
16246      * @property  hideProgress
16247      * true to disable the building progress bar.. usefull on single page renders.
16248      * @type Boolean
16249      */
16250     hideProgress : false,
16251     /**
16252      * @property  buildCompleted
16253      * True when the builder has completed building the interface.
16254      * @type Boolean
16255      */
16256     buildCompleted : false,
16257      
16258     /**
16259      * @property  topModule
16260      * the upper most module - uses document.element as it's constructor.
16261      * @type Object
16262      */
16263      
16264     topModule  : false,
16265       
16266     /**
16267      * @property  modules
16268      * array of modules to be created by registration system.
16269      * @type {Array} of Roo.XComponent
16270      */
16271     
16272     modules : [],
16273     /**
16274      * @property  elmodules
16275      * array of modules to be created by which use #ID 
16276      * @type {Array} of Roo.XComponent
16277      */
16278      
16279     elmodules : [],
16280
16281      /**
16282      * @property  is_alt
16283      * Is an alternative Root - normally used by bootstrap or other systems,
16284      *    where the top element in the tree can wrap 'body' 
16285      * @type {boolean}  (default false)
16286      */
16287      
16288     is_alt : false,
16289     /**
16290      * @property  build_from_html
16291      * Build elements from html - used by bootstrap HTML stuff 
16292      *    - this is cleared after build is completed
16293      * @type {boolean}    (default false)
16294      */
16295      
16296     build_from_html : false,
16297     /**
16298      * Register components to be built later.
16299      *
16300      * This solves the following issues
16301      * - Building is not done on page load, but after an authentication process has occured.
16302      * - Interface elements are registered on page load
16303      * - Parent Interface elements may not be loaded before child, so this handles that..
16304      * 
16305      *
16306      * example:
16307      * 
16308      * MyApp.register({
16309           order : '000001',
16310           module : 'Pman.Tab.projectMgr',
16311           region : 'center',
16312           parent : 'Pman.layout',
16313           disabled : false,  // or use a function..
16314         })
16315      
16316      * * @param {Object} details about module
16317      */
16318     register : function(obj) {
16319                 
16320         Roo.XComponent.event.fireEvent('register', obj);
16321         switch(typeof(obj.disabled) ) {
16322                 
16323             case 'undefined':
16324                 break;
16325             
16326             case 'function':
16327                 if ( obj.disabled() ) {
16328                         return;
16329                 }
16330                 break;
16331             
16332             default:
16333                 if (obj.disabled) {
16334                         return;
16335                 }
16336                 break;
16337         }
16338                 
16339         this.modules.push(obj);
16340          
16341     },
16342     /**
16343      * convert a string to an object..
16344      * eg. 'AAA.BBB' -> finds AAA.BBB
16345
16346      */
16347     
16348     toObject : function(str)
16349     {
16350         if (!str || typeof(str) == 'object') {
16351             return str;
16352         }
16353         if (str.substring(0,1) == '#') {
16354             return str;
16355         }
16356
16357         var ar = str.split('.');
16358         var rt, o;
16359         rt = ar.shift();
16360             /** eval:var:o */
16361         try {
16362             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16363         } catch (e) {
16364             throw "Module not found : " + str;
16365         }
16366         
16367         if (o === false) {
16368             throw "Module not found : " + str;
16369         }
16370         Roo.each(ar, function(e) {
16371             if (typeof(o[e]) == 'undefined') {
16372                 throw "Module not found : " + str;
16373             }
16374             o = o[e];
16375         });
16376         
16377         return o;
16378         
16379     },
16380     
16381     
16382     /**
16383      * move modules into their correct place in the tree..
16384      * 
16385      */
16386     preBuild : function ()
16387     {
16388         var _t = this;
16389         Roo.each(this.modules , function (obj)
16390         {
16391             Roo.XComponent.event.fireEvent('beforebuild', obj);
16392             
16393             var opar = obj.parent;
16394             try { 
16395                 obj.parent = this.toObject(opar);
16396             } catch(e) {
16397                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16398                 return;
16399             }
16400             
16401             if (!obj.parent) {
16402                 Roo.debug && Roo.log("GOT top level module");
16403                 Roo.debug && Roo.log(obj);
16404                 obj.modules = new Roo.util.MixedCollection(false, 
16405                     function(o) { return o.order + '' }
16406                 );
16407                 this.topModule = obj;
16408                 return;
16409             }
16410                         // parent is a string (usually a dom element name..)
16411             if (typeof(obj.parent) == 'string') {
16412                 this.elmodules.push(obj);
16413                 return;
16414             }
16415             if (obj.parent.constructor != Roo.XComponent) {
16416                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16417             }
16418             if (!obj.parent.modules) {
16419                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16420                     function(o) { return o.order + '' }
16421                 );
16422             }
16423             if (obj.parent.disabled) {
16424                 obj.disabled = true;
16425             }
16426             obj.parent.modules.add(obj);
16427         }, this);
16428     },
16429     
16430      /**
16431      * make a list of modules to build.
16432      * @return {Array} list of modules. 
16433      */ 
16434     
16435     buildOrder : function()
16436     {
16437         var _this = this;
16438         var cmp = function(a,b) {   
16439             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16440         };
16441         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16442             throw "No top level modules to build";
16443         }
16444         
16445         // make a flat list in order of modules to build.
16446         var mods = this.topModule ? [ this.topModule ] : [];
16447                 
16448         
16449         // elmodules (is a list of DOM based modules )
16450         Roo.each(this.elmodules, function(e) {
16451             mods.push(e);
16452             if (!this.topModule &&
16453                 typeof(e.parent) == 'string' &&
16454                 e.parent.substring(0,1) == '#' &&
16455                 Roo.get(e.parent.substr(1))
16456                ) {
16457                 
16458                 _this.topModule = e;
16459             }
16460             
16461         });
16462
16463         
16464         // add modules to their parents..
16465         var addMod = function(m) {
16466             Roo.debug && Roo.log("build Order: add: " + m.name);
16467                 
16468             mods.push(m);
16469             if (m.modules && !m.disabled) {
16470                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16471                 m.modules.keySort('ASC',  cmp );
16472                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16473     
16474                 m.modules.each(addMod);
16475             } else {
16476                 Roo.debug && Roo.log("build Order: no child modules");
16477             }
16478             // not sure if this is used any more..
16479             if (m.finalize) {
16480                 m.finalize.name = m.name + " (clean up) ";
16481                 mods.push(m.finalize);
16482             }
16483             
16484         }
16485         if (this.topModule && this.topModule.modules) { 
16486             this.topModule.modules.keySort('ASC',  cmp );
16487             this.topModule.modules.each(addMod);
16488         } 
16489         return mods;
16490     },
16491     
16492      /**
16493      * Build the registered modules.
16494      * @param {Object} parent element.
16495      * @param {Function} optional method to call after module has been added.
16496      * 
16497      */ 
16498    
16499     build : function(opts) 
16500     {
16501         
16502         if (typeof(opts) != 'undefined') {
16503             Roo.apply(this,opts);
16504         }
16505         
16506         this.preBuild();
16507         var mods = this.buildOrder();
16508       
16509         //this.allmods = mods;
16510         //Roo.debug && Roo.log(mods);
16511         //return;
16512         if (!mods.length) { // should not happen
16513             throw "NO modules!!!";
16514         }
16515         
16516         
16517         var msg = "Building Interface...";
16518         // flash it up as modal - so we store the mask!?
16519         if (!this.hideProgress && Roo.MessageBox) {
16520             Roo.MessageBox.show({ title: 'loading' });
16521             Roo.MessageBox.show({
16522                title: "Please wait...",
16523                msg: msg,
16524                width:450,
16525                progress:true,
16526                closable:false,
16527                modal: false
16528               
16529             });
16530         }
16531         var total = mods.length;
16532         
16533         var _this = this;
16534         var progressRun = function() {
16535             if (!mods.length) {
16536                 Roo.debug && Roo.log('hide?');
16537                 if (!this.hideProgress && Roo.MessageBox) {
16538                     Roo.MessageBox.hide();
16539                 }
16540                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16541                 
16542                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16543                 
16544                 // THE END...
16545                 return false;   
16546             }
16547             
16548             var m = mods.shift();
16549             
16550             
16551             Roo.debug && Roo.log(m);
16552             // not sure if this is supported any more.. - modules that are are just function
16553             if (typeof(m) == 'function') { 
16554                 m.call(this);
16555                 return progressRun.defer(10, _this);
16556             } 
16557             
16558             
16559             msg = "Building Interface " + (total  - mods.length) + 
16560                     " of " + total + 
16561                     (m.name ? (' - ' + m.name) : '');
16562                         Roo.debug && Roo.log(msg);
16563             if (!_this.hideProgress &&  Roo.MessageBox) { 
16564                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16565             }
16566             
16567          
16568             // is the module disabled?
16569             var disabled = (typeof(m.disabled) == 'function') ?
16570                 m.disabled.call(m.module.disabled) : m.disabled;    
16571             
16572             
16573             if (disabled) {
16574                 return progressRun(); // we do not update the display!
16575             }
16576             
16577             // now build 
16578             
16579                         
16580                         
16581             m.render();
16582             // it's 10 on top level, and 1 on others??? why...
16583             return progressRun.defer(10, _this);
16584              
16585         }
16586         progressRun.defer(1, _this);
16587      
16588         
16589         
16590     },
16591         
16592         
16593         /**
16594          * Event Object.
16595          *
16596          *
16597          */
16598         event: false, 
16599     /**
16600          * wrapper for event.on - aliased later..  
16601          * Typically use to register a event handler for register:
16602          *
16603          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16604          *
16605          */
16606     on : false
16607    
16608     
16609     
16610 });
16611
16612 Roo.XComponent.event = new Roo.util.Observable({
16613                 events : { 
16614                         /**
16615                          * @event register
16616                          * Fires when an Component is registered,
16617                          * set the disable property on the Component to stop registration.
16618                          * @param {Roo.XComponent} c the component being registerd.
16619                          * 
16620                          */
16621                         'register' : true,
16622             /**
16623                          * @event beforebuild
16624                          * Fires before each Component is built
16625                          * can be used to apply permissions.
16626                          * @param {Roo.XComponent} c the component being registerd.
16627                          * 
16628                          */
16629                         'beforebuild' : true,
16630                         /**
16631                          * @event buildcomplete
16632                          * Fires on the top level element when all elements have been built
16633                          * @param {Roo.XComponent} the top level component.
16634                          */
16635                         'buildcomplete' : true
16636                         
16637                 }
16638 });
16639
16640 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16641  //
16642  /**
16643  * marked - a markdown parser
16644  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16645  * https://github.com/chjj/marked
16646  */
16647
16648
16649 /**
16650  *
16651  * Roo.Markdown - is a very crude wrapper around marked..
16652  *
16653  * usage:
16654  * 
16655  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16656  * 
16657  * Note: move the sample code to the bottom of this
16658  * file before uncommenting it.
16659  *
16660  */
16661
16662 Roo.Markdown = {};
16663 Roo.Markdown.toHtml = function(text) {
16664     
16665     var c = new Roo.Markdown.marked.setOptions({
16666             renderer: new Roo.Markdown.marked.Renderer(),
16667             gfm: true,
16668             tables: true,
16669             breaks: false,
16670             pedantic: false,
16671             sanitize: false,
16672             smartLists: true,
16673             smartypants: false
16674           });
16675     // A FEW HACKS!!?
16676     
16677     text = text.replace(/\\\n/g,' ');
16678     return Roo.Markdown.marked(text);
16679 };
16680 //
16681 // converter
16682 //
16683 // Wraps all "globals" so that the only thing
16684 // exposed is makeHtml().
16685 //
16686 (function() {
16687     
16688     /**
16689      * Block-Level Grammar
16690      */
16691     
16692     var block = {
16693       newline: /^\n+/,
16694       code: /^( {4}[^\n]+\n*)+/,
16695       fences: noop,
16696       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16697       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16698       nptable: noop,
16699       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16700       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16701       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16702       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16703       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16704       table: noop,
16705       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16706       text: /^[^\n]+/
16707     };
16708     
16709     block.bullet = /(?:[*+-]|\d+\.)/;
16710     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16711     block.item = replace(block.item, 'gm')
16712       (/bull/g, block.bullet)
16713       ();
16714     
16715     block.list = replace(block.list)
16716       (/bull/g, block.bullet)
16717       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16718       ('def', '\\n+(?=' + block.def.source + ')')
16719       ();
16720     
16721     block.blockquote = replace(block.blockquote)
16722       ('def', block.def)
16723       ();
16724     
16725     block._tag = '(?!(?:'
16726       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16727       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16728       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16729     
16730     block.html = replace(block.html)
16731       ('comment', /<!--[\s\S]*?-->/)
16732       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16733       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16734       (/tag/g, block._tag)
16735       ();
16736     
16737     block.paragraph = replace(block.paragraph)
16738       ('hr', block.hr)
16739       ('heading', block.heading)
16740       ('lheading', block.lheading)
16741       ('blockquote', block.blockquote)
16742       ('tag', '<' + block._tag)
16743       ('def', block.def)
16744       ();
16745     
16746     /**
16747      * Normal Block Grammar
16748      */
16749     
16750     block.normal = merge({}, block);
16751     
16752     /**
16753      * GFM Block Grammar
16754      */
16755     
16756     block.gfm = merge({}, block.normal, {
16757       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16758       paragraph: /^/,
16759       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16760     });
16761     
16762     block.gfm.paragraph = replace(block.paragraph)
16763       ('(?!', '(?!'
16764         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16765         + block.list.source.replace('\\1', '\\3') + '|')
16766       ();
16767     
16768     /**
16769      * GFM + Tables Block Grammar
16770      */
16771     
16772     block.tables = merge({}, block.gfm, {
16773       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16774       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16775     });
16776     
16777     /**
16778      * Block Lexer
16779      */
16780     
16781     function Lexer(options) {
16782       this.tokens = [];
16783       this.tokens.links = {};
16784       this.options = options || marked.defaults;
16785       this.rules = block.normal;
16786     
16787       if (this.options.gfm) {
16788         if (this.options.tables) {
16789           this.rules = block.tables;
16790         } else {
16791           this.rules = block.gfm;
16792         }
16793       }
16794     }
16795     
16796     /**
16797      * Expose Block Rules
16798      */
16799     
16800     Lexer.rules = block;
16801     
16802     /**
16803      * Static Lex Method
16804      */
16805     
16806     Lexer.lex = function(src, options) {
16807       var lexer = new Lexer(options);
16808       return lexer.lex(src);
16809     };
16810     
16811     /**
16812      * Preprocessing
16813      */
16814     
16815     Lexer.prototype.lex = function(src) {
16816       src = src
16817         .replace(/\r\n|\r/g, '\n')
16818         .replace(/\t/g, '    ')
16819         .replace(/\u00a0/g, ' ')
16820         .replace(/\u2424/g, '\n');
16821     
16822       return this.token(src, true);
16823     };
16824     
16825     /**
16826      * Lexing
16827      */
16828     
16829     Lexer.prototype.token = function(src, top, bq) {
16830       var src = src.replace(/^ +$/gm, '')
16831         , next
16832         , loose
16833         , cap
16834         , bull
16835         , b
16836         , item
16837         , space
16838         , i
16839         , l;
16840     
16841       while (src) {
16842         // newline
16843         if (cap = this.rules.newline.exec(src)) {
16844           src = src.substring(cap[0].length);
16845           if (cap[0].length > 1) {
16846             this.tokens.push({
16847               type: 'space'
16848             });
16849           }
16850         }
16851     
16852         // code
16853         if (cap = this.rules.code.exec(src)) {
16854           src = src.substring(cap[0].length);
16855           cap = cap[0].replace(/^ {4}/gm, '');
16856           this.tokens.push({
16857             type: 'code',
16858             text: !this.options.pedantic
16859               ? cap.replace(/\n+$/, '')
16860               : cap
16861           });
16862           continue;
16863         }
16864     
16865         // fences (gfm)
16866         if (cap = this.rules.fences.exec(src)) {
16867           src = src.substring(cap[0].length);
16868           this.tokens.push({
16869             type: 'code',
16870             lang: cap[2],
16871             text: cap[3] || ''
16872           });
16873           continue;
16874         }
16875     
16876         // heading
16877         if (cap = this.rules.heading.exec(src)) {
16878           src = src.substring(cap[0].length);
16879           this.tokens.push({
16880             type: 'heading',
16881             depth: cap[1].length,
16882             text: cap[2]
16883           });
16884           continue;
16885         }
16886     
16887         // table no leading pipe (gfm)
16888         if (top && (cap = this.rules.nptable.exec(src))) {
16889           src = src.substring(cap[0].length);
16890     
16891           item = {
16892             type: 'table',
16893             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16894             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16895             cells: cap[3].replace(/\n$/, '').split('\n')
16896           };
16897     
16898           for (i = 0; i < item.align.length; i++) {
16899             if (/^ *-+: *$/.test(item.align[i])) {
16900               item.align[i] = 'right';
16901             } else if (/^ *:-+: *$/.test(item.align[i])) {
16902               item.align[i] = 'center';
16903             } else if (/^ *:-+ *$/.test(item.align[i])) {
16904               item.align[i] = 'left';
16905             } else {
16906               item.align[i] = null;
16907             }
16908           }
16909     
16910           for (i = 0; i < item.cells.length; i++) {
16911             item.cells[i] = item.cells[i].split(/ *\| */);
16912           }
16913     
16914           this.tokens.push(item);
16915     
16916           continue;
16917         }
16918     
16919         // lheading
16920         if (cap = this.rules.lheading.exec(src)) {
16921           src = src.substring(cap[0].length);
16922           this.tokens.push({
16923             type: 'heading',
16924             depth: cap[2] === '=' ? 1 : 2,
16925             text: cap[1]
16926           });
16927           continue;
16928         }
16929     
16930         // hr
16931         if (cap = this.rules.hr.exec(src)) {
16932           src = src.substring(cap[0].length);
16933           this.tokens.push({
16934             type: 'hr'
16935           });
16936           continue;
16937         }
16938     
16939         // blockquote
16940         if (cap = this.rules.blockquote.exec(src)) {
16941           src = src.substring(cap[0].length);
16942     
16943           this.tokens.push({
16944             type: 'blockquote_start'
16945           });
16946     
16947           cap = cap[0].replace(/^ *> ?/gm, '');
16948     
16949           // Pass `top` to keep the current
16950           // "toplevel" state. This is exactly
16951           // how markdown.pl works.
16952           this.token(cap, top, true);
16953     
16954           this.tokens.push({
16955             type: 'blockquote_end'
16956           });
16957     
16958           continue;
16959         }
16960     
16961         // list
16962         if (cap = this.rules.list.exec(src)) {
16963           src = src.substring(cap[0].length);
16964           bull = cap[2];
16965     
16966           this.tokens.push({
16967             type: 'list_start',
16968             ordered: bull.length > 1
16969           });
16970     
16971           // Get each top-level item.
16972           cap = cap[0].match(this.rules.item);
16973     
16974           next = false;
16975           l = cap.length;
16976           i = 0;
16977     
16978           for (; i < l; i++) {
16979             item = cap[i];
16980     
16981             // Remove the list item's bullet
16982             // so it is seen as the next token.
16983             space = item.length;
16984             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16985     
16986             // Outdent whatever the
16987             // list item contains. Hacky.
16988             if (~item.indexOf('\n ')) {
16989               space -= item.length;
16990               item = !this.options.pedantic
16991                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16992                 : item.replace(/^ {1,4}/gm, '');
16993             }
16994     
16995             // Determine whether the next list item belongs here.
16996             // Backpedal if it does not belong in this list.
16997             if (this.options.smartLists && i !== l - 1) {
16998               b = block.bullet.exec(cap[i + 1])[0];
16999               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17000                 src = cap.slice(i + 1).join('\n') + src;
17001                 i = l - 1;
17002               }
17003             }
17004     
17005             // Determine whether item is loose or not.
17006             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17007             // for discount behavior.
17008             loose = next || /\n\n(?!\s*$)/.test(item);
17009             if (i !== l - 1) {
17010               next = item.charAt(item.length - 1) === '\n';
17011               if (!loose) { loose = next; }
17012             }
17013     
17014             this.tokens.push({
17015               type: loose
17016                 ? 'loose_item_start'
17017                 : 'list_item_start'
17018             });
17019     
17020             // Recurse.
17021             this.token(item, false, bq);
17022     
17023             this.tokens.push({
17024               type: 'list_item_end'
17025             });
17026           }
17027     
17028           this.tokens.push({
17029             type: 'list_end'
17030           });
17031     
17032           continue;
17033         }
17034     
17035         // html
17036         if (cap = this.rules.html.exec(src)) {
17037           src = src.substring(cap[0].length);
17038           this.tokens.push({
17039             type: this.options.sanitize
17040               ? 'paragraph'
17041               : 'html',
17042             pre: !this.options.sanitizer
17043               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17044             text: cap[0]
17045           });
17046           continue;
17047         }
17048     
17049         // def
17050         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17051           src = src.substring(cap[0].length);
17052           this.tokens.links[cap[1].toLowerCase()] = {
17053             href: cap[2],
17054             title: cap[3]
17055           };
17056           continue;
17057         }
17058     
17059         // table (gfm)
17060         if (top && (cap = this.rules.table.exec(src))) {
17061           src = src.substring(cap[0].length);
17062     
17063           item = {
17064             type: 'table',
17065             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17066             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17067             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17068           };
17069     
17070           for (i = 0; i < item.align.length; i++) {
17071             if (/^ *-+: *$/.test(item.align[i])) {
17072               item.align[i] = 'right';
17073             } else if (/^ *:-+: *$/.test(item.align[i])) {
17074               item.align[i] = 'center';
17075             } else if (/^ *:-+ *$/.test(item.align[i])) {
17076               item.align[i] = 'left';
17077             } else {
17078               item.align[i] = null;
17079             }
17080           }
17081     
17082           for (i = 0; i < item.cells.length; i++) {
17083             item.cells[i] = item.cells[i]
17084               .replace(/^ *\| *| *\| *$/g, '')
17085               .split(/ *\| */);
17086           }
17087     
17088           this.tokens.push(item);
17089     
17090           continue;
17091         }
17092     
17093         // top-level paragraph
17094         if (top && (cap = this.rules.paragraph.exec(src))) {
17095           src = src.substring(cap[0].length);
17096           this.tokens.push({
17097             type: 'paragraph',
17098             text: cap[1].charAt(cap[1].length - 1) === '\n'
17099               ? cap[1].slice(0, -1)
17100               : cap[1]
17101           });
17102           continue;
17103         }
17104     
17105         // text
17106         if (cap = this.rules.text.exec(src)) {
17107           // Top-level should never reach here.
17108           src = src.substring(cap[0].length);
17109           this.tokens.push({
17110             type: 'text',
17111             text: cap[0]
17112           });
17113           continue;
17114         }
17115     
17116         if (src) {
17117           throw new
17118             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17119         }
17120       }
17121     
17122       return this.tokens;
17123     };
17124     
17125     /**
17126      * Inline-Level Grammar
17127      */
17128     
17129     var inline = {
17130       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17131       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17132       url: noop,
17133       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17134       link: /^!?\[(inside)\]\(href\)/,
17135       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17136       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17137       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17138       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17139       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17140       br: /^ {2,}\n(?!\s*$)/,
17141       del: noop,
17142       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17143     };
17144     
17145     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17146     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17147     
17148     inline.link = replace(inline.link)
17149       ('inside', inline._inside)
17150       ('href', inline._href)
17151       ();
17152     
17153     inline.reflink = replace(inline.reflink)
17154       ('inside', inline._inside)
17155       ();
17156     
17157     /**
17158      * Normal Inline Grammar
17159      */
17160     
17161     inline.normal = merge({}, inline);
17162     
17163     /**
17164      * Pedantic Inline Grammar
17165      */
17166     
17167     inline.pedantic = merge({}, inline.normal, {
17168       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17169       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17170     });
17171     
17172     /**
17173      * GFM Inline Grammar
17174      */
17175     
17176     inline.gfm = merge({}, inline.normal, {
17177       escape: replace(inline.escape)('])', '~|])')(),
17178       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17179       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17180       text: replace(inline.text)
17181         (']|', '~]|')
17182         ('|', '|https?://|')
17183         ()
17184     });
17185     
17186     /**
17187      * GFM + Line Breaks Inline Grammar
17188      */
17189     
17190     inline.breaks = merge({}, inline.gfm, {
17191       br: replace(inline.br)('{2,}', '*')(),
17192       text: replace(inline.gfm.text)('{2,}', '*')()
17193     });
17194     
17195     /**
17196      * Inline Lexer & Compiler
17197      */
17198     
17199     function InlineLexer(links, options) {
17200       this.options = options || marked.defaults;
17201       this.links = links;
17202       this.rules = inline.normal;
17203       this.renderer = this.options.renderer || new Renderer;
17204       this.renderer.options = this.options;
17205     
17206       if (!this.links) {
17207         throw new
17208           Error('Tokens array requires a `links` property.');
17209       }
17210     
17211       if (this.options.gfm) {
17212         if (this.options.breaks) {
17213           this.rules = inline.breaks;
17214         } else {
17215           this.rules = inline.gfm;
17216         }
17217       } else if (this.options.pedantic) {
17218         this.rules = inline.pedantic;
17219       }
17220     }
17221     
17222     /**
17223      * Expose Inline Rules
17224      */
17225     
17226     InlineLexer.rules = inline;
17227     
17228     /**
17229      * Static Lexing/Compiling Method
17230      */
17231     
17232     InlineLexer.output = function(src, links, options) {
17233       var inline = new InlineLexer(links, options);
17234       return inline.output(src);
17235     };
17236     
17237     /**
17238      * Lexing/Compiling
17239      */
17240     
17241     InlineLexer.prototype.output = function(src) {
17242       var out = ''
17243         , link
17244         , text
17245         , href
17246         , cap;
17247     
17248       while (src) {
17249         // escape
17250         if (cap = this.rules.escape.exec(src)) {
17251           src = src.substring(cap[0].length);
17252           out += cap[1];
17253           continue;
17254         }
17255     
17256         // autolink
17257         if (cap = this.rules.autolink.exec(src)) {
17258           src = src.substring(cap[0].length);
17259           if (cap[2] === '@') {
17260             text = cap[1].charAt(6) === ':'
17261               ? this.mangle(cap[1].substring(7))
17262               : this.mangle(cap[1]);
17263             href = this.mangle('mailto:') + text;
17264           } else {
17265             text = escape(cap[1]);
17266             href = text;
17267           }
17268           out += this.renderer.link(href, null, text);
17269           continue;
17270         }
17271     
17272         // url (gfm)
17273         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17274           src = src.substring(cap[0].length);
17275           text = escape(cap[1]);
17276           href = text;
17277           out += this.renderer.link(href, null, text);
17278           continue;
17279         }
17280     
17281         // tag
17282         if (cap = this.rules.tag.exec(src)) {
17283           if (!this.inLink && /^<a /i.test(cap[0])) {
17284             this.inLink = true;
17285           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17286             this.inLink = false;
17287           }
17288           src = src.substring(cap[0].length);
17289           out += this.options.sanitize
17290             ? this.options.sanitizer
17291               ? this.options.sanitizer(cap[0])
17292               : escape(cap[0])
17293             : cap[0];
17294           continue;
17295         }
17296     
17297         // link
17298         if (cap = this.rules.link.exec(src)) {
17299           src = src.substring(cap[0].length);
17300           this.inLink = true;
17301           out += this.outputLink(cap, {
17302             href: cap[2],
17303             title: cap[3]
17304           });
17305           this.inLink = false;
17306           continue;
17307         }
17308     
17309         // reflink, nolink
17310         if ((cap = this.rules.reflink.exec(src))
17311             || (cap = this.rules.nolink.exec(src))) {
17312           src = src.substring(cap[0].length);
17313           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17314           link = this.links[link.toLowerCase()];
17315           if (!link || !link.href) {
17316             out += cap[0].charAt(0);
17317             src = cap[0].substring(1) + src;
17318             continue;
17319           }
17320           this.inLink = true;
17321           out += this.outputLink(cap, link);
17322           this.inLink = false;
17323           continue;
17324         }
17325     
17326         // strong
17327         if (cap = this.rules.strong.exec(src)) {
17328           src = src.substring(cap[0].length);
17329           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17330           continue;
17331         }
17332     
17333         // em
17334         if (cap = this.rules.em.exec(src)) {
17335           src = src.substring(cap[0].length);
17336           out += this.renderer.em(this.output(cap[2] || cap[1]));
17337           continue;
17338         }
17339     
17340         // code
17341         if (cap = this.rules.code.exec(src)) {
17342           src = src.substring(cap[0].length);
17343           out += this.renderer.codespan(escape(cap[2], true));
17344           continue;
17345         }
17346     
17347         // br
17348         if (cap = this.rules.br.exec(src)) {
17349           src = src.substring(cap[0].length);
17350           out += this.renderer.br();
17351           continue;
17352         }
17353     
17354         // del (gfm)
17355         if (cap = this.rules.del.exec(src)) {
17356           src = src.substring(cap[0].length);
17357           out += this.renderer.del(this.output(cap[1]));
17358           continue;
17359         }
17360     
17361         // text
17362         if (cap = this.rules.text.exec(src)) {
17363           src = src.substring(cap[0].length);
17364           out += this.renderer.text(escape(this.smartypants(cap[0])));
17365           continue;
17366         }
17367     
17368         if (src) {
17369           throw new
17370             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17371         }
17372       }
17373     
17374       return out;
17375     };
17376     
17377     /**
17378      * Compile Link
17379      */
17380     
17381     InlineLexer.prototype.outputLink = function(cap, link) {
17382       var href = escape(link.href)
17383         , title = link.title ? escape(link.title) : null;
17384     
17385       return cap[0].charAt(0) !== '!'
17386         ? this.renderer.link(href, title, this.output(cap[1]))
17387         : this.renderer.image(href, title, escape(cap[1]));
17388     };
17389     
17390     /**
17391      * Smartypants Transformations
17392      */
17393     
17394     InlineLexer.prototype.smartypants = function(text) {
17395       if (!this.options.smartypants)  { return text; }
17396       return text
17397         // em-dashes
17398         .replace(/---/g, '\u2014')
17399         // en-dashes
17400         .replace(/--/g, '\u2013')
17401         // opening singles
17402         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17403         // closing singles & apostrophes
17404         .replace(/'/g, '\u2019')
17405         // opening doubles
17406         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17407         // closing doubles
17408         .replace(/"/g, '\u201d')
17409         // ellipses
17410         .replace(/\.{3}/g, '\u2026');
17411     };
17412     
17413     /**
17414      * Mangle Links
17415      */
17416     
17417     InlineLexer.prototype.mangle = function(text) {
17418       if (!this.options.mangle) { return text; }
17419       var out = ''
17420         , l = text.length
17421         , i = 0
17422         , ch;
17423     
17424       for (; i < l; i++) {
17425         ch = text.charCodeAt(i);
17426         if (Math.random() > 0.5) {
17427           ch = 'x' + ch.toString(16);
17428         }
17429         out += '&#' + ch + ';';
17430       }
17431     
17432       return out;
17433     };
17434     
17435     /**
17436      * Renderer
17437      */
17438     
17439     function Renderer(options) {
17440       this.options = options || {};
17441     }
17442     
17443     Renderer.prototype.code = function(code, lang, escaped) {
17444       if (this.options.highlight) {
17445         var out = this.options.highlight(code, lang);
17446         if (out != null && out !== code) {
17447           escaped = true;
17448           code = out;
17449         }
17450       } else {
17451             // hack!!! - it's already escapeD?
17452             escaped = true;
17453       }
17454     
17455       if (!lang) {
17456         return '<pre><code>'
17457           + (escaped ? code : escape(code, true))
17458           + '\n</code></pre>';
17459       }
17460     
17461       return '<pre><code class="'
17462         + this.options.langPrefix
17463         + escape(lang, true)
17464         + '">'
17465         + (escaped ? code : escape(code, true))
17466         + '\n</code></pre>\n';
17467     };
17468     
17469     Renderer.prototype.blockquote = function(quote) {
17470       return '<blockquote>\n' + quote + '</blockquote>\n';
17471     };
17472     
17473     Renderer.prototype.html = function(html) {
17474       return html;
17475     };
17476     
17477     Renderer.prototype.heading = function(text, level, raw) {
17478       return '<h'
17479         + level
17480         + ' id="'
17481         + this.options.headerPrefix
17482         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17483         + '">'
17484         + text
17485         + '</h'
17486         + level
17487         + '>\n';
17488     };
17489     
17490     Renderer.prototype.hr = function() {
17491       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17492     };
17493     
17494     Renderer.prototype.list = function(body, ordered) {
17495       var type = ordered ? 'ol' : 'ul';
17496       return '<' + type + '>\n' + body + '</' + type + '>\n';
17497     };
17498     
17499     Renderer.prototype.listitem = function(text) {
17500       return '<li>' + text + '</li>\n';
17501     };
17502     
17503     Renderer.prototype.paragraph = function(text) {
17504       return '<p>' + text + '</p>\n';
17505     };
17506     
17507     Renderer.prototype.table = function(header, body) {
17508       return '<table class="table table-striped">\n'
17509         + '<thead>\n'
17510         + header
17511         + '</thead>\n'
17512         + '<tbody>\n'
17513         + body
17514         + '</tbody>\n'
17515         + '</table>\n';
17516     };
17517     
17518     Renderer.prototype.tablerow = function(content) {
17519       return '<tr>\n' + content + '</tr>\n';
17520     };
17521     
17522     Renderer.prototype.tablecell = function(content, flags) {
17523       var type = flags.header ? 'th' : 'td';
17524       var tag = flags.align
17525         ? '<' + type + ' style="text-align:' + flags.align + '">'
17526         : '<' + type + '>';
17527       return tag + content + '</' + type + '>\n';
17528     };
17529     
17530     // span level renderer
17531     Renderer.prototype.strong = function(text) {
17532       return '<strong>' + text + '</strong>';
17533     };
17534     
17535     Renderer.prototype.em = function(text) {
17536       return '<em>' + text + '</em>';
17537     };
17538     
17539     Renderer.prototype.codespan = function(text) {
17540       return '<code>' + text + '</code>';
17541     };
17542     
17543     Renderer.prototype.br = function() {
17544       return this.options.xhtml ? '<br/>' : '<br>';
17545     };
17546     
17547     Renderer.prototype.del = function(text) {
17548       return '<del>' + text + '</del>';
17549     };
17550     
17551     Renderer.prototype.link = function(href, title, text) {
17552       if (this.options.sanitize) {
17553         try {
17554           var prot = decodeURIComponent(unescape(href))
17555             .replace(/[^\w:]/g, '')
17556             .toLowerCase();
17557         } catch (e) {
17558           return '';
17559         }
17560         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17561           return '';
17562         }
17563       }
17564       var out = '<a href="' + href + '"';
17565       if (title) {
17566         out += ' title="' + title + '"';
17567       }
17568       out += '>' + text + '</a>';
17569       return out;
17570     };
17571     
17572     Renderer.prototype.image = function(href, title, text) {
17573       var out = '<img src="' + href + '" alt="' + text + '"';
17574       if (title) {
17575         out += ' title="' + title + '"';
17576       }
17577       out += this.options.xhtml ? '/>' : '>';
17578       return out;
17579     };
17580     
17581     Renderer.prototype.text = function(text) {
17582       return text;
17583     };
17584     
17585     /**
17586      * Parsing & Compiling
17587      */
17588     
17589     function Parser(options) {
17590       this.tokens = [];
17591       this.token = null;
17592       this.options = options || marked.defaults;
17593       this.options.renderer = this.options.renderer || new Renderer;
17594       this.renderer = this.options.renderer;
17595       this.renderer.options = this.options;
17596     }
17597     
17598     /**
17599      * Static Parse Method
17600      */
17601     
17602     Parser.parse = function(src, options, renderer) {
17603       var parser = new Parser(options, renderer);
17604       return parser.parse(src);
17605     };
17606     
17607     /**
17608      * Parse Loop
17609      */
17610     
17611     Parser.prototype.parse = function(src) {
17612       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17613       this.tokens = src.reverse();
17614     
17615       var out = '';
17616       while (this.next()) {
17617         out += this.tok();
17618       }
17619     
17620       return out;
17621     };
17622     
17623     /**
17624      * Next Token
17625      */
17626     
17627     Parser.prototype.next = function() {
17628       return this.token = this.tokens.pop();
17629     };
17630     
17631     /**
17632      * Preview Next Token
17633      */
17634     
17635     Parser.prototype.peek = function() {
17636       return this.tokens[this.tokens.length - 1] || 0;
17637     };
17638     
17639     /**
17640      * Parse Text Tokens
17641      */
17642     
17643     Parser.prototype.parseText = function() {
17644       var body = this.token.text;
17645     
17646       while (this.peek().type === 'text') {
17647         body += '\n' + this.next().text;
17648       }
17649     
17650       return this.inline.output(body);
17651     };
17652     
17653     /**
17654      * Parse Current Token
17655      */
17656     
17657     Parser.prototype.tok = function() {
17658       switch (this.token.type) {
17659         case 'space': {
17660           return '';
17661         }
17662         case 'hr': {
17663           return this.renderer.hr();
17664         }
17665         case 'heading': {
17666           return this.renderer.heading(
17667             this.inline.output(this.token.text),
17668             this.token.depth,
17669             this.token.text);
17670         }
17671         case 'code': {
17672           return this.renderer.code(this.token.text,
17673             this.token.lang,
17674             this.token.escaped);
17675         }
17676         case 'table': {
17677           var header = ''
17678             , body = ''
17679             , i
17680             , row
17681             , cell
17682             , flags
17683             , j;
17684     
17685           // header
17686           cell = '';
17687           for (i = 0; i < this.token.header.length; i++) {
17688             flags = { header: true, align: this.token.align[i] };
17689             cell += this.renderer.tablecell(
17690               this.inline.output(this.token.header[i]),
17691               { header: true, align: this.token.align[i] }
17692             );
17693           }
17694           header += this.renderer.tablerow(cell);
17695     
17696           for (i = 0; i < this.token.cells.length; i++) {
17697             row = this.token.cells[i];
17698     
17699             cell = '';
17700             for (j = 0; j < row.length; j++) {
17701               cell += this.renderer.tablecell(
17702                 this.inline.output(row[j]),
17703                 { header: false, align: this.token.align[j] }
17704               );
17705             }
17706     
17707             body += this.renderer.tablerow(cell);
17708           }
17709           return this.renderer.table(header, body);
17710         }
17711         case 'blockquote_start': {
17712           var body = '';
17713     
17714           while (this.next().type !== 'blockquote_end') {
17715             body += this.tok();
17716           }
17717     
17718           return this.renderer.blockquote(body);
17719         }
17720         case 'list_start': {
17721           var body = ''
17722             , ordered = this.token.ordered;
17723     
17724           while (this.next().type !== 'list_end') {
17725             body += this.tok();
17726           }
17727     
17728           return this.renderer.list(body, ordered);
17729         }
17730         case 'list_item_start': {
17731           var body = '';
17732     
17733           while (this.next().type !== 'list_item_end') {
17734             body += this.token.type === 'text'
17735               ? this.parseText()
17736               : this.tok();
17737           }
17738     
17739           return this.renderer.listitem(body);
17740         }
17741         case 'loose_item_start': {
17742           var body = '';
17743     
17744           while (this.next().type !== 'list_item_end') {
17745             body += this.tok();
17746           }
17747     
17748           return this.renderer.listitem(body);
17749         }
17750         case 'html': {
17751           var html = !this.token.pre && !this.options.pedantic
17752             ? this.inline.output(this.token.text)
17753             : this.token.text;
17754           return this.renderer.html(html);
17755         }
17756         case 'paragraph': {
17757           return this.renderer.paragraph(this.inline.output(this.token.text));
17758         }
17759         case 'text': {
17760           return this.renderer.paragraph(this.parseText());
17761         }
17762       }
17763     };
17764     
17765     /**
17766      * Helpers
17767      */
17768     
17769     function escape(html, encode) {
17770       return html
17771         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17772         .replace(/</g, '&lt;')
17773         .replace(/>/g, '&gt;')
17774         .replace(/"/g, '&quot;')
17775         .replace(/'/g, '&#39;');
17776     }
17777     
17778     function unescape(html) {
17779         // explicitly match decimal, hex, and named HTML entities 
17780       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17781         n = n.toLowerCase();
17782         if (n === 'colon') { return ':'; }
17783         if (n.charAt(0) === '#') {
17784           return n.charAt(1) === 'x'
17785             ? String.fromCharCode(parseInt(n.substring(2), 16))
17786             : String.fromCharCode(+n.substring(1));
17787         }
17788         return '';
17789       });
17790     }
17791     
17792     function replace(regex, opt) {
17793       regex = regex.source;
17794       opt = opt || '';
17795       return function self(name, val) {
17796         if (!name) { return new RegExp(regex, opt); }
17797         val = val.source || val;
17798         val = val.replace(/(^|[^\[])\^/g, '$1');
17799         regex = regex.replace(name, val);
17800         return self;
17801       };
17802     }
17803     
17804     function noop() {}
17805     noop.exec = noop;
17806     
17807     function merge(obj) {
17808       var i = 1
17809         , target
17810         , key;
17811     
17812       for (; i < arguments.length; i++) {
17813         target = arguments[i];
17814         for (key in target) {
17815           if (Object.prototype.hasOwnProperty.call(target, key)) {
17816             obj[key] = target[key];
17817           }
17818         }
17819       }
17820     
17821       return obj;
17822     }
17823     
17824     
17825     /**
17826      * Marked
17827      */
17828     
17829     function marked(src, opt, callback) {
17830       if (callback || typeof opt === 'function') {
17831         if (!callback) {
17832           callback = opt;
17833           opt = null;
17834         }
17835     
17836         opt = merge({}, marked.defaults, opt || {});
17837     
17838         var highlight = opt.highlight
17839           , tokens
17840           , pending
17841           , i = 0;
17842     
17843         try {
17844           tokens = Lexer.lex(src, opt)
17845         } catch (e) {
17846           return callback(e);
17847         }
17848     
17849         pending = tokens.length;
17850     
17851         var done = function(err) {
17852           if (err) {
17853             opt.highlight = highlight;
17854             return callback(err);
17855           }
17856     
17857           var out;
17858     
17859           try {
17860             out = Parser.parse(tokens, opt);
17861           } catch (e) {
17862             err = e;
17863           }
17864     
17865           opt.highlight = highlight;
17866     
17867           return err
17868             ? callback(err)
17869             : callback(null, out);
17870         };
17871     
17872         if (!highlight || highlight.length < 3) {
17873           return done();
17874         }
17875     
17876         delete opt.highlight;
17877     
17878         if (!pending) { return done(); }
17879     
17880         for (; i < tokens.length; i++) {
17881           (function(token) {
17882             if (token.type !== 'code') {
17883               return --pending || done();
17884             }
17885             return highlight(token.text, token.lang, function(err, code) {
17886               if (err) { return done(err); }
17887               if (code == null || code === token.text) {
17888                 return --pending || done();
17889               }
17890               token.text = code;
17891               token.escaped = true;
17892               --pending || done();
17893             });
17894           })(tokens[i]);
17895         }
17896     
17897         return;
17898       }
17899       try {
17900         if (opt) { opt = merge({}, marked.defaults, opt); }
17901         return Parser.parse(Lexer.lex(src, opt), opt);
17902       } catch (e) {
17903         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17904         if ((opt || marked.defaults).silent) {
17905           return '<p>An error occured:</p><pre>'
17906             + escape(e.message + '', true)
17907             + '</pre>';
17908         }
17909         throw e;
17910       }
17911     }
17912     
17913     /**
17914      * Options
17915      */
17916     
17917     marked.options =
17918     marked.setOptions = function(opt) {
17919       merge(marked.defaults, opt);
17920       return marked;
17921     };
17922     
17923     marked.defaults = {
17924       gfm: true,
17925       tables: true,
17926       breaks: false,
17927       pedantic: false,
17928       sanitize: false,
17929       sanitizer: null,
17930       mangle: true,
17931       smartLists: false,
17932       silent: false,
17933       highlight: null,
17934       langPrefix: 'lang-',
17935       smartypants: false,
17936       headerPrefix: '',
17937       renderer: new Renderer,
17938       xhtml: false
17939     };
17940     
17941     /**
17942      * Expose
17943      */
17944     
17945     marked.Parser = Parser;
17946     marked.parser = Parser.parse;
17947     
17948     marked.Renderer = Renderer;
17949     
17950     marked.Lexer = Lexer;
17951     marked.lexer = Lexer.lex;
17952     
17953     marked.InlineLexer = InlineLexer;
17954     marked.inlineLexer = InlineLexer.output;
17955     
17956     marked.parse = marked;
17957     
17958     Roo.Markdown.marked = marked;
17959
17960 })();/*
17961  * Based on:
17962  * Ext JS Library 1.1.1
17963  * Copyright(c) 2006-2007, Ext JS, LLC.
17964  *
17965  * Originally Released Under LGPL - original licence link has changed is not relivant.
17966  *
17967  * Fork - LGPL
17968  * <script type="text/javascript">
17969  */
17970
17971
17972
17973 /*
17974  * These classes are derivatives of the similarly named classes in the YUI Library.
17975  * The original license:
17976  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17977  * Code licensed under the BSD License:
17978  * http://developer.yahoo.net/yui/license.txt
17979  */
17980
17981 (function() {
17982
17983 var Event=Roo.EventManager;
17984 var Dom=Roo.lib.Dom;
17985
17986 /**
17987  * @class Roo.dd.DragDrop
17988  * @extends Roo.util.Observable
17989  * Defines the interface and base operation of items that that can be
17990  * dragged or can be drop targets.  It was designed to be extended, overriding
17991  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17992  * Up to three html elements can be associated with a DragDrop instance:
17993  * <ul>
17994  * <li>linked element: the element that is passed into the constructor.
17995  * This is the element which defines the boundaries for interaction with
17996  * other DragDrop objects.</li>
17997  * <li>handle element(s): The drag operation only occurs if the element that
17998  * was clicked matches a handle element.  By default this is the linked
17999  * element, but there are times that you will want only a portion of the
18000  * linked element to initiate the drag operation, and the setHandleElId()
18001  * method provides a way to define this.</li>
18002  * <li>drag element: this represents the element that would be moved along
18003  * with the cursor during a drag operation.  By default, this is the linked
18004  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
18005  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18006  * </li>
18007  * </ul>
18008  * This class should not be instantiated until the onload event to ensure that
18009  * the associated elements are available.
18010  * The following would define a DragDrop obj that would interact with any
18011  * other DragDrop obj in the "group1" group:
18012  * <pre>
18013  *  dd = new Roo.dd.DragDrop("div1", "group1");
18014  * </pre>
18015  * Since none of the event handlers have been implemented, nothing would
18016  * actually happen if you were to run the code above.  Normally you would
18017  * override this class or one of the default implementations, but you can
18018  * also override the methods you want on an instance of the class...
18019  * <pre>
18020  *  dd.onDragDrop = function(e, id) {
18021  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18022  *  }
18023  * </pre>
18024  * @constructor
18025  * @param {String} id of the element that is linked to this instance
18026  * @param {String} sGroup the group of related DragDrop objects
18027  * @param {object} config an object containing configurable attributes
18028  *                Valid properties for DragDrop:
18029  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18030  */
18031 Roo.dd.DragDrop = function(id, sGroup, config) {
18032     if (id) {
18033         this.init(id, sGroup, config);
18034     }
18035     
18036 };
18037
18038 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18039
18040     /**
18041      * The id of the element associated with this object.  This is what we
18042      * refer to as the "linked element" because the size and position of
18043      * this element is used to determine when the drag and drop objects have
18044      * interacted.
18045      * @property id
18046      * @type String
18047      */
18048     id: null,
18049
18050     /**
18051      * Configuration attributes passed into the constructor
18052      * @property config
18053      * @type object
18054      */
18055     config: null,
18056
18057     /**
18058      * The id of the element that will be dragged.  By default this is same
18059      * as the linked element , but could be changed to another element. Ex:
18060      * Roo.dd.DDProxy
18061      * @property dragElId
18062      * @type String
18063      * @private
18064      */
18065     dragElId: null,
18066
18067     /**
18068      * the id of the element that initiates the drag operation.  By default
18069      * this is the linked element, but could be changed to be a child of this
18070      * element.  This lets us do things like only starting the drag when the
18071      * header element within the linked html element is clicked.
18072      * @property handleElId
18073      * @type String
18074      * @private
18075      */
18076     handleElId: null,
18077
18078     /**
18079      * An associative array of HTML tags that will be ignored if clicked.
18080      * @property invalidHandleTypes
18081      * @type {string: string}
18082      */
18083     invalidHandleTypes: null,
18084
18085     /**
18086      * An associative array of ids for elements that will be ignored if clicked
18087      * @property invalidHandleIds
18088      * @type {string: string}
18089      */
18090     invalidHandleIds: null,
18091
18092     /**
18093      * An indexted array of css class names for elements that will be ignored
18094      * if clicked.
18095      * @property invalidHandleClasses
18096      * @type string[]
18097      */
18098     invalidHandleClasses: null,
18099
18100     /**
18101      * The linked element's absolute X position at the time the drag was
18102      * started
18103      * @property startPageX
18104      * @type int
18105      * @private
18106      */
18107     startPageX: 0,
18108
18109     /**
18110      * The linked element's absolute X position at the time the drag was
18111      * started
18112      * @property startPageY
18113      * @type int
18114      * @private
18115      */
18116     startPageY: 0,
18117
18118     /**
18119      * The group defines a logical collection of DragDrop objects that are
18120      * related.  Instances only get events when interacting with other
18121      * DragDrop object in the same group.  This lets us define multiple
18122      * groups using a single DragDrop subclass if we want.
18123      * @property groups
18124      * @type {string: string}
18125      */
18126     groups: null,
18127
18128     /**
18129      * Individual drag/drop instances can be locked.  This will prevent
18130      * onmousedown start drag.
18131      * @property locked
18132      * @type boolean
18133      * @private
18134      */
18135     locked: false,
18136
18137     /**
18138      * Lock this instance
18139      * @method lock
18140      */
18141     lock: function() { this.locked = true; },
18142
18143     /**
18144      * Unlock this instace
18145      * @method unlock
18146      */
18147     unlock: function() { this.locked = false; },
18148
18149     /**
18150      * By default, all insances can be a drop target.  This can be disabled by
18151      * setting isTarget to false.
18152      * @method isTarget
18153      * @type boolean
18154      */
18155     isTarget: true,
18156
18157     /**
18158      * The padding configured for this drag and drop object for calculating
18159      * the drop zone intersection with this object.
18160      * @method padding
18161      * @type int[]
18162      */
18163     padding: null,
18164
18165     /**
18166      * Cached reference to the linked element
18167      * @property _domRef
18168      * @private
18169      */
18170     _domRef: null,
18171
18172     /**
18173      * Internal typeof flag
18174      * @property __ygDragDrop
18175      * @private
18176      */
18177     __ygDragDrop: true,
18178
18179     /**
18180      * Set to true when horizontal contraints are applied
18181      * @property constrainX
18182      * @type boolean
18183      * @private
18184      */
18185     constrainX: false,
18186
18187     /**
18188      * Set to true when vertical contraints are applied
18189      * @property constrainY
18190      * @type boolean
18191      * @private
18192      */
18193     constrainY: false,
18194
18195     /**
18196      * The left constraint
18197      * @property minX
18198      * @type int
18199      * @private
18200      */
18201     minX: 0,
18202
18203     /**
18204      * The right constraint
18205      * @property maxX
18206      * @type int
18207      * @private
18208      */
18209     maxX: 0,
18210
18211     /**
18212      * The up constraint
18213      * @property minY
18214      * @type int
18215      * @type int
18216      * @private
18217      */
18218     minY: 0,
18219
18220     /**
18221      * The down constraint
18222      * @property maxY
18223      * @type int
18224      * @private
18225      */
18226     maxY: 0,
18227
18228     /**
18229      * Maintain offsets when we resetconstraints.  Set to true when you want
18230      * the position of the element relative to its parent to stay the same
18231      * when the page changes
18232      *
18233      * @property maintainOffset
18234      * @type boolean
18235      */
18236     maintainOffset: false,
18237
18238     /**
18239      * Array of pixel locations the element will snap to if we specified a
18240      * horizontal graduation/interval.  This array is generated automatically
18241      * when you define a tick interval.
18242      * @property xTicks
18243      * @type int[]
18244      */
18245     xTicks: null,
18246
18247     /**
18248      * Array of pixel locations the element will snap to if we specified a
18249      * vertical graduation/interval.  This array is generated automatically
18250      * when you define a tick interval.
18251      * @property yTicks
18252      * @type int[]
18253      */
18254     yTicks: null,
18255
18256     /**
18257      * By default the drag and drop instance will only respond to the primary
18258      * button click (left button for a right-handed mouse).  Set to true to
18259      * allow drag and drop to start with any mouse click that is propogated
18260      * by the browser
18261      * @property primaryButtonOnly
18262      * @type boolean
18263      */
18264     primaryButtonOnly: true,
18265
18266     /**
18267      * The availabe property is false until the linked dom element is accessible.
18268      * @property available
18269      * @type boolean
18270      */
18271     available: false,
18272
18273     /**
18274      * By default, drags can only be initiated if the mousedown occurs in the
18275      * region the linked element is.  This is done in part to work around a
18276      * bug in some browsers that mis-report the mousedown if the previous
18277      * mouseup happened outside of the window.  This property is set to true
18278      * if outer handles are defined.
18279      *
18280      * @property hasOuterHandles
18281      * @type boolean
18282      * @default false
18283      */
18284     hasOuterHandles: false,
18285
18286     /**
18287      * Code that executes immediately before the startDrag event
18288      * @method b4StartDrag
18289      * @private
18290      */
18291     b4StartDrag: function(x, y) { },
18292
18293     /**
18294      * Abstract method called after a drag/drop object is clicked
18295      * and the drag or mousedown time thresholds have beeen met.
18296      * @method startDrag
18297      * @param {int} X click location
18298      * @param {int} Y click location
18299      */
18300     startDrag: function(x, y) { /* override this */ },
18301
18302     /**
18303      * Code that executes immediately before the onDrag event
18304      * @method b4Drag
18305      * @private
18306      */
18307     b4Drag: function(e) { },
18308
18309     /**
18310      * Abstract method called during the onMouseMove event while dragging an
18311      * object.
18312      * @method onDrag
18313      * @param {Event} e the mousemove event
18314      */
18315     onDrag: function(e) { /* override this */ },
18316
18317     /**
18318      * Abstract method called when this element fist begins hovering over
18319      * another DragDrop obj
18320      * @method onDragEnter
18321      * @param {Event} e the mousemove event
18322      * @param {String|DragDrop[]} id In POINT mode, the element
18323      * id this is hovering over.  In INTERSECT mode, an array of one or more
18324      * dragdrop items being hovered over.
18325      */
18326     onDragEnter: function(e, id) { /* override this */ },
18327
18328     /**
18329      * Code that executes immediately before the onDragOver event
18330      * @method b4DragOver
18331      * @private
18332      */
18333     b4DragOver: function(e) { },
18334
18335     /**
18336      * Abstract method called when this element is hovering over another
18337      * DragDrop obj
18338      * @method onDragOver
18339      * @param {Event} e the mousemove event
18340      * @param {String|DragDrop[]} id In POINT mode, the element
18341      * id this is hovering over.  In INTERSECT mode, an array of dd items
18342      * being hovered over.
18343      */
18344     onDragOver: function(e, id) { /* override this */ },
18345
18346     /**
18347      * Code that executes immediately before the onDragOut event
18348      * @method b4DragOut
18349      * @private
18350      */
18351     b4DragOut: function(e) { },
18352
18353     /**
18354      * Abstract method called when we are no longer hovering over an element
18355      * @method onDragOut
18356      * @param {Event} e the mousemove event
18357      * @param {String|DragDrop[]} id In POINT mode, the element
18358      * id this was hovering over.  In INTERSECT mode, an array of dd items
18359      * that the mouse is no longer over.
18360      */
18361     onDragOut: function(e, id) { /* override this */ },
18362
18363     /**
18364      * Code that executes immediately before the onDragDrop event
18365      * @method b4DragDrop
18366      * @private
18367      */
18368     b4DragDrop: function(e) { },
18369
18370     /**
18371      * Abstract method called when this item is dropped on another DragDrop
18372      * obj
18373      * @method onDragDrop
18374      * @param {Event} e the mouseup event
18375      * @param {String|DragDrop[]} id In POINT mode, the element
18376      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18377      * was dropped on.
18378      */
18379     onDragDrop: function(e, id) { /* override this */ },
18380
18381     /**
18382      * Abstract method called when this item is dropped on an area with no
18383      * drop target
18384      * @method onInvalidDrop
18385      * @param {Event} e the mouseup event
18386      */
18387     onInvalidDrop: function(e) { /* override this */ },
18388
18389     /**
18390      * Code that executes immediately before the endDrag event
18391      * @method b4EndDrag
18392      * @private
18393      */
18394     b4EndDrag: function(e) { },
18395
18396     /**
18397      * Fired when we are done dragging the object
18398      * @method endDrag
18399      * @param {Event} e the mouseup event
18400      */
18401     endDrag: function(e) { /* override this */ },
18402
18403     /**
18404      * Code executed immediately before the onMouseDown event
18405      * @method b4MouseDown
18406      * @param {Event} e the mousedown event
18407      * @private
18408      */
18409     b4MouseDown: function(e) {  },
18410
18411     /**
18412      * Event handler that fires when a drag/drop obj gets a mousedown
18413      * @method onMouseDown
18414      * @param {Event} e the mousedown event
18415      */
18416     onMouseDown: function(e) { /* override this */ },
18417
18418     /**
18419      * Event handler that fires when a drag/drop obj gets a mouseup
18420      * @method onMouseUp
18421      * @param {Event} e the mouseup event
18422      */
18423     onMouseUp: function(e) { /* override this */ },
18424
18425     /**
18426      * Override the onAvailable method to do what is needed after the initial
18427      * position was determined.
18428      * @method onAvailable
18429      */
18430     onAvailable: function () {
18431     },
18432
18433     /*
18434      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18435      * @type Object
18436      */
18437     defaultPadding : {left:0, right:0, top:0, bottom:0},
18438
18439     /*
18440      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18441  *
18442  * Usage:
18443  <pre><code>
18444  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18445                 { dragElId: "existingProxyDiv" });
18446  dd.startDrag = function(){
18447      this.constrainTo("parent-id");
18448  };
18449  </code></pre>
18450  * Or you can initalize it using the {@link Roo.Element} object:
18451  <pre><code>
18452  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18453      startDrag : function(){
18454          this.constrainTo("parent-id");
18455      }
18456  });
18457  </code></pre>
18458      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18459      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18460      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18461      * an object containing the sides to pad. For example: {right:10, bottom:10}
18462      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18463      */
18464     constrainTo : function(constrainTo, pad, inContent){
18465         if(typeof pad == "number"){
18466             pad = {left: pad, right:pad, top:pad, bottom:pad};
18467         }
18468         pad = pad || this.defaultPadding;
18469         var b = Roo.get(this.getEl()).getBox();
18470         var ce = Roo.get(constrainTo);
18471         var s = ce.getScroll();
18472         var c, cd = ce.dom;
18473         if(cd == document.body){
18474             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18475         }else{
18476             xy = ce.getXY();
18477             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18478         }
18479
18480
18481         var topSpace = b.y - c.y;
18482         var leftSpace = b.x - c.x;
18483
18484         this.resetConstraints();
18485         this.setXConstraint(leftSpace - (pad.left||0), // left
18486                 c.width - leftSpace - b.width - (pad.right||0) //right
18487         );
18488         this.setYConstraint(topSpace - (pad.top||0), //top
18489                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18490         );
18491     },
18492
18493     /**
18494      * Returns a reference to the linked element
18495      * @method getEl
18496      * @return {HTMLElement} the html element
18497      */
18498     getEl: function() {
18499         if (!this._domRef) {
18500             this._domRef = Roo.getDom(this.id);
18501         }
18502
18503         return this._domRef;
18504     },
18505
18506     /**
18507      * Returns a reference to the actual element to drag.  By default this is
18508      * the same as the html element, but it can be assigned to another
18509      * element. An example of this can be found in Roo.dd.DDProxy
18510      * @method getDragEl
18511      * @return {HTMLElement} the html element
18512      */
18513     getDragEl: function() {
18514         return Roo.getDom(this.dragElId);
18515     },
18516
18517     /**
18518      * Sets up the DragDrop object.  Must be called in the constructor of any
18519      * Roo.dd.DragDrop subclass
18520      * @method init
18521      * @param id the id of the linked element
18522      * @param {String} sGroup the group of related items
18523      * @param {object} config configuration attributes
18524      */
18525     init: function(id, sGroup, config) {
18526         this.initTarget(id, sGroup, config);
18527         if (!Roo.isTouch) {
18528             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18529         }
18530         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18531         // Event.on(this.id, "selectstart", Event.preventDefault);
18532     },
18533
18534     /**
18535      * Initializes Targeting functionality only... the object does not
18536      * get a mousedown handler.
18537      * @method initTarget
18538      * @param id the id of the linked element
18539      * @param {String} sGroup the group of related items
18540      * @param {object} config configuration attributes
18541      */
18542     initTarget: function(id, sGroup, config) {
18543
18544         // configuration attributes
18545         this.config = config || {};
18546
18547         // create a local reference to the drag and drop manager
18548         this.DDM = Roo.dd.DDM;
18549         // initialize the groups array
18550         this.groups = {};
18551
18552         // assume that we have an element reference instead of an id if the
18553         // parameter is not a string
18554         if (typeof id !== "string") {
18555             id = Roo.id(id);
18556         }
18557
18558         // set the id
18559         this.id = id;
18560
18561         // add to an interaction group
18562         this.addToGroup((sGroup) ? sGroup : "default");
18563
18564         // We don't want to register this as the handle with the manager
18565         // so we just set the id rather than calling the setter.
18566         this.handleElId = id;
18567
18568         // the linked element is the element that gets dragged by default
18569         this.setDragElId(id);
18570
18571         // by default, clicked anchors will not start drag operations.
18572         this.invalidHandleTypes = { A: "A" };
18573         this.invalidHandleIds = {};
18574         this.invalidHandleClasses = [];
18575
18576         this.applyConfig();
18577
18578         this.handleOnAvailable();
18579     },
18580
18581     /**
18582      * Applies the configuration parameters that were passed into the constructor.
18583      * This is supposed to happen at each level through the inheritance chain.  So
18584      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18585      * DragDrop in order to get all of the parameters that are available in
18586      * each object.
18587      * @method applyConfig
18588      */
18589     applyConfig: function() {
18590
18591         // configurable properties:
18592         //    padding, isTarget, maintainOffset, primaryButtonOnly
18593         this.padding           = this.config.padding || [0, 0, 0, 0];
18594         this.isTarget          = (this.config.isTarget !== false);
18595         this.maintainOffset    = (this.config.maintainOffset);
18596         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18597
18598     },
18599
18600     /**
18601      * Executed when the linked element is available
18602      * @method handleOnAvailable
18603      * @private
18604      */
18605     handleOnAvailable: function() {
18606         this.available = true;
18607         this.resetConstraints();
18608         this.onAvailable();
18609     },
18610
18611      /**
18612      * Configures the padding for the target zone in px.  Effectively expands
18613      * (or reduces) the virtual object size for targeting calculations.
18614      * Supports css-style shorthand; if only one parameter is passed, all sides
18615      * will have that padding, and if only two are passed, the top and bottom
18616      * will have the first param, the left and right the second.
18617      * @method setPadding
18618      * @param {int} iTop    Top pad
18619      * @param {int} iRight  Right pad
18620      * @param {int} iBot    Bot pad
18621      * @param {int} iLeft   Left pad
18622      */
18623     setPadding: function(iTop, iRight, iBot, iLeft) {
18624         // this.padding = [iLeft, iRight, iTop, iBot];
18625         if (!iRight && 0 !== iRight) {
18626             this.padding = [iTop, iTop, iTop, iTop];
18627         } else if (!iBot && 0 !== iBot) {
18628             this.padding = [iTop, iRight, iTop, iRight];
18629         } else {
18630             this.padding = [iTop, iRight, iBot, iLeft];
18631         }
18632     },
18633
18634     /**
18635      * Stores the initial placement of the linked element.
18636      * @method setInitialPosition
18637      * @param {int} diffX   the X offset, default 0
18638      * @param {int} diffY   the Y offset, default 0
18639      */
18640     setInitPosition: function(diffX, diffY) {
18641         var el = this.getEl();
18642
18643         if (!this.DDM.verifyEl(el)) {
18644             return;
18645         }
18646
18647         var dx = diffX || 0;
18648         var dy = diffY || 0;
18649
18650         var p = Dom.getXY( el );
18651
18652         this.initPageX = p[0] - dx;
18653         this.initPageY = p[1] - dy;
18654
18655         this.lastPageX = p[0];
18656         this.lastPageY = p[1];
18657
18658
18659         this.setStartPosition(p);
18660     },
18661
18662     /**
18663      * Sets the start position of the element.  This is set when the obj
18664      * is initialized, the reset when a drag is started.
18665      * @method setStartPosition
18666      * @param pos current position (from previous lookup)
18667      * @private
18668      */
18669     setStartPosition: function(pos) {
18670         var p = pos || Dom.getXY( this.getEl() );
18671         this.deltaSetXY = null;
18672
18673         this.startPageX = p[0];
18674         this.startPageY = p[1];
18675     },
18676
18677     /**
18678      * Add this instance to a group of related drag/drop objects.  All
18679      * instances belong to at least one group, and can belong to as many
18680      * groups as needed.
18681      * @method addToGroup
18682      * @param sGroup {string} the name of the group
18683      */
18684     addToGroup: function(sGroup) {
18685         this.groups[sGroup] = true;
18686         this.DDM.regDragDrop(this, sGroup);
18687     },
18688
18689     /**
18690      * Remove's this instance from the supplied interaction group
18691      * @method removeFromGroup
18692      * @param {string}  sGroup  The group to drop
18693      */
18694     removeFromGroup: function(sGroup) {
18695         if (this.groups[sGroup]) {
18696             delete this.groups[sGroup];
18697         }
18698
18699         this.DDM.removeDDFromGroup(this, sGroup);
18700     },
18701
18702     /**
18703      * Allows you to specify that an element other than the linked element
18704      * will be moved with the cursor during a drag
18705      * @method setDragElId
18706      * @param id {string} the id of the element that will be used to initiate the drag
18707      */
18708     setDragElId: function(id) {
18709         this.dragElId = id;
18710     },
18711
18712     /**
18713      * Allows you to specify a child of the linked element that should be
18714      * used to initiate the drag operation.  An example of this would be if
18715      * you have a content div with text and links.  Clicking anywhere in the
18716      * content area would normally start the drag operation.  Use this method
18717      * to specify that an element inside of the content div is the element
18718      * that starts the drag operation.
18719      * @method setHandleElId
18720      * @param id {string} the id of the element that will be used to
18721      * initiate the drag.
18722      */
18723     setHandleElId: function(id) {
18724         if (typeof id !== "string") {
18725             id = Roo.id(id);
18726         }
18727         this.handleElId = id;
18728         this.DDM.regHandle(this.id, id);
18729     },
18730
18731     /**
18732      * Allows you to set an element outside of the linked element as a drag
18733      * handle
18734      * @method setOuterHandleElId
18735      * @param id the id of the element that will be used to initiate the drag
18736      */
18737     setOuterHandleElId: function(id) {
18738         if (typeof id !== "string") {
18739             id = Roo.id(id);
18740         }
18741         Event.on(id, "mousedown",
18742                 this.handleMouseDown, this);
18743         this.setHandleElId(id);
18744
18745         this.hasOuterHandles = true;
18746     },
18747
18748     /**
18749      * Remove all drag and drop hooks for this element
18750      * @method unreg
18751      */
18752     unreg: function() {
18753         Event.un(this.id, "mousedown",
18754                 this.handleMouseDown);
18755         Event.un(this.id, "touchstart",
18756                 this.handleMouseDown);
18757         this._domRef = null;
18758         this.DDM._remove(this);
18759     },
18760
18761     destroy : function(){
18762         this.unreg();
18763     },
18764
18765     /**
18766      * Returns true if this instance is locked, or the drag drop mgr is locked
18767      * (meaning that all drag/drop is disabled on the page.)
18768      * @method isLocked
18769      * @return {boolean} true if this obj or all drag/drop is locked, else
18770      * false
18771      */
18772     isLocked: function() {
18773         return (this.DDM.isLocked() || this.locked);
18774     },
18775
18776     /**
18777      * Fired when this object is clicked
18778      * @method handleMouseDown
18779      * @param {Event} e
18780      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18781      * @private
18782      */
18783     handleMouseDown: function(e, oDD){
18784      
18785         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18786             //Roo.log('not touch/ button !=0');
18787             return;
18788         }
18789         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18790             return; // double touch..
18791         }
18792         
18793
18794         if (this.isLocked()) {
18795             //Roo.log('locked');
18796             return;
18797         }
18798
18799         this.DDM.refreshCache(this.groups);
18800 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18801         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18802         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18803             //Roo.log('no outer handes or not over target');
18804                 // do nothing.
18805         } else {
18806 //            Roo.log('check validator');
18807             if (this.clickValidator(e)) {
18808 //                Roo.log('validate success');
18809                 // set the initial element position
18810                 this.setStartPosition();
18811
18812
18813                 this.b4MouseDown(e);
18814                 this.onMouseDown(e);
18815
18816                 this.DDM.handleMouseDown(e, this);
18817
18818                 this.DDM.stopEvent(e);
18819             } else {
18820
18821
18822             }
18823         }
18824     },
18825
18826     clickValidator: function(e) {
18827         var target = e.getTarget();
18828         return ( this.isValidHandleChild(target) &&
18829                     (this.id == this.handleElId ||
18830                         this.DDM.handleWasClicked(target, this.id)) );
18831     },
18832
18833     /**
18834      * Allows you to specify a tag name that should not start a drag operation
18835      * when clicked.  This is designed to facilitate embedding links within a
18836      * drag handle that do something other than start the drag.
18837      * @method addInvalidHandleType
18838      * @param {string} tagName the type of element to exclude
18839      */
18840     addInvalidHandleType: function(tagName) {
18841         var type = tagName.toUpperCase();
18842         this.invalidHandleTypes[type] = type;
18843     },
18844
18845     /**
18846      * Lets you to specify an element id for a child of a drag handle
18847      * that should not initiate a drag
18848      * @method addInvalidHandleId
18849      * @param {string} id the element id of the element you wish to ignore
18850      */
18851     addInvalidHandleId: function(id) {
18852         if (typeof id !== "string") {
18853             id = Roo.id(id);
18854         }
18855         this.invalidHandleIds[id] = id;
18856     },
18857
18858     /**
18859      * Lets you specify a css class of elements that will not initiate a drag
18860      * @method addInvalidHandleClass
18861      * @param {string} cssClass the class of the elements you wish to ignore
18862      */
18863     addInvalidHandleClass: function(cssClass) {
18864         this.invalidHandleClasses.push(cssClass);
18865     },
18866
18867     /**
18868      * Unsets an excluded tag name set by addInvalidHandleType
18869      * @method removeInvalidHandleType
18870      * @param {string} tagName the type of element to unexclude
18871      */
18872     removeInvalidHandleType: function(tagName) {
18873         var type = tagName.toUpperCase();
18874         // this.invalidHandleTypes[type] = null;
18875         delete this.invalidHandleTypes[type];
18876     },
18877
18878     /**
18879      * Unsets an invalid handle id
18880      * @method removeInvalidHandleId
18881      * @param {string} id the id of the element to re-enable
18882      */
18883     removeInvalidHandleId: function(id) {
18884         if (typeof id !== "string") {
18885             id = Roo.id(id);
18886         }
18887         delete this.invalidHandleIds[id];
18888     },
18889
18890     /**
18891      * Unsets an invalid css class
18892      * @method removeInvalidHandleClass
18893      * @param {string} cssClass the class of the element(s) you wish to
18894      * re-enable
18895      */
18896     removeInvalidHandleClass: function(cssClass) {
18897         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18898             if (this.invalidHandleClasses[i] == cssClass) {
18899                 delete this.invalidHandleClasses[i];
18900             }
18901         }
18902     },
18903
18904     /**
18905      * Checks the tag exclusion list to see if this click should be ignored
18906      * @method isValidHandleChild
18907      * @param {HTMLElement} node the HTMLElement to evaluate
18908      * @return {boolean} true if this is a valid tag type, false if not
18909      */
18910     isValidHandleChild: function(node) {
18911
18912         var valid = true;
18913         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18914         var nodeName;
18915         try {
18916             nodeName = node.nodeName.toUpperCase();
18917         } catch(e) {
18918             nodeName = node.nodeName;
18919         }
18920         valid = valid && !this.invalidHandleTypes[nodeName];
18921         valid = valid && !this.invalidHandleIds[node.id];
18922
18923         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18924             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18925         }
18926
18927
18928         return valid;
18929
18930     },
18931
18932     /**
18933      * Create the array of horizontal tick marks if an interval was specified
18934      * in setXConstraint().
18935      * @method setXTicks
18936      * @private
18937      */
18938     setXTicks: function(iStartX, iTickSize) {
18939         this.xTicks = [];
18940         this.xTickSize = iTickSize;
18941
18942         var tickMap = {};
18943
18944         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18945             if (!tickMap[i]) {
18946                 this.xTicks[this.xTicks.length] = i;
18947                 tickMap[i] = true;
18948             }
18949         }
18950
18951         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18952             if (!tickMap[i]) {
18953                 this.xTicks[this.xTicks.length] = i;
18954                 tickMap[i] = true;
18955             }
18956         }
18957
18958         this.xTicks.sort(this.DDM.numericSort) ;
18959     },
18960
18961     /**
18962      * Create the array of vertical tick marks if an interval was specified in
18963      * setYConstraint().
18964      * @method setYTicks
18965      * @private
18966      */
18967     setYTicks: function(iStartY, iTickSize) {
18968         this.yTicks = [];
18969         this.yTickSize = iTickSize;
18970
18971         var tickMap = {};
18972
18973         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18974             if (!tickMap[i]) {
18975                 this.yTicks[this.yTicks.length] = i;
18976                 tickMap[i] = true;
18977             }
18978         }
18979
18980         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18981             if (!tickMap[i]) {
18982                 this.yTicks[this.yTicks.length] = i;
18983                 tickMap[i] = true;
18984             }
18985         }
18986
18987         this.yTicks.sort(this.DDM.numericSort) ;
18988     },
18989
18990     /**
18991      * By default, the element can be dragged any place on the screen.  Use
18992      * this method to limit the horizontal travel of the element.  Pass in
18993      * 0,0 for the parameters if you want to lock the drag to the y axis.
18994      * @method setXConstraint
18995      * @param {int} iLeft the number of pixels the element can move to the left
18996      * @param {int} iRight the number of pixels the element can move to the
18997      * right
18998      * @param {int} iTickSize optional parameter for specifying that the
18999      * element
19000      * should move iTickSize pixels at a time.
19001      */
19002     setXConstraint: function(iLeft, iRight, iTickSize) {
19003         this.leftConstraint = iLeft;
19004         this.rightConstraint = iRight;
19005
19006         this.minX = this.initPageX - iLeft;
19007         this.maxX = this.initPageX + iRight;
19008         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19009
19010         this.constrainX = true;
19011     },
19012
19013     /**
19014      * Clears any constraints applied to this instance.  Also clears ticks
19015      * since they can't exist independent of a constraint at this time.
19016      * @method clearConstraints
19017      */
19018     clearConstraints: function() {
19019         this.constrainX = false;
19020         this.constrainY = false;
19021         this.clearTicks();
19022     },
19023
19024     /**
19025      * Clears any tick interval defined for this instance
19026      * @method clearTicks
19027      */
19028     clearTicks: function() {
19029         this.xTicks = null;
19030         this.yTicks = null;
19031         this.xTickSize = 0;
19032         this.yTickSize = 0;
19033     },
19034
19035     /**
19036      * By default, the element can be dragged any place on the screen.  Set
19037      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19038      * parameters if you want to lock the drag to the x axis.
19039      * @method setYConstraint
19040      * @param {int} iUp the number of pixels the element can move up
19041      * @param {int} iDown the number of pixels the element can move down
19042      * @param {int} iTickSize optional parameter for specifying that the
19043      * element should move iTickSize pixels at a time.
19044      */
19045     setYConstraint: function(iUp, iDown, iTickSize) {
19046         this.topConstraint = iUp;
19047         this.bottomConstraint = iDown;
19048
19049         this.minY = this.initPageY - iUp;
19050         this.maxY = this.initPageY + iDown;
19051         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19052
19053         this.constrainY = true;
19054
19055     },
19056
19057     /**
19058      * resetConstraints must be called if you manually reposition a dd element.
19059      * @method resetConstraints
19060      * @param {boolean} maintainOffset
19061      */
19062     resetConstraints: function() {
19063
19064
19065         // Maintain offsets if necessary
19066         if (this.initPageX || this.initPageX === 0) {
19067             // figure out how much this thing has moved
19068             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19069             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19070
19071             this.setInitPosition(dx, dy);
19072
19073         // This is the first time we have detected the element's position
19074         } else {
19075             this.setInitPosition();
19076         }
19077
19078         if (this.constrainX) {
19079             this.setXConstraint( this.leftConstraint,
19080                                  this.rightConstraint,
19081                                  this.xTickSize        );
19082         }
19083
19084         if (this.constrainY) {
19085             this.setYConstraint( this.topConstraint,
19086                                  this.bottomConstraint,
19087                                  this.yTickSize         );
19088         }
19089     },
19090
19091     /**
19092      * Normally the drag element is moved pixel by pixel, but we can specify
19093      * that it move a number of pixels at a time.  This method resolves the
19094      * location when we have it set up like this.
19095      * @method getTick
19096      * @param {int} val where we want to place the object
19097      * @param {int[]} tickArray sorted array of valid points
19098      * @return {int} the closest tick
19099      * @private
19100      */
19101     getTick: function(val, tickArray) {
19102
19103         if (!tickArray) {
19104             // If tick interval is not defined, it is effectively 1 pixel,
19105             // so we return the value passed to us.
19106             return val;
19107         } else if (tickArray[0] >= val) {
19108             // The value is lower than the first tick, so we return the first
19109             // tick.
19110             return tickArray[0];
19111         } else {
19112             for (var i=0, len=tickArray.length; i<len; ++i) {
19113                 var next = i + 1;
19114                 if (tickArray[next] && tickArray[next] >= val) {
19115                     var diff1 = val - tickArray[i];
19116                     var diff2 = tickArray[next] - val;
19117                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19118                 }
19119             }
19120
19121             // The value is larger than the last tick, so we return the last
19122             // tick.
19123             return tickArray[tickArray.length - 1];
19124         }
19125     },
19126
19127     /**
19128      * toString method
19129      * @method toString
19130      * @return {string} string representation of the dd obj
19131      */
19132     toString: function() {
19133         return ("DragDrop " + this.id);
19134     }
19135
19136 });
19137
19138 })();
19139 /*
19140  * Based on:
19141  * Ext JS Library 1.1.1
19142  * Copyright(c) 2006-2007, Ext JS, LLC.
19143  *
19144  * Originally Released Under LGPL - original licence link has changed is not relivant.
19145  *
19146  * Fork - LGPL
19147  * <script type="text/javascript">
19148  */
19149
19150
19151 /**
19152  * The drag and drop utility provides a framework for building drag and drop
19153  * applications.  In addition to enabling drag and drop for specific elements,
19154  * the drag and drop elements are tracked by the manager class, and the
19155  * interactions between the various elements are tracked during the drag and
19156  * the implementing code is notified about these important moments.
19157  */
19158
19159 // Only load the library once.  Rewriting the manager class would orphan
19160 // existing drag and drop instances.
19161 if (!Roo.dd.DragDropMgr) {
19162
19163 /**
19164  * @class Roo.dd.DragDropMgr
19165  * DragDropMgr is a singleton that tracks the element interaction for
19166  * all DragDrop items in the window.  Generally, you will not call
19167  * this class directly, but it does have helper methods that could
19168  * be useful in your DragDrop implementations.
19169  * @singleton
19170  */
19171 Roo.dd.DragDropMgr = function() {
19172
19173     var Event = Roo.EventManager;
19174
19175     return {
19176
19177         /**
19178          * Two dimensional Array of registered DragDrop objects.  The first
19179          * dimension is the DragDrop item group, the second the DragDrop
19180          * object.
19181          * @property ids
19182          * @type {string: string}
19183          * @private
19184          * @static
19185          */
19186         ids: {},
19187
19188         /**
19189          * Array of element ids defined as drag handles.  Used to determine
19190          * if the element that generated the mousedown event is actually the
19191          * handle and not the html element itself.
19192          * @property handleIds
19193          * @type {string: string}
19194          * @private
19195          * @static
19196          */
19197         handleIds: {},
19198
19199         /**
19200          * the DragDrop object that is currently being dragged
19201          * @property dragCurrent
19202          * @type DragDrop
19203          * @private
19204          * @static
19205          **/
19206         dragCurrent: null,
19207
19208         /**
19209          * the DragDrop object(s) that are being hovered over
19210          * @property dragOvers
19211          * @type Array
19212          * @private
19213          * @static
19214          */
19215         dragOvers: {},
19216
19217         /**
19218          * the X distance between the cursor and the object being dragged
19219          * @property deltaX
19220          * @type int
19221          * @private
19222          * @static
19223          */
19224         deltaX: 0,
19225
19226         /**
19227          * the Y distance between the cursor and the object being dragged
19228          * @property deltaY
19229          * @type int
19230          * @private
19231          * @static
19232          */
19233         deltaY: 0,
19234
19235         /**
19236          * Flag to determine if we should prevent the default behavior of the
19237          * events we define. By default this is true, but this can be set to
19238          * false if you need the default behavior (not recommended)
19239          * @property preventDefault
19240          * @type boolean
19241          * @static
19242          */
19243         preventDefault: true,
19244
19245         /**
19246          * Flag to determine if we should stop the propagation of the events
19247          * we generate. This is true by default but you may want to set it to
19248          * false if the html element contains other features that require the
19249          * mouse click.
19250          * @property stopPropagation
19251          * @type boolean
19252          * @static
19253          */
19254         stopPropagation: true,
19255
19256         /**
19257          * Internal flag that is set to true when drag and drop has been
19258          * intialized
19259          * @property initialized
19260          * @private
19261          * @static
19262          */
19263         initalized: false,
19264
19265         /**
19266          * All drag and drop can be disabled.
19267          * @property locked
19268          * @private
19269          * @static
19270          */
19271         locked: false,
19272
19273         /**
19274          * Called the first time an element is registered.
19275          * @method init
19276          * @private
19277          * @static
19278          */
19279         init: function() {
19280             this.initialized = true;
19281         },
19282
19283         /**
19284          * In point mode, drag and drop interaction is defined by the
19285          * location of the cursor during the drag/drop
19286          * @property POINT
19287          * @type int
19288          * @static
19289          */
19290         POINT: 0,
19291
19292         /**
19293          * In intersect mode, drag and drop interactio nis defined by the
19294          * overlap of two or more drag and drop objects.
19295          * @property INTERSECT
19296          * @type int
19297          * @static
19298          */
19299         INTERSECT: 1,
19300
19301         /**
19302          * The current drag and drop mode.  Default: POINT
19303          * @property mode
19304          * @type int
19305          * @static
19306          */
19307         mode: 0,
19308
19309         /**
19310          * Runs method on all drag and drop objects
19311          * @method _execOnAll
19312          * @private
19313          * @static
19314          */
19315         _execOnAll: function(sMethod, args) {
19316             for (var i in this.ids) {
19317                 for (var j in this.ids[i]) {
19318                     var oDD = this.ids[i][j];
19319                     if (! this.isTypeOfDD(oDD)) {
19320                         continue;
19321                     }
19322                     oDD[sMethod].apply(oDD, args);
19323                 }
19324             }
19325         },
19326
19327         /**
19328          * Drag and drop initialization.  Sets up the global event handlers
19329          * @method _onLoad
19330          * @private
19331          * @static
19332          */
19333         _onLoad: function() {
19334
19335             this.init();
19336
19337             if (!Roo.isTouch) {
19338                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19339                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19340             }
19341             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19342             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19343             
19344             Event.on(window,   "unload",    this._onUnload, this, true);
19345             Event.on(window,   "resize",    this._onResize, this, true);
19346             // Event.on(window,   "mouseout",    this._test);
19347
19348         },
19349
19350         /**
19351          * Reset constraints on all drag and drop objs
19352          * @method _onResize
19353          * @private
19354          * @static
19355          */
19356         _onResize: function(e) {
19357             this._execOnAll("resetConstraints", []);
19358         },
19359
19360         /**
19361          * Lock all drag and drop functionality
19362          * @method lock
19363          * @static
19364          */
19365         lock: function() { this.locked = true; },
19366
19367         /**
19368          * Unlock all drag and drop functionality
19369          * @method unlock
19370          * @static
19371          */
19372         unlock: function() { this.locked = false; },
19373
19374         /**
19375          * Is drag and drop locked?
19376          * @method isLocked
19377          * @return {boolean} True if drag and drop is locked, false otherwise.
19378          * @static
19379          */
19380         isLocked: function() { return this.locked; },
19381
19382         /**
19383          * Location cache that is set for all drag drop objects when a drag is
19384          * initiated, cleared when the drag is finished.
19385          * @property locationCache
19386          * @private
19387          * @static
19388          */
19389         locationCache: {},
19390
19391         /**
19392          * Set useCache to false if you want to force object the lookup of each
19393          * drag and drop linked element constantly during a drag.
19394          * @property useCache
19395          * @type boolean
19396          * @static
19397          */
19398         useCache: true,
19399
19400         /**
19401          * The number of pixels that the mouse needs to move after the
19402          * mousedown before the drag is initiated.  Default=3;
19403          * @property clickPixelThresh
19404          * @type int
19405          * @static
19406          */
19407         clickPixelThresh: 3,
19408
19409         /**
19410          * The number of milliseconds after the mousedown event to initiate the
19411          * drag if we don't get a mouseup event. Default=1000
19412          * @property clickTimeThresh
19413          * @type int
19414          * @static
19415          */
19416         clickTimeThresh: 350,
19417
19418         /**
19419          * Flag that indicates that either the drag pixel threshold or the
19420          * mousdown time threshold has been met
19421          * @property dragThreshMet
19422          * @type boolean
19423          * @private
19424          * @static
19425          */
19426         dragThreshMet: false,
19427
19428         /**
19429          * Timeout used for the click time threshold
19430          * @property clickTimeout
19431          * @type Object
19432          * @private
19433          * @static
19434          */
19435         clickTimeout: null,
19436
19437         /**
19438          * The X position of the mousedown event stored for later use when a
19439          * drag threshold is met.
19440          * @property startX
19441          * @type int
19442          * @private
19443          * @static
19444          */
19445         startX: 0,
19446
19447         /**
19448          * The Y position of the mousedown event stored for later use when a
19449          * drag threshold is met.
19450          * @property startY
19451          * @type int
19452          * @private
19453          * @static
19454          */
19455         startY: 0,
19456
19457         /**
19458          * Each DragDrop instance must be registered with the DragDropMgr.
19459          * This is executed in DragDrop.init()
19460          * @method regDragDrop
19461          * @param {DragDrop} oDD the DragDrop object to register
19462          * @param {String} sGroup the name of the group this element belongs to
19463          * @static
19464          */
19465         regDragDrop: function(oDD, sGroup) {
19466             if (!this.initialized) { this.init(); }
19467
19468             if (!this.ids[sGroup]) {
19469                 this.ids[sGroup] = {};
19470             }
19471             this.ids[sGroup][oDD.id] = oDD;
19472         },
19473
19474         /**
19475          * Removes the supplied dd instance from the supplied group. Executed
19476          * by DragDrop.removeFromGroup, so don't call this function directly.
19477          * @method removeDDFromGroup
19478          * @private
19479          * @static
19480          */
19481         removeDDFromGroup: function(oDD, sGroup) {
19482             if (!this.ids[sGroup]) {
19483                 this.ids[sGroup] = {};
19484             }
19485
19486             var obj = this.ids[sGroup];
19487             if (obj && obj[oDD.id]) {
19488                 delete obj[oDD.id];
19489             }
19490         },
19491
19492         /**
19493          * Unregisters a drag and drop item.  This is executed in
19494          * DragDrop.unreg, use that method instead of calling this directly.
19495          * @method _remove
19496          * @private
19497          * @static
19498          */
19499         _remove: function(oDD) {
19500             for (var g in oDD.groups) {
19501                 if (g && this.ids[g][oDD.id]) {
19502                     delete this.ids[g][oDD.id];
19503                 }
19504             }
19505             delete this.handleIds[oDD.id];
19506         },
19507
19508         /**
19509          * Each DragDrop handle element must be registered.  This is done
19510          * automatically when executing DragDrop.setHandleElId()
19511          * @method regHandle
19512          * @param {String} sDDId the DragDrop id this element is a handle for
19513          * @param {String} sHandleId the id of the element that is the drag
19514          * handle
19515          * @static
19516          */
19517         regHandle: function(sDDId, sHandleId) {
19518             if (!this.handleIds[sDDId]) {
19519                 this.handleIds[sDDId] = {};
19520             }
19521             this.handleIds[sDDId][sHandleId] = sHandleId;
19522         },
19523
19524         /**
19525          * Utility function to determine if a given element has been
19526          * registered as a drag drop item.
19527          * @method isDragDrop
19528          * @param {String} id the element id to check
19529          * @return {boolean} true if this element is a DragDrop item,
19530          * false otherwise
19531          * @static
19532          */
19533         isDragDrop: function(id) {
19534             return ( this.getDDById(id) ) ? true : false;
19535         },
19536
19537         /**
19538          * Returns the drag and drop instances that are in all groups the
19539          * passed in instance belongs to.
19540          * @method getRelated
19541          * @param {DragDrop} p_oDD the obj to get related data for
19542          * @param {boolean} bTargetsOnly if true, only return targetable objs
19543          * @return {DragDrop[]} the related instances
19544          * @static
19545          */
19546         getRelated: function(p_oDD, bTargetsOnly) {
19547             var oDDs = [];
19548             for (var i in p_oDD.groups) {
19549                 for (j in this.ids[i]) {
19550                     var dd = this.ids[i][j];
19551                     if (! this.isTypeOfDD(dd)) {
19552                         continue;
19553                     }
19554                     if (!bTargetsOnly || dd.isTarget) {
19555                         oDDs[oDDs.length] = dd;
19556                     }
19557                 }
19558             }
19559
19560             return oDDs;
19561         },
19562
19563         /**
19564          * Returns true if the specified dd target is a legal target for
19565          * the specifice drag obj
19566          * @method isLegalTarget
19567          * @param {DragDrop} the drag obj
19568          * @param {DragDrop} the target
19569          * @return {boolean} true if the target is a legal target for the
19570          * dd obj
19571          * @static
19572          */
19573         isLegalTarget: function (oDD, oTargetDD) {
19574             var targets = this.getRelated(oDD, true);
19575             for (var i=0, len=targets.length;i<len;++i) {
19576                 if (targets[i].id == oTargetDD.id) {
19577                     return true;
19578                 }
19579             }
19580
19581             return false;
19582         },
19583
19584         /**
19585          * My goal is to be able to transparently determine if an object is
19586          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19587          * returns "object", oDD.constructor.toString() always returns
19588          * "DragDrop" and not the name of the subclass.  So for now it just
19589          * evaluates a well-known variable in DragDrop.
19590          * @method isTypeOfDD
19591          * @param {Object} the object to evaluate
19592          * @return {boolean} true if typeof oDD = DragDrop
19593          * @static
19594          */
19595         isTypeOfDD: function (oDD) {
19596             return (oDD && oDD.__ygDragDrop);
19597         },
19598
19599         /**
19600          * Utility function to determine if a given element has been
19601          * registered as a drag drop handle for the given Drag Drop object.
19602          * @method isHandle
19603          * @param {String} id the element id to check
19604          * @return {boolean} true if this element is a DragDrop handle, false
19605          * otherwise
19606          * @static
19607          */
19608         isHandle: function(sDDId, sHandleId) {
19609             return ( this.handleIds[sDDId] &&
19610                             this.handleIds[sDDId][sHandleId] );
19611         },
19612
19613         /**
19614          * Returns the DragDrop instance for a given id
19615          * @method getDDById
19616          * @param {String} id the id of the DragDrop object
19617          * @return {DragDrop} the drag drop object, null if it is not found
19618          * @static
19619          */
19620         getDDById: function(id) {
19621             for (var i in this.ids) {
19622                 if (this.ids[i][id]) {
19623                     return this.ids[i][id];
19624                 }
19625             }
19626             return null;
19627         },
19628
19629         /**
19630          * Fired after a registered DragDrop object gets the mousedown event.
19631          * Sets up the events required to track the object being dragged
19632          * @method handleMouseDown
19633          * @param {Event} e the event
19634          * @param oDD the DragDrop object being dragged
19635          * @private
19636          * @static
19637          */
19638         handleMouseDown: function(e, oDD) {
19639             if(Roo.QuickTips){
19640                 Roo.QuickTips.disable();
19641             }
19642             this.currentTarget = e.getTarget();
19643
19644             this.dragCurrent = oDD;
19645
19646             var el = oDD.getEl();
19647
19648             // track start position
19649             this.startX = e.getPageX();
19650             this.startY = e.getPageY();
19651
19652             this.deltaX = this.startX - el.offsetLeft;
19653             this.deltaY = this.startY - el.offsetTop;
19654
19655             this.dragThreshMet = false;
19656
19657             this.clickTimeout = setTimeout(
19658                     function() {
19659                         var DDM = Roo.dd.DDM;
19660                         DDM.startDrag(DDM.startX, DDM.startY);
19661                     },
19662                     this.clickTimeThresh );
19663         },
19664
19665         /**
19666          * Fired when either the drag pixel threshol or the mousedown hold
19667          * time threshold has been met.
19668          * @method startDrag
19669          * @param x {int} the X position of the original mousedown
19670          * @param y {int} the Y position of the original mousedown
19671          * @static
19672          */
19673         startDrag: function(x, y) {
19674             clearTimeout(this.clickTimeout);
19675             if (this.dragCurrent) {
19676                 this.dragCurrent.b4StartDrag(x, y);
19677                 this.dragCurrent.startDrag(x, y);
19678             }
19679             this.dragThreshMet = true;
19680         },
19681
19682         /**
19683          * Internal function to handle the mouseup event.  Will be invoked
19684          * from the context of the document.
19685          * @method handleMouseUp
19686          * @param {Event} e the event
19687          * @private
19688          * @static
19689          */
19690         handleMouseUp: function(e) {
19691
19692             if(Roo.QuickTips){
19693                 Roo.QuickTips.enable();
19694             }
19695             if (! this.dragCurrent) {
19696                 return;
19697             }
19698
19699             clearTimeout(this.clickTimeout);
19700
19701             if (this.dragThreshMet) {
19702                 this.fireEvents(e, true);
19703             } else {
19704             }
19705
19706             this.stopDrag(e);
19707
19708             this.stopEvent(e);
19709         },
19710
19711         /**
19712          * Utility to stop event propagation and event default, if these
19713          * features are turned on.
19714          * @method stopEvent
19715          * @param {Event} e the event as returned by this.getEvent()
19716          * @static
19717          */
19718         stopEvent: function(e){
19719             if(this.stopPropagation) {
19720                 e.stopPropagation();
19721             }
19722
19723             if (this.preventDefault) {
19724                 e.preventDefault();
19725             }
19726         },
19727
19728         /**
19729          * Internal function to clean up event handlers after the drag
19730          * operation is complete
19731          * @method stopDrag
19732          * @param {Event} e the event
19733          * @private
19734          * @static
19735          */
19736         stopDrag: function(e) {
19737             // Fire the drag end event for the item that was dragged
19738             if (this.dragCurrent) {
19739                 if (this.dragThreshMet) {
19740                     this.dragCurrent.b4EndDrag(e);
19741                     this.dragCurrent.endDrag(e);
19742                 }
19743
19744                 this.dragCurrent.onMouseUp(e);
19745             }
19746
19747             this.dragCurrent = null;
19748             this.dragOvers = {};
19749         },
19750
19751         /**
19752          * Internal function to handle the mousemove event.  Will be invoked
19753          * from the context of the html element.
19754          *
19755          * @TODO figure out what we can do about mouse events lost when the
19756          * user drags objects beyond the window boundary.  Currently we can
19757          * detect this in internet explorer by verifying that the mouse is
19758          * down during the mousemove event.  Firefox doesn't give us the
19759          * button state on the mousemove event.
19760          * @method handleMouseMove
19761          * @param {Event} e the event
19762          * @private
19763          * @static
19764          */
19765         handleMouseMove: function(e) {
19766             if (! this.dragCurrent) {
19767                 return true;
19768             }
19769
19770             // var button = e.which || e.button;
19771
19772             // check for IE mouseup outside of page boundary
19773             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19774                 this.stopEvent(e);
19775                 return this.handleMouseUp(e);
19776             }
19777
19778             if (!this.dragThreshMet) {
19779                 var diffX = Math.abs(this.startX - e.getPageX());
19780                 var diffY = Math.abs(this.startY - e.getPageY());
19781                 if (diffX > this.clickPixelThresh ||
19782                             diffY > this.clickPixelThresh) {
19783                     this.startDrag(this.startX, this.startY);
19784                 }
19785             }
19786
19787             if (this.dragThreshMet) {
19788                 this.dragCurrent.b4Drag(e);
19789                 this.dragCurrent.onDrag(e);
19790                 if(!this.dragCurrent.moveOnly){
19791                     this.fireEvents(e, false);
19792                 }
19793             }
19794
19795             this.stopEvent(e);
19796
19797             return true;
19798         },
19799
19800         /**
19801          * Iterates over all of the DragDrop elements to find ones we are
19802          * hovering over or dropping on
19803          * @method fireEvents
19804          * @param {Event} e the event
19805          * @param {boolean} isDrop is this a drop op or a mouseover op?
19806          * @private
19807          * @static
19808          */
19809         fireEvents: function(e, isDrop) {
19810             var dc = this.dragCurrent;
19811
19812             // If the user did the mouse up outside of the window, we could
19813             // get here even though we have ended the drag.
19814             if (!dc || dc.isLocked()) {
19815                 return;
19816             }
19817
19818             var pt = e.getPoint();
19819
19820             // cache the previous dragOver array
19821             var oldOvers = [];
19822
19823             var outEvts   = [];
19824             var overEvts  = [];
19825             var dropEvts  = [];
19826             var enterEvts = [];
19827
19828             // Check to see if the object(s) we were hovering over is no longer
19829             // being hovered over so we can fire the onDragOut event
19830             for (var i in this.dragOvers) {
19831
19832                 var ddo = this.dragOvers[i];
19833
19834                 if (! this.isTypeOfDD(ddo)) {
19835                     continue;
19836                 }
19837
19838                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19839                     outEvts.push( ddo );
19840                 }
19841
19842                 oldOvers[i] = true;
19843                 delete this.dragOvers[i];
19844             }
19845
19846             for (var sGroup in dc.groups) {
19847
19848                 if ("string" != typeof sGroup) {
19849                     continue;
19850                 }
19851
19852                 for (i in this.ids[sGroup]) {
19853                     var oDD = this.ids[sGroup][i];
19854                     if (! this.isTypeOfDD(oDD)) {
19855                         continue;
19856                     }
19857
19858                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19859                         if (this.isOverTarget(pt, oDD, this.mode)) {
19860                             // look for drop interactions
19861                             if (isDrop) {
19862                                 dropEvts.push( oDD );
19863                             // look for drag enter and drag over interactions
19864                             } else {
19865
19866                                 // initial drag over: dragEnter fires
19867                                 if (!oldOvers[oDD.id]) {
19868                                     enterEvts.push( oDD );
19869                                 // subsequent drag overs: dragOver fires
19870                                 } else {
19871                                     overEvts.push( oDD );
19872                                 }
19873
19874                                 this.dragOvers[oDD.id] = oDD;
19875                             }
19876                         }
19877                     }
19878                 }
19879             }
19880
19881             if (this.mode) {
19882                 if (outEvts.length) {
19883                     dc.b4DragOut(e, outEvts);
19884                     dc.onDragOut(e, outEvts);
19885                 }
19886
19887                 if (enterEvts.length) {
19888                     dc.onDragEnter(e, enterEvts);
19889                 }
19890
19891                 if (overEvts.length) {
19892                     dc.b4DragOver(e, overEvts);
19893                     dc.onDragOver(e, overEvts);
19894                 }
19895
19896                 if (dropEvts.length) {
19897                     dc.b4DragDrop(e, dropEvts);
19898                     dc.onDragDrop(e, dropEvts);
19899                 }
19900
19901             } else {
19902                 // fire dragout events
19903                 var len = 0;
19904                 for (i=0, len=outEvts.length; i<len; ++i) {
19905                     dc.b4DragOut(e, outEvts[i].id);
19906                     dc.onDragOut(e, outEvts[i].id);
19907                 }
19908
19909                 // fire enter events
19910                 for (i=0,len=enterEvts.length; i<len; ++i) {
19911                     // dc.b4DragEnter(e, oDD.id);
19912                     dc.onDragEnter(e, enterEvts[i].id);
19913                 }
19914
19915                 // fire over events
19916                 for (i=0,len=overEvts.length; i<len; ++i) {
19917                     dc.b4DragOver(e, overEvts[i].id);
19918                     dc.onDragOver(e, overEvts[i].id);
19919                 }
19920
19921                 // fire drop events
19922                 for (i=0, len=dropEvts.length; i<len; ++i) {
19923                     dc.b4DragDrop(e, dropEvts[i].id);
19924                     dc.onDragDrop(e, dropEvts[i].id);
19925                 }
19926
19927             }
19928
19929             // notify about a drop that did not find a target
19930             if (isDrop && !dropEvts.length) {
19931                 dc.onInvalidDrop(e);
19932             }
19933
19934         },
19935
19936         /**
19937          * Helper function for getting the best match from the list of drag
19938          * and drop objects returned by the drag and drop events when we are
19939          * in INTERSECT mode.  It returns either the first object that the
19940          * cursor is over, or the object that has the greatest overlap with
19941          * the dragged element.
19942          * @method getBestMatch
19943          * @param  {DragDrop[]} dds The array of drag and drop objects
19944          * targeted
19945          * @return {DragDrop}       The best single match
19946          * @static
19947          */
19948         getBestMatch: function(dds) {
19949             var winner = null;
19950             // Return null if the input is not what we expect
19951             //if (!dds || !dds.length || dds.length == 0) {
19952                // winner = null;
19953             // If there is only one item, it wins
19954             //} else if (dds.length == 1) {
19955
19956             var len = dds.length;
19957
19958             if (len == 1) {
19959                 winner = dds[0];
19960             } else {
19961                 // Loop through the targeted items
19962                 for (var i=0; i<len; ++i) {
19963                     var dd = dds[i];
19964                     // If the cursor is over the object, it wins.  If the
19965                     // cursor is over multiple matches, the first one we come
19966                     // to wins.
19967                     if (dd.cursorIsOver) {
19968                         winner = dd;
19969                         break;
19970                     // Otherwise the object with the most overlap wins
19971                     } else {
19972                         if (!winner ||
19973                             winner.overlap.getArea() < dd.overlap.getArea()) {
19974                             winner = dd;
19975                         }
19976                     }
19977                 }
19978             }
19979
19980             return winner;
19981         },
19982
19983         /**
19984          * Refreshes the cache of the top-left and bottom-right points of the
19985          * drag and drop objects in the specified group(s).  This is in the
19986          * format that is stored in the drag and drop instance, so typical
19987          * usage is:
19988          * <code>
19989          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19990          * </code>
19991          * Alternatively:
19992          * <code>
19993          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19994          * </code>
19995          * @TODO this really should be an indexed array.  Alternatively this
19996          * method could accept both.
19997          * @method refreshCache
19998          * @param {Object} groups an associative array of groups to refresh
19999          * @static
20000          */
20001         refreshCache: function(groups) {
20002             for (var sGroup in groups) {
20003                 if ("string" != typeof sGroup) {
20004                     continue;
20005                 }
20006                 for (var i in this.ids[sGroup]) {
20007                     var oDD = this.ids[sGroup][i];
20008
20009                     if (this.isTypeOfDD(oDD)) {
20010                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20011                         var loc = this.getLocation(oDD);
20012                         if (loc) {
20013                             this.locationCache[oDD.id] = loc;
20014                         } else {
20015                             delete this.locationCache[oDD.id];
20016                             // this will unregister the drag and drop object if
20017                             // the element is not in a usable state
20018                             // oDD.unreg();
20019                         }
20020                     }
20021                 }
20022             }
20023         },
20024
20025         /**
20026          * This checks to make sure an element exists and is in the DOM.  The
20027          * main purpose is to handle cases where innerHTML is used to remove
20028          * drag and drop objects from the DOM.  IE provides an 'unspecified
20029          * error' when trying to access the offsetParent of such an element
20030          * @method verifyEl
20031          * @param {HTMLElement} el the element to check
20032          * @return {boolean} true if the element looks usable
20033          * @static
20034          */
20035         verifyEl: function(el) {
20036             if (el) {
20037                 var parent;
20038                 if(Roo.isIE){
20039                     try{
20040                         parent = el.offsetParent;
20041                     }catch(e){}
20042                 }else{
20043                     parent = el.offsetParent;
20044                 }
20045                 if (parent) {
20046                     return true;
20047                 }
20048             }
20049
20050             return false;
20051         },
20052
20053         /**
20054          * Returns a Region object containing the drag and drop element's position
20055          * and size, including the padding configured for it
20056          * @method getLocation
20057          * @param {DragDrop} oDD the drag and drop object to get the
20058          *                       location for
20059          * @return {Roo.lib.Region} a Region object representing the total area
20060          *                             the element occupies, including any padding
20061          *                             the instance is configured for.
20062          * @static
20063          */
20064         getLocation: function(oDD) {
20065             if (! this.isTypeOfDD(oDD)) {
20066                 return null;
20067             }
20068
20069             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20070
20071             try {
20072                 pos= Roo.lib.Dom.getXY(el);
20073             } catch (e) { }
20074
20075             if (!pos) {
20076                 return null;
20077             }
20078
20079             x1 = pos[0];
20080             x2 = x1 + el.offsetWidth;
20081             y1 = pos[1];
20082             y2 = y1 + el.offsetHeight;
20083
20084             t = y1 - oDD.padding[0];
20085             r = x2 + oDD.padding[1];
20086             b = y2 + oDD.padding[2];
20087             l = x1 - oDD.padding[3];
20088
20089             return new Roo.lib.Region( t, r, b, l );
20090         },
20091
20092         /**
20093          * Checks the cursor location to see if it over the target
20094          * @method isOverTarget
20095          * @param {Roo.lib.Point} pt The point to evaluate
20096          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20097          * @return {boolean} true if the mouse is over the target
20098          * @private
20099          * @static
20100          */
20101         isOverTarget: function(pt, oTarget, intersect) {
20102             // use cache if available
20103             var loc = this.locationCache[oTarget.id];
20104             if (!loc || !this.useCache) {
20105                 loc = this.getLocation(oTarget);
20106                 this.locationCache[oTarget.id] = loc;
20107
20108             }
20109
20110             if (!loc) {
20111                 return false;
20112             }
20113
20114             oTarget.cursorIsOver = loc.contains( pt );
20115
20116             // DragDrop is using this as a sanity check for the initial mousedown
20117             // in this case we are done.  In POINT mode, if the drag obj has no
20118             // contraints, we are also done. Otherwise we need to evaluate the
20119             // location of the target as related to the actual location of the
20120             // dragged element.
20121             var dc = this.dragCurrent;
20122             if (!dc || !dc.getTargetCoord ||
20123                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20124                 return oTarget.cursorIsOver;
20125             }
20126
20127             oTarget.overlap = null;
20128
20129             // Get the current location of the drag element, this is the
20130             // location of the mouse event less the delta that represents
20131             // where the original mousedown happened on the element.  We
20132             // need to consider constraints and ticks as well.
20133             var pos = dc.getTargetCoord(pt.x, pt.y);
20134
20135             var el = dc.getDragEl();
20136             var curRegion = new Roo.lib.Region( pos.y,
20137                                                    pos.x + el.offsetWidth,
20138                                                    pos.y + el.offsetHeight,
20139                                                    pos.x );
20140
20141             var overlap = curRegion.intersect(loc);
20142
20143             if (overlap) {
20144                 oTarget.overlap = overlap;
20145                 return (intersect) ? true : oTarget.cursorIsOver;
20146             } else {
20147                 return false;
20148             }
20149         },
20150
20151         /**
20152          * unload event handler
20153          * @method _onUnload
20154          * @private
20155          * @static
20156          */
20157         _onUnload: function(e, me) {
20158             Roo.dd.DragDropMgr.unregAll();
20159         },
20160
20161         /**
20162          * Cleans up the drag and drop events and objects.
20163          * @method unregAll
20164          * @private
20165          * @static
20166          */
20167         unregAll: function() {
20168
20169             if (this.dragCurrent) {
20170                 this.stopDrag();
20171                 this.dragCurrent = null;
20172             }
20173
20174             this._execOnAll("unreg", []);
20175
20176             for (i in this.elementCache) {
20177                 delete this.elementCache[i];
20178             }
20179
20180             this.elementCache = {};
20181             this.ids = {};
20182         },
20183
20184         /**
20185          * A cache of DOM elements
20186          * @property elementCache
20187          * @private
20188          * @static
20189          */
20190         elementCache: {},
20191
20192         /**
20193          * Get the wrapper for the DOM element specified
20194          * @method getElWrapper
20195          * @param {String} id the id of the element to get
20196          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20197          * @private
20198          * @deprecated This wrapper isn't that useful
20199          * @static
20200          */
20201         getElWrapper: function(id) {
20202             var oWrapper = this.elementCache[id];
20203             if (!oWrapper || !oWrapper.el) {
20204                 oWrapper = this.elementCache[id] =
20205                     new this.ElementWrapper(Roo.getDom(id));
20206             }
20207             return oWrapper;
20208         },
20209
20210         /**
20211          * Returns the actual DOM element
20212          * @method getElement
20213          * @param {String} id the id of the elment to get
20214          * @return {Object} The element
20215          * @deprecated use Roo.getDom instead
20216          * @static
20217          */
20218         getElement: function(id) {
20219             return Roo.getDom(id);
20220         },
20221
20222         /**
20223          * Returns the style property for the DOM element (i.e.,
20224          * document.getElById(id).style)
20225          * @method getCss
20226          * @param {String} id the id of the elment to get
20227          * @return {Object} The style property of the element
20228          * @deprecated use Roo.getDom instead
20229          * @static
20230          */
20231         getCss: function(id) {
20232             var el = Roo.getDom(id);
20233             return (el) ? el.style : null;
20234         },
20235
20236         /**
20237          * Inner class for cached elements
20238          * @class DragDropMgr.ElementWrapper
20239          * @for DragDropMgr
20240          * @private
20241          * @deprecated
20242          */
20243         ElementWrapper: function(el) {
20244                 /**
20245                  * The element
20246                  * @property el
20247                  */
20248                 this.el = el || null;
20249                 /**
20250                  * The element id
20251                  * @property id
20252                  */
20253                 this.id = this.el && el.id;
20254                 /**
20255                  * A reference to the style property
20256                  * @property css
20257                  */
20258                 this.css = this.el && el.style;
20259             },
20260
20261         /**
20262          * Returns the X position of an html element
20263          * @method getPosX
20264          * @param el the element for which to get the position
20265          * @return {int} the X coordinate
20266          * @for DragDropMgr
20267          * @deprecated use Roo.lib.Dom.getX instead
20268          * @static
20269          */
20270         getPosX: function(el) {
20271             return Roo.lib.Dom.getX(el);
20272         },
20273
20274         /**
20275          * Returns the Y position of an html element
20276          * @method getPosY
20277          * @param el the element for which to get the position
20278          * @return {int} the Y coordinate
20279          * @deprecated use Roo.lib.Dom.getY instead
20280          * @static
20281          */
20282         getPosY: function(el) {
20283             return Roo.lib.Dom.getY(el);
20284         },
20285
20286         /**
20287          * Swap two nodes.  In IE, we use the native method, for others we
20288          * emulate the IE behavior
20289          * @method swapNode
20290          * @param n1 the first node to swap
20291          * @param n2 the other node to swap
20292          * @static
20293          */
20294         swapNode: function(n1, n2) {
20295             if (n1.swapNode) {
20296                 n1.swapNode(n2);
20297             } else {
20298                 var p = n2.parentNode;
20299                 var s = n2.nextSibling;
20300
20301                 if (s == n1) {
20302                     p.insertBefore(n1, n2);
20303                 } else if (n2 == n1.nextSibling) {
20304                     p.insertBefore(n2, n1);
20305                 } else {
20306                     n1.parentNode.replaceChild(n2, n1);
20307                     p.insertBefore(n1, s);
20308                 }
20309             }
20310         },
20311
20312         /**
20313          * Returns the current scroll position
20314          * @method getScroll
20315          * @private
20316          * @static
20317          */
20318         getScroll: function () {
20319             var t, l, dde=document.documentElement, db=document.body;
20320             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20321                 t = dde.scrollTop;
20322                 l = dde.scrollLeft;
20323             } else if (db) {
20324                 t = db.scrollTop;
20325                 l = db.scrollLeft;
20326             } else {
20327
20328             }
20329             return { top: t, left: l };
20330         },
20331
20332         /**
20333          * Returns the specified element style property
20334          * @method getStyle
20335          * @param {HTMLElement} el          the element
20336          * @param {string}      styleProp   the style property
20337          * @return {string} The value of the style property
20338          * @deprecated use Roo.lib.Dom.getStyle
20339          * @static
20340          */
20341         getStyle: function(el, styleProp) {
20342             return Roo.fly(el).getStyle(styleProp);
20343         },
20344
20345         /**
20346          * Gets the scrollTop
20347          * @method getScrollTop
20348          * @return {int} the document's scrollTop
20349          * @static
20350          */
20351         getScrollTop: function () { return this.getScroll().top; },
20352
20353         /**
20354          * Gets the scrollLeft
20355          * @method getScrollLeft
20356          * @return {int} the document's scrollTop
20357          * @static
20358          */
20359         getScrollLeft: function () { return this.getScroll().left; },
20360
20361         /**
20362          * Sets the x/y position of an element to the location of the
20363          * target element.
20364          * @method moveToEl
20365          * @param {HTMLElement} moveEl      The element to move
20366          * @param {HTMLElement} targetEl    The position reference element
20367          * @static
20368          */
20369         moveToEl: function (moveEl, targetEl) {
20370             var aCoord = Roo.lib.Dom.getXY(targetEl);
20371             Roo.lib.Dom.setXY(moveEl, aCoord);
20372         },
20373
20374         /**
20375          * Numeric array sort function
20376          * @method numericSort
20377          * @static
20378          */
20379         numericSort: function(a, b) { return (a - b); },
20380
20381         /**
20382          * Internal counter
20383          * @property _timeoutCount
20384          * @private
20385          * @static
20386          */
20387         _timeoutCount: 0,
20388
20389         /**
20390          * Trying to make the load order less important.  Without this we get
20391          * an error if this file is loaded before the Event Utility.
20392          * @method _addListeners
20393          * @private
20394          * @static
20395          */
20396         _addListeners: function() {
20397             var DDM = Roo.dd.DDM;
20398             if ( Roo.lib.Event && document ) {
20399                 DDM._onLoad();
20400             } else {
20401                 if (DDM._timeoutCount > 2000) {
20402                 } else {
20403                     setTimeout(DDM._addListeners, 10);
20404                     if (document && document.body) {
20405                         DDM._timeoutCount += 1;
20406                     }
20407                 }
20408             }
20409         },
20410
20411         /**
20412          * Recursively searches the immediate parent and all child nodes for
20413          * the handle element in order to determine wheter or not it was
20414          * clicked.
20415          * @method handleWasClicked
20416          * @param node the html element to inspect
20417          * @static
20418          */
20419         handleWasClicked: function(node, id) {
20420             if (this.isHandle(id, node.id)) {
20421                 return true;
20422             } else {
20423                 // check to see if this is a text node child of the one we want
20424                 var p = node.parentNode;
20425
20426                 while (p) {
20427                     if (this.isHandle(id, p.id)) {
20428                         return true;
20429                     } else {
20430                         p = p.parentNode;
20431                     }
20432                 }
20433             }
20434
20435             return false;
20436         }
20437
20438     };
20439
20440 }();
20441
20442 // shorter alias, save a few bytes
20443 Roo.dd.DDM = Roo.dd.DragDropMgr;
20444 Roo.dd.DDM._addListeners();
20445
20446 }/*
20447  * Based on:
20448  * Ext JS Library 1.1.1
20449  * Copyright(c) 2006-2007, Ext JS, LLC.
20450  *
20451  * Originally Released Under LGPL - original licence link has changed is not relivant.
20452  *
20453  * Fork - LGPL
20454  * <script type="text/javascript">
20455  */
20456
20457 /**
20458  * @class Roo.dd.DD
20459  * A DragDrop implementation where the linked element follows the
20460  * mouse cursor during a drag.
20461  * @extends Roo.dd.DragDrop
20462  * @constructor
20463  * @param {String} id the id of the linked element
20464  * @param {String} sGroup the group of related DragDrop items
20465  * @param {object} config an object containing configurable attributes
20466  *                Valid properties for DD:
20467  *                    scroll
20468  */
20469 Roo.dd.DD = function(id, sGroup, config) {
20470     if (id) {
20471         this.init(id, sGroup, config);
20472     }
20473 };
20474
20475 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20476
20477     /**
20478      * When set to true, the utility automatically tries to scroll the browser
20479      * window wehn a drag and drop element is dragged near the viewport boundary.
20480      * Defaults to true.
20481      * @property scroll
20482      * @type boolean
20483      */
20484     scroll: true,
20485
20486     /**
20487      * Sets the pointer offset to the distance between the linked element's top
20488      * left corner and the location the element was clicked
20489      * @method autoOffset
20490      * @param {int} iPageX the X coordinate of the click
20491      * @param {int} iPageY the Y coordinate of the click
20492      */
20493     autoOffset: function(iPageX, iPageY) {
20494         var x = iPageX - this.startPageX;
20495         var y = iPageY - this.startPageY;
20496         this.setDelta(x, y);
20497     },
20498
20499     /**
20500      * Sets the pointer offset.  You can call this directly to force the
20501      * offset to be in a particular location (e.g., pass in 0,0 to set it
20502      * to the center of the object)
20503      * @method setDelta
20504      * @param {int} iDeltaX the distance from the left
20505      * @param {int} iDeltaY the distance from the top
20506      */
20507     setDelta: function(iDeltaX, iDeltaY) {
20508         this.deltaX = iDeltaX;
20509         this.deltaY = iDeltaY;
20510     },
20511
20512     /**
20513      * Sets the drag element to the location of the mousedown or click event,
20514      * maintaining the cursor location relative to the location on the element
20515      * that was clicked.  Override this if you want to place the element in a
20516      * location other than where the cursor is.
20517      * @method setDragElPos
20518      * @param {int} iPageX the X coordinate of the mousedown or drag event
20519      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20520      */
20521     setDragElPos: function(iPageX, iPageY) {
20522         // the first time we do this, we are going to check to make sure
20523         // the element has css positioning
20524
20525         var el = this.getDragEl();
20526         this.alignElWithMouse(el, iPageX, iPageY);
20527     },
20528
20529     /**
20530      * Sets the element to the location of the mousedown or click event,
20531      * maintaining the cursor location relative to the location on the element
20532      * that was clicked.  Override this if you want to place the element in a
20533      * location other than where the cursor is.
20534      * @method alignElWithMouse
20535      * @param {HTMLElement} el the element to move
20536      * @param {int} iPageX the X coordinate of the mousedown or drag event
20537      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20538      */
20539     alignElWithMouse: function(el, iPageX, iPageY) {
20540         var oCoord = this.getTargetCoord(iPageX, iPageY);
20541         var fly = el.dom ? el : Roo.fly(el);
20542         if (!this.deltaSetXY) {
20543             var aCoord = [oCoord.x, oCoord.y];
20544             fly.setXY(aCoord);
20545             var newLeft = fly.getLeft(true);
20546             var newTop  = fly.getTop(true);
20547             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20548         } else {
20549             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20550         }
20551
20552         this.cachePosition(oCoord.x, oCoord.y);
20553         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20554         return oCoord;
20555     },
20556
20557     /**
20558      * Saves the most recent position so that we can reset the constraints and
20559      * tick marks on-demand.  We need to know this so that we can calculate the
20560      * number of pixels the element is offset from its original position.
20561      * @method cachePosition
20562      * @param iPageX the current x position (optional, this just makes it so we
20563      * don't have to look it up again)
20564      * @param iPageY the current y position (optional, this just makes it so we
20565      * don't have to look it up again)
20566      */
20567     cachePosition: function(iPageX, iPageY) {
20568         if (iPageX) {
20569             this.lastPageX = iPageX;
20570             this.lastPageY = iPageY;
20571         } else {
20572             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20573             this.lastPageX = aCoord[0];
20574             this.lastPageY = aCoord[1];
20575         }
20576     },
20577
20578     /**
20579      * Auto-scroll the window if the dragged object has been moved beyond the
20580      * visible window boundary.
20581      * @method autoScroll
20582      * @param {int} x the drag element's x position
20583      * @param {int} y the drag element's y position
20584      * @param {int} h the height of the drag element
20585      * @param {int} w the width of the drag element
20586      * @private
20587      */
20588     autoScroll: function(x, y, h, w) {
20589
20590         if (this.scroll) {
20591             // The client height
20592             var clientH = Roo.lib.Dom.getViewWidth();
20593
20594             // The client width
20595             var clientW = Roo.lib.Dom.getViewHeight();
20596
20597             // The amt scrolled down
20598             var st = this.DDM.getScrollTop();
20599
20600             // The amt scrolled right
20601             var sl = this.DDM.getScrollLeft();
20602
20603             // Location of the bottom of the element
20604             var bot = h + y;
20605
20606             // Location of the right of the element
20607             var right = w + x;
20608
20609             // The distance from the cursor to the bottom of the visible area,
20610             // adjusted so that we don't scroll if the cursor is beyond the
20611             // element drag constraints
20612             var toBot = (clientH + st - y - this.deltaY);
20613
20614             // The distance from the cursor to the right of the visible area
20615             var toRight = (clientW + sl - x - this.deltaX);
20616
20617
20618             // How close to the edge the cursor must be before we scroll
20619             // var thresh = (document.all) ? 100 : 40;
20620             var thresh = 40;
20621
20622             // How many pixels to scroll per autoscroll op.  This helps to reduce
20623             // clunky scrolling. IE is more sensitive about this ... it needs this
20624             // value to be higher.
20625             var scrAmt = (document.all) ? 80 : 30;
20626
20627             // Scroll down if we are near the bottom of the visible page and the
20628             // obj extends below the crease
20629             if ( bot > clientH && toBot < thresh ) {
20630                 window.scrollTo(sl, st + scrAmt);
20631             }
20632
20633             // Scroll up if the window is scrolled down and the top of the object
20634             // goes above the top border
20635             if ( y < st && st > 0 && y - st < thresh ) {
20636                 window.scrollTo(sl, st - scrAmt);
20637             }
20638
20639             // Scroll right if the obj is beyond the right border and the cursor is
20640             // near the border.
20641             if ( right > clientW && toRight < thresh ) {
20642                 window.scrollTo(sl + scrAmt, st);
20643             }
20644
20645             // Scroll left if the window has been scrolled to the right and the obj
20646             // extends past the left border
20647             if ( x < sl && sl > 0 && x - sl < thresh ) {
20648                 window.scrollTo(sl - scrAmt, st);
20649             }
20650         }
20651     },
20652
20653     /**
20654      * Finds the location the element should be placed if we want to move
20655      * it to where the mouse location less the click offset would place us.
20656      * @method getTargetCoord
20657      * @param {int} iPageX the X coordinate of the click
20658      * @param {int} iPageY the Y coordinate of the click
20659      * @return an object that contains the coordinates (Object.x and Object.y)
20660      * @private
20661      */
20662     getTargetCoord: function(iPageX, iPageY) {
20663
20664
20665         var x = iPageX - this.deltaX;
20666         var y = iPageY - this.deltaY;
20667
20668         if (this.constrainX) {
20669             if (x < this.minX) { x = this.minX; }
20670             if (x > this.maxX) { x = this.maxX; }
20671         }
20672
20673         if (this.constrainY) {
20674             if (y < this.minY) { y = this.minY; }
20675             if (y > this.maxY) { y = this.maxY; }
20676         }
20677
20678         x = this.getTick(x, this.xTicks);
20679         y = this.getTick(y, this.yTicks);
20680
20681
20682         return {x:x, y:y};
20683     },
20684
20685     /*
20686      * Sets up config options specific to this class. Overrides
20687      * Roo.dd.DragDrop, but all versions of this method through the
20688      * inheritance chain are called
20689      */
20690     applyConfig: function() {
20691         Roo.dd.DD.superclass.applyConfig.call(this);
20692         this.scroll = (this.config.scroll !== false);
20693     },
20694
20695     /*
20696      * Event that fires prior to the onMouseDown event.  Overrides
20697      * Roo.dd.DragDrop.
20698      */
20699     b4MouseDown: function(e) {
20700         // this.resetConstraints();
20701         this.autoOffset(e.getPageX(),
20702                             e.getPageY());
20703     },
20704
20705     /*
20706      * Event that fires prior to the onDrag event.  Overrides
20707      * Roo.dd.DragDrop.
20708      */
20709     b4Drag: function(e) {
20710         this.setDragElPos(e.getPageX(),
20711                             e.getPageY());
20712     },
20713
20714     toString: function() {
20715         return ("DD " + this.id);
20716     }
20717
20718     //////////////////////////////////////////////////////////////////////////
20719     // Debugging ygDragDrop events that can be overridden
20720     //////////////////////////////////////////////////////////////////////////
20721     /*
20722     startDrag: function(x, y) {
20723     },
20724
20725     onDrag: function(e) {
20726     },
20727
20728     onDragEnter: function(e, id) {
20729     },
20730
20731     onDragOver: function(e, id) {
20732     },
20733
20734     onDragOut: function(e, id) {
20735     },
20736
20737     onDragDrop: function(e, id) {
20738     },
20739
20740     endDrag: function(e) {
20741     }
20742
20743     */
20744
20745 });/*
20746  * Based on:
20747  * Ext JS Library 1.1.1
20748  * Copyright(c) 2006-2007, Ext JS, LLC.
20749  *
20750  * Originally Released Under LGPL - original licence link has changed is not relivant.
20751  *
20752  * Fork - LGPL
20753  * <script type="text/javascript">
20754  */
20755
20756 /**
20757  * @class Roo.dd.DDProxy
20758  * A DragDrop implementation that inserts an empty, bordered div into
20759  * the document that follows the cursor during drag operations.  At the time of
20760  * the click, the frame div is resized to the dimensions of the linked html
20761  * element, and moved to the exact location of the linked element.
20762  *
20763  * References to the "frame" element refer to the single proxy element that
20764  * was created to be dragged in place of all DDProxy elements on the
20765  * page.
20766  *
20767  * @extends Roo.dd.DD
20768  * @constructor
20769  * @param {String} id the id of the linked html element
20770  * @param {String} sGroup the group of related DragDrop objects
20771  * @param {object} config an object containing configurable attributes
20772  *                Valid properties for DDProxy in addition to those in DragDrop:
20773  *                   resizeFrame, centerFrame, dragElId
20774  */
20775 Roo.dd.DDProxy = function(id, sGroup, config) {
20776     if (id) {
20777         this.init(id, sGroup, config);
20778         this.initFrame();
20779     }
20780 };
20781
20782 /**
20783  * The default drag frame div id
20784  * @property Roo.dd.DDProxy.dragElId
20785  * @type String
20786  * @static
20787  */
20788 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20789
20790 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20791
20792     /**
20793      * By default we resize the drag frame to be the same size as the element
20794      * we want to drag (this is to get the frame effect).  We can turn it off
20795      * if we want a different behavior.
20796      * @property resizeFrame
20797      * @type boolean
20798      */
20799     resizeFrame: true,
20800
20801     /**
20802      * By default the frame is positioned exactly where the drag element is, so
20803      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20804      * you do not have constraints on the obj is to have the drag frame centered
20805      * around the cursor.  Set centerFrame to true for this effect.
20806      * @property centerFrame
20807      * @type boolean
20808      */
20809     centerFrame: false,
20810
20811     /**
20812      * Creates the proxy element if it does not yet exist
20813      * @method createFrame
20814      */
20815     createFrame: function() {
20816         var self = this;
20817         var body = document.body;
20818
20819         if (!body || !body.firstChild) {
20820             setTimeout( function() { self.createFrame(); }, 50 );
20821             return;
20822         }
20823
20824         var div = this.getDragEl();
20825
20826         if (!div) {
20827             div    = document.createElement("div");
20828             div.id = this.dragElId;
20829             var s  = div.style;
20830
20831             s.position   = "absolute";
20832             s.visibility = "hidden";
20833             s.cursor     = "move";
20834             s.border     = "2px solid #aaa";
20835             s.zIndex     = 999;
20836
20837             // appendChild can blow up IE if invoked prior to the window load event
20838             // while rendering a table.  It is possible there are other scenarios
20839             // that would cause this to happen as well.
20840             body.insertBefore(div, body.firstChild);
20841         }
20842     },
20843
20844     /**
20845      * Initialization for the drag frame element.  Must be called in the
20846      * constructor of all subclasses
20847      * @method initFrame
20848      */
20849     initFrame: function() {
20850         this.createFrame();
20851     },
20852
20853     applyConfig: function() {
20854         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20855
20856         this.resizeFrame = (this.config.resizeFrame !== false);
20857         this.centerFrame = (this.config.centerFrame);
20858         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20859     },
20860
20861     /**
20862      * Resizes the drag frame to the dimensions of the clicked object, positions
20863      * it over the object, and finally displays it
20864      * @method showFrame
20865      * @param {int} iPageX X click position
20866      * @param {int} iPageY Y click position
20867      * @private
20868      */
20869     showFrame: function(iPageX, iPageY) {
20870         var el = this.getEl();
20871         var dragEl = this.getDragEl();
20872         var s = dragEl.style;
20873
20874         this._resizeProxy();
20875
20876         if (this.centerFrame) {
20877             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20878                            Math.round(parseInt(s.height, 10)/2) );
20879         }
20880
20881         this.setDragElPos(iPageX, iPageY);
20882
20883         Roo.fly(dragEl).show();
20884     },
20885
20886     /**
20887      * The proxy is automatically resized to the dimensions of the linked
20888      * element when a drag is initiated, unless resizeFrame is set to false
20889      * @method _resizeProxy
20890      * @private
20891      */
20892     _resizeProxy: function() {
20893         if (this.resizeFrame) {
20894             var el = this.getEl();
20895             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20896         }
20897     },
20898
20899     // overrides Roo.dd.DragDrop
20900     b4MouseDown: function(e) {
20901         var x = e.getPageX();
20902         var y = e.getPageY();
20903         this.autoOffset(x, y);
20904         this.setDragElPos(x, y);
20905     },
20906
20907     // overrides Roo.dd.DragDrop
20908     b4StartDrag: function(x, y) {
20909         // show the drag frame
20910         this.showFrame(x, y);
20911     },
20912
20913     // overrides Roo.dd.DragDrop
20914     b4EndDrag: function(e) {
20915         Roo.fly(this.getDragEl()).hide();
20916     },
20917
20918     // overrides Roo.dd.DragDrop
20919     // By default we try to move the element to the last location of the frame.
20920     // This is so that the default behavior mirrors that of Roo.dd.DD.
20921     endDrag: function(e) {
20922
20923         var lel = this.getEl();
20924         var del = this.getDragEl();
20925
20926         // Show the drag frame briefly so we can get its position
20927         del.style.visibility = "";
20928
20929         this.beforeMove();
20930         // Hide the linked element before the move to get around a Safari
20931         // rendering bug.
20932         lel.style.visibility = "hidden";
20933         Roo.dd.DDM.moveToEl(lel, del);
20934         del.style.visibility = "hidden";
20935         lel.style.visibility = "";
20936
20937         this.afterDrag();
20938     },
20939
20940     beforeMove : function(){
20941
20942     },
20943
20944     afterDrag : function(){
20945
20946     },
20947
20948     toString: function() {
20949         return ("DDProxy " + this.id);
20950     }
20951
20952 });
20953 /*
20954  * Based on:
20955  * Ext JS Library 1.1.1
20956  * Copyright(c) 2006-2007, Ext JS, LLC.
20957  *
20958  * Originally Released Under LGPL - original licence link has changed is not relivant.
20959  *
20960  * Fork - LGPL
20961  * <script type="text/javascript">
20962  */
20963
20964  /**
20965  * @class Roo.dd.DDTarget
20966  * A DragDrop implementation that does not move, but can be a drop
20967  * target.  You would get the same result by simply omitting implementation
20968  * for the event callbacks, but this way we reduce the processing cost of the
20969  * event listener and the callbacks.
20970  * @extends Roo.dd.DragDrop
20971  * @constructor
20972  * @param {String} id the id of the element that is a drop target
20973  * @param {String} sGroup the group of related DragDrop objects
20974  * @param {object} config an object containing configurable attributes
20975  *                 Valid properties for DDTarget in addition to those in
20976  *                 DragDrop:
20977  *                    none
20978  */
20979 Roo.dd.DDTarget = function(id, sGroup, config) {
20980     if (id) {
20981         this.initTarget(id, sGroup, config);
20982     }
20983     if (config.listeners || config.events) { 
20984        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20985             listeners : config.listeners || {}, 
20986             events : config.events || {} 
20987         });    
20988     }
20989 };
20990
20991 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20992 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20993     toString: function() {
20994         return ("DDTarget " + this.id);
20995     }
20996 });
20997 /*
20998  * Based on:
20999  * Ext JS Library 1.1.1
21000  * Copyright(c) 2006-2007, Ext JS, LLC.
21001  *
21002  * Originally Released Under LGPL - original licence link has changed is not relivant.
21003  *
21004  * Fork - LGPL
21005  * <script type="text/javascript">
21006  */
21007  
21008
21009 /**
21010  * @class Roo.dd.ScrollManager
21011  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21012  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21013  * @singleton
21014  */
21015 Roo.dd.ScrollManager = function(){
21016     var ddm = Roo.dd.DragDropMgr;
21017     var els = {};
21018     var dragEl = null;
21019     var proc = {};
21020     
21021     
21022     
21023     var onStop = function(e){
21024         dragEl = null;
21025         clearProc();
21026     };
21027     
21028     var triggerRefresh = function(){
21029         if(ddm.dragCurrent){
21030              ddm.refreshCache(ddm.dragCurrent.groups);
21031         }
21032     };
21033     
21034     var doScroll = function(){
21035         if(ddm.dragCurrent){
21036             var dds = Roo.dd.ScrollManager;
21037             if(!dds.animate){
21038                 if(proc.el.scroll(proc.dir, dds.increment)){
21039                     triggerRefresh();
21040                 }
21041             }else{
21042                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21043             }
21044         }
21045     };
21046     
21047     var clearProc = function(){
21048         if(proc.id){
21049             clearInterval(proc.id);
21050         }
21051         proc.id = 0;
21052         proc.el = null;
21053         proc.dir = "";
21054     };
21055     
21056     var startProc = function(el, dir){
21057          Roo.log('scroll startproc');
21058         clearProc();
21059         proc.el = el;
21060         proc.dir = dir;
21061         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21062     };
21063     
21064     var onFire = function(e, isDrop){
21065        
21066         if(isDrop || !ddm.dragCurrent){ return; }
21067         var dds = Roo.dd.ScrollManager;
21068         if(!dragEl || dragEl != ddm.dragCurrent){
21069             dragEl = ddm.dragCurrent;
21070             // refresh regions on drag start
21071             dds.refreshCache();
21072         }
21073         
21074         var xy = Roo.lib.Event.getXY(e);
21075         var pt = new Roo.lib.Point(xy[0], xy[1]);
21076         for(var id in els){
21077             var el = els[id], r = el._region;
21078             if(r && r.contains(pt) && el.isScrollable()){
21079                 if(r.bottom - pt.y <= dds.thresh){
21080                     if(proc.el != el){
21081                         startProc(el, "down");
21082                     }
21083                     return;
21084                 }else if(r.right - pt.x <= dds.thresh){
21085                     if(proc.el != el){
21086                         startProc(el, "left");
21087                     }
21088                     return;
21089                 }else if(pt.y - r.top <= dds.thresh){
21090                     if(proc.el != el){
21091                         startProc(el, "up");
21092                     }
21093                     return;
21094                 }else if(pt.x - r.left <= dds.thresh){
21095                     if(proc.el != el){
21096                         startProc(el, "right");
21097                     }
21098                     return;
21099                 }
21100             }
21101         }
21102         clearProc();
21103     };
21104     
21105     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21106     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21107     
21108     return {
21109         /**
21110          * Registers new overflow element(s) to auto scroll
21111          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21112          */
21113         register : function(el){
21114             if(el instanceof Array){
21115                 for(var i = 0, len = el.length; i < len; i++) {
21116                         this.register(el[i]);
21117                 }
21118             }else{
21119                 el = Roo.get(el);
21120                 els[el.id] = el;
21121             }
21122             Roo.dd.ScrollManager.els = els;
21123         },
21124         
21125         /**
21126          * Unregisters overflow element(s) so they are no longer scrolled
21127          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21128          */
21129         unregister : function(el){
21130             if(el instanceof Array){
21131                 for(var i = 0, len = el.length; i < len; i++) {
21132                         this.unregister(el[i]);
21133                 }
21134             }else{
21135                 el = Roo.get(el);
21136                 delete els[el.id];
21137             }
21138         },
21139         
21140         /**
21141          * The number of pixels from the edge of a container the pointer needs to be to 
21142          * trigger scrolling (defaults to 25)
21143          * @type Number
21144          */
21145         thresh : 25,
21146         
21147         /**
21148          * The number of pixels to scroll in each scroll increment (defaults to 50)
21149          * @type Number
21150          */
21151         increment : 100,
21152         
21153         /**
21154          * The frequency of scrolls in milliseconds (defaults to 500)
21155          * @type Number
21156          */
21157         frequency : 500,
21158         
21159         /**
21160          * True to animate the scroll (defaults to true)
21161          * @type Boolean
21162          */
21163         animate: true,
21164         
21165         /**
21166          * The animation duration in seconds - 
21167          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21168          * @type Number
21169          */
21170         animDuration: .4,
21171         
21172         /**
21173          * Manually trigger a cache refresh.
21174          */
21175         refreshCache : function(){
21176             for(var id in els){
21177                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21178                     els[id]._region = els[id].getRegion();
21179                 }
21180             }
21181         }
21182     };
21183 }();/*
21184  * Based on:
21185  * Ext JS Library 1.1.1
21186  * Copyright(c) 2006-2007, Ext JS, LLC.
21187  *
21188  * Originally Released Under LGPL - original licence link has changed is not relivant.
21189  *
21190  * Fork - LGPL
21191  * <script type="text/javascript">
21192  */
21193  
21194
21195 /**
21196  * @class Roo.dd.Registry
21197  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21198  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21199  * @singleton
21200  */
21201 Roo.dd.Registry = function(){
21202     var elements = {}; 
21203     var handles = {}; 
21204     var autoIdSeed = 0;
21205
21206     var getId = function(el, autogen){
21207         if(typeof el == "string"){
21208             return el;
21209         }
21210         var id = el.id;
21211         if(!id && autogen !== false){
21212             id = "roodd-" + (++autoIdSeed);
21213             el.id = id;
21214         }
21215         return id;
21216     };
21217     
21218     return {
21219     /**
21220      * Register a drag drop element
21221      * @param {String|HTMLElement} element The id or DOM node to register
21222      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21223      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21224      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21225      * populated in the data object (if applicable):
21226      * <pre>
21227 Value      Description<br />
21228 ---------  ------------------------------------------<br />
21229 handles    Array of DOM nodes that trigger dragging<br />
21230            for the element being registered<br />
21231 isHandle   True if the element passed in triggers<br />
21232            dragging itself, else false
21233 </pre>
21234      */
21235         register : function(el, data){
21236             data = data || {};
21237             if(typeof el == "string"){
21238                 el = document.getElementById(el);
21239             }
21240             data.ddel = el;
21241             elements[getId(el)] = data;
21242             if(data.isHandle !== false){
21243                 handles[data.ddel.id] = data;
21244             }
21245             if(data.handles){
21246                 var hs = data.handles;
21247                 for(var i = 0, len = hs.length; i < len; i++){
21248                         handles[getId(hs[i])] = data;
21249                 }
21250             }
21251         },
21252
21253     /**
21254      * Unregister a drag drop element
21255      * @param {String|HTMLElement}  element The id or DOM node to unregister
21256      */
21257         unregister : function(el){
21258             var id = getId(el, false);
21259             var data = elements[id];
21260             if(data){
21261                 delete elements[id];
21262                 if(data.handles){
21263                     var hs = data.handles;
21264                     for(var i = 0, len = hs.length; i < len; i++){
21265                         delete handles[getId(hs[i], false)];
21266                     }
21267                 }
21268             }
21269         },
21270
21271     /**
21272      * Returns the handle registered for a DOM Node by id
21273      * @param {String|HTMLElement} id The DOM node or id to look up
21274      * @return {Object} handle The custom handle data
21275      */
21276         getHandle : function(id){
21277             if(typeof id != "string"){ // must be element?
21278                 id = id.id;
21279             }
21280             return handles[id];
21281         },
21282
21283     /**
21284      * Returns the handle that is registered for the DOM node that is the target of the event
21285      * @param {Event} e The event
21286      * @return {Object} handle The custom handle data
21287      */
21288         getHandleFromEvent : function(e){
21289             var t = Roo.lib.Event.getTarget(e);
21290             return t ? handles[t.id] : null;
21291         },
21292
21293     /**
21294      * Returns a custom data object that is registered for a DOM node by id
21295      * @param {String|HTMLElement} id The DOM node or id to look up
21296      * @return {Object} data The custom data
21297      */
21298         getTarget : function(id){
21299             if(typeof id != "string"){ // must be element?
21300                 id = id.id;
21301             }
21302             return elements[id];
21303         },
21304
21305     /**
21306      * Returns a custom data object that is registered for the DOM node that is the target of the event
21307      * @param {Event} e The event
21308      * @return {Object} data The custom data
21309      */
21310         getTargetFromEvent : function(e){
21311             var t = Roo.lib.Event.getTarget(e);
21312             return t ? elements[t.id] || handles[t.id] : null;
21313         }
21314     };
21315 }();/*
21316  * Based on:
21317  * Ext JS Library 1.1.1
21318  * Copyright(c) 2006-2007, Ext JS, LLC.
21319  *
21320  * Originally Released Under LGPL - original licence link has changed is not relivant.
21321  *
21322  * Fork - LGPL
21323  * <script type="text/javascript">
21324  */
21325  
21326
21327 /**
21328  * @class Roo.dd.StatusProxy
21329  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21330  * default drag proxy used by all Roo.dd components.
21331  * @constructor
21332  * @param {Object} config
21333  */
21334 Roo.dd.StatusProxy = function(config){
21335     Roo.apply(this, config);
21336     this.id = this.id || Roo.id();
21337     this.el = new Roo.Layer({
21338         dh: {
21339             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21340                 {tag: "div", cls: "x-dd-drop-icon"},
21341                 {tag: "div", cls: "x-dd-drag-ghost"}
21342             ]
21343         }, 
21344         shadow: !config || config.shadow !== false
21345     });
21346     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21347     this.dropStatus = this.dropNotAllowed;
21348 };
21349
21350 Roo.dd.StatusProxy.prototype = {
21351     /**
21352      * @cfg {String} dropAllowed
21353      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21354      */
21355     dropAllowed : "x-dd-drop-ok",
21356     /**
21357      * @cfg {String} dropNotAllowed
21358      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21359      */
21360     dropNotAllowed : "x-dd-drop-nodrop",
21361
21362     /**
21363      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21364      * over the current target element.
21365      * @param {String} cssClass The css class for the new drop status indicator image
21366      */
21367     setStatus : function(cssClass){
21368         cssClass = cssClass || this.dropNotAllowed;
21369         if(this.dropStatus != cssClass){
21370             this.el.replaceClass(this.dropStatus, cssClass);
21371             this.dropStatus = cssClass;
21372         }
21373     },
21374
21375     /**
21376      * Resets the status indicator to the default dropNotAllowed value
21377      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21378      */
21379     reset : function(clearGhost){
21380         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21381         this.dropStatus = this.dropNotAllowed;
21382         if(clearGhost){
21383             this.ghost.update("");
21384         }
21385     },
21386
21387     /**
21388      * Updates the contents of the ghost element
21389      * @param {String} html The html that will replace the current innerHTML of the ghost element
21390      */
21391     update : function(html){
21392         if(typeof html == "string"){
21393             this.ghost.update(html);
21394         }else{
21395             this.ghost.update("");
21396             html.style.margin = "0";
21397             this.ghost.dom.appendChild(html);
21398         }
21399         // ensure float = none set?? cant remember why though.
21400         var el = this.ghost.dom.firstChild;
21401                 if(el){
21402                         Roo.fly(el).setStyle('float', 'none');
21403                 }
21404     },
21405     
21406     /**
21407      * Returns the underlying proxy {@link Roo.Layer}
21408      * @return {Roo.Layer} el
21409     */
21410     getEl : function(){
21411         return this.el;
21412     },
21413
21414     /**
21415      * Returns the ghost element
21416      * @return {Roo.Element} el
21417      */
21418     getGhost : function(){
21419         return this.ghost;
21420     },
21421
21422     /**
21423      * Hides the proxy
21424      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21425      */
21426     hide : function(clear){
21427         this.el.hide();
21428         if(clear){
21429             this.reset(true);
21430         }
21431     },
21432
21433     /**
21434      * Stops the repair animation if it's currently running
21435      */
21436     stop : function(){
21437         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21438             this.anim.stop();
21439         }
21440     },
21441
21442     /**
21443      * Displays this proxy
21444      */
21445     show : function(){
21446         this.el.show();
21447     },
21448
21449     /**
21450      * Force the Layer to sync its shadow and shim positions to the element
21451      */
21452     sync : function(){
21453         this.el.sync();
21454     },
21455
21456     /**
21457      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21458      * invalid drop operation by the item being dragged.
21459      * @param {Array} xy The XY position of the element ([x, y])
21460      * @param {Function} callback The function to call after the repair is complete
21461      * @param {Object} scope The scope in which to execute the callback
21462      */
21463     repair : function(xy, callback, scope){
21464         this.callback = callback;
21465         this.scope = scope;
21466         if(xy && this.animRepair !== false){
21467             this.el.addClass("x-dd-drag-repair");
21468             this.el.hideUnders(true);
21469             this.anim = this.el.shift({
21470                 duration: this.repairDuration || .5,
21471                 easing: 'easeOut',
21472                 xy: xy,
21473                 stopFx: true,
21474                 callback: this.afterRepair,
21475                 scope: this
21476             });
21477         }else{
21478             this.afterRepair();
21479         }
21480     },
21481
21482     // private
21483     afterRepair : function(){
21484         this.hide(true);
21485         if(typeof this.callback == "function"){
21486             this.callback.call(this.scope || this);
21487         }
21488         this.callback = null;
21489         this.scope = null;
21490     }
21491 };/*
21492  * Based on:
21493  * Ext JS Library 1.1.1
21494  * Copyright(c) 2006-2007, Ext JS, LLC.
21495  *
21496  * Originally Released Under LGPL - original licence link has changed is not relivant.
21497  *
21498  * Fork - LGPL
21499  * <script type="text/javascript">
21500  */
21501
21502 /**
21503  * @class Roo.dd.DragSource
21504  * @extends Roo.dd.DDProxy
21505  * A simple class that provides the basic implementation needed to make any element draggable.
21506  * @constructor
21507  * @param {String/HTMLElement/Element} el The container element
21508  * @param {Object} config
21509  */
21510 Roo.dd.DragSource = function(el, config){
21511     this.el = Roo.get(el);
21512     this.dragData = {};
21513     
21514     Roo.apply(this, config);
21515     
21516     if(!this.proxy){
21517         this.proxy = new Roo.dd.StatusProxy();
21518     }
21519
21520     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21521           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21522     
21523     this.dragging = false;
21524 };
21525
21526 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21527     /**
21528      * @cfg {String} dropAllowed
21529      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21530      */
21531     dropAllowed : "x-dd-drop-ok",
21532     /**
21533      * @cfg {String} dropNotAllowed
21534      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21535      */
21536     dropNotAllowed : "x-dd-drop-nodrop",
21537
21538     /**
21539      * Returns the data object associated with this drag source
21540      * @return {Object} data An object containing arbitrary data
21541      */
21542     getDragData : function(e){
21543         return this.dragData;
21544     },
21545
21546     // private
21547     onDragEnter : function(e, id){
21548         var target = Roo.dd.DragDropMgr.getDDById(id);
21549         this.cachedTarget = target;
21550         if(this.beforeDragEnter(target, e, id) !== false){
21551             if(target.isNotifyTarget){
21552                 var status = target.notifyEnter(this, e, this.dragData);
21553                 this.proxy.setStatus(status);
21554             }else{
21555                 this.proxy.setStatus(this.dropAllowed);
21556             }
21557             
21558             if(this.afterDragEnter){
21559                 /**
21560                  * An empty function by default, but provided so that you can perform a custom action
21561                  * when the dragged item enters the drop target by providing an implementation.
21562                  * @param {Roo.dd.DragDrop} target The drop target
21563                  * @param {Event} e The event object
21564                  * @param {String} id The id of the dragged element
21565                  * @method afterDragEnter
21566                  */
21567                 this.afterDragEnter(target, e, id);
21568             }
21569         }
21570     },
21571
21572     /**
21573      * An empty function by default, but provided so that you can perform a custom action
21574      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21575      * @param {Roo.dd.DragDrop} target The drop target
21576      * @param {Event} e The event object
21577      * @param {String} id The id of the dragged element
21578      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21579      */
21580     beforeDragEnter : function(target, e, id){
21581         return true;
21582     },
21583
21584     // private
21585     alignElWithMouse: function() {
21586         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21587         this.proxy.sync();
21588     },
21589
21590     // private
21591     onDragOver : function(e, id){
21592         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21593         if(this.beforeDragOver(target, e, id) !== false){
21594             if(target.isNotifyTarget){
21595                 var status = target.notifyOver(this, e, this.dragData);
21596                 this.proxy.setStatus(status);
21597             }
21598
21599             if(this.afterDragOver){
21600                 /**
21601                  * An empty function by default, but provided so that you can perform a custom action
21602                  * while the dragged item is over the drop target by providing an implementation.
21603                  * @param {Roo.dd.DragDrop} target The drop target
21604                  * @param {Event} e The event object
21605                  * @param {String} id The id of the dragged element
21606                  * @method afterDragOver
21607                  */
21608                 this.afterDragOver(target, e, id);
21609             }
21610         }
21611     },
21612
21613     /**
21614      * An empty function by default, but provided so that you can perform a custom action
21615      * while the dragged item is over the drop target and optionally cancel the onDragOver.
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 drag event is valid, else false to cancel
21620      */
21621     beforeDragOver : function(target, e, id){
21622         return true;
21623     },
21624
21625     // private
21626     onDragOut : function(e, id){
21627         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21628         if(this.beforeDragOut(target, e, id) !== false){
21629             if(target.isNotifyTarget){
21630                 target.notifyOut(this, e, this.dragData);
21631             }
21632             this.proxy.reset();
21633             if(this.afterDragOut){
21634                 /**
21635                  * An empty function by default, but provided so that you can perform a custom action
21636                  * after the dragged item is dragged out of the target without dropping.
21637                  * @param {Roo.dd.DragDrop} target The drop target
21638                  * @param {Event} e The event object
21639                  * @param {String} id The id of the dragged element
21640                  * @method afterDragOut
21641                  */
21642                 this.afterDragOut(target, e, id);
21643             }
21644         }
21645         this.cachedTarget = null;
21646     },
21647
21648     /**
21649      * An empty function by default, but provided so that you can perform a custom action before the dragged
21650      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21651      * @param {Roo.dd.DragDrop} target The drop target
21652      * @param {Event} e The event object
21653      * @param {String} id The id of the dragged element
21654      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21655      */
21656     beforeDragOut : function(target, e, id){
21657         return true;
21658     },
21659     
21660     // private
21661     onDragDrop : function(e, id){
21662         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21663         if(this.beforeDragDrop(target, e, id) !== false){
21664             if(target.isNotifyTarget){
21665                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21666                     this.onValidDrop(target, e, id);
21667                 }else{
21668                     this.onInvalidDrop(target, e, id);
21669                 }
21670             }else{
21671                 this.onValidDrop(target, e, id);
21672             }
21673             
21674             if(this.afterDragDrop){
21675                 /**
21676                  * An empty function by default, but provided so that you can perform a custom action
21677                  * after a valid drag drop has occurred by providing an implementation.
21678                  * @param {Roo.dd.DragDrop} target The drop target
21679                  * @param {Event} e The event object
21680                  * @param {String} id The id of the dropped element
21681                  * @method afterDragDrop
21682                  */
21683                 this.afterDragDrop(target, e, id);
21684             }
21685         }
21686         delete this.cachedTarget;
21687     },
21688
21689     /**
21690      * An empty function by default, but provided so that you can perform a custom action before the dragged
21691      * item is dropped onto the target and optionally cancel the onDragDrop.
21692      * @param {Roo.dd.DragDrop} target The drop target
21693      * @param {Event} e The event object
21694      * @param {String} id The id of the dragged element
21695      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21696      */
21697     beforeDragDrop : function(target, e, id){
21698         return true;
21699     },
21700
21701     // private
21702     onValidDrop : function(target, e, id){
21703         this.hideProxy();
21704         if(this.afterValidDrop){
21705             /**
21706              * An empty function by default, but provided so that you can perform a custom action
21707              * after a valid drop has occurred by providing an implementation.
21708              * @param {Object} target The target DD 
21709              * @param {Event} e The event object
21710              * @param {String} id The id of the dropped element
21711              * @method afterInvalidDrop
21712              */
21713             this.afterValidDrop(target, e, id);
21714         }
21715     },
21716
21717     // private
21718     getRepairXY : function(e, data){
21719         return this.el.getXY();  
21720     },
21721
21722     // private
21723     onInvalidDrop : function(target, e, id){
21724         this.beforeInvalidDrop(target, e, id);
21725         if(this.cachedTarget){
21726             if(this.cachedTarget.isNotifyTarget){
21727                 this.cachedTarget.notifyOut(this, e, this.dragData);
21728             }
21729             this.cacheTarget = null;
21730         }
21731         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21732
21733         if(this.afterInvalidDrop){
21734             /**
21735              * An empty function by default, but provided so that you can perform a custom action
21736              * after an invalid drop has occurred by providing an implementation.
21737              * @param {Event} e The event object
21738              * @param {String} id The id of the dropped element
21739              * @method afterInvalidDrop
21740              */
21741             this.afterInvalidDrop(e, id);
21742         }
21743     },
21744
21745     // private
21746     afterRepair : function(){
21747         if(Roo.enableFx){
21748             this.el.highlight(this.hlColor || "c3daf9");
21749         }
21750         this.dragging = false;
21751     },
21752
21753     /**
21754      * An empty function by default, but provided so that you can perform a custom action after an invalid
21755      * drop has occurred.
21756      * @param {Roo.dd.DragDrop} target The drop target
21757      * @param {Event} e The event object
21758      * @param {String} id The id of the dragged element
21759      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21760      */
21761     beforeInvalidDrop : function(target, e, id){
21762         return true;
21763     },
21764
21765     // private
21766     handleMouseDown : function(e){
21767         if(this.dragging) {
21768             return;
21769         }
21770         var data = this.getDragData(e);
21771         if(data && this.onBeforeDrag(data, e) !== false){
21772             this.dragData = data;
21773             this.proxy.stop();
21774             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21775         } 
21776     },
21777
21778     /**
21779      * An empty function by default, but provided so that you can perform a custom action before the initial
21780      * drag event begins and optionally cancel it.
21781      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21782      * @param {Event} e The event object
21783      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21784      */
21785     onBeforeDrag : function(data, e){
21786         return true;
21787     },
21788
21789     /**
21790      * An empty function by default, but provided so that you can perform a custom action once the initial
21791      * drag event has begun.  The drag cannot be canceled from this function.
21792      * @param {Number} x The x position of the click on the dragged object
21793      * @param {Number} y The y position of the click on the dragged object
21794      */
21795     onStartDrag : Roo.emptyFn,
21796
21797     // private - YUI override
21798     startDrag : function(x, y){
21799         this.proxy.reset();
21800         this.dragging = true;
21801         this.proxy.update("");
21802         this.onInitDrag(x, y);
21803         this.proxy.show();
21804     },
21805
21806     // private
21807     onInitDrag : function(x, y){
21808         var clone = this.el.dom.cloneNode(true);
21809         clone.id = Roo.id(); // prevent duplicate ids
21810         this.proxy.update(clone);
21811         this.onStartDrag(x, y);
21812         return true;
21813     },
21814
21815     /**
21816      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21817      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21818      */
21819     getProxy : function(){
21820         return this.proxy;  
21821     },
21822
21823     /**
21824      * Hides the drag source's {@link Roo.dd.StatusProxy}
21825      */
21826     hideProxy : function(){
21827         this.proxy.hide();  
21828         this.proxy.reset(true);
21829         this.dragging = false;
21830     },
21831
21832     // private
21833     triggerCacheRefresh : function(){
21834         Roo.dd.DDM.refreshCache(this.groups);
21835     },
21836
21837     // private - override to prevent hiding
21838     b4EndDrag: function(e) {
21839     },
21840
21841     // private - override to prevent moving
21842     endDrag : function(e){
21843         this.onEndDrag(this.dragData, e);
21844     },
21845
21846     // private
21847     onEndDrag : function(data, e){
21848     },
21849     
21850     // private - pin to cursor
21851     autoOffset : function(x, y) {
21852         this.setDelta(-12, -20);
21853     }    
21854 });/*
21855  * Based on:
21856  * Ext JS Library 1.1.1
21857  * Copyright(c) 2006-2007, Ext JS, LLC.
21858  *
21859  * Originally Released Under LGPL - original licence link has changed is not relivant.
21860  *
21861  * Fork - LGPL
21862  * <script type="text/javascript">
21863  */
21864
21865
21866 /**
21867  * @class Roo.dd.DropTarget
21868  * @extends Roo.dd.DDTarget
21869  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21870  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21871  * @constructor
21872  * @param {String/HTMLElement/Element} el The container element
21873  * @param {Object} config
21874  */
21875 Roo.dd.DropTarget = function(el, config){
21876     this.el = Roo.get(el);
21877     
21878     var listeners = false; ;
21879     if (config && config.listeners) {
21880         listeners= config.listeners;
21881         delete config.listeners;
21882     }
21883     Roo.apply(this, config);
21884     
21885     if(this.containerScroll){
21886         Roo.dd.ScrollManager.register(this.el);
21887     }
21888     this.addEvents( {
21889          /**
21890          * @scope Roo.dd.DropTarget
21891          */
21892          
21893          /**
21894          * @event enter
21895          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21896          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21897          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21898          * 
21899          * IMPORTANT : it should set this.overClass and this.dropAllowed
21900          * 
21901          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21902          * @param {Event} e The event
21903          * @param {Object} data An object containing arbitrary data supplied by the drag source
21904          */
21905         "enter" : true,
21906         
21907          /**
21908          * @event over
21909          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21910          * This method will be called on every mouse movement while the drag source is over the drop target.
21911          * This default implementation simply returns the dropAllowed config value.
21912          * 
21913          * IMPORTANT : it should set this.dropAllowed
21914          * 
21915          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21916          * @param {Event} e The event
21917          * @param {Object} data An object containing arbitrary data supplied by the drag source
21918          
21919          */
21920         "over" : true,
21921         /**
21922          * @event out
21923          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21924          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21925          * overClass (if any) from the drop element.
21926          * 
21927          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21928          * @param {Event} e The event
21929          * @param {Object} data An object containing arbitrary data supplied by the drag source
21930          */
21931          "out" : true,
21932          
21933         /**
21934          * @event drop
21935          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21936          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21937          * implementation that does something to process the drop event and returns true so that the drag source's
21938          * repair action does not run.
21939          * 
21940          * IMPORTANT : it should set this.success
21941          * 
21942          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21943          * @param {Event} e The event
21944          * @param {Object} data An object containing arbitrary data supplied by the drag source
21945         */
21946          "drop" : true
21947     });
21948             
21949      
21950     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21951         this.el.dom, 
21952         this.ddGroup || this.group,
21953         {
21954             isTarget: true,
21955             listeners : listeners || {} 
21956            
21957         
21958         }
21959     );
21960
21961 };
21962
21963 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21964     /**
21965      * @cfg {String} overClass
21966      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21967      */
21968      /**
21969      * @cfg {String} ddGroup
21970      * The drag drop group to handle drop events for
21971      */
21972      
21973     /**
21974      * @cfg {String} dropAllowed
21975      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21976      */
21977     dropAllowed : "x-dd-drop-ok",
21978     /**
21979      * @cfg {String} dropNotAllowed
21980      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21981      */
21982     dropNotAllowed : "x-dd-drop-nodrop",
21983     /**
21984      * @cfg {boolean} success
21985      * set this after drop listener.. 
21986      */
21987     success : false,
21988     /**
21989      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21990      * if the drop point is valid for over/enter..
21991      */
21992     valid : false,
21993     // private
21994     isTarget : true,
21995
21996     // private
21997     isNotifyTarget : true,
21998     
21999     /**
22000      * @hide
22001      */
22002     notifyEnter : function(dd, e, data)
22003     {
22004         this.valid = true;
22005         this.fireEvent('enter', dd, e, data);
22006         if(this.overClass){
22007             this.el.addClass(this.overClass);
22008         }
22009         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22010             this.valid ? this.dropAllowed : this.dropNotAllowed
22011         );
22012     },
22013
22014     /**
22015      * @hide
22016      */
22017     notifyOver : function(dd, e, data)
22018     {
22019         this.valid = true;
22020         this.fireEvent('over', dd, e, data);
22021         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22022             this.valid ? this.dropAllowed : this.dropNotAllowed
22023         );
22024     },
22025
22026     /**
22027      * @hide
22028      */
22029     notifyOut : function(dd, e, data)
22030     {
22031         this.fireEvent('out', dd, e, data);
22032         if(this.overClass){
22033             this.el.removeClass(this.overClass);
22034         }
22035     },
22036
22037     /**
22038      * @hide
22039      */
22040     notifyDrop : function(dd, e, data)
22041     {
22042         this.success = false;
22043         this.fireEvent('drop', dd, e, data);
22044         return this.success;
22045     }
22046 });/*
22047  * Based on:
22048  * Ext JS Library 1.1.1
22049  * Copyright(c) 2006-2007, Ext JS, LLC.
22050  *
22051  * Originally Released Under LGPL - original licence link has changed is not relivant.
22052  *
22053  * Fork - LGPL
22054  * <script type="text/javascript">
22055  */
22056
22057
22058 /**
22059  * @class Roo.dd.DragZone
22060  * @extends Roo.dd.DragSource
22061  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22062  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22063  * @constructor
22064  * @param {String/HTMLElement/Element} el The container element
22065  * @param {Object} config
22066  */
22067 Roo.dd.DragZone = function(el, config){
22068     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22069     if(this.containerScroll){
22070         Roo.dd.ScrollManager.register(this.el);
22071     }
22072 };
22073
22074 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22075     /**
22076      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22077      * for auto scrolling during drag operations.
22078      */
22079     /**
22080      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22081      * method after a failed drop (defaults to "c3daf9" - light blue)
22082      */
22083
22084     /**
22085      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22086      * for a valid target to drag based on the mouse down. Override this method
22087      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22088      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22089      * @param {EventObject} e The mouse down event
22090      * @return {Object} The dragData
22091      */
22092     getDragData : function(e){
22093         return Roo.dd.Registry.getHandleFromEvent(e);
22094     },
22095     
22096     /**
22097      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22098      * this.dragData.ddel
22099      * @param {Number} x The x position of the click on the dragged object
22100      * @param {Number} y The y position of the click on the dragged object
22101      * @return {Boolean} true to continue the drag, false to cancel
22102      */
22103     onInitDrag : function(x, y){
22104         this.proxy.update(this.dragData.ddel.cloneNode(true));
22105         this.onStartDrag(x, y);
22106         return true;
22107     },
22108     
22109     /**
22110      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22111      */
22112     afterRepair : function(){
22113         if(Roo.enableFx){
22114             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22115         }
22116         this.dragging = false;
22117     },
22118
22119     /**
22120      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22121      * the XY of this.dragData.ddel
22122      * @param {EventObject} e The mouse up event
22123      * @return {Array} The xy location (e.g. [100, 200])
22124      */
22125     getRepairXY : function(e){
22126         return Roo.Element.fly(this.dragData.ddel).getXY();  
22127     }
22128 });/*
22129  * Based on:
22130  * Ext JS Library 1.1.1
22131  * Copyright(c) 2006-2007, Ext JS, LLC.
22132  *
22133  * Originally Released Under LGPL - original licence link has changed is not relivant.
22134  *
22135  * Fork - LGPL
22136  * <script type="text/javascript">
22137  */
22138 /**
22139  * @class Roo.dd.DropZone
22140  * @extends Roo.dd.DropTarget
22141  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22142  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22143  * @constructor
22144  * @param {String/HTMLElement/Element} el The container element
22145  * @param {Object} config
22146  */
22147 Roo.dd.DropZone = function(el, config){
22148     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22149 };
22150
22151 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22152     /**
22153      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22154      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22155      * provide your own custom lookup.
22156      * @param {Event} e The event
22157      * @return {Object} data The custom data
22158      */
22159     getTargetFromEvent : function(e){
22160         return Roo.dd.Registry.getTargetFromEvent(e);
22161     },
22162
22163     /**
22164      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22165      * that it has registered.  This method has no default implementation and should be overridden to provide
22166      * node-specific processing if necessary.
22167      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22168      * {@link #getTargetFromEvent} for this node)
22169      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22170      * @param {Event} e The event
22171      * @param {Object} data An object containing arbitrary data supplied by the drag source
22172      */
22173     onNodeEnter : function(n, dd, e, data){
22174         
22175     },
22176
22177     /**
22178      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22179      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22180      * overridden to provide the proper feedback.
22181      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22182      * {@link #getTargetFromEvent} for this node)
22183      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22184      * @param {Event} e The event
22185      * @param {Object} data An object containing arbitrary data supplied by the drag source
22186      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22187      * underlying {@link Roo.dd.StatusProxy} can be updated
22188      */
22189     onNodeOver : function(n, dd, e, data){
22190         return this.dropAllowed;
22191     },
22192
22193     /**
22194      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22195      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22196      * node-specific processing if necessary.
22197      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22198      * {@link #getTargetFromEvent} for this node)
22199      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22200      * @param {Event} e The event
22201      * @param {Object} data An object containing arbitrary data supplied by the drag source
22202      */
22203     onNodeOut : function(n, dd, e, data){
22204         
22205     },
22206
22207     /**
22208      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22209      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22210      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22211      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22212      * {@link #getTargetFromEvent} for this node)
22213      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22214      * @param {Event} e The event
22215      * @param {Object} data An object containing arbitrary data supplied by the drag source
22216      * @return {Boolean} True if the drop was valid, else false
22217      */
22218     onNodeDrop : function(n, dd, e, data){
22219         return false;
22220     },
22221
22222     /**
22223      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22224      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22225      * it should be overridden to provide the proper feedback if necessary.
22226      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22227      * @param {Event} e The event
22228      * @param {Object} data An object containing arbitrary data supplied by the drag source
22229      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22230      * underlying {@link Roo.dd.StatusProxy} can be updated
22231      */
22232     onContainerOver : function(dd, e, data){
22233         return this.dropNotAllowed;
22234     },
22235
22236     /**
22237      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22238      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22239      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22240      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22241      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22242      * @param {Event} e The event
22243      * @param {Object} data An object containing arbitrary data supplied by the drag source
22244      * @return {Boolean} True if the drop was valid, else false
22245      */
22246     onContainerDrop : function(dd, e, data){
22247         return false;
22248     },
22249
22250     /**
22251      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22252      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22253      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22254      * you should override this method and provide a custom implementation.
22255      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22256      * @param {Event} e The event
22257      * @param {Object} data An object containing arbitrary data supplied by the drag source
22258      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22259      * underlying {@link Roo.dd.StatusProxy} can be updated
22260      */
22261     notifyEnter : function(dd, e, data){
22262         return this.dropNotAllowed;
22263     },
22264
22265     /**
22266      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22267      * This method will be called on every mouse movement while the drag source is over the drop zone.
22268      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22269      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22270      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22271      * registered node, it will call {@link #onContainerOver}.
22272      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22273      * @param {Event} e The event
22274      * @param {Object} data An object containing arbitrary data supplied by the drag source
22275      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22276      * underlying {@link Roo.dd.StatusProxy} can be updated
22277      */
22278     notifyOver : function(dd, e, data){
22279         var n = this.getTargetFromEvent(e);
22280         if(!n){ // not over valid drop target
22281             if(this.lastOverNode){
22282                 this.onNodeOut(this.lastOverNode, dd, e, data);
22283                 this.lastOverNode = null;
22284             }
22285             return this.onContainerOver(dd, e, data);
22286         }
22287         if(this.lastOverNode != n){
22288             if(this.lastOverNode){
22289                 this.onNodeOut(this.lastOverNode, dd, e, data);
22290             }
22291             this.onNodeEnter(n, dd, e, data);
22292             this.lastOverNode = n;
22293         }
22294         return this.onNodeOver(n, dd, e, data);
22295     },
22296
22297     /**
22298      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22299      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22300      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22301      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22302      * @param {Event} e The event
22303      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22304      */
22305     notifyOut : function(dd, e, data){
22306         if(this.lastOverNode){
22307             this.onNodeOut(this.lastOverNode, dd, e, data);
22308             this.lastOverNode = null;
22309         }
22310     },
22311
22312     /**
22313      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22314      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22315      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22316      * otherwise it will call {@link #onContainerDrop}.
22317      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22318      * @param {Event} e The event
22319      * @param {Object} data An object containing arbitrary data supplied by the drag source
22320      * @return {Boolean} True if the drop was valid, else false
22321      */
22322     notifyDrop : function(dd, e, data){
22323         if(this.lastOverNode){
22324             this.onNodeOut(this.lastOverNode, dd, e, data);
22325             this.lastOverNode = null;
22326         }
22327         var n = this.getTargetFromEvent(e);
22328         return n ?
22329             this.onNodeDrop(n, dd, e, data) :
22330             this.onContainerDrop(dd, e, data);
22331     },
22332
22333     // private
22334     triggerCacheRefresh : function(){
22335         Roo.dd.DDM.refreshCache(this.groups);
22336     }  
22337 });