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                     
7194                     alert('is android : ' + Roo.isAndroid);
7195                     alert('is ios : ' + Roo.isIOS);
7196
7197                     if(Roo.isAndroid){
7198                         alert('Is Android');
7199                         return Roo.get(document.documentElement);
7200                     }
7201
7202                     if(!Roo.isAndroid){
7203                         alert('not android');
7204                     }
7205
7206                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7207                 }
7208             }
7209             
7210             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7211         },
7212
7213         /**
7214          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7215          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7216          * @param {String} selector The simple selector to test
7217          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7218                 search as a number or element (defaults to 10 || document.body)
7219          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7220          */
7221         up : function(simpleSelector, maxDepth){
7222             return this.findParentNode(simpleSelector, maxDepth, true);
7223         },
7224
7225
7226
7227         /**
7228          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7229          * @param {String} selector The simple selector to test
7230          * @return {Boolean} True if this element matches the selector, else false
7231          */
7232         is : function(simpleSelector){
7233             return Roo.DomQuery.is(this.dom, simpleSelector);
7234         },
7235
7236         /**
7237          * Perform animation on this element.
7238          * @param {Object} args The YUI animation control args
7239          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7240          * @param {Function} onComplete (optional) Function to call when animation completes
7241          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7242          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7243          * @return {Roo.Element} this
7244          */
7245         animate : function(args, duration, onComplete, easing, animType){
7246             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7247             return this;
7248         },
7249
7250         /*
7251          * @private Internal animation call
7252          */
7253         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7254             animType = animType || 'run';
7255             opt = opt || {};
7256             var anim = Roo.lib.Anim[animType](
7257                 this.dom, args,
7258                 (opt.duration || defaultDur) || .35,
7259                 (opt.easing || defaultEase) || 'easeOut',
7260                 function(){
7261                     Roo.callback(cb, this);
7262                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7263                 },
7264                 this
7265             );
7266             opt.anim = anim;
7267             return anim;
7268         },
7269
7270         // private legacy anim prep
7271         preanim : function(a, i){
7272             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7273         },
7274
7275         /**
7276          * Removes worthless text nodes
7277          * @param {Boolean} forceReclean (optional) By default the element
7278          * keeps track if it has been cleaned already so
7279          * you can call this over and over. However, if you update the element and
7280          * need to force a reclean, you can pass true.
7281          */
7282         clean : function(forceReclean){
7283             if(this.isCleaned && forceReclean !== true){
7284                 return this;
7285             }
7286             var ns = /\S/;
7287             var d = this.dom, n = d.firstChild, ni = -1;
7288             while(n){
7289                 var nx = n.nextSibling;
7290                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7291                     d.removeChild(n);
7292                 }else{
7293                     n.nodeIndex = ++ni;
7294                 }
7295                 n = nx;
7296             }
7297             this.isCleaned = true;
7298             return this;
7299         },
7300
7301         // private
7302         calcOffsetsTo : function(el){
7303             el = Roo.get(el);
7304             var d = el.dom;
7305             var restorePos = false;
7306             if(el.getStyle('position') == 'static'){
7307                 el.position('relative');
7308                 restorePos = true;
7309             }
7310             var x = 0, y =0;
7311             var op = this.dom;
7312             while(op && op != d && op.tagName != 'HTML'){
7313                 x+= op.offsetLeft;
7314                 y+= op.offsetTop;
7315                 op = op.offsetParent;
7316             }
7317             if(restorePos){
7318                 el.position('static');
7319             }
7320             return [x, y];
7321         },
7322
7323         /**
7324          * Scrolls this element into view within the passed container.
7325          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7326          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7327          * @return {Roo.Element} this
7328          */
7329         scrollIntoView : function(container, hscroll){
7330             var c = Roo.getDom(container) || document.body;
7331             var el = this.dom;
7332
7333             var o = this.calcOffsetsTo(c),
7334                 l = o[0],
7335                 t = o[1],
7336                 b = t+el.offsetHeight,
7337                 r = l+el.offsetWidth;
7338
7339             var ch = c.clientHeight;
7340             var ct = parseInt(c.scrollTop, 10);
7341             var cl = parseInt(c.scrollLeft, 10);
7342             var cb = ct + ch;
7343             var cr = cl + c.clientWidth;
7344
7345             if(t < ct){
7346                 c.scrollTop = t;
7347             }else if(b > cb){
7348                 c.scrollTop = b-ch;
7349             }
7350
7351             if(hscroll !== false){
7352                 if(l < cl){
7353                     c.scrollLeft = l;
7354                 }else if(r > cr){
7355                     c.scrollLeft = r-c.clientWidth;
7356                 }
7357             }
7358             return this;
7359         },
7360
7361         // private
7362         scrollChildIntoView : function(child, hscroll){
7363             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7364         },
7365
7366         /**
7367          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7368          * the new height may not be available immediately.
7369          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7370          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7371          * @param {Function} onComplete (optional) Function to call when animation completes
7372          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7373          * @return {Roo.Element} this
7374          */
7375         autoHeight : function(animate, duration, onComplete, easing){
7376             var oldHeight = this.getHeight();
7377             this.clip();
7378             this.setHeight(1); // force clipping
7379             setTimeout(function(){
7380                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7381                 if(!animate){
7382                     this.setHeight(height);
7383                     this.unclip();
7384                     if(typeof onComplete == "function"){
7385                         onComplete();
7386                     }
7387                 }else{
7388                     this.setHeight(oldHeight); // restore original height
7389                     this.setHeight(height, animate, duration, function(){
7390                         this.unclip();
7391                         if(typeof onComplete == "function") { onComplete(); }
7392                     }.createDelegate(this), easing);
7393                 }
7394             }.createDelegate(this), 0);
7395             return this;
7396         },
7397
7398         /**
7399          * Returns true if this element is an ancestor of the passed element
7400          * @param {HTMLElement/String} el The element to check
7401          * @return {Boolean} True if this element is an ancestor of el, else false
7402          */
7403         contains : function(el){
7404             if(!el){return false;}
7405             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7406         },
7407
7408         /**
7409          * Checks whether the element is currently visible using both visibility and display properties.
7410          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7411          * @return {Boolean} True if the element is currently visible, else false
7412          */
7413         isVisible : function(deep) {
7414             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7415             if(deep !== true || !vis){
7416                 return vis;
7417             }
7418             var p = this.dom.parentNode;
7419             while(p && p.tagName.toLowerCase() != "body"){
7420                 if(!Roo.fly(p, '_isVisible').isVisible()){
7421                     return false;
7422                 }
7423                 p = p.parentNode;
7424             }
7425             return true;
7426         },
7427
7428         /**
7429          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7430          * @param {String} selector The CSS selector
7431          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7432          * @return {CompositeElement/CompositeElementLite} The composite element
7433          */
7434         select : function(selector, unique){
7435             return El.select(selector, unique, this.dom);
7436         },
7437
7438         /**
7439          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7440          * @param {String} selector The CSS selector
7441          * @return {Array} An array of the matched nodes
7442          */
7443         query : function(selector, unique){
7444             return Roo.DomQuery.select(selector, this.dom);
7445         },
7446
7447         /**
7448          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7449          * @param {String} selector The CSS selector
7450          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7451          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7452          */
7453         child : function(selector, returnDom){
7454             var n = Roo.DomQuery.selectNode(selector, this.dom);
7455             return returnDom ? n : Roo.get(n);
7456         },
7457
7458         /**
7459          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7460          * @param {String} selector The CSS selector
7461          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7462          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7463          */
7464         down : function(selector, returnDom){
7465             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7466             return returnDom ? n : Roo.get(n);
7467         },
7468
7469         /**
7470          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7471          * @param {String} group The group the DD object is member of
7472          * @param {Object} config The DD config object
7473          * @param {Object} overrides An object containing methods to override/implement on the DD object
7474          * @return {Roo.dd.DD} The DD object
7475          */
7476         initDD : function(group, config, overrides){
7477             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7478             return Roo.apply(dd, overrides);
7479         },
7480
7481         /**
7482          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7483          * @param {String} group The group the DDProxy object is member of
7484          * @param {Object} config The DDProxy config object
7485          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7486          * @return {Roo.dd.DDProxy} The DDProxy object
7487          */
7488         initDDProxy : function(group, config, overrides){
7489             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7490             return Roo.apply(dd, overrides);
7491         },
7492
7493         /**
7494          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7495          * @param {String} group The group the DDTarget object is member of
7496          * @param {Object} config The DDTarget config object
7497          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7498          * @return {Roo.dd.DDTarget} The DDTarget object
7499          */
7500         initDDTarget : function(group, config, overrides){
7501             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7502             return Roo.apply(dd, overrides);
7503         },
7504
7505         /**
7506          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7507          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7508          * @param {Boolean} visible Whether the element is visible
7509          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7510          * @return {Roo.Element} this
7511          */
7512          setVisible : function(visible, animate){
7513             if(!animate || !A){
7514                 if(this.visibilityMode == El.DISPLAY){
7515                     this.setDisplayed(visible);
7516                 }else{
7517                     this.fixDisplay();
7518                     this.dom.style.visibility = visible ? "visible" : "hidden";
7519                 }
7520             }else{
7521                 // closure for composites
7522                 var dom = this.dom;
7523                 var visMode = this.visibilityMode;
7524                 if(visible){
7525                     this.setOpacity(.01);
7526                     this.setVisible(true);
7527                 }
7528                 this.anim({opacity: { to: (visible?1:0) }},
7529                       this.preanim(arguments, 1),
7530                       null, .35, 'easeIn', function(){
7531                          if(!visible){
7532                              if(visMode == El.DISPLAY){
7533                                  dom.style.display = "none";
7534                              }else{
7535                                  dom.style.visibility = "hidden";
7536                              }
7537                              Roo.get(dom).setOpacity(1);
7538                          }
7539                      });
7540             }
7541             return this;
7542         },
7543
7544         /**
7545          * Returns true if display is not "none"
7546          * @return {Boolean}
7547          */
7548         isDisplayed : function() {
7549             return this.getStyle("display") != "none";
7550         },
7551
7552         /**
7553          * Toggles the element's visibility or display, depending on visibility mode.
7554          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7555          * @return {Roo.Element} this
7556          */
7557         toggle : function(animate){
7558             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7559             return this;
7560         },
7561
7562         /**
7563          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7564          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7565          * @return {Roo.Element} this
7566          */
7567         setDisplayed : function(value) {
7568             if(typeof value == "boolean"){
7569                value = value ? this.originalDisplay : "none";
7570             }
7571             this.setStyle("display", value);
7572             return this;
7573         },
7574
7575         /**
7576          * Tries to focus the element. Any exceptions are caught and ignored.
7577          * @return {Roo.Element} this
7578          */
7579         focus : function() {
7580             try{
7581                 this.dom.focus();
7582             }catch(e){}
7583             return this;
7584         },
7585
7586         /**
7587          * Tries to blur the element. Any exceptions are caught and ignored.
7588          * @return {Roo.Element} this
7589          */
7590         blur : function() {
7591             try{
7592                 this.dom.blur();
7593             }catch(e){}
7594             return this;
7595         },
7596
7597         /**
7598          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7599          * @param {String/Array} className The CSS class to add, or an array of classes
7600          * @return {Roo.Element} this
7601          */
7602         addClass : function(className){
7603             if(className instanceof Array){
7604                 for(var i = 0, len = className.length; i < len; i++) {
7605                     this.addClass(className[i]);
7606                 }
7607             }else{
7608                 if(className && !this.hasClass(className)){
7609                     this.dom.className = this.dom.className + " " + className;
7610                 }
7611             }
7612             return this;
7613         },
7614
7615         /**
7616          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7617          * @param {String/Array} className The CSS class to add, or an array of classes
7618          * @return {Roo.Element} this
7619          */
7620         radioClass : function(className){
7621             var siblings = this.dom.parentNode.childNodes;
7622             for(var i = 0; i < siblings.length; i++) {
7623                 var s = siblings[i];
7624                 if(s.nodeType == 1){
7625                     Roo.get(s).removeClass(className);
7626                 }
7627             }
7628             this.addClass(className);
7629             return this;
7630         },
7631
7632         /**
7633          * Removes one or more CSS classes from the element.
7634          * @param {String/Array} className The CSS class to remove, or an array of classes
7635          * @return {Roo.Element} this
7636          */
7637         removeClass : function(className){
7638             if(!className || !this.dom.className){
7639                 return this;
7640             }
7641             if(className instanceof Array){
7642                 for(var i = 0, len = className.length; i < len; i++) {
7643                     this.removeClass(className[i]);
7644                 }
7645             }else{
7646                 if(this.hasClass(className)){
7647                     var re = this.classReCache[className];
7648                     if (!re) {
7649                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7650                        this.classReCache[className] = re;
7651                     }
7652                     this.dom.className =
7653                         this.dom.className.replace(re, " ");
7654                 }
7655             }
7656             return this;
7657         },
7658
7659         // private
7660         classReCache: {},
7661
7662         /**
7663          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7664          * @param {String} className The CSS class to toggle
7665          * @return {Roo.Element} this
7666          */
7667         toggleClass : function(className){
7668             if(this.hasClass(className)){
7669                 this.removeClass(className);
7670             }else{
7671                 this.addClass(className);
7672             }
7673             return this;
7674         },
7675
7676         /**
7677          * Checks if the specified CSS class exists on this element's DOM node.
7678          * @param {String} className The CSS class to check for
7679          * @return {Boolean} True if the class exists, else false
7680          */
7681         hasClass : function(className){
7682             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7683         },
7684
7685         /**
7686          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7687          * @param {String} oldClassName The CSS class to replace
7688          * @param {String} newClassName The replacement CSS class
7689          * @return {Roo.Element} this
7690          */
7691         replaceClass : function(oldClassName, newClassName){
7692             this.removeClass(oldClassName);
7693             this.addClass(newClassName);
7694             return this;
7695         },
7696
7697         /**
7698          * Returns an object with properties matching the styles requested.
7699          * For example, el.getStyles('color', 'font-size', 'width') might return
7700          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7701          * @param {String} style1 A style name
7702          * @param {String} style2 A style name
7703          * @param {String} etc.
7704          * @return {Object} The style object
7705          */
7706         getStyles : function(){
7707             var a = arguments, len = a.length, r = {};
7708             for(var i = 0; i < len; i++){
7709                 r[a[i]] = this.getStyle(a[i]);
7710             }
7711             return r;
7712         },
7713
7714         /**
7715          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7716          * @param {String} property The style property whose value is returned.
7717          * @return {String} The current value of the style property for this element.
7718          */
7719         getStyle : function(){
7720             return view && view.getComputedStyle ?
7721                 function(prop){
7722                     var el = this.dom, v, cs, camel;
7723                     if(prop == 'float'){
7724                         prop = "cssFloat";
7725                     }
7726                     if(el.style && (v = el.style[prop])){
7727                         return v;
7728                     }
7729                     if(cs = view.getComputedStyle(el, "")){
7730                         if(!(camel = propCache[prop])){
7731                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7732                         }
7733                         return cs[camel];
7734                     }
7735                     return null;
7736                 } :
7737                 function(prop){
7738                     var el = this.dom, v, cs, camel;
7739                     if(prop == 'opacity'){
7740                         if(typeof el.style.filter == 'string'){
7741                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7742                             if(m){
7743                                 var fv = parseFloat(m[1]);
7744                                 if(!isNaN(fv)){
7745                                     return fv ? fv / 100 : 0;
7746                                 }
7747                             }
7748                         }
7749                         return 1;
7750                     }else if(prop == 'float'){
7751                         prop = "styleFloat";
7752                     }
7753                     if(!(camel = propCache[prop])){
7754                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7755                     }
7756                     if(v = el.style[camel]){
7757                         return v;
7758                     }
7759                     if(cs = el.currentStyle){
7760                         return cs[camel];
7761                     }
7762                     return null;
7763                 };
7764         }(),
7765
7766         /**
7767          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7768          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7769          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7770          * @return {Roo.Element} this
7771          */
7772         setStyle : function(prop, value){
7773             if(typeof prop == "string"){
7774                 
7775                 if (prop == 'float') {
7776                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7777                     return this;
7778                 }
7779                 
7780                 var camel;
7781                 if(!(camel = propCache[prop])){
7782                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7783                 }
7784                 
7785                 if(camel == 'opacity') {
7786                     this.setOpacity(value);
7787                 }else{
7788                     this.dom.style[camel] = value;
7789                 }
7790             }else{
7791                 for(var style in prop){
7792                     if(typeof prop[style] != "function"){
7793                        this.setStyle(style, prop[style]);
7794                     }
7795                 }
7796             }
7797             return this;
7798         },
7799
7800         /**
7801          * More flexible version of {@link #setStyle} for setting style properties.
7802          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7803          * a function which returns such a specification.
7804          * @return {Roo.Element} this
7805          */
7806         applyStyles : function(style){
7807             Roo.DomHelper.applyStyles(this.dom, style);
7808             return this;
7809         },
7810
7811         /**
7812           * 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).
7813           * @return {Number} The X position of the element
7814           */
7815         getX : function(){
7816             return D.getX(this.dom);
7817         },
7818
7819         /**
7820           * 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).
7821           * @return {Number} The Y position of the element
7822           */
7823         getY : function(){
7824             return D.getY(this.dom);
7825         },
7826
7827         /**
7828           * 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).
7829           * @return {Array} The XY position of the element
7830           */
7831         getXY : function(){
7832             return D.getXY(this.dom);
7833         },
7834
7835         /**
7836          * 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).
7837          * @param {Number} The X position of the element
7838          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7839          * @return {Roo.Element} this
7840          */
7841         setX : function(x, animate){
7842             if(!animate || !A){
7843                 D.setX(this.dom, x);
7844             }else{
7845                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7846             }
7847             return this;
7848         },
7849
7850         /**
7851          * 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).
7852          * @param {Number} The Y position of the element
7853          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7854          * @return {Roo.Element} this
7855          */
7856         setY : function(y, animate){
7857             if(!animate || !A){
7858                 D.setY(this.dom, y);
7859             }else{
7860                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7861             }
7862             return this;
7863         },
7864
7865         /**
7866          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7867          * @param {String} left The left CSS property value
7868          * @return {Roo.Element} this
7869          */
7870         setLeft : function(left){
7871             this.setStyle("left", this.addUnits(left));
7872             return this;
7873         },
7874
7875         /**
7876          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7877          * @param {String} top The top CSS property value
7878          * @return {Roo.Element} this
7879          */
7880         setTop : function(top){
7881             this.setStyle("top", this.addUnits(top));
7882             return this;
7883         },
7884
7885         /**
7886          * Sets the element's CSS right style.
7887          * @param {String} right The right CSS property value
7888          * @return {Roo.Element} this
7889          */
7890         setRight : function(right){
7891             this.setStyle("right", this.addUnits(right));
7892             return this;
7893         },
7894
7895         /**
7896          * Sets the element's CSS bottom style.
7897          * @param {String} bottom The bottom CSS property value
7898          * @return {Roo.Element} this
7899          */
7900         setBottom : function(bottom){
7901             this.setStyle("bottom", this.addUnits(bottom));
7902             return this;
7903         },
7904
7905         /**
7906          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7907          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7908          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7909          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7910          * @return {Roo.Element} this
7911          */
7912         setXY : function(pos, animate){
7913             if(!animate || !A){
7914                 D.setXY(this.dom, pos);
7915             }else{
7916                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7917             }
7918             return this;
7919         },
7920
7921         /**
7922          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7923          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7924          * @param {Number} x X value for new position (coordinates are page-based)
7925          * @param {Number} y Y value for new position (coordinates are page-based)
7926          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7927          * @return {Roo.Element} this
7928          */
7929         setLocation : function(x, y, animate){
7930             this.setXY([x, y], this.preanim(arguments, 2));
7931             return this;
7932         },
7933
7934         /**
7935          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7936          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7937          * @param {Number} x X value for new position (coordinates are page-based)
7938          * @param {Number} y Y value for new position (coordinates are page-based)
7939          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7940          * @return {Roo.Element} this
7941          */
7942         moveTo : function(x, y, animate){
7943             this.setXY([x, y], this.preanim(arguments, 2));
7944             return this;
7945         },
7946
7947         /**
7948          * Returns the region of the given element.
7949          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7950          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7951          */
7952         getRegion : function(){
7953             return D.getRegion(this.dom);
7954         },
7955
7956         /**
7957          * Returns the offset height of the element
7958          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7959          * @return {Number} The element's height
7960          */
7961         getHeight : function(contentHeight){
7962             var h = this.dom.offsetHeight || 0;
7963             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7964         },
7965
7966         /**
7967          * Returns the offset width of the element
7968          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7969          * @return {Number} The element's width
7970          */
7971         getWidth : function(contentWidth){
7972             var w = this.dom.offsetWidth || 0;
7973             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7974         },
7975
7976         /**
7977          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7978          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7979          * if a height has not been set using CSS.
7980          * @return {Number}
7981          */
7982         getComputedHeight : function(){
7983             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7984             if(!h){
7985                 h = parseInt(this.getStyle('height'), 10) || 0;
7986                 if(!this.isBorderBox()){
7987                     h += this.getFrameWidth('tb');
7988                 }
7989             }
7990             return h;
7991         },
7992
7993         /**
7994          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7995          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7996          * if a width has not been set using CSS.
7997          * @return {Number}
7998          */
7999         getComputedWidth : function(){
8000             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8001             if(!w){
8002                 w = parseInt(this.getStyle('width'), 10) || 0;
8003                 if(!this.isBorderBox()){
8004                     w += this.getFrameWidth('lr');
8005                 }
8006             }
8007             return w;
8008         },
8009
8010         /**
8011          * Returns the size of the element.
8012          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8013          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8014          */
8015         getSize : function(contentSize){
8016             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8017         },
8018
8019         /**
8020          * Returns the width and height of the viewport.
8021          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8022          */
8023         getViewSize : function(){
8024             var d = this.dom, doc = document, aw = 0, ah = 0;
8025             if(d == doc || d == doc.body){
8026                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8027             }else{
8028                 return {
8029                     width : d.clientWidth,
8030                     height: d.clientHeight
8031                 };
8032             }
8033         },
8034
8035         /**
8036          * Returns the value of the "value" attribute
8037          * @param {Boolean} asNumber true to parse the value as a number
8038          * @return {String/Number}
8039          */
8040         getValue : function(asNumber){
8041             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8042         },
8043
8044         // private
8045         adjustWidth : function(width){
8046             if(typeof width == "number"){
8047                 if(this.autoBoxAdjust && !this.isBorderBox()){
8048                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8049                 }
8050                 if(width < 0){
8051                     width = 0;
8052                 }
8053             }
8054             return width;
8055         },
8056
8057         // private
8058         adjustHeight : function(height){
8059             if(typeof height == "number"){
8060                if(this.autoBoxAdjust && !this.isBorderBox()){
8061                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8062                }
8063                if(height < 0){
8064                    height = 0;
8065                }
8066             }
8067             return height;
8068         },
8069
8070         /**
8071          * Set the width of the element
8072          * @param {Number} width The new width
8073          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8074          * @return {Roo.Element} this
8075          */
8076         setWidth : function(width, animate){
8077             width = this.adjustWidth(width);
8078             if(!animate || !A){
8079                 this.dom.style.width = this.addUnits(width);
8080             }else{
8081                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8082             }
8083             return this;
8084         },
8085
8086         /**
8087          * Set the height of the element
8088          * @param {Number} height The new height
8089          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8090          * @return {Roo.Element} this
8091          */
8092          setHeight : function(height, animate){
8093             height = this.adjustHeight(height);
8094             if(!animate || !A){
8095                 this.dom.style.height = this.addUnits(height);
8096             }else{
8097                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8098             }
8099             return this;
8100         },
8101
8102         /**
8103          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8104          * @param {Number} width The new width
8105          * @param {Number} height The new height
8106          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8107          * @return {Roo.Element} this
8108          */
8109          setSize : function(width, height, animate){
8110             if(typeof width == "object"){ // in case of object from getSize()
8111                 height = width.height; width = width.width;
8112             }
8113             width = this.adjustWidth(width); height = this.adjustHeight(height);
8114             if(!animate || !A){
8115                 this.dom.style.width = this.addUnits(width);
8116                 this.dom.style.height = this.addUnits(height);
8117             }else{
8118                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8119             }
8120             return this;
8121         },
8122
8123         /**
8124          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8125          * @param {Number} x X value for new position (coordinates are page-based)
8126          * @param {Number} y Y value for new position (coordinates are page-based)
8127          * @param {Number} width The new width
8128          * @param {Number} height The new height
8129          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8130          * @return {Roo.Element} this
8131          */
8132         setBounds : function(x, y, width, height, animate){
8133             if(!animate || !A){
8134                 this.setSize(width, height);
8135                 this.setLocation(x, y);
8136             }else{
8137                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8138                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8139                               this.preanim(arguments, 4), 'motion');
8140             }
8141             return this;
8142         },
8143
8144         /**
8145          * 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.
8146          * @param {Roo.lib.Region} region The region to fill
8147          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8148          * @return {Roo.Element} this
8149          */
8150         setRegion : function(region, animate){
8151             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8152             return this;
8153         },
8154
8155         /**
8156          * Appends an event handler
8157          *
8158          * @param {String}   eventName     The type of event to append
8159          * @param {Function} fn        The method the event invokes
8160          * @param {Object} scope       (optional) The scope (this object) of the fn
8161          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8162          */
8163         addListener : function(eventName, fn, scope, options){
8164             if (this.dom) {
8165                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8166             }
8167         },
8168
8169         /**
8170          * Removes an event handler from this element
8171          * @param {String} eventName the type of event to remove
8172          * @param {Function} fn the method the event invokes
8173          * @return {Roo.Element} this
8174          */
8175         removeListener : function(eventName, fn){
8176             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8177             return this;
8178         },
8179
8180         /**
8181          * Removes all previous added listeners from this element
8182          * @return {Roo.Element} this
8183          */
8184         removeAllListeners : function(){
8185             E.purgeElement(this.dom);
8186             return this;
8187         },
8188
8189         relayEvent : function(eventName, observable){
8190             this.on(eventName, function(e){
8191                 observable.fireEvent(eventName, e);
8192             });
8193         },
8194
8195         /**
8196          * Set the opacity of the element
8197          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8198          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8199          * @return {Roo.Element} this
8200          */
8201          setOpacity : function(opacity, animate){
8202             if(!animate || !A){
8203                 var s = this.dom.style;
8204                 if(Roo.isIE){
8205                     s.zoom = 1;
8206                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8207                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8208                 }else{
8209                     s.opacity = opacity;
8210                 }
8211             }else{
8212                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8213             }
8214             return this;
8215         },
8216
8217         /**
8218          * Gets the left X coordinate
8219          * @param {Boolean} local True to get the local css position instead of page coordinate
8220          * @return {Number}
8221          */
8222         getLeft : function(local){
8223             if(!local){
8224                 return this.getX();
8225             }else{
8226                 return parseInt(this.getStyle("left"), 10) || 0;
8227             }
8228         },
8229
8230         /**
8231          * Gets the right X coordinate of the element (element X position + element width)
8232          * @param {Boolean} local True to get the local css position instead of page coordinate
8233          * @return {Number}
8234          */
8235         getRight : function(local){
8236             if(!local){
8237                 return this.getX() + this.getWidth();
8238             }else{
8239                 return (this.getLeft(true) + this.getWidth()) || 0;
8240             }
8241         },
8242
8243         /**
8244          * Gets the top Y coordinate
8245          * @param {Boolean} local True to get the local css position instead of page coordinate
8246          * @return {Number}
8247          */
8248         getTop : function(local) {
8249             if(!local){
8250                 return this.getY();
8251             }else{
8252                 return parseInt(this.getStyle("top"), 10) || 0;
8253             }
8254         },
8255
8256         /**
8257          * Gets the bottom Y coordinate of the element (element Y position + element height)
8258          * @param {Boolean} local True to get the local css position instead of page coordinate
8259          * @return {Number}
8260          */
8261         getBottom : function(local){
8262             if(!local){
8263                 return this.getY() + this.getHeight();
8264             }else{
8265                 return (this.getTop(true) + this.getHeight()) || 0;
8266             }
8267         },
8268
8269         /**
8270         * Initializes positioning on this element. If a desired position is not passed, it will make the
8271         * the element positioned relative IF it is not already positioned.
8272         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8273         * @param {Number} zIndex (optional) The zIndex to apply
8274         * @param {Number} x (optional) Set the page X position
8275         * @param {Number} y (optional) Set the page Y position
8276         */
8277         position : function(pos, zIndex, x, y){
8278             if(!pos){
8279                if(this.getStyle('position') == 'static'){
8280                    this.setStyle('position', 'relative');
8281                }
8282             }else{
8283                 this.setStyle("position", pos);
8284             }
8285             if(zIndex){
8286                 this.setStyle("z-index", zIndex);
8287             }
8288             if(x !== undefined && y !== undefined){
8289                 this.setXY([x, y]);
8290             }else if(x !== undefined){
8291                 this.setX(x);
8292             }else if(y !== undefined){
8293                 this.setY(y);
8294             }
8295         },
8296
8297         /**
8298         * Clear positioning back to the default when the document was loaded
8299         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8300         * @return {Roo.Element} this
8301          */
8302         clearPositioning : function(value){
8303             value = value ||'';
8304             this.setStyle({
8305                 "left": value,
8306                 "right": value,
8307                 "top": value,
8308                 "bottom": value,
8309                 "z-index": "",
8310                 "position" : "static"
8311             });
8312             return this;
8313         },
8314
8315         /**
8316         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8317         * snapshot before performing an update and then restoring the element.
8318         * @return {Object}
8319         */
8320         getPositioning : function(){
8321             var l = this.getStyle("left");
8322             var t = this.getStyle("top");
8323             return {
8324                 "position" : this.getStyle("position"),
8325                 "left" : l,
8326                 "right" : l ? "" : this.getStyle("right"),
8327                 "top" : t,
8328                 "bottom" : t ? "" : this.getStyle("bottom"),
8329                 "z-index" : this.getStyle("z-index")
8330             };
8331         },
8332
8333         /**
8334          * Gets the width of the border(s) for the specified side(s)
8335          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8336          * passing lr would get the border (l)eft width + the border (r)ight width.
8337          * @return {Number} The width of the sides passed added together
8338          */
8339         getBorderWidth : function(side){
8340             return this.addStyles(side, El.borders);
8341         },
8342
8343         /**
8344          * Gets the width of the padding(s) for the specified side(s)
8345          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8346          * passing lr would get the padding (l)eft + the padding (r)ight.
8347          * @return {Number} The padding of the sides passed added together
8348          */
8349         getPadding : function(side){
8350             return this.addStyles(side, El.paddings);
8351         },
8352
8353         /**
8354         * Set positioning with an object returned by getPositioning().
8355         * @param {Object} posCfg
8356         * @return {Roo.Element} this
8357          */
8358         setPositioning : function(pc){
8359             this.applyStyles(pc);
8360             if(pc.right == "auto"){
8361                 this.dom.style.right = "";
8362             }
8363             if(pc.bottom == "auto"){
8364                 this.dom.style.bottom = "";
8365             }
8366             return this;
8367         },
8368
8369         // private
8370         fixDisplay : function(){
8371             if(this.getStyle("display") == "none"){
8372                 this.setStyle("visibility", "hidden");
8373                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8374                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8375                     this.setStyle("display", "block");
8376                 }
8377             }
8378         },
8379
8380         /**
8381          * Quick set left and top adding default units
8382          * @param {String} left The left CSS property value
8383          * @param {String} top The top CSS property value
8384          * @return {Roo.Element} this
8385          */
8386          setLeftTop : function(left, top){
8387             this.dom.style.left = this.addUnits(left);
8388             this.dom.style.top = this.addUnits(top);
8389             return this;
8390         },
8391
8392         /**
8393          * Move this element relative to its current position.
8394          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8395          * @param {Number} distance How far to move the element in pixels
8396          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8397          * @return {Roo.Element} this
8398          */
8399          move : function(direction, distance, animate){
8400             var xy = this.getXY();
8401             direction = direction.toLowerCase();
8402             switch(direction){
8403                 case "l":
8404                 case "left":
8405                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8406                     break;
8407                case "r":
8408                case "right":
8409                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8410                     break;
8411                case "t":
8412                case "top":
8413                case "up":
8414                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8415                     break;
8416                case "b":
8417                case "bottom":
8418                case "down":
8419                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8420                     break;
8421             }
8422             return this;
8423         },
8424
8425         /**
8426          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8427          * @return {Roo.Element} this
8428          */
8429         clip : function(){
8430             if(!this.isClipped){
8431                this.isClipped = true;
8432                this.originalClip = {
8433                    "o": this.getStyle("overflow"),
8434                    "x": this.getStyle("overflow-x"),
8435                    "y": this.getStyle("overflow-y")
8436                };
8437                this.setStyle("overflow", "hidden");
8438                this.setStyle("overflow-x", "hidden");
8439                this.setStyle("overflow-y", "hidden");
8440             }
8441             return this;
8442         },
8443
8444         /**
8445          *  Return clipping (overflow) to original clipping before clip() was called
8446          * @return {Roo.Element} this
8447          */
8448         unclip : function(){
8449             if(this.isClipped){
8450                 this.isClipped = false;
8451                 var o = this.originalClip;
8452                 if(o.o){this.setStyle("overflow", o.o);}
8453                 if(o.x){this.setStyle("overflow-x", o.x);}
8454                 if(o.y){this.setStyle("overflow-y", o.y);}
8455             }
8456             return this;
8457         },
8458
8459
8460         /**
8461          * Gets the x,y coordinates specified by the anchor position on the element.
8462          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8463          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8464          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8465          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8466          * @return {Array} [x, y] An array containing the element's x and y coordinates
8467          */
8468         getAnchorXY : function(anchor, local, s){
8469             //Passing a different size is useful for pre-calculating anchors,
8470             //especially for anchored animations that change the el size.
8471
8472             var w, h, vp = false;
8473             if(!s){
8474                 var d = this.dom;
8475                 if(d == document.body || d == document){
8476                     vp = true;
8477                     w = D.getViewWidth(); h = D.getViewHeight();
8478                 }else{
8479                     w = this.getWidth(); h = this.getHeight();
8480                 }
8481             }else{
8482                 w = s.width;  h = s.height;
8483             }
8484             var x = 0, y = 0, r = Math.round;
8485             switch((anchor || "tl").toLowerCase()){
8486                 case "c":
8487                     x = r(w*.5);
8488                     y = r(h*.5);
8489                 break;
8490                 case "t":
8491                     x = r(w*.5);
8492                     y = 0;
8493                 break;
8494                 case "l":
8495                     x = 0;
8496                     y = r(h*.5);
8497                 break;
8498                 case "r":
8499                     x = w;
8500                     y = r(h*.5);
8501                 break;
8502                 case "b":
8503                     x = r(w*.5);
8504                     y = h;
8505                 break;
8506                 case "tl":
8507                     x = 0;
8508                     y = 0;
8509                 break;
8510                 case "bl":
8511                     x = 0;
8512                     y = h;
8513                 break;
8514                 case "br":
8515                     x = w;
8516                     y = h;
8517                 break;
8518                 case "tr":
8519                     x = w;
8520                     y = 0;
8521                 break;
8522             }
8523             if(local === true){
8524                 return [x, y];
8525             }
8526             if(vp){
8527                 var sc = this.getScroll();
8528                 return [x + sc.left, y + sc.top];
8529             }
8530             //Add the element's offset xy
8531             var o = this.getXY();
8532             return [x+o[0], y+o[1]];
8533         },
8534
8535         /**
8536          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8537          * supported position values.
8538          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8539          * @param {String} position The position to align to.
8540          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8541          * @return {Array} [x, y]
8542          */
8543         getAlignToXY : function(el, p, o){
8544             el = Roo.get(el);
8545             var d = this.dom;
8546             if(!el.dom){
8547                 throw "Element.alignTo with an element that doesn't exist";
8548             }
8549             var c = false; //constrain to viewport
8550             var p1 = "", p2 = "";
8551             o = o || [0,0];
8552
8553             if(!p){
8554                 p = "tl-bl";
8555             }else if(p == "?"){
8556                 p = "tl-bl?";
8557             }else if(p.indexOf("-") == -1){
8558                 p = "tl-" + p;
8559             }
8560             p = p.toLowerCase();
8561             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8562             if(!m){
8563                throw "Element.alignTo with an invalid alignment " + p;
8564             }
8565             p1 = m[1]; p2 = m[2]; c = !!m[3];
8566
8567             //Subtract the aligned el's internal xy from the target's offset xy
8568             //plus custom offset to get the aligned el's new offset xy
8569             var a1 = this.getAnchorXY(p1, true);
8570             var a2 = el.getAnchorXY(p2, false);
8571             var x = a2[0] - a1[0] + o[0];
8572             var y = a2[1] - a1[1] + o[1];
8573             if(c){
8574                 //constrain the aligned el to viewport if necessary
8575                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8576                 // 5px of margin for ie
8577                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8578
8579                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8580                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8581                 //otherwise swap the aligned el to the opposite border of the target.
8582                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8583                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8584                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8585                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8586
8587                var doc = document;
8588                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8589                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8590
8591                if((x+w) > dw + scrollX){
8592                     x = swapX ? r.left-w : dw+scrollX-w;
8593                 }
8594                if(x < scrollX){
8595                    x = swapX ? r.right : scrollX;
8596                }
8597                if((y+h) > dh + scrollY){
8598                     y = swapY ? r.top-h : dh+scrollY-h;
8599                 }
8600                if (y < scrollY){
8601                    y = swapY ? r.bottom : scrollY;
8602                }
8603             }
8604             return [x,y];
8605         },
8606
8607         // private
8608         getConstrainToXY : function(){
8609             var os = {top:0, left:0, bottom:0, right: 0};
8610
8611             return function(el, local, offsets, proposedXY){
8612                 el = Roo.get(el);
8613                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8614
8615                 var vw, vh, vx = 0, vy = 0;
8616                 if(el.dom == document.body || el.dom == document){
8617                     vw = Roo.lib.Dom.getViewWidth();
8618                     vh = Roo.lib.Dom.getViewHeight();
8619                 }else{
8620                     vw = el.dom.clientWidth;
8621                     vh = el.dom.clientHeight;
8622                     if(!local){
8623                         var vxy = el.getXY();
8624                         vx = vxy[0];
8625                         vy = vxy[1];
8626                     }
8627                 }
8628
8629                 var s = el.getScroll();
8630
8631                 vx += offsets.left + s.left;
8632                 vy += offsets.top + s.top;
8633
8634                 vw -= offsets.right;
8635                 vh -= offsets.bottom;
8636
8637                 var vr = vx+vw;
8638                 var vb = vy+vh;
8639
8640                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8641                 var x = xy[0], y = xy[1];
8642                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8643
8644                 // only move it if it needs it
8645                 var moved = false;
8646
8647                 // first validate right/bottom
8648                 if((x + w) > vr){
8649                     x = vr - w;
8650                     moved = true;
8651                 }
8652                 if((y + h) > vb){
8653                     y = vb - h;
8654                     moved = true;
8655                 }
8656                 // then make sure top/left isn't negative
8657                 if(x < vx){
8658                     x = vx;
8659                     moved = true;
8660                 }
8661                 if(y < vy){
8662                     y = vy;
8663                     moved = true;
8664                 }
8665                 return moved ? [x, y] : false;
8666             };
8667         }(),
8668
8669         // private
8670         adjustForConstraints : function(xy, parent, offsets){
8671             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8672         },
8673
8674         /**
8675          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8676          * document it aligns it to the viewport.
8677          * The position parameter is optional, and can be specified in any one of the following formats:
8678          * <ul>
8679          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8680          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8681          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8682          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8683          *   <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
8684          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8685          * </ul>
8686          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8687          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8688          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8689          * that specified in order to enforce the viewport constraints.
8690          * Following are all of the supported anchor positions:
8691     <pre>
8692     Value  Description
8693     -----  -----------------------------
8694     tl     The top left corner (default)
8695     t      The center of the top edge
8696     tr     The top right corner
8697     l      The center of the left edge
8698     c      In the center of the element
8699     r      The center of the right edge
8700     bl     The bottom left corner
8701     b      The center of the bottom edge
8702     br     The bottom right corner
8703     </pre>
8704     Example Usage:
8705     <pre><code>
8706     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8707     el.alignTo("other-el");
8708
8709     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8710     el.alignTo("other-el", "tr?");
8711
8712     // align the bottom right corner of el with the center left edge of other-el
8713     el.alignTo("other-el", "br-l?");
8714
8715     // align the center of el with the bottom left corner of other-el and
8716     // adjust the x position by -6 pixels (and the y position by 0)
8717     el.alignTo("other-el", "c-bl", [-6, 0]);
8718     </code></pre>
8719          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8720          * @param {String} position The position to align to.
8721          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8722          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8723          * @return {Roo.Element} this
8724          */
8725         alignTo : function(element, position, offsets, animate){
8726             var xy = this.getAlignToXY(element, position, offsets);
8727             this.setXY(xy, this.preanim(arguments, 3));
8728             return this;
8729         },
8730
8731         /**
8732          * Anchors an element to another element and realigns it when the window is resized.
8733          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8734          * @param {String} position The position to align to.
8735          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8736          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8737          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8738          * is a number, it is used as the buffer delay (defaults to 50ms).
8739          * @param {Function} callback The function to call after the animation finishes
8740          * @return {Roo.Element} this
8741          */
8742         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8743             var action = function(){
8744                 this.alignTo(el, alignment, offsets, animate);
8745                 Roo.callback(callback, this);
8746             };
8747             Roo.EventManager.onWindowResize(action, this);
8748             var tm = typeof monitorScroll;
8749             if(tm != 'undefined'){
8750                 Roo.EventManager.on(window, 'scroll', action, this,
8751                     {buffer: tm == 'number' ? monitorScroll : 50});
8752             }
8753             action.call(this); // align immediately
8754             return this;
8755         },
8756         /**
8757          * Clears any opacity settings from this element. Required in some cases for IE.
8758          * @return {Roo.Element} this
8759          */
8760         clearOpacity : function(){
8761             if (window.ActiveXObject) {
8762                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8763                     this.dom.style.filter = "";
8764                 }
8765             } else {
8766                 this.dom.style.opacity = "";
8767                 this.dom.style["-moz-opacity"] = "";
8768                 this.dom.style["-khtml-opacity"] = "";
8769             }
8770             return this;
8771         },
8772
8773         /**
8774          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8775          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8776          * @return {Roo.Element} this
8777          */
8778         hide : function(animate){
8779             this.setVisible(false, this.preanim(arguments, 0));
8780             return this;
8781         },
8782
8783         /**
8784         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8785         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8786          * @return {Roo.Element} this
8787          */
8788         show : function(animate){
8789             this.setVisible(true, this.preanim(arguments, 0));
8790             return this;
8791         },
8792
8793         /**
8794          * @private Test if size has a unit, otherwise appends the default
8795          */
8796         addUnits : function(size){
8797             return Roo.Element.addUnits(size, this.defaultUnit);
8798         },
8799
8800         /**
8801          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8802          * @return {Roo.Element} this
8803          */
8804         beginMeasure : function(){
8805             var el = this.dom;
8806             if(el.offsetWidth || el.offsetHeight){
8807                 return this; // offsets work already
8808             }
8809             var changed = [];
8810             var p = this.dom, b = document.body; // start with this element
8811             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8812                 var pe = Roo.get(p);
8813                 if(pe.getStyle('display') == 'none'){
8814                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8815                     p.style.visibility = "hidden";
8816                     p.style.display = "block";
8817                 }
8818                 p = p.parentNode;
8819             }
8820             this._measureChanged = changed;
8821             return this;
8822
8823         },
8824
8825         /**
8826          * Restores displays to before beginMeasure was called
8827          * @return {Roo.Element} this
8828          */
8829         endMeasure : function(){
8830             var changed = this._measureChanged;
8831             if(changed){
8832                 for(var i = 0, len = changed.length; i < len; i++) {
8833                     var r = changed[i];
8834                     r.el.style.visibility = r.visibility;
8835                     r.el.style.display = "none";
8836                 }
8837                 this._measureChanged = null;
8838             }
8839             return this;
8840         },
8841
8842         /**
8843         * Update the innerHTML of this element, optionally searching for and processing scripts
8844         * @param {String} html The new HTML
8845         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8846         * @param {Function} callback For async script loading you can be noticed when the update completes
8847         * @return {Roo.Element} this
8848          */
8849         update : function(html, loadScripts, callback){
8850             if(typeof html == "undefined"){
8851                 html = "";
8852             }
8853             if(loadScripts !== true){
8854                 this.dom.innerHTML = html;
8855                 if(typeof callback == "function"){
8856                     callback();
8857                 }
8858                 return this;
8859             }
8860             var id = Roo.id();
8861             var dom = this.dom;
8862
8863             html += '<span id="' + id + '"></span>';
8864
8865             E.onAvailable(id, function(){
8866                 var hd = document.getElementsByTagName("head")[0];
8867                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8868                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8869                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8870
8871                 var match;
8872                 while(match = re.exec(html)){
8873                     var attrs = match[1];
8874                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8875                     if(srcMatch && srcMatch[2]){
8876                        var s = document.createElement("script");
8877                        s.src = srcMatch[2];
8878                        var typeMatch = attrs.match(typeRe);
8879                        if(typeMatch && typeMatch[2]){
8880                            s.type = typeMatch[2];
8881                        }
8882                        hd.appendChild(s);
8883                     }else if(match[2] && match[2].length > 0){
8884                         if(window.execScript) {
8885                            window.execScript(match[2]);
8886                         } else {
8887                             /**
8888                              * eval:var:id
8889                              * eval:var:dom
8890                              * eval:var:html
8891                              * 
8892                              */
8893                            window.eval(match[2]);
8894                         }
8895                     }
8896                 }
8897                 var el = document.getElementById(id);
8898                 if(el){el.parentNode.removeChild(el);}
8899                 if(typeof callback == "function"){
8900                     callback();
8901                 }
8902             });
8903             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8904             return this;
8905         },
8906
8907         /**
8908          * Direct access to the UpdateManager update() method (takes the same parameters).
8909          * @param {String/Function} url The url for this request or a function to call to get the url
8910          * @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}
8911          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8912          * @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.
8913          * @return {Roo.Element} this
8914          */
8915         load : function(){
8916             var um = this.getUpdateManager();
8917             um.update.apply(um, arguments);
8918             return this;
8919         },
8920
8921         /**
8922         * Gets this element's UpdateManager
8923         * @return {Roo.UpdateManager} The UpdateManager
8924         */
8925         getUpdateManager : function(){
8926             if(!this.updateManager){
8927                 this.updateManager = new Roo.UpdateManager(this);
8928             }
8929             return this.updateManager;
8930         },
8931
8932         /**
8933          * Disables text selection for this element (normalized across browsers)
8934          * @return {Roo.Element} this
8935          */
8936         unselectable : function(){
8937             this.dom.unselectable = "on";
8938             this.swallowEvent("selectstart", true);
8939             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8940             this.addClass("x-unselectable");
8941             return this;
8942         },
8943
8944         /**
8945         * Calculates the x, y to center this element on the screen
8946         * @return {Array} The x, y values [x, y]
8947         */
8948         getCenterXY : function(){
8949             return this.getAlignToXY(document, 'c-c');
8950         },
8951
8952         /**
8953         * Centers the Element in either the viewport, or another Element.
8954         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8955         */
8956         center : function(centerIn){
8957             this.alignTo(centerIn || document, 'c-c');
8958             return this;
8959         },
8960
8961         /**
8962          * Tests various css rules/browsers to determine if this element uses a border box
8963          * @return {Boolean}
8964          */
8965         isBorderBox : function(){
8966             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8967         },
8968
8969         /**
8970          * Return a box {x, y, width, height} that can be used to set another elements
8971          * size/location to match this element.
8972          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8973          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8974          * @return {Object} box An object in the format {x, y, width, height}
8975          */
8976         getBox : function(contentBox, local){
8977             var xy;
8978             if(!local){
8979                 xy = this.getXY();
8980             }else{
8981                 var left = parseInt(this.getStyle("left"), 10) || 0;
8982                 var top = parseInt(this.getStyle("top"), 10) || 0;
8983                 xy = [left, top];
8984             }
8985             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8986             if(!contentBox){
8987                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8988             }else{
8989                 var l = this.getBorderWidth("l")+this.getPadding("l");
8990                 var r = this.getBorderWidth("r")+this.getPadding("r");
8991                 var t = this.getBorderWidth("t")+this.getPadding("t");
8992                 var b = this.getBorderWidth("b")+this.getPadding("b");
8993                 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)};
8994             }
8995             bx.right = bx.x + bx.width;
8996             bx.bottom = bx.y + bx.height;
8997             return bx;
8998         },
8999
9000         /**
9001          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9002          for more information about the sides.
9003          * @param {String} sides
9004          * @return {Number}
9005          */
9006         getFrameWidth : function(sides, onlyContentBox){
9007             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9008         },
9009
9010         /**
9011          * 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.
9012          * @param {Object} box The box to fill {x, y, width, height}
9013          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9014          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9015          * @return {Roo.Element} this
9016          */
9017         setBox : function(box, adjust, animate){
9018             var w = box.width, h = box.height;
9019             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9020                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9021                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9022             }
9023             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9024             return this;
9025         },
9026
9027         /**
9028          * Forces the browser to repaint this element
9029          * @return {Roo.Element} this
9030          */
9031          repaint : function(){
9032             var dom = this.dom;
9033             this.addClass("x-repaint");
9034             setTimeout(function(){
9035                 Roo.get(dom).removeClass("x-repaint");
9036             }, 1);
9037             return this;
9038         },
9039
9040         /**
9041          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9042          * then it returns the calculated width of the sides (see getPadding)
9043          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9044          * @return {Object/Number}
9045          */
9046         getMargins : function(side){
9047             if(!side){
9048                 return {
9049                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9050                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9051                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9052                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9053                 };
9054             }else{
9055                 return this.addStyles(side, El.margins);
9056              }
9057         },
9058
9059         // private
9060         addStyles : function(sides, styles){
9061             var val = 0, v, w;
9062             for(var i = 0, len = sides.length; i < len; i++){
9063                 v = this.getStyle(styles[sides.charAt(i)]);
9064                 if(v){
9065                      w = parseInt(v, 10);
9066                      if(w){ val += w; }
9067                 }
9068             }
9069             return val;
9070         },
9071
9072         /**
9073          * Creates a proxy element of this element
9074          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9075          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9076          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9077          * @return {Roo.Element} The new proxy element
9078          */
9079         createProxy : function(config, renderTo, matchBox){
9080             if(renderTo){
9081                 renderTo = Roo.getDom(renderTo);
9082             }else{
9083                 renderTo = document.body;
9084             }
9085             config = typeof config == "object" ?
9086                 config : {tag : "div", cls: config};
9087             var proxy = Roo.DomHelper.append(renderTo, config, true);
9088             if(matchBox){
9089                proxy.setBox(this.getBox());
9090             }
9091             return proxy;
9092         },
9093
9094         /**
9095          * Puts a mask over this element to disable user interaction. Requires core.css.
9096          * This method can only be applied to elements which accept child nodes.
9097          * @param {String} msg (optional) A message to display in the mask
9098          * @param {String} msgCls (optional) A css class to apply to the msg element
9099          * @return {Element} The mask  element
9100          */
9101         mask : function(msg, msgCls)
9102         {
9103             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9104                 this.setStyle("position", "relative");
9105             }
9106             if(!this._mask){
9107                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9108             }
9109             this.addClass("x-masked");
9110             this._mask.setDisplayed(true);
9111             
9112             // we wander
9113             var z = 0;
9114             var dom = this.dom;
9115             while (dom && dom.style) {
9116                 if (!isNaN(parseInt(dom.style.zIndex))) {
9117                     z = Math.max(z, parseInt(dom.style.zIndex));
9118                 }
9119                 dom = dom.parentNode;
9120             }
9121             // if we are masking the body - then it hides everything..
9122             if (this.dom == document.body) {
9123                 z = 1000000;
9124                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9125                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9126             }
9127            
9128             if(typeof msg == 'string'){
9129                 if(!this._maskMsg){
9130                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9131                 }
9132                 var mm = this._maskMsg;
9133                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9134                 if (mm.dom.firstChild) { // weird IE issue?
9135                     mm.dom.firstChild.innerHTML = msg;
9136                 }
9137                 mm.setDisplayed(true);
9138                 mm.center(this);
9139                 mm.setStyle('z-index', z + 102);
9140             }
9141             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9142                 this._mask.setHeight(this.getHeight());
9143             }
9144             this._mask.setStyle('z-index', z + 100);
9145             
9146             return this._mask;
9147         },
9148
9149         /**
9150          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9151          * it is cached for reuse.
9152          */
9153         unmask : function(removeEl){
9154             if(this._mask){
9155                 if(removeEl === true){
9156                     this._mask.remove();
9157                     delete this._mask;
9158                     if(this._maskMsg){
9159                         this._maskMsg.remove();
9160                         delete this._maskMsg;
9161                     }
9162                 }else{
9163                     this._mask.setDisplayed(false);
9164                     if(this._maskMsg){
9165                         this._maskMsg.setDisplayed(false);
9166                     }
9167                 }
9168             }
9169             this.removeClass("x-masked");
9170         },
9171
9172         /**
9173          * Returns true if this element is masked
9174          * @return {Boolean}
9175          */
9176         isMasked : function(){
9177             return this._mask && this._mask.isVisible();
9178         },
9179
9180         /**
9181          * Creates an iframe shim for this element to keep selects and other windowed objects from
9182          * showing through.
9183          * @return {Roo.Element} The new shim element
9184          */
9185         createShim : function(){
9186             var el = document.createElement('iframe');
9187             el.frameBorder = 'no';
9188             el.className = 'roo-shim';
9189             if(Roo.isIE && Roo.isSecure){
9190                 el.src = Roo.SSL_SECURE_URL;
9191             }
9192             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9193             shim.autoBoxAdjust = false;
9194             return shim;
9195         },
9196
9197         /**
9198          * Removes this element from the DOM and deletes it from the cache
9199          */
9200         remove : function(){
9201             if(this.dom.parentNode){
9202                 this.dom.parentNode.removeChild(this.dom);
9203             }
9204             delete El.cache[this.dom.id];
9205         },
9206
9207         /**
9208          * Sets up event handlers to add and remove a css class when the mouse is over this element
9209          * @param {String} className
9210          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9211          * mouseout events for children elements
9212          * @return {Roo.Element} this
9213          */
9214         addClassOnOver : function(className, preventFlicker){
9215             this.on("mouseover", function(){
9216                 Roo.fly(this, '_internal').addClass(className);
9217             }, this.dom);
9218             var removeFn = function(e){
9219                 if(preventFlicker !== true || !e.within(this, true)){
9220                     Roo.fly(this, '_internal').removeClass(className);
9221                 }
9222             };
9223             this.on("mouseout", removeFn, this.dom);
9224             return this;
9225         },
9226
9227         /**
9228          * Sets up event handlers to add and remove a css class when this element has the focus
9229          * @param {String} className
9230          * @return {Roo.Element} this
9231          */
9232         addClassOnFocus : function(className){
9233             this.on("focus", function(){
9234                 Roo.fly(this, '_internal').addClass(className);
9235             }, this.dom);
9236             this.on("blur", function(){
9237                 Roo.fly(this, '_internal').removeClass(className);
9238             }, this.dom);
9239             return this;
9240         },
9241         /**
9242          * 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)
9243          * @param {String} className
9244          * @return {Roo.Element} this
9245          */
9246         addClassOnClick : function(className){
9247             var dom = this.dom;
9248             this.on("mousedown", function(){
9249                 Roo.fly(dom, '_internal').addClass(className);
9250                 var d = Roo.get(document);
9251                 var fn = function(){
9252                     Roo.fly(dom, '_internal').removeClass(className);
9253                     d.removeListener("mouseup", fn);
9254                 };
9255                 d.on("mouseup", fn);
9256             });
9257             return this;
9258         },
9259
9260         /**
9261          * Stops the specified event from bubbling and optionally prevents the default action
9262          * @param {String} eventName
9263          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9264          * @return {Roo.Element} this
9265          */
9266         swallowEvent : function(eventName, preventDefault){
9267             var fn = function(e){
9268                 e.stopPropagation();
9269                 if(preventDefault){
9270                     e.preventDefault();
9271                 }
9272             };
9273             if(eventName instanceof Array){
9274                 for(var i = 0, len = eventName.length; i < len; i++){
9275                      this.on(eventName[i], fn);
9276                 }
9277                 return this;
9278             }
9279             this.on(eventName, fn);
9280             return this;
9281         },
9282
9283         /**
9284          * @private
9285          */
9286       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9287
9288         /**
9289          * Sizes this element to its parent element's dimensions performing
9290          * neccessary box adjustments.
9291          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9292          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9293          * @return {Roo.Element} this
9294          */
9295         fitToParent : function(monitorResize, targetParent) {
9296           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9297           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9298           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9299             return;
9300           }
9301           var p = Roo.get(targetParent || this.dom.parentNode);
9302           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9303           if (monitorResize === true) {
9304             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9305             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9306           }
9307           return this;
9308         },
9309
9310         /**
9311          * Gets the next sibling, skipping text nodes
9312          * @return {HTMLElement} The next sibling or null
9313          */
9314         getNextSibling : function(){
9315             var n = this.dom.nextSibling;
9316             while(n && n.nodeType != 1){
9317                 n = n.nextSibling;
9318             }
9319             return n;
9320         },
9321
9322         /**
9323          * Gets the previous sibling, skipping text nodes
9324          * @return {HTMLElement} The previous sibling or null
9325          */
9326         getPrevSibling : function(){
9327             var n = this.dom.previousSibling;
9328             while(n && n.nodeType != 1){
9329                 n = n.previousSibling;
9330             }
9331             return n;
9332         },
9333
9334
9335         /**
9336          * Appends the passed element(s) to this element
9337          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9338          * @return {Roo.Element} this
9339          */
9340         appendChild: function(el){
9341             el = Roo.get(el);
9342             el.appendTo(this);
9343             return this;
9344         },
9345
9346         /**
9347          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9348          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9349          * automatically generated with the specified attributes.
9350          * @param {HTMLElement} insertBefore (optional) a child element of this element
9351          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9352          * @return {Roo.Element} The new child element
9353          */
9354         createChild: function(config, insertBefore, returnDom){
9355             config = config || {tag:'div'};
9356             if(insertBefore){
9357                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9358             }
9359             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9360         },
9361
9362         /**
9363          * Appends this element to the passed element
9364          * @param {String/HTMLElement/Element} el The new parent element
9365          * @return {Roo.Element} this
9366          */
9367         appendTo: function(el){
9368             el = Roo.getDom(el);
9369             el.appendChild(this.dom);
9370             return this;
9371         },
9372
9373         /**
9374          * Inserts this element before the passed element in the DOM
9375          * @param {String/HTMLElement/Element} el The element to insert before
9376          * @return {Roo.Element} this
9377          */
9378         insertBefore: function(el){
9379             el = Roo.getDom(el);
9380             el.parentNode.insertBefore(this.dom, el);
9381             return this;
9382         },
9383
9384         /**
9385          * Inserts this element after the passed element in the DOM
9386          * @param {String/HTMLElement/Element} el The element to insert after
9387          * @return {Roo.Element} this
9388          */
9389         insertAfter: function(el){
9390             el = Roo.getDom(el);
9391             el.parentNode.insertBefore(this.dom, el.nextSibling);
9392             return this;
9393         },
9394
9395         /**
9396          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9397          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9398          * @return {Roo.Element} The new child
9399          */
9400         insertFirst: function(el, returnDom){
9401             el = el || {};
9402             if(typeof el == 'object' && !el.nodeType){ // dh config
9403                 return this.createChild(el, this.dom.firstChild, returnDom);
9404             }else{
9405                 el = Roo.getDom(el);
9406                 this.dom.insertBefore(el, this.dom.firstChild);
9407                 return !returnDom ? Roo.get(el) : el;
9408             }
9409         },
9410
9411         /**
9412          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9413          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9414          * @param {String} where (optional) 'before' or 'after' defaults to before
9415          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9416          * @return {Roo.Element} the inserted Element
9417          */
9418         insertSibling: function(el, where, returnDom){
9419             where = where ? where.toLowerCase() : 'before';
9420             el = el || {};
9421             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9422
9423             if(typeof el == 'object' && !el.nodeType){ // dh config
9424                 if(where == 'after' && !this.dom.nextSibling){
9425                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9426                 }else{
9427                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9428                 }
9429
9430             }else{
9431                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9432                             where == 'before' ? this.dom : this.dom.nextSibling);
9433                 if(!returnDom){
9434                     rt = Roo.get(rt);
9435                 }
9436             }
9437             return rt;
9438         },
9439
9440         /**
9441          * Creates and wraps this element with another element
9442          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9443          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9444          * @return {HTMLElement/Element} The newly created wrapper element
9445          */
9446         wrap: function(config, returnDom){
9447             if(!config){
9448                 config = {tag: "div"};
9449             }
9450             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9451             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9452             return newEl;
9453         },
9454
9455         /**
9456          * Replaces the passed element with this element
9457          * @param {String/HTMLElement/Element} el The element to replace
9458          * @return {Roo.Element} this
9459          */
9460         replace: function(el){
9461             el = Roo.get(el);
9462             this.insertBefore(el);
9463             el.remove();
9464             return this;
9465         },
9466
9467         /**
9468          * Inserts an html fragment into this element
9469          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9470          * @param {String} html The HTML fragment
9471          * @param {Boolean} returnEl True to return an Roo.Element
9472          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9473          */
9474         insertHtml : function(where, html, returnEl){
9475             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9476             return returnEl ? Roo.get(el) : el;
9477         },
9478
9479         /**
9480          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9481          * @param {Object} o The object with the attributes
9482          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9483          * @return {Roo.Element} this
9484          */
9485         set : function(o, useSet){
9486             var el = this.dom;
9487             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9488             for(var attr in o){
9489                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9490                 if(attr=="cls"){
9491                     el.className = o["cls"];
9492                 }else{
9493                     if(useSet) {
9494                         el.setAttribute(attr, o[attr]);
9495                     } else {
9496                         el[attr] = o[attr];
9497                     }
9498                 }
9499             }
9500             if(o.style){
9501                 Roo.DomHelper.applyStyles(el, o.style);
9502             }
9503             return this;
9504         },
9505
9506         /**
9507          * Convenience method for constructing a KeyMap
9508          * @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:
9509          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9510          * @param {Function} fn The function to call
9511          * @param {Object} scope (optional) The scope of the function
9512          * @return {Roo.KeyMap} The KeyMap created
9513          */
9514         addKeyListener : function(key, fn, scope){
9515             var config;
9516             if(typeof key != "object" || key instanceof Array){
9517                 config = {
9518                     key: key,
9519                     fn: fn,
9520                     scope: scope
9521                 };
9522             }else{
9523                 config = {
9524                     key : key.key,
9525                     shift : key.shift,
9526                     ctrl : key.ctrl,
9527                     alt : key.alt,
9528                     fn: fn,
9529                     scope: scope
9530                 };
9531             }
9532             return new Roo.KeyMap(this, config);
9533         },
9534
9535         /**
9536          * Creates a KeyMap for this element
9537          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9538          * @return {Roo.KeyMap} The KeyMap created
9539          */
9540         addKeyMap : function(config){
9541             return new Roo.KeyMap(this, config);
9542         },
9543
9544         /**
9545          * Returns true if this element is scrollable.
9546          * @return {Boolean}
9547          */
9548          isScrollable : function(){
9549             var dom = this.dom;
9550             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9551         },
9552
9553         /**
9554          * 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().
9555          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9556          * @param {Number} value The new scroll value
9557          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9558          * @return {Element} this
9559          */
9560
9561         scrollTo : function(side, value, animate){
9562             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9563             if(!animate || !A){
9564                 this.dom[prop] = value;
9565             }else{
9566                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9567                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9568             }
9569             return this;
9570         },
9571
9572         /**
9573          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9574          * within this element's scrollable range.
9575          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9576          * @param {Number} distance How far to scroll the element in pixels
9577          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9578          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9579          * was scrolled as far as it could go.
9580          */
9581          scroll : function(direction, distance, animate){
9582              if(!this.isScrollable()){
9583                  return;
9584              }
9585              var el = this.dom;
9586              var l = el.scrollLeft, t = el.scrollTop;
9587              var w = el.scrollWidth, h = el.scrollHeight;
9588              var cw = el.clientWidth, ch = el.clientHeight;
9589              direction = direction.toLowerCase();
9590              var scrolled = false;
9591              var a = this.preanim(arguments, 2);
9592              switch(direction){
9593                  case "l":
9594                  case "left":
9595                      if(w - l > cw){
9596                          var v = Math.min(l + distance, w-cw);
9597                          this.scrollTo("left", v, a);
9598                          scrolled = true;
9599                      }
9600                      break;
9601                 case "r":
9602                 case "right":
9603                      if(l > 0){
9604                          var v = Math.max(l - distance, 0);
9605                          this.scrollTo("left", v, a);
9606                          scrolled = true;
9607                      }
9608                      break;
9609                 case "t":
9610                 case "top":
9611                 case "up":
9612                      if(t > 0){
9613                          var v = Math.max(t - distance, 0);
9614                          this.scrollTo("top", v, a);
9615                          scrolled = true;
9616                      }
9617                      break;
9618                 case "b":
9619                 case "bottom":
9620                 case "down":
9621                      if(h - t > ch){
9622                          var v = Math.min(t + distance, h-ch);
9623                          this.scrollTo("top", v, a);
9624                          scrolled = true;
9625                      }
9626                      break;
9627              }
9628              return scrolled;
9629         },
9630
9631         /**
9632          * Translates the passed page coordinates into left/top css values for this element
9633          * @param {Number/Array} x The page x or an array containing [x, y]
9634          * @param {Number} y The page y
9635          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9636          */
9637         translatePoints : function(x, y){
9638             if(typeof x == 'object' || x instanceof Array){
9639                 y = x[1]; x = x[0];
9640             }
9641             var p = this.getStyle('position');
9642             var o = this.getXY();
9643
9644             var l = parseInt(this.getStyle('left'), 10);
9645             var t = parseInt(this.getStyle('top'), 10);
9646
9647             if(isNaN(l)){
9648                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9649             }
9650             if(isNaN(t)){
9651                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9652             }
9653
9654             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9655         },
9656
9657         /**
9658          * Returns the current scroll position of the element.
9659          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9660          */
9661         getScroll : function(){
9662             var d = this.dom, doc = document;
9663             if(d == doc || d == doc.body){
9664                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9665                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9666                 return {left: l, top: t};
9667             }else{
9668                 return {left: d.scrollLeft, top: d.scrollTop};
9669             }
9670         },
9671
9672         /**
9673          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9674          * are convert to standard 6 digit hex color.
9675          * @param {String} attr The css attribute
9676          * @param {String} defaultValue The default value to use when a valid color isn't found
9677          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9678          * YUI color anims.
9679          */
9680         getColor : function(attr, defaultValue, prefix){
9681             var v = this.getStyle(attr);
9682             if(!v || v == "transparent" || v == "inherit") {
9683                 return defaultValue;
9684             }
9685             var color = typeof prefix == "undefined" ? "#" : prefix;
9686             if(v.substr(0, 4) == "rgb("){
9687                 var rvs = v.slice(4, v.length -1).split(",");
9688                 for(var i = 0; i < 3; i++){
9689                     var h = parseInt(rvs[i]).toString(16);
9690                     if(h < 16){
9691                         h = "0" + h;
9692                     }
9693                     color += h;
9694                 }
9695             } else {
9696                 if(v.substr(0, 1) == "#"){
9697                     if(v.length == 4) {
9698                         for(var i = 1; i < 4; i++){
9699                             var c = v.charAt(i);
9700                             color +=  c + c;
9701                         }
9702                     }else if(v.length == 7){
9703                         color += v.substr(1);
9704                     }
9705                 }
9706             }
9707             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9708         },
9709
9710         /**
9711          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9712          * gradient background, rounded corners and a 4-way shadow.
9713          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9714          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9715          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9716          * @return {Roo.Element} this
9717          */
9718         boxWrap : function(cls){
9719             cls = cls || 'x-box';
9720             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9721             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9722             return el;
9723         },
9724
9725         /**
9726          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9727          * @param {String} namespace The namespace in which to look for the attribute
9728          * @param {String} name The attribute name
9729          * @return {String} The attribute value
9730          */
9731         getAttributeNS : Roo.isIE ? function(ns, name){
9732             var d = this.dom;
9733             var type = typeof d[ns+":"+name];
9734             if(type != 'undefined' && type != 'unknown'){
9735                 return d[ns+":"+name];
9736             }
9737             return d[name];
9738         } : function(ns, name){
9739             var d = this.dom;
9740             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9741         },
9742         
9743         
9744         /**
9745          * Sets or Returns the value the dom attribute value
9746          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9747          * @param {String} value (optional) The value to set the attribute to
9748          * @return {String} The attribute value
9749          */
9750         attr : function(name){
9751             if (arguments.length > 1) {
9752                 this.dom.setAttribute(name, arguments[1]);
9753                 return arguments[1];
9754             }
9755             if (typeof(name) == 'object') {
9756                 for(var i in name) {
9757                     this.attr(i, name[i]);
9758                 }
9759                 return name;
9760             }
9761             
9762             
9763             if (!this.dom.hasAttribute(name)) {
9764                 return undefined;
9765             }
9766             return this.dom.getAttribute(name);
9767         }
9768         
9769         
9770         
9771     };
9772
9773     var ep = El.prototype;
9774
9775     /**
9776      * Appends an event handler (Shorthand for addListener)
9777      * @param {String}   eventName     The type of event to append
9778      * @param {Function} fn        The method the event invokes
9779      * @param {Object} scope       (optional) The scope (this object) of the fn
9780      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9781      * @method
9782      */
9783     ep.on = ep.addListener;
9784         // backwards compat
9785     ep.mon = ep.addListener;
9786
9787     /**
9788      * Removes an event handler from this element (shorthand for removeListener)
9789      * @param {String} eventName the type of event to remove
9790      * @param {Function} fn the method the event invokes
9791      * @return {Roo.Element} this
9792      * @method
9793      */
9794     ep.un = ep.removeListener;
9795
9796     /**
9797      * true to automatically adjust width and height settings for box-model issues (default to true)
9798      */
9799     ep.autoBoxAdjust = true;
9800
9801     // private
9802     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9803
9804     // private
9805     El.addUnits = function(v, defaultUnit){
9806         if(v === "" || v == "auto"){
9807             return v;
9808         }
9809         if(v === undefined){
9810             return '';
9811         }
9812         if(typeof v == "number" || !El.unitPattern.test(v)){
9813             return v + (defaultUnit || 'px');
9814         }
9815         return v;
9816     };
9817
9818     // special markup used throughout Roo when box wrapping elements
9819     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>';
9820     /**
9821      * Visibility mode constant - Use visibility to hide element
9822      * @static
9823      * @type Number
9824      */
9825     El.VISIBILITY = 1;
9826     /**
9827      * Visibility mode constant - Use display to hide element
9828      * @static
9829      * @type Number
9830      */
9831     El.DISPLAY = 2;
9832
9833     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9834     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9835     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9836
9837
9838
9839     /**
9840      * @private
9841      */
9842     El.cache = {};
9843
9844     var docEl;
9845
9846     /**
9847      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9848      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9849      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9850      * @return {Element} The Element object
9851      * @static
9852      */
9853     El.get = function(el){
9854         var ex, elm, id;
9855         if(!el){ return null; }
9856         if(typeof el == "string"){ // element id
9857             if(!(elm = document.getElementById(el))){
9858                 return null;
9859             }
9860             if(ex = El.cache[el]){
9861                 ex.dom = elm;
9862             }else{
9863                 ex = El.cache[el] = new El(elm);
9864             }
9865             return ex;
9866         }else if(el.tagName){ // dom element
9867             if(!(id = el.id)){
9868                 id = Roo.id(el);
9869             }
9870             if(ex = El.cache[id]){
9871                 ex.dom = el;
9872             }else{
9873                 ex = El.cache[id] = new El(el);
9874             }
9875             return ex;
9876         }else if(el instanceof El){
9877             if(el != docEl){
9878                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9879                                                               // catch case where it hasn't been appended
9880                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9881             }
9882             return el;
9883         }else if(el.isComposite){
9884             return el;
9885         }else if(el instanceof Array){
9886             return El.select(el);
9887         }else if(el == document){
9888             // create a bogus element object representing the document object
9889             if(!docEl){
9890                 var f = function(){};
9891                 f.prototype = El.prototype;
9892                 docEl = new f();
9893                 docEl.dom = document;
9894             }
9895             return docEl;
9896         }
9897         return null;
9898     };
9899
9900     // private
9901     El.uncache = function(el){
9902         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9903             if(a[i]){
9904                 delete El.cache[a[i].id || a[i]];
9905             }
9906         }
9907     };
9908
9909     // private
9910     // Garbage collection - uncache elements/purge listeners on orphaned elements
9911     // so we don't hold a reference and cause the browser to retain them
9912     El.garbageCollect = function(){
9913         if(!Roo.enableGarbageCollector){
9914             clearInterval(El.collectorThread);
9915             return;
9916         }
9917         for(var eid in El.cache){
9918             var el = El.cache[eid], d = el.dom;
9919             // -------------------------------------------------------
9920             // Determining what is garbage:
9921             // -------------------------------------------------------
9922             // !d
9923             // dom node is null, definitely garbage
9924             // -------------------------------------------------------
9925             // !d.parentNode
9926             // no parentNode == direct orphan, definitely garbage
9927             // -------------------------------------------------------
9928             // !d.offsetParent && !document.getElementById(eid)
9929             // display none elements have no offsetParent so we will
9930             // also try to look it up by it's id. However, check
9931             // offsetParent first so we don't do unneeded lookups.
9932             // This enables collection of elements that are not orphans
9933             // directly, but somewhere up the line they have an orphan
9934             // parent.
9935             // -------------------------------------------------------
9936             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9937                 delete El.cache[eid];
9938                 if(d && Roo.enableListenerCollection){
9939                     E.purgeElement(d);
9940                 }
9941             }
9942         }
9943     }
9944     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9945
9946
9947     // dom is optional
9948     El.Flyweight = function(dom){
9949         this.dom = dom;
9950     };
9951     El.Flyweight.prototype = El.prototype;
9952
9953     El._flyweights = {};
9954     /**
9955      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9956      * the dom node can be overwritten by other code.
9957      * @param {String/HTMLElement} el The dom node or id
9958      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9959      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9960      * @static
9961      * @return {Element} The shared Element object
9962      */
9963     El.fly = function(el, named){
9964         named = named || '_global';
9965         el = Roo.getDom(el);
9966         if(!el){
9967             return null;
9968         }
9969         if(!El._flyweights[named]){
9970             El._flyweights[named] = new El.Flyweight();
9971         }
9972         El._flyweights[named].dom = el;
9973         return El._flyweights[named];
9974     };
9975
9976     /**
9977      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9978      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9979      * Shorthand of {@link Roo.Element#get}
9980      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9981      * @return {Element} The Element object
9982      * @member Roo
9983      * @method get
9984      */
9985     Roo.get = El.get;
9986     /**
9987      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9988      * the dom node can be overwritten by other code.
9989      * Shorthand of {@link Roo.Element#fly}
9990      * @param {String/HTMLElement} el The dom node or id
9991      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9992      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9993      * @static
9994      * @return {Element} The shared Element object
9995      * @member Roo
9996      * @method fly
9997      */
9998     Roo.fly = El.fly;
9999
10000     // speedy lookup for elements never to box adjust
10001     var noBoxAdjust = Roo.isStrict ? {
10002         select:1
10003     } : {
10004         input:1, select:1, textarea:1
10005     };
10006     if(Roo.isIE || Roo.isGecko){
10007         noBoxAdjust['button'] = 1;
10008     }
10009
10010
10011     Roo.EventManager.on(window, 'unload', function(){
10012         delete El.cache;
10013         delete El._flyweights;
10014     });
10015 })();
10016
10017
10018
10019
10020 if(Roo.DomQuery){
10021     Roo.Element.selectorFunction = Roo.DomQuery.select;
10022 }
10023
10024 Roo.Element.select = function(selector, unique, root){
10025     var els;
10026     if(typeof selector == "string"){
10027         els = Roo.Element.selectorFunction(selector, root);
10028     }else if(selector.length !== undefined){
10029         els = selector;
10030     }else{
10031         throw "Invalid selector";
10032     }
10033     if(unique === true){
10034         return new Roo.CompositeElement(els);
10035     }else{
10036         return new Roo.CompositeElementLite(els);
10037     }
10038 };
10039 /**
10040  * Selects elements based on the passed CSS selector to enable working on them as 1.
10041  * @param {String/Array} selector The CSS selector or an array of elements
10042  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10043  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10044  * @return {CompositeElementLite/CompositeElement}
10045  * @member Roo
10046  * @method select
10047  */
10048 Roo.select = Roo.Element.select;
10049
10050
10051
10052
10053
10054
10055
10056
10057
10058
10059
10060
10061
10062
10063 /*
10064  * Based on:
10065  * Ext JS Library 1.1.1
10066  * Copyright(c) 2006-2007, Ext JS, LLC.
10067  *
10068  * Originally Released Under LGPL - original licence link has changed is not relivant.
10069  *
10070  * Fork - LGPL
10071  * <script type="text/javascript">
10072  */
10073
10074
10075
10076 //Notifies Element that fx methods are available
10077 Roo.enableFx = true;
10078
10079 /**
10080  * @class Roo.Fx
10081  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10082  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10083  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10084  * Element effects to work.</p><br/>
10085  *
10086  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10087  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10088  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10089  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10090  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10091  * expected results and should be done with care.</p><br/>
10092  *
10093  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10094  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10095 <pre>
10096 Value  Description
10097 -----  -----------------------------
10098 tl     The top left corner
10099 t      The center of the top edge
10100 tr     The top right corner
10101 l      The center of the left edge
10102 r      The center of the right edge
10103 bl     The bottom left corner
10104 b      The center of the bottom edge
10105 br     The bottom right corner
10106 </pre>
10107  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10108  * below are common options that can be passed to any Fx method.</b>
10109  * @cfg {Function} callback A function called when the effect is finished
10110  * @cfg {Object} scope The scope of the effect function
10111  * @cfg {String} easing A valid Easing value for the effect
10112  * @cfg {String} afterCls A css class to apply after the effect
10113  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10114  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10115  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10116  * effects that end with the element being visually hidden, ignored otherwise)
10117  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10118  * a function which returns such a specification that will be applied to the Element after the effect finishes
10119  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10120  * @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
10121  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10122  */
10123 Roo.Fx = {
10124         /**
10125          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10126          * origin for the slide effect.  This function automatically handles wrapping the element with
10127          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10128          * Usage:
10129          *<pre><code>
10130 // default: slide the element in from the top
10131 el.slideIn();
10132
10133 // custom: slide the element in from the right with a 2-second duration
10134 el.slideIn('r', { duration: 2 });
10135
10136 // common config options shown with default values
10137 el.slideIn('t', {
10138     easing: 'easeOut',
10139     duration: .5
10140 });
10141 </code></pre>
10142          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10143          * @param {Object} options (optional) Object literal with any of the Fx config options
10144          * @return {Roo.Element} The Element
10145          */
10146     slideIn : function(anchor, o){
10147         var el = this.getFxEl();
10148         o = o || {};
10149
10150         el.queueFx(o, function(){
10151
10152             anchor = anchor || "t";
10153
10154             // fix display to visibility
10155             this.fixDisplay();
10156
10157             // restore values after effect
10158             var r = this.getFxRestore();
10159             var b = this.getBox();
10160             // fixed size for slide
10161             this.setSize(b);
10162
10163             // wrap if needed
10164             var wrap = this.fxWrap(r.pos, o, "hidden");
10165
10166             var st = this.dom.style;
10167             st.visibility = "visible";
10168             st.position = "absolute";
10169
10170             // clear out temp styles after slide and unwrap
10171             var after = function(){
10172                 el.fxUnwrap(wrap, r.pos, o);
10173                 st.width = r.width;
10174                 st.height = r.height;
10175                 el.afterFx(o);
10176             };
10177             // time to calc the positions
10178             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10179
10180             switch(anchor.toLowerCase()){
10181                 case "t":
10182                     wrap.setSize(b.width, 0);
10183                     st.left = st.bottom = "0";
10184                     a = {height: bh};
10185                 break;
10186                 case "l":
10187                     wrap.setSize(0, b.height);
10188                     st.right = st.top = "0";
10189                     a = {width: bw};
10190                 break;
10191                 case "r":
10192                     wrap.setSize(0, b.height);
10193                     wrap.setX(b.right);
10194                     st.left = st.top = "0";
10195                     a = {width: bw, points: pt};
10196                 break;
10197                 case "b":
10198                     wrap.setSize(b.width, 0);
10199                     wrap.setY(b.bottom);
10200                     st.left = st.top = "0";
10201                     a = {height: bh, points: pt};
10202                 break;
10203                 case "tl":
10204                     wrap.setSize(0, 0);
10205                     st.right = st.bottom = "0";
10206                     a = {width: bw, height: bh};
10207                 break;
10208                 case "bl":
10209                     wrap.setSize(0, 0);
10210                     wrap.setY(b.y+b.height);
10211                     st.right = st.top = "0";
10212                     a = {width: bw, height: bh, points: pt};
10213                 break;
10214                 case "br":
10215                     wrap.setSize(0, 0);
10216                     wrap.setXY([b.right, b.bottom]);
10217                     st.left = st.top = "0";
10218                     a = {width: bw, height: bh, points: pt};
10219                 break;
10220                 case "tr":
10221                     wrap.setSize(0, 0);
10222                     wrap.setX(b.x+b.width);
10223                     st.left = st.bottom = "0";
10224                     a = {width: bw, height: bh, points: pt};
10225                 break;
10226             }
10227             this.dom.style.visibility = "visible";
10228             wrap.show();
10229
10230             arguments.callee.anim = wrap.fxanim(a,
10231                 o,
10232                 'motion',
10233                 .5,
10234                 'easeOut', after);
10235         });
10236         return this;
10237     },
10238     
10239         /**
10240          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10241          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10242          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10243          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10244          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10245          * Usage:
10246          *<pre><code>
10247 // default: slide the element out to the top
10248 el.slideOut();
10249
10250 // custom: slide the element out to the right with a 2-second duration
10251 el.slideOut('r', { duration: 2 });
10252
10253 // common config options shown with default values
10254 el.slideOut('t', {
10255     easing: 'easeOut',
10256     duration: .5,
10257     remove: false,
10258     useDisplay: false
10259 });
10260 </code></pre>
10261          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10262          * @param {Object} options (optional) Object literal with any of the Fx config options
10263          * @return {Roo.Element} The Element
10264          */
10265     slideOut : function(anchor, o){
10266         var el = this.getFxEl();
10267         o = o || {};
10268
10269         el.queueFx(o, function(){
10270
10271             anchor = anchor || "t";
10272
10273             // restore values after effect
10274             var r = this.getFxRestore();
10275             
10276             var b = this.getBox();
10277             // fixed size for slide
10278             this.setSize(b);
10279
10280             // wrap if needed
10281             var wrap = this.fxWrap(r.pos, o, "visible");
10282
10283             var st = this.dom.style;
10284             st.visibility = "visible";
10285             st.position = "absolute";
10286
10287             wrap.setSize(b);
10288
10289             var after = function(){
10290                 if(o.useDisplay){
10291                     el.setDisplayed(false);
10292                 }else{
10293                     el.hide();
10294                 }
10295
10296                 el.fxUnwrap(wrap, r.pos, o);
10297
10298                 st.width = r.width;
10299                 st.height = r.height;
10300
10301                 el.afterFx(o);
10302             };
10303
10304             var a, zero = {to: 0};
10305             switch(anchor.toLowerCase()){
10306                 case "t":
10307                     st.left = st.bottom = "0";
10308                     a = {height: zero};
10309                 break;
10310                 case "l":
10311                     st.right = st.top = "0";
10312                     a = {width: zero};
10313                 break;
10314                 case "r":
10315                     st.left = st.top = "0";
10316                     a = {width: zero, points: {to:[b.right, b.y]}};
10317                 break;
10318                 case "b":
10319                     st.left = st.top = "0";
10320                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10321                 break;
10322                 case "tl":
10323                     st.right = st.bottom = "0";
10324                     a = {width: zero, height: zero};
10325                 break;
10326                 case "bl":
10327                     st.right = st.top = "0";
10328                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10329                 break;
10330                 case "br":
10331                     st.left = st.top = "0";
10332                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10333                 break;
10334                 case "tr":
10335                     st.left = st.bottom = "0";
10336                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10337                 break;
10338             }
10339
10340             arguments.callee.anim = wrap.fxanim(a,
10341                 o,
10342                 'motion',
10343                 .5,
10344                 "easeOut", after);
10345         });
10346         return this;
10347     },
10348
10349         /**
10350          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10351          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10352          * The element must be removed from the DOM using the 'remove' config option if desired.
10353          * Usage:
10354          *<pre><code>
10355 // default
10356 el.puff();
10357
10358 // common config options shown with default values
10359 el.puff({
10360     easing: 'easeOut',
10361     duration: .5,
10362     remove: false,
10363     useDisplay: false
10364 });
10365 </code></pre>
10366          * @param {Object} options (optional) Object literal with any of the Fx config options
10367          * @return {Roo.Element} The Element
10368          */
10369     puff : function(o){
10370         var el = this.getFxEl();
10371         o = o || {};
10372
10373         el.queueFx(o, function(){
10374             this.clearOpacity();
10375             this.show();
10376
10377             // restore values after effect
10378             var r = this.getFxRestore();
10379             var st = this.dom.style;
10380
10381             var after = function(){
10382                 if(o.useDisplay){
10383                     el.setDisplayed(false);
10384                 }else{
10385                     el.hide();
10386                 }
10387
10388                 el.clearOpacity();
10389
10390                 el.setPositioning(r.pos);
10391                 st.width = r.width;
10392                 st.height = r.height;
10393                 st.fontSize = '';
10394                 el.afterFx(o);
10395             };
10396
10397             var width = this.getWidth();
10398             var height = this.getHeight();
10399
10400             arguments.callee.anim = this.fxanim({
10401                     width : {to: this.adjustWidth(width * 2)},
10402                     height : {to: this.adjustHeight(height * 2)},
10403                     points : {by: [-(width * .5), -(height * .5)]},
10404                     opacity : {to: 0},
10405                     fontSize: {to:200, unit: "%"}
10406                 },
10407                 o,
10408                 'motion',
10409                 .5,
10410                 "easeOut", after);
10411         });
10412         return this;
10413     },
10414
10415         /**
10416          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10417          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10418          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10419          * Usage:
10420          *<pre><code>
10421 // default
10422 el.switchOff();
10423
10424 // all config options shown with default values
10425 el.switchOff({
10426     easing: 'easeIn',
10427     duration: .3,
10428     remove: false,
10429     useDisplay: false
10430 });
10431 </code></pre>
10432          * @param {Object} options (optional) Object literal with any of the Fx config options
10433          * @return {Roo.Element} The Element
10434          */
10435     switchOff : function(o){
10436         var el = this.getFxEl();
10437         o = o || {};
10438
10439         el.queueFx(o, function(){
10440             this.clearOpacity();
10441             this.clip();
10442
10443             // restore values after effect
10444             var r = this.getFxRestore();
10445             var st = this.dom.style;
10446
10447             var after = function(){
10448                 if(o.useDisplay){
10449                     el.setDisplayed(false);
10450                 }else{
10451                     el.hide();
10452                 }
10453
10454                 el.clearOpacity();
10455                 el.setPositioning(r.pos);
10456                 st.width = r.width;
10457                 st.height = r.height;
10458
10459                 el.afterFx(o);
10460             };
10461
10462             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10463                 this.clearOpacity();
10464                 (function(){
10465                     this.fxanim({
10466                         height:{to:1},
10467                         points:{by:[0, this.getHeight() * .5]}
10468                     }, o, 'motion', 0.3, 'easeIn', after);
10469                 }).defer(100, this);
10470             });
10471         });
10472         return this;
10473     },
10474
10475     /**
10476      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10477      * changed using the "attr" config option) and then fading back to the original color. If no original
10478      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10479      * Usage:
10480 <pre><code>
10481 // default: highlight background to yellow
10482 el.highlight();
10483
10484 // custom: highlight foreground text to blue for 2 seconds
10485 el.highlight("0000ff", { attr: 'color', duration: 2 });
10486
10487 // common config options shown with default values
10488 el.highlight("ffff9c", {
10489     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10490     endColor: (current color) or "ffffff",
10491     easing: 'easeIn',
10492     duration: 1
10493 });
10494 </code></pre>
10495      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10496      * @param {Object} options (optional) Object literal with any of the Fx config options
10497      * @return {Roo.Element} The Element
10498      */ 
10499     highlight : function(color, o){
10500         var el = this.getFxEl();
10501         o = o || {};
10502
10503         el.queueFx(o, function(){
10504             color = color || "ffff9c";
10505             attr = o.attr || "backgroundColor";
10506
10507             this.clearOpacity();
10508             this.show();
10509
10510             var origColor = this.getColor(attr);
10511             var restoreColor = this.dom.style[attr];
10512             endColor = (o.endColor || origColor) || "ffffff";
10513
10514             var after = function(){
10515                 el.dom.style[attr] = restoreColor;
10516                 el.afterFx(o);
10517             };
10518
10519             var a = {};
10520             a[attr] = {from: color, to: endColor};
10521             arguments.callee.anim = this.fxanim(a,
10522                 o,
10523                 'color',
10524                 1,
10525                 'easeIn', after);
10526         });
10527         return this;
10528     },
10529
10530    /**
10531     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10532     * Usage:
10533 <pre><code>
10534 // default: a single light blue ripple
10535 el.frame();
10536
10537 // custom: 3 red ripples lasting 3 seconds total
10538 el.frame("ff0000", 3, { duration: 3 });
10539
10540 // common config options shown with default values
10541 el.frame("C3DAF9", 1, {
10542     duration: 1 //duration of entire animation (not each individual ripple)
10543     // Note: Easing is not configurable and will be ignored if included
10544 });
10545 </code></pre>
10546     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10547     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10548     * @param {Object} options (optional) Object literal with any of the Fx config options
10549     * @return {Roo.Element} The Element
10550     */
10551     frame : function(color, count, o){
10552         var el = this.getFxEl();
10553         o = o || {};
10554
10555         el.queueFx(o, function(){
10556             color = color || "#C3DAF9";
10557             if(color.length == 6){
10558                 color = "#" + color;
10559             }
10560             count = count || 1;
10561             duration = o.duration || 1;
10562             this.show();
10563
10564             var b = this.getBox();
10565             var animFn = function(){
10566                 var proxy = this.createProxy({
10567
10568                      style:{
10569                         visbility:"hidden",
10570                         position:"absolute",
10571                         "z-index":"35000", // yee haw
10572                         border:"0px solid " + color
10573                      }
10574                   });
10575                 var scale = Roo.isBorderBox ? 2 : 1;
10576                 proxy.animate({
10577                     top:{from:b.y, to:b.y - 20},
10578                     left:{from:b.x, to:b.x - 20},
10579                     borderWidth:{from:0, to:10},
10580                     opacity:{from:1, to:0},
10581                     height:{from:b.height, to:(b.height + (20*scale))},
10582                     width:{from:b.width, to:(b.width + (20*scale))}
10583                 }, duration, function(){
10584                     proxy.remove();
10585                 });
10586                 if(--count > 0){
10587                      animFn.defer((duration/2)*1000, this);
10588                 }else{
10589                     el.afterFx(o);
10590                 }
10591             };
10592             animFn.call(this);
10593         });
10594         return this;
10595     },
10596
10597    /**
10598     * Creates a pause before any subsequent queued effects begin.  If there are
10599     * no effects queued after the pause it will have no effect.
10600     * Usage:
10601 <pre><code>
10602 el.pause(1);
10603 </code></pre>
10604     * @param {Number} seconds The length of time to pause (in seconds)
10605     * @return {Roo.Element} The Element
10606     */
10607     pause : function(seconds){
10608         var el = this.getFxEl();
10609         var o = {};
10610
10611         el.queueFx(o, function(){
10612             setTimeout(function(){
10613                 el.afterFx(o);
10614             }, seconds * 1000);
10615         });
10616         return this;
10617     },
10618
10619    /**
10620     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10621     * using the "endOpacity" config option.
10622     * Usage:
10623 <pre><code>
10624 // default: fade in from opacity 0 to 100%
10625 el.fadeIn();
10626
10627 // custom: fade in from opacity 0 to 75% over 2 seconds
10628 el.fadeIn({ endOpacity: .75, duration: 2});
10629
10630 // common config options shown with default values
10631 el.fadeIn({
10632     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10633     easing: 'easeOut',
10634     duration: .5
10635 });
10636 </code></pre>
10637     * @param {Object} options (optional) Object literal with any of the Fx config options
10638     * @return {Roo.Element} The Element
10639     */
10640     fadeIn : function(o){
10641         var el = this.getFxEl();
10642         o = o || {};
10643         el.queueFx(o, function(){
10644             this.setOpacity(0);
10645             this.fixDisplay();
10646             this.dom.style.visibility = 'visible';
10647             var to = o.endOpacity || 1;
10648             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10649                 o, null, .5, "easeOut", function(){
10650                 if(to == 1){
10651                     this.clearOpacity();
10652                 }
10653                 el.afterFx(o);
10654             });
10655         });
10656         return this;
10657     },
10658
10659    /**
10660     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10661     * using the "endOpacity" config option.
10662     * Usage:
10663 <pre><code>
10664 // default: fade out from the element's current opacity to 0
10665 el.fadeOut();
10666
10667 // custom: fade out from the element's current opacity to 25% over 2 seconds
10668 el.fadeOut({ endOpacity: .25, duration: 2});
10669
10670 // common config options shown with default values
10671 el.fadeOut({
10672     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10673     easing: 'easeOut',
10674     duration: .5
10675     remove: false,
10676     useDisplay: false
10677 });
10678 </code></pre>
10679     * @param {Object} options (optional) Object literal with any of the Fx config options
10680     * @return {Roo.Element} The Element
10681     */
10682     fadeOut : function(o){
10683         var el = this.getFxEl();
10684         o = o || {};
10685         el.queueFx(o, function(){
10686             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10687                 o, null, .5, "easeOut", function(){
10688                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10689                      this.dom.style.display = "none";
10690                 }else{
10691                      this.dom.style.visibility = "hidden";
10692                 }
10693                 this.clearOpacity();
10694                 el.afterFx(o);
10695             });
10696         });
10697         return this;
10698     },
10699
10700    /**
10701     * Animates the transition of an element's dimensions from a starting height/width
10702     * to an ending height/width.
10703     * Usage:
10704 <pre><code>
10705 // change height and width to 100x100 pixels
10706 el.scale(100, 100);
10707
10708 // common config options shown with default values.  The height and width will default to
10709 // the element's existing values if passed as null.
10710 el.scale(
10711     [element's width],
10712     [element's height], {
10713     easing: 'easeOut',
10714     duration: .35
10715 });
10716 </code></pre>
10717     * @param {Number} width  The new width (pass undefined to keep the original width)
10718     * @param {Number} height  The new height (pass undefined to keep the original height)
10719     * @param {Object} options (optional) Object literal with any of the Fx config options
10720     * @return {Roo.Element} The Element
10721     */
10722     scale : function(w, h, o){
10723         this.shift(Roo.apply({}, o, {
10724             width: w,
10725             height: h
10726         }));
10727         return this;
10728     },
10729
10730    /**
10731     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10732     * Any of these properties not specified in the config object will not be changed.  This effect 
10733     * requires that at least one new dimension, position or opacity setting must be passed in on
10734     * the config object in order for the function to have any effect.
10735     * Usage:
10736 <pre><code>
10737 // slide the element horizontally to x position 200 while changing the height and opacity
10738 el.shift({ x: 200, height: 50, opacity: .8 });
10739
10740 // common config options shown with default values.
10741 el.shift({
10742     width: [element's width],
10743     height: [element's height],
10744     x: [element's x position],
10745     y: [element's y position],
10746     opacity: [element's opacity],
10747     easing: 'easeOut',
10748     duration: .35
10749 });
10750 </code></pre>
10751     * @param {Object} options  Object literal with any of the Fx config options
10752     * @return {Roo.Element} The Element
10753     */
10754     shift : function(o){
10755         var el = this.getFxEl();
10756         o = o || {};
10757         el.queueFx(o, function(){
10758             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10759             if(w !== undefined){
10760                 a.width = {to: this.adjustWidth(w)};
10761             }
10762             if(h !== undefined){
10763                 a.height = {to: this.adjustHeight(h)};
10764             }
10765             if(x !== undefined || y !== undefined){
10766                 a.points = {to: [
10767                     x !== undefined ? x : this.getX(),
10768                     y !== undefined ? y : this.getY()
10769                 ]};
10770             }
10771             if(op !== undefined){
10772                 a.opacity = {to: op};
10773             }
10774             if(o.xy !== undefined){
10775                 a.points = {to: o.xy};
10776             }
10777             arguments.callee.anim = this.fxanim(a,
10778                 o, 'motion', .35, "easeOut", function(){
10779                 el.afterFx(o);
10780             });
10781         });
10782         return this;
10783     },
10784
10785         /**
10786          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10787          * ending point of the effect.
10788          * Usage:
10789          *<pre><code>
10790 // default: slide the element downward while fading out
10791 el.ghost();
10792
10793 // custom: slide the element out to the right with a 2-second duration
10794 el.ghost('r', { duration: 2 });
10795
10796 // common config options shown with default values
10797 el.ghost('b', {
10798     easing: 'easeOut',
10799     duration: .5
10800     remove: false,
10801     useDisplay: false
10802 });
10803 </code></pre>
10804          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10805          * @param {Object} options (optional) Object literal with any of the Fx config options
10806          * @return {Roo.Element} The Element
10807          */
10808     ghost : function(anchor, o){
10809         var el = this.getFxEl();
10810         o = o || {};
10811
10812         el.queueFx(o, function(){
10813             anchor = anchor || "b";
10814
10815             // restore values after effect
10816             var r = this.getFxRestore();
10817             var w = this.getWidth(),
10818                 h = this.getHeight();
10819
10820             var st = this.dom.style;
10821
10822             var after = function(){
10823                 if(o.useDisplay){
10824                     el.setDisplayed(false);
10825                 }else{
10826                     el.hide();
10827                 }
10828
10829                 el.clearOpacity();
10830                 el.setPositioning(r.pos);
10831                 st.width = r.width;
10832                 st.height = r.height;
10833
10834                 el.afterFx(o);
10835             };
10836
10837             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10838             switch(anchor.toLowerCase()){
10839                 case "t":
10840                     pt.by = [0, -h];
10841                 break;
10842                 case "l":
10843                     pt.by = [-w, 0];
10844                 break;
10845                 case "r":
10846                     pt.by = [w, 0];
10847                 break;
10848                 case "b":
10849                     pt.by = [0, h];
10850                 break;
10851                 case "tl":
10852                     pt.by = [-w, -h];
10853                 break;
10854                 case "bl":
10855                     pt.by = [-w, h];
10856                 break;
10857                 case "br":
10858                     pt.by = [w, h];
10859                 break;
10860                 case "tr":
10861                     pt.by = [w, -h];
10862                 break;
10863             }
10864
10865             arguments.callee.anim = this.fxanim(a,
10866                 o,
10867                 'motion',
10868                 .5,
10869                 "easeOut", after);
10870         });
10871         return this;
10872     },
10873
10874         /**
10875          * Ensures that all effects queued after syncFx is called on the element are
10876          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10877          * @return {Roo.Element} The Element
10878          */
10879     syncFx : function(){
10880         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10881             block : false,
10882             concurrent : true,
10883             stopFx : false
10884         });
10885         return this;
10886     },
10887
10888         /**
10889          * Ensures that all effects queued after sequenceFx is called on the element are
10890          * run in sequence.  This is the opposite of {@link #syncFx}.
10891          * @return {Roo.Element} The Element
10892          */
10893     sequenceFx : function(){
10894         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10895             block : false,
10896             concurrent : false,
10897             stopFx : false
10898         });
10899         return this;
10900     },
10901
10902         /* @private */
10903     nextFx : function(){
10904         var ef = this.fxQueue[0];
10905         if(ef){
10906             ef.call(this);
10907         }
10908     },
10909
10910         /**
10911          * Returns true if the element has any effects actively running or queued, else returns false.
10912          * @return {Boolean} True if element has active effects, else false
10913          */
10914     hasActiveFx : function(){
10915         return this.fxQueue && this.fxQueue[0];
10916     },
10917
10918         /**
10919          * Stops any running effects and clears the element's internal effects queue if it contains
10920          * any additional effects that haven't started yet.
10921          * @return {Roo.Element} The Element
10922          */
10923     stopFx : function(){
10924         if(this.hasActiveFx()){
10925             var cur = this.fxQueue[0];
10926             if(cur && cur.anim && cur.anim.isAnimated()){
10927                 this.fxQueue = [cur]; // clear out others
10928                 cur.anim.stop(true);
10929             }
10930         }
10931         return this;
10932     },
10933
10934         /* @private */
10935     beforeFx : function(o){
10936         if(this.hasActiveFx() && !o.concurrent){
10937            if(o.stopFx){
10938                this.stopFx();
10939                return true;
10940            }
10941            return false;
10942         }
10943         return true;
10944     },
10945
10946         /**
10947          * Returns true if the element is currently blocking so that no other effect can be queued
10948          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10949          * used to ensure that an effect initiated by a user action runs to completion prior to the
10950          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10951          * @return {Boolean} True if blocking, else false
10952          */
10953     hasFxBlock : function(){
10954         var q = this.fxQueue;
10955         return q && q[0] && q[0].block;
10956     },
10957
10958         /* @private */
10959     queueFx : function(o, fn){
10960         if(!this.fxQueue){
10961             this.fxQueue = [];
10962         }
10963         if(!this.hasFxBlock()){
10964             Roo.applyIf(o, this.fxDefaults);
10965             if(!o.concurrent){
10966                 var run = this.beforeFx(o);
10967                 fn.block = o.block;
10968                 this.fxQueue.push(fn);
10969                 if(run){
10970                     this.nextFx();
10971                 }
10972             }else{
10973                 fn.call(this);
10974             }
10975         }
10976         return this;
10977     },
10978
10979         /* @private */
10980     fxWrap : function(pos, o, vis){
10981         var wrap;
10982         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10983             var wrapXY;
10984             if(o.fixPosition){
10985                 wrapXY = this.getXY();
10986             }
10987             var div = document.createElement("div");
10988             div.style.visibility = vis;
10989             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10990             wrap.setPositioning(pos);
10991             if(wrap.getStyle("position") == "static"){
10992                 wrap.position("relative");
10993             }
10994             this.clearPositioning('auto');
10995             wrap.clip();
10996             wrap.dom.appendChild(this.dom);
10997             if(wrapXY){
10998                 wrap.setXY(wrapXY);
10999             }
11000         }
11001         return wrap;
11002     },
11003
11004         /* @private */
11005     fxUnwrap : function(wrap, pos, o){
11006         this.clearPositioning();
11007         this.setPositioning(pos);
11008         if(!o.wrap){
11009             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11010             wrap.remove();
11011         }
11012     },
11013
11014         /* @private */
11015     getFxRestore : function(){
11016         var st = this.dom.style;
11017         return {pos: this.getPositioning(), width: st.width, height : st.height};
11018     },
11019
11020         /* @private */
11021     afterFx : function(o){
11022         if(o.afterStyle){
11023             this.applyStyles(o.afterStyle);
11024         }
11025         if(o.afterCls){
11026             this.addClass(o.afterCls);
11027         }
11028         if(o.remove === true){
11029             this.remove();
11030         }
11031         Roo.callback(o.callback, o.scope, [this]);
11032         if(!o.concurrent){
11033             this.fxQueue.shift();
11034             this.nextFx();
11035         }
11036     },
11037
11038         /* @private */
11039     getFxEl : function(){ // support for composite element fx
11040         return Roo.get(this.dom);
11041     },
11042
11043         /* @private */
11044     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11045         animType = animType || 'run';
11046         opt = opt || {};
11047         var anim = Roo.lib.Anim[animType](
11048             this.dom, args,
11049             (opt.duration || defaultDur) || .35,
11050             (opt.easing || defaultEase) || 'easeOut',
11051             function(){
11052                 Roo.callback(cb, this);
11053             },
11054             this
11055         );
11056         opt.anim = anim;
11057         return anim;
11058     }
11059 };
11060
11061 // backwords compat
11062 Roo.Fx.resize = Roo.Fx.scale;
11063
11064 //When included, Roo.Fx is automatically applied to Element so that all basic
11065 //effects are available directly via the Element API
11066 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11067  * Based on:
11068  * Ext JS Library 1.1.1
11069  * Copyright(c) 2006-2007, Ext JS, LLC.
11070  *
11071  * Originally Released Under LGPL - original licence link has changed is not relivant.
11072  *
11073  * Fork - LGPL
11074  * <script type="text/javascript">
11075  */
11076
11077
11078 /**
11079  * @class Roo.CompositeElement
11080  * Standard composite class. Creates a Roo.Element for every element in the collection.
11081  * <br><br>
11082  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11083  * actions will be performed on all the elements in this collection.</b>
11084  * <br><br>
11085  * All methods return <i>this</i> and can be chained.
11086  <pre><code>
11087  var els = Roo.select("#some-el div.some-class", true);
11088  // or select directly from an existing element
11089  var el = Roo.get('some-el');
11090  el.select('div.some-class', true);
11091
11092  els.setWidth(100); // all elements become 100 width
11093  els.hide(true); // all elements fade out and hide
11094  // or
11095  els.setWidth(100).hide(true);
11096  </code></pre>
11097  */
11098 Roo.CompositeElement = function(els){
11099     this.elements = [];
11100     this.addElements(els);
11101 };
11102 Roo.CompositeElement.prototype = {
11103     isComposite: true,
11104     addElements : function(els){
11105         if(!els) {
11106             return this;
11107         }
11108         if(typeof els == "string"){
11109             els = Roo.Element.selectorFunction(els);
11110         }
11111         var yels = this.elements;
11112         var index = yels.length-1;
11113         for(var i = 0, len = els.length; i < len; i++) {
11114                 yels[++index] = Roo.get(els[i]);
11115         }
11116         return this;
11117     },
11118
11119     /**
11120     * Clears this composite and adds the elements returned by the passed selector.
11121     * @param {String/Array} els A string CSS selector, an array of elements or an element
11122     * @return {CompositeElement} this
11123     */
11124     fill : function(els){
11125         this.elements = [];
11126         this.add(els);
11127         return this;
11128     },
11129
11130     /**
11131     * Filters this composite to only elements that match the passed selector.
11132     * @param {String} selector A string CSS selector
11133     * @param {Boolean} inverse return inverse filter (not matches)
11134     * @return {CompositeElement} this
11135     */
11136     filter : function(selector, inverse){
11137         var els = [];
11138         inverse = inverse || false;
11139         this.each(function(el){
11140             var match = inverse ? !el.is(selector) : el.is(selector);
11141             if(match){
11142                 els[els.length] = el.dom;
11143             }
11144         });
11145         this.fill(els);
11146         return this;
11147     },
11148
11149     invoke : function(fn, args){
11150         var els = this.elements;
11151         for(var i = 0, len = els.length; i < len; i++) {
11152                 Roo.Element.prototype[fn].apply(els[i], args);
11153         }
11154         return this;
11155     },
11156     /**
11157     * Adds elements to this composite.
11158     * @param {String/Array} els A string CSS selector, an array of elements or an element
11159     * @return {CompositeElement} this
11160     */
11161     add : function(els){
11162         if(typeof els == "string"){
11163             this.addElements(Roo.Element.selectorFunction(els));
11164         }else if(els.length !== undefined){
11165             this.addElements(els);
11166         }else{
11167             this.addElements([els]);
11168         }
11169         return this;
11170     },
11171     /**
11172     * Calls the passed function passing (el, this, index) for each element in this composite.
11173     * @param {Function} fn The function to call
11174     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11175     * @return {CompositeElement} this
11176     */
11177     each : function(fn, scope){
11178         var els = this.elements;
11179         for(var i = 0, len = els.length; i < len; i++){
11180             if(fn.call(scope || els[i], els[i], this, i) === false) {
11181                 break;
11182             }
11183         }
11184         return this;
11185     },
11186
11187     /**
11188      * Returns the Element object at the specified index
11189      * @param {Number} index
11190      * @return {Roo.Element}
11191      */
11192     item : function(index){
11193         return this.elements[index] || null;
11194     },
11195
11196     /**
11197      * Returns the first Element
11198      * @return {Roo.Element}
11199      */
11200     first : function(){
11201         return this.item(0);
11202     },
11203
11204     /**
11205      * Returns the last Element
11206      * @return {Roo.Element}
11207      */
11208     last : function(){
11209         return this.item(this.elements.length-1);
11210     },
11211
11212     /**
11213      * Returns the number of elements in this composite
11214      * @return Number
11215      */
11216     getCount : function(){
11217         return this.elements.length;
11218     },
11219
11220     /**
11221      * Returns true if this composite contains the passed element
11222      * @return Boolean
11223      */
11224     contains : function(el){
11225         return this.indexOf(el) !== -1;
11226     },
11227
11228     /**
11229      * Returns true if this composite contains the passed element
11230      * @return Boolean
11231      */
11232     indexOf : function(el){
11233         return this.elements.indexOf(Roo.get(el));
11234     },
11235
11236
11237     /**
11238     * Removes the specified element(s).
11239     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11240     * or an array of any of those.
11241     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11242     * @return {CompositeElement} this
11243     */
11244     removeElement : function(el, removeDom){
11245         if(el instanceof Array){
11246             for(var i = 0, len = el.length; i < len; i++){
11247                 this.removeElement(el[i]);
11248             }
11249             return this;
11250         }
11251         var index = typeof el == 'number' ? el : this.indexOf(el);
11252         if(index !== -1){
11253             if(removeDom){
11254                 var d = this.elements[index];
11255                 if(d.dom){
11256                     d.remove();
11257                 }else{
11258                     d.parentNode.removeChild(d);
11259                 }
11260             }
11261             this.elements.splice(index, 1);
11262         }
11263         return this;
11264     },
11265
11266     /**
11267     * Replaces the specified element with the passed element.
11268     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11269     * to replace.
11270     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11271     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11272     * @return {CompositeElement} this
11273     */
11274     replaceElement : function(el, replacement, domReplace){
11275         var index = typeof el == 'number' ? el : this.indexOf(el);
11276         if(index !== -1){
11277             if(domReplace){
11278                 this.elements[index].replaceWith(replacement);
11279             }else{
11280                 this.elements.splice(index, 1, Roo.get(replacement))
11281             }
11282         }
11283         return this;
11284     },
11285
11286     /**
11287      * Removes all elements.
11288      */
11289     clear : function(){
11290         this.elements = [];
11291     }
11292 };
11293 (function(){
11294     Roo.CompositeElement.createCall = function(proto, fnName){
11295         if(!proto[fnName]){
11296             proto[fnName] = function(){
11297                 return this.invoke(fnName, arguments);
11298             };
11299         }
11300     };
11301     for(var fnName in Roo.Element.prototype){
11302         if(typeof Roo.Element.prototype[fnName] == "function"){
11303             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11304         }
11305     };
11306 })();
11307 /*
11308  * Based on:
11309  * Ext JS Library 1.1.1
11310  * Copyright(c) 2006-2007, Ext JS, LLC.
11311  *
11312  * Originally Released Under LGPL - original licence link has changed is not relivant.
11313  *
11314  * Fork - LGPL
11315  * <script type="text/javascript">
11316  */
11317
11318 /**
11319  * @class Roo.CompositeElementLite
11320  * @extends Roo.CompositeElement
11321  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11322  <pre><code>
11323  var els = Roo.select("#some-el div.some-class");
11324  // or select directly from an existing element
11325  var el = Roo.get('some-el');
11326  el.select('div.some-class');
11327
11328  els.setWidth(100); // all elements become 100 width
11329  els.hide(true); // all elements fade out and hide
11330  // or
11331  els.setWidth(100).hide(true);
11332  </code></pre><br><br>
11333  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11334  * actions will be performed on all the elements in this collection.</b>
11335  */
11336 Roo.CompositeElementLite = function(els){
11337     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11338     this.el = new Roo.Element.Flyweight();
11339 };
11340 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11341     addElements : function(els){
11342         if(els){
11343             if(els instanceof Array){
11344                 this.elements = this.elements.concat(els);
11345             }else{
11346                 var yels = this.elements;
11347                 var index = yels.length-1;
11348                 for(var i = 0, len = els.length; i < len; i++) {
11349                     yels[++index] = els[i];
11350                 }
11351             }
11352         }
11353         return this;
11354     },
11355     invoke : function(fn, args){
11356         var els = this.elements;
11357         var el = this.el;
11358         for(var i = 0, len = els.length; i < len; i++) {
11359             el.dom = els[i];
11360                 Roo.Element.prototype[fn].apply(el, args);
11361         }
11362         return this;
11363     },
11364     /**
11365      * Returns a flyweight Element of the dom element object at the specified index
11366      * @param {Number} index
11367      * @return {Roo.Element}
11368      */
11369     item : function(index){
11370         if(!this.elements[index]){
11371             return null;
11372         }
11373         this.el.dom = this.elements[index];
11374         return this.el;
11375     },
11376
11377     // fixes scope with flyweight
11378     addListener : function(eventName, handler, scope, opt){
11379         var els = this.elements;
11380         for(var i = 0, len = els.length; i < len; i++) {
11381             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11382         }
11383         return this;
11384     },
11385
11386     /**
11387     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11388     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11389     * a reference to the dom node, use el.dom.</b>
11390     * @param {Function} fn The function to call
11391     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11392     * @return {CompositeElement} this
11393     */
11394     each : function(fn, scope){
11395         var els = this.elements;
11396         var el = this.el;
11397         for(var i = 0, len = els.length; i < len; i++){
11398             el.dom = els[i];
11399                 if(fn.call(scope || el, el, this, i) === false){
11400                 break;
11401             }
11402         }
11403         return this;
11404     },
11405
11406     indexOf : function(el){
11407         return this.elements.indexOf(Roo.getDom(el));
11408     },
11409
11410     replaceElement : function(el, replacement, domReplace){
11411         var index = typeof el == 'number' ? el : this.indexOf(el);
11412         if(index !== -1){
11413             replacement = Roo.getDom(replacement);
11414             if(domReplace){
11415                 var d = this.elements[index];
11416                 d.parentNode.insertBefore(replacement, d);
11417                 d.parentNode.removeChild(d);
11418             }
11419             this.elements.splice(index, 1, replacement);
11420         }
11421         return this;
11422     }
11423 });
11424 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11425
11426 /*
11427  * Based on:
11428  * Ext JS Library 1.1.1
11429  * Copyright(c) 2006-2007, Ext JS, LLC.
11430  *
11431  * Originally Released Under LGPL - original licence link has changed is not relivant.
11432  *
11433  * Fork - LGPL
11434  * <script type="text/javascript">
11435  */
11436
11437  
11438
11439 /**
11440  * @class Roo.data.Connection
11441  * @extends Roo.util.Observable
11442  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11443  * either to a configured URL, or to a URL specified at request time.<br><br>
11444  * <p>
11445  * Requests made by this class are asynchronous, and will return immediately. No data from
11446  * the server will be available to the statement immediately following the {@link #request} call.
11447  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11448  * <p>
11449  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11450  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11451  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11452  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11453  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11454  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11455  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11456  * standard DOM methods.
11457  * @constructor
11458  * @param {Object} config a configuration object.
11459  */
11460 Roo.data.Connection = function(config){
11461     Roo.apply(this, config);
11462     this.addEvents({
11463         /**
11464          * @event beforerequest
11465          * Fires before a network request is made to retrieve a data object.
11466          * @param {Connection} conn This Connection object.
11467          * @param {Object} options The options config object passed to the {@link #request} method.
11468          */
11469         "beforerequest" : true,
11470         /**
11471          * @event requestcomplete
11472          * Fires if the request was successfully completed.
11473          * @param {Connection} conn This Connection object.
11474          * @param {Object} response The XHR object containing the response data.
11475          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11476          * @param {Object} options The options config object passed to the {@link #request} method.
11477          */
11478         "requestcomplete" : true,
11479         /**
11480          * @event requestexception
11481          * Fires if an error HTTP status was returned from the server.
11482          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11483          * @param {Connection} conn This Connection object.
11484          * @param {Object} response The XHR object containing the response data.
11485          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11486          * @param {Object} options The options config object passed to the {@link #request} method.
11487          */
11488         "requestexception" : true
11489     });
11490     Roo.data.Connection.superclass.constructor.call(this);
11491 };
11492
11493 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11494     /**
11495      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11496      */
11497     /**
11498      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11499      * extra parameters to each request made by this object. (defaults to undefined)
11500      */
11501     /**
11502      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11503      *  to each request made by this object. (defaults to undefined)
11504      */
11505     /**
11506      * @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)
11507      */
11508     /**
11509      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11510      */
11511     timeout : 30000,
11512     /**
11513      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11514      * @type Boolean
11515      */
11516     autoAbort:false,
11517
11518     /**
11519      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11520      * @type Boolean
11521      */
11522     disableCaching: true,
11523
11524     /**
11525      * Sends an HTTP request to a remote server.
11526      * @param {Object} options An object which may contain the following properties:<ul>
11527      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11528      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11529      * request, a url encoded string or a function to call to get either.</li>
11530      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11531      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11532      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11533      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11534      * <li>options {Object} The parameter to the request call.</li>
11535      * <li>success {Boolean} True if the request succeeded.</li>
11536      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11537      * </ul></li>
11538      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11539      * The callback is passed the following parameters:<ul>
11540      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11541      * <li>options {Object} The parameter to the request call.</li>
11542      * </ul></li>
11543      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11544      * The callback is passed the following parameters:<ul>
11545      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11546      * <li>options {Object} The parameter to the request call.</li>
11547      * </ul></li>
11548      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11549      * for the callback function. Defaults to the browser window.</li>
11550      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11551      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11552      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11553      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11554      * params for the post data. Any params will be appended to the URL.</li>
11555      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11556      * </ul>
11557      * @return {Number} transactionId
11558      */
11559     request : function(o){
11560         if(this.fireEvent("beforerequest", this, o) !== false){
11561             var p = o.params;
11562
11563             if(typeof p == "function"){
11564                 p = p.call(o.scope||window, o);
11565             }
11566             if(typeof p == "object"){
11567                 p = Roo.urlEncode(o.params);
11568             }
11569             if(this.extraParams){
11570                 var extras = Roo.urlEncode(this.extraParams);
11571                 p = p ? (p + '&' + extras) : extras;
11572             }
11573
11574             var url = o.url || this.url;
11575             if(typeof url == 'function'){
11576                 url = url.call(o.scope||window, o);
11577             }
11578
11579             if(o.form){
11580                 var form = Roo.getDom(o.form);
11581                 url = url || form.action;
11582
11583                 var enctype = form.getAttribute("enctype");
11584                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11585                     return this.doFormUpload(o, p, url);
11586                 }
11587                 var f = Roo.lib.Ajax.serializeForm(form);
11588                 p = p ? (p + '&' + f) : f;
11589             }
11590
11591             var hs = o.headers;
11592             if(this.defaultHeaders){
11593                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11594                 if(!o.headers){
11595                     o.headers = hs;
11596                 }
11597             }
11598
11599             var cb = {
11600                 success: this.handleResponse,
11601                 failure: this.handleFailure,
11602                 scope: this,
11603                 argument: {options: o},
11604                 timeout : o.timeout || this.timeout
11605             };
11606
11607             var method = o.method||this.method||(p ? "POST" : "GET");
11608
11609             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11610                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11611             }
11612
11613             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11614                 if(o.autoAbort){
11615                     this.abort();
11616                 }
11617             }else if(this.autoAbort !== false){
11618                 this.abort();
11619             }
11620
11621             if((method == 'GET' && p) || o.xmlData){
11622                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11623                 p = '';
11624             }
11625             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11626             return this.transId;
11627         }else{
11628             Roo.callback(o.callback, o.scope, [o, null, null]);
11629             return null;
11630         }
11631     },
11632
11633     /**
11634      * Determine whether this object has a request outstanding.
11635      * @param {Number} transactionId (Optional) defaults to the last transaction
11636      * @return {Boolean} True if there is an outstanding request.
11637      */
11638     isLoading : function(transId){
11639         if(transId){
11640             return Roo.lib.Ajax.isCallInProgress(transId);
11641         }else{
11642             return this.transId ? true : false;
11643         }
11644     },
11645
11646     /**
11647      * Aborts any outstanding request.
11648      * @param {Number} transactionId (Optional) defaults to the last transaction
11649      */
11650     abort : function(transId){
11651         if(transId || this.isLoading()){
11652             Roo.lib.Ajax.abort(transId || this.transId);
11653         }
11654     },
11655
11656     // private
11657     handleResponse : function(response){
11658         this.transId = false;
11659         var options = response.argument.options;
11660         response.argument = options ? options.argument : null;
11661         this.fireEvent("requestcomplete", this, response, options);
11662         Roo.callback(options.success, options.scope, [response, options]);
11663         Roo.callback(options.callback, options.scope, [options, true, response]);
11664     },
11665
11666     // private
11667     handleFailure : function(response, e){
11668         this.transId = false;
11669         var options = response.argument.options;
11670         response.argument = options ? options.argument : null;
11671         this.fireEvent("requestexception", this, response, options, e);
11672         Roo.callback(options.failure, options.scope, [response, options]);
11673         Roo.callback(options.callback, options.scope, [options, false, response]);
11674     },
11675
11676     // private
11677     doFormUpload : function(o, ps, url){
11678         var id = Roo.id();
11679         var frame = document.createElement('iframe');
11680         frame.id = id;
11681         frame.name = id;
11682         frame.className = 'x-hidden';
11683         if(Roo.isIE){
11684             frame.src = Roo.SSL_SECURE_URL;
11685         }
11686         document.body.appendChild(frame);
11687
11688         if(Roo.isIE){
11689            document.frames[id].name = id;
11690         }
11691
11692         var form = Roo.getDom(o.form);
11693         form.target = id;
11694         form.method = 'POST';
11695         form.enctype = form.encoding = 'multipart/form-data';
11696         if(url){
11697             form.action = url;
11698         }
11699
11700         var hiddens, hd;
11701         if(ps){ // add dynamic params
11702             hiddens = [];
11703             ps = Roo.urlDecode(ps, false);
11704             for(var k in ps){
11705                 if(ps.hasOwnProperty(k)){
11706                     hd = document.createElement('input');
11707                     hd.type = 'hidden';
11708                     hd.name = k;
11709                     hd.value = ps[k];
11710                     form.appendChild(hd);
11711                     hiddens.push(hd);
11712                 }
11713             }
11714         }
11715
11716         function cb(){
11717             var r = {  // bogus response object
11718                 responseText : '',
11719                 responseXML : null
11720             };
11721
11722             r.argument = o ? o.argument : null;
11723
11724             try { //
11725                 var doc;
11726                 if(Roo.isIE){
11727                     doc = frame.contentWindow.document;
11728                 }else {
11729                     doc = (frame.contentDocument || window.frames[id].document);
11730                 }
11731                 if(doc && doc.body){
11732                     r.responseText = doc.body.innerHTML;
11733                 }
11734                 if(doc && doc.XMLDocument){
11735                     r.responseXML = doc.XMLDocument;
11736                 }else {
11737                     r.responseXML = doc;
11738                 }
11739             }
11740             catch(e) {
11741                 // ignore
11742             }
11743
11744             Roo.EventManager.removeListener(frame, 'load', cb, this);
11745
11746             this.fireEvent("requestcomplete", this, r, o);
11747             Roo.callback(o.success, o.scope, [r, o]);
11748             Roo.callback(o.callback, o.scope, [o, true, r]);
11749
11750             setTimeout(function(){document.body.removeChild(frame);}, 100);
11751         }
11752
11753         Roo.EventManager.on(frame, 'load', cb, this);
11754         form.submit();
11755
11756         if(hiddens){ // remove dynamic params
11757             for(var i = 0, len = hiddens.length; i < len; i++){
11758                 form.removeChild(hiddens[i]);
11759             }
11760         }
11761     }
11762 });
11763 /*
11764  * Based on:
11765  * Ext JS Library 1.1.1
11766  * Copyright(c) 2006-2007, Ext JS, LLC.
11767  *
11768  * Originally Released Under LGPL - original licence link has changed is not relivant.
11769  *
11770  * Fork - LGPL
11771  * <script type="text/javascript">
11772  */
11773  
11774 /**
11775  * Global Ajax request class.
11776  * 
11777  * @class Roo.Ajax
11778  * @extends Roo.data.Connection
11779  * @static
11780  * 
11781  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11782  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11783  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11784  * @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)
11785  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11786  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11787  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11788  */
11789 Roo.Ajax = new Roo.data.Connection({
11790     // fix up the docs
11791     /**
11792      * @scope Roo.Ajax
11793      * @type {Boolear} 
11794      */
11795     autoAbort : false,
11796
11797     /**
11798      * Serialize the passed form into a url encoded string
11799      * @scope Roo.Ajax
11800      * @param {String/HTMLElement} form
11801      * @return {String}
11802      */
11803     serializeForm : function(form){
11804         return Roo.lib.Ajax.serializeForm(form);
11805     }
11806 });/*
11807  * Based on:
11808  * Ext JS Library 1.1.1
11809  * Copyright(c) 2006-2007, Ext JS, LLC.
11810  *
11811  * Originally Released Under LGPL - original licence link has changed is not relivant.
11812  *
11813  * Fork - LGPL
11814  * <script type="text/javascript">
11815  */
11816
11817  
11818 /**
11819  * @class Roo.UpdateManager
11820  * @extends Roo.util.Observable
11821  * Provides AJAX-style update for Element object.<br><br>
11822  * Usage:<br>
11823  * <pre><code>
11824  * // Get it from a Roo.Element object
11825  * var el = Roo.get("foo");
11826  * var mgr = el.getUpdateManager();
11827  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11828  * ...
11829  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11830  * <br>
11831  * // or directly (returns the same UpdateManager instance)
11832  * var mgr = new Roo.UpdateManager("myElementId");
11833  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11834  * mgr.on("update", myFcnNeedsToKnow);
11835  * <br>
11836    // short handed call directly from the element object
11837    Roo.get("foo").load({
11838         url: "bar.php",
11839         scripts:true,
11840         params: "for=bar",
11841         text: "Loading Foo..."
11842    });
11843  * </code></pre>
11844  * @constructor
11845  * Create new UpdateManager directly.
11846  * @param {String/HTMLElement/Roo.Element} el The element to update
11847  * @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).
11848  */
11849 Roo.UpdateManager = function(el, forceNew){
11850     el = Roo.get(el);
11851     if(!forceNew && el.updateManager){
11852         return el.updateManager;
11853     }
11854     /**
11855      * The Element object
11856      * @type Roo.Element
11857      */
11858     this.el = el;
11859     /**
11860      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11861      * @type String
11862      */
11863     this.defaultUrl = null;
11864
11865     this.addEvents({
11866         /**
11867          * @event beforeupdate
11868          * Fired before an update is made, return false from your handler and the update is cancelled.
11869          * @param {Roo.Element} el
11870          * @param {String/Object/Function} url
11871          * @param {String/Object} params
11872          */
11873         "beforeupdate": true,
11874         /**
11875          * @event update
11876          * Fired after successful update is made.
11877          * @param {Roo.Element} el
11878          * @param {Object} oResponseObject The response Object
11879          */
11880         "update": true,
11881         /**
11882          * @event failure
11883          * Fired on update failure.
11884          * @param {Roo.Element} el
11885          * @param {Object} oResponseObject The response Object
11886          */
11887         "failure": true
11888     });
11889     var d = Roo.UpdateManager.defaults;
11890     /**
11891      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11892      * @type String
11893      */
11894     this.sslBlankUrl = d.sslBlankUrl;
11895     /**
11896      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11897      * @type Boolean
11898      */
11899     this.disableCaching = d.disableCaching;
11900     /**
11901      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11902      * @type String
11903      */
11904     this.indicatorText = d.indicatorText;
11905     /**
11906      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11907      * @type String
11908      */
11909     this.showLoadIndicator = d.showLoadIndicator;
11910     /**
11911      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11912      * @type Number
11913      */
11914     this.timeout = d.timeout;
11915
11916     /**
11917      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11918      * @type Boolean
11919      */
11920     this.loadScripts = d.loadScripts;
11921
11922     /**
11923      * Transaction object of current executing transaction
11924      */
11925     this.transaction = null;
11926
11927     /**
11928      * @private
11929      */
11930     this.autoRefreshProcId = null;
11931     /**
11932      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11933      * @type Function
11934      */
11935     this.refreshDelegate = this.refresh.createDelegate(this);
11936     /**
11937      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11938      * @type Function
11939      */
11940     this.updateDelegate = this.update.createDelegate(this);
11941     /**
11942      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11943      * @type Function
11944      */
11945     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11946     /**
11947      * @private
11948      */
11949     this.successDelegate = this.processSuccess.createDelegate(this);
11950     /**
11951      * @private
11952      */
11953     this.failureDelegate = this.processFailure.createDelegate(this);
11954
11955     if(!this.renderer){
11956      /**
11957       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11958       */
11959     this.renderer = new Roo.UpdateManager.BasicRenderer();
11960     }
11961     
11962     Roo.UpdateManager.superclass.constructor.call(this);
11963 };
11964
11965 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11966     /**
11967      * Get the Element this UpdateManager is bound to
11968      * @return {Roo.Element} The element
11969      */
11970     getEl : function(){
11971         return this.el;
11972     },
11973     /**
11974      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11975      * @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:
11976 <pre><code>
11977 um.update({<br/>
11978     url: "your-url.php",<br/>
11979     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11980     callback: yourFunction,<br/>
11981     scope: yourObject, //(optional scope)  <br/>
11982     discardUrl: false, <br/>
11983     nocache: false,<br/>
11984     text: "Loading...",<br/>
11985     timeout: 30,<br/>
11986     scripts: false<br/>
11987 });
11988 </code></pre>
11989      * The only required property is url. The optional properties nocache, text and scripts
11990      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11991      * @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}
11992      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11993      * @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.
11994      */
11995     update : function(url, params, callback, discardUrl){
11996         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11997             var method = this.method,
11998                 cfg;
11999             if(typeof url == "object"){ // must be config object
12000                 cfg = url;
12001                 url = cfg.url;
12002                 params = params || cfg.params;
12003                 callback = callback || cfg.callback;
12004                 discardUrl = discardUrl || cfg.discardUrl;
12005                 if(callback && cfg.scope){
12006                     callback = callback.createDelegate(cfg.scope);
12007                 }
12008                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12009                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12010                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12011                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12012                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12013             }
12014             this.showLoading();
12015             if(!discardUrl){
12016                 this.defaultUrl = url;
12017             }
12018             if(typeof url == "function"){
12019                 url = url.call(this);
12020             }
12021
12022             method = method || (params ? "POST" : "GET");
12023             if(method == "GET"){
12024                 url = this.prepareUrl(url);
12025             }
12026
12027             var o = Roo.apply(cfg ||{}, {
12028                 url : url,
12029                 params: params,
12030                 success: this.successDelegate,
12031                 failure: this.failureDelegate,
12032                 callback: undefined,
12033                 timeout: (this.timeout*1000),
12034                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12035             });
12036             Roo.log("updated manager called with timeout of " + o.timeout);
12037             this.transaction = Roo.Ajax.request(o);
12038         }
12039     },
12040
12041     /**
12042      * 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.
12043      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12044      * @param {String/HTMLElement} form The form Id or form element
12045      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12046      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12047      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12048      */
12049     formUpdate : function(form, url, reset, callback){
12050         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12051             if(typeof url == "function"){
12052                 url = url.call(this);
12053             }
12054             form = Roo.getDom(form);
12055             this.transaction = Roo.Ajax.request({
12056                 form: form,
12057                 url:url,
12058                 success: this.successDelegate,
12059                 failure: this.failureDelegate,
12060                 timeout: (this.timeout*1000),
12061                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12062             });
12063             this.showLoading.defer(1, this);
12064         }
12065     },
12066
12067     /**
12068      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12069      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12070      */
12071     refresh : function(callback){
12072         if(this.defaultUrl == null){
12073             return;
12074         }
12075         this.update(this.defaultUrl, null, callback, true);
12076     },
12077
12078     /**
12079      * Set this element to auto refresh.
12080      * @param {Number} interval How often to update (in seconds).
12081      * @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)
12082      * @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}
12083      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12084      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12085      */
12086     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12087         if(refreshNow){
12088             this.update(url || this.defaultUrl, params, callback, true);
12089         }
12090         if(this.autoRefreshProcId){
12091             clearInterval(this.autoRefreshProcId);
12092         }
12093         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12094     },
12095
12096     /**
12097      * Stop auto refresh on this element.
12098      */
12099      stopAutoRefresh : function(){
12100         if(this.autoRefreshProcId){
12101             clearInterval(this.autoRefreshProcId);
12102             delete this.autoRefreshProcId;
12103         }
12104     },
12105
12106     isAutoRefreshing : function(){
12107        return this.autoRefreshProcId ? true : false;
12108     },
12109     /**
12110      * Called to update the element to "Loading" state. Override to perform custom action.
12111      */
12112     showLoading : function(){
12113         if(this.showLoadIndicator){
12114             this.el.update(this.indicatorText);
12115         }
12116     },
12117
12118     /**
12119      * Adds unique parameter to query string if disableCaching = true
12120      * @private
12121      */
12122     prepareUrl : function(url){
12123         if(this.disableCaching){
12124             var append = "_dc=" + (new Date().getTime());
12125             if(url.indexOf("?") !== -1){
12126                 url += "&" + append;
12127             }else{
12128                 url += "?" + append;
12129             }
12130         }
12131         return url;
12132     },
12133
12134     /**
12135      * @private
12136      */
12137     processSuccess : function(response){
12138         this.transaction = null;
12139         if(response.argument.form && response.argument.reset){
12140             try{ // put in try/catch since some older FF releases had problems with this
12141                 response.argument.form.reset();
12142             }catch(e){}
12143         }
12144         if(this.loadScripts){
12145             this.renderer.render(this.el, response, this,
12146                 this.updateComplete.createDelegate(this, [response]));
12147         }else{
12148             this.renderer.render(this.el, response, this);
12149             this.updateComplete(response);
12150         }
12151     },
12152
12153     updateComplete : function(response){
12154         this.fireEvent("update", this.el, response);
12155         if(typeof response.argument.callback == "function"){
12156             response.argument.callback(this.el, true, response);
12157         }
12158     },
12159
12160     /**
12161      * @private
12162      */
12163     processFailure : function(response){
12164         this.transaction = null;
12165         this.fireEvent("failure", this.el, response);
12166         if(typeof response.argument.callback == "function"){
12167             response.argument.callback(this.el, false, response);
12168         }
12169     },
12170
12171     /**
12172      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12173      * @param {Object} renderer The object implementing the render() method
12174      */
12175     setRenderer : function(renderer){
12176         this.renderer = renderer;
12177     },
12178
12179     getRenderer : function(){
12180        return this.renderer;
12181     },
12182
12183     /**
12184      * Set the defaultUrl used for updates
12185      * @param {String/Function} defaultUrl The url or a function to call to get the url
12186      */
12187     setDefaultUrl : function(defaultUrl){
12188         this.defaultUrl = defaultUrl;
12189     },
12190
12191     /**
12192      * Aborts the executing transaction
12193      */
12194     abort : function(){
12195         if(this.transaction){
12196             Roo.Ajax.abort(this.transaction);
12197         }
12198     },
12199
12200     /**
12201      * Returns true if an update is in progress
12202      * @return {Boolean}
12203      */
12204     isUpdating : function(){
12205         if(this.transaction){
12206             return Roo.Ajax.isLoading(this.transaction);
12207         }
12208         return false;
12209     }
12210 });
12211
12212 /**
12213  * @class Roo.UpdateManager.defaults
12214  * @static (not really - but it helps the doc tool)
12215  * The defaults collection enables customizing the default properties of UpdateManager
12216  */
12217    Roo.UpdateManager.defaults = {
12218        /**
12219          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12220          * @type Number
12221          */
12222          timeout : 30,
12223
12224          /**
12225          * True to process scripts by default (Defaults to false).
12226          * @type Boolean
12227          */
12228         loadScripts : false,
12229
12230         /**
12231         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12232         * @type String
12233         */
12234         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12235         /**
12236          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12237          * @type Boolean
12238          */
12239         disableCaching : false,
12240         /**
12241          * Whether to show indicatorText when loading (Defaults to true).
12242          * @type Boolean
12243          */
12244         showLoadIndicator : true,
12245         /**
12246          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12247          * @type String
12248          */
12249         indicatorText : '<div class="loading-indicator">Loading...</div>'
12250    };
12251
12252 /**
12253  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12254  *Usage:
12255  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12256  * @param {String/HTMLElement/Roo.Element} el The element to update
12257  * @param {String} url The url
12258  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12259  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12260  * @static
12261  * @deprecated
12262  * @member Roo.UpdateManager
12263  */
12264 Roo.UpdateManager.updateElement = function(el, url, params, options){
12265     var um = Roo.get(el, true).getUpdateManager();
12266     Roo.apply(um, options);
12267     um.update(url, params, options ? options.callback : null);
12268 };
12269 // alias for backwards compat
12270 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12271 /**
12272  * @class Roo.UpdateManager.BasicRenderer
12273  * Default Content renderer. Updates the elements innerHTML with the responseText.
12274  */
12275 Roo.UpdateManager.BasicRenderer = function(){};
12276
12277 Roo.UpdateManager.BasicRenderer.prototype = {
12278     /**
12279      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12280      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12281      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12282      * @param {Roo.Element} el The element being rendered
12283      * @param {Object} response The YUI Connect response object
12284      * @param {UpdateManager} updateManager The calling update manager
12285      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12286      */
12287      render : function(el, response, updateManager, callback){
12288         el.update(response.responseText, updateManager.loadScripts, callback);
12289     }
12290 };
12291 /*
12292  * Based on:
12293  * Roo JS
12294  * (c)) Alan Knowles
12295  * Licence : LGPL
12296  */
12297
12298
12299 /**
12300  * @class Roo.DomTemplate
12301  * @extends Roo.Template
12302  * An effort at a dom based template engine..
12303  *
12304  * Similar to XTemplate, except it uses dom parsing to create the template..
12305  *
12306  * Supported features:
12307  *
12308  *  Tags:
12309
12310 <pre><code>
12311       {a_variable} - output encoded.
12312       {a_variable.format:("Y-m-d")} - call a method on the variable
12313       {a_variable:raw} - unencoded output
12314       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12315       {a_variable:this.method_on_template(...)} - call a method on the template object.
12316  
12317 </code></pre>
12318  *  The tpl tag:
12319 <pre><code>
12320         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12321         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12322         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12323         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12324   
12325 </code></pre>
12326  *      
12327  */
12328 Roo.DomTemplate = function()
12329 {
12330      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12331      if (this.html) {
12332         this.compile();
12333      }
12334 };
12335
12336
12337 Roo.extend(Roo.DomTemplate, Roo.Template, {
12338     /**
12339      * id counter for sub templates.
12340      */
12341     id : 0,
12342     /**
12343      * flag to indicate if dom parser is inside a pre,
12344      * it will strip whitespace if not.
12345      */
12346     inPre : false,
12347     
12348     /**
12349      * The various sub templates
12350      */
12351     tpls : false,
12352     
12353     
12354     
12355     /**
12356      *
12357      * basic tag replacing syntax
12358      * WORD:WORD()
12359      *
12360      * // you can fake an object call by doing this
12361      *  x.t:(test,tesT) 
12362      * 
12363      */
12364     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12365     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12366     
12367     iterChild : function (node, method) {
12368         
12369         var oldPre = this.inPre;
12370         if (node.tagName == 'PRE') {
12371             this.inPre = true;
12372         }
12373         for( var i = 0; i < node.childNodes.length; i++) {
12374             method.call(this, node.childNodes[i]);
12375         }
12376         this.inPre = oldPre;
12377     },
12378     
12379     
12380     
12381     /**
12382      * compile the template
12383      *
12384      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12385      *
12386      */
12387     compile: function()
12388     {
12389         var s = this.html;
12390         
12391         // covert the html into DOM...
12392         var doc = false;
12393         var div =false;
12394         try {
12395             doc = document.implementation.createHTMLDocument("");
12396             doc.documentElement.innerHTML =   this.html  ;
12397             div = doc.documentElement;
12398         } catch (e) {
12399             // old IE... - nasty -- it causes all sorts of issues.. with
12400             // images getting pulled from server..
12401             div = document.createElement('div');
12402             div.innerHTML = this.html;
12403         }
12404         //doc.documentElement.innerHTML = htmlBody
12405          
12406         
12407         
12408         this.tpls = [];
12409         var _t = this;
12410         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12411         
12412         var tpls = this.tpls;
12413         
12414         // create a top level template from the snippet..
12415         
12416         //Roo.log(div.innerHTML);
12417         
12418         var tpl = {
12419             uid : 'master',
12420             id : this.id++,
12421             attr : false,
12422             value : false,
12423             body : div.innerHTML,
12424             
12425             forCall : false,
12426             execCall : false,
12427             dom : div,
12428             isTop : true
12429             
12430         };
12431         tpls.unshift(tpl);
12432         
12433         
12434         // compile them...
12435         this.tpls = [];
12436         Roo.each(tpls, function(tp){
12437             this.compileTpl(tp);
12438             this.tpls[tp.id] = tp;
12439         }, this);
12440         
12441         this.master = tpls[0];
12442         return this;
12443         
12444         
12445     },
12446     
12447     compileNode : function(node, istop) {
12448         // test for
12449         //Roo.log(node);
12450         
12451         
12452         // skip anything not a tag..
12453         if (node.nodeType != 1) {
12454             if (node.nodeType == 3 && !this.inPre) {
12455                 // reduce white space..
12456                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12457                 
12458             }
12459             return;
12460         }
12461         
12462         var tpl = {
12463             uid : false,
12464             id : false,
12465             attr : false,
12466             value : false,
12467             body : '',
12468             
12469             forCall : false,
12470             execCall : false,
12471             dom : false,
12472             isTop : istop
12473             
12474             
12475         };
12476         
12477         
12478         switch(true) {
12479             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12480             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12481             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12482             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12483             // no default..
12484         }
12485         
12486         
12487         if (!tpl.attr) {
12488             // just itterate children..
12489             this.iterChild(node,this.compileNode);
12490             return;
12491         }
12492         tpl.uid = this.id++;
12493         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12494         node.removeAttribute('roo-'+ tpl.attr);
12495         if (tpl.attr != 'name') {
12496             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12497             node.parentNode.replaceChild(placeholder,  node);
12498         } else {
12499             
12500             var placeholder =  document.createElement('span');
12501             placeholder.className = 'roo-tpl-' + tpl.value;
12502             node.parentNode.replaceChild(placeholder,  node);
12503         }
12504         
12505         // parent now sees '{domtplXXXX}
12506         this.iterChild(node,this.compileNode);
12507         
12508         // we should now have node body...
12509         var div = document.createElement('div');
12510         div.appendChild(node);
12511         tpl.dom = node;
12512         // this has the unfortunate side effect of converting tagged attributes
12513         // eg. href="{...}" into %7C...%7D
12514         // this has been fixed by searching for those combo's although it's a bit hacky..
12515         
12516         
12517         tpl.body = div.innerHTML;
12518         
12519         
12520          
12521         tpl.id = tpl.uid;
12522         switch(tpl.attr) {
12523             case 'for' :
12524                 switch (tpl.value) {
12525                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12526                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12527                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12528                 }
12529                 break;
12530             
12531             case 'exec':
12532                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12533                 break;
12534             
12535             case 'if':     
12536                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12537                 break;
12538             
12539             case 'name':
12540                 tpl.id  = tpl.value; // replace non characters???
12541                 break;
12542             
12543         }
12544         
12545         
12546         this.tpls.push(tpl);
12547         
12548         
12549         
12550     },
12551     
12552     
12553     
12554     
12555     /**
12556      * Compile a segment of the template into a 'sub-template'
12557      *
12558      * 
12559      * 
12560      *
12561      */
12562     compileTpl : function(tpl)
12563     {
12564         var fm = Roo.util.Format;
12565         var useF = this.disableFormats !== true;
12566         
12567         var sep = Roo.isGecko ? "+\n" : ",\n";
12568         
12569         var undef = function(str) {
12570             Roo.debug && Roo.log("Property not found :"  + str);
12571             return '';
12572         };
12573           
12574         //Roo.log(tpl.body);
12575         
12576         
12577         
12578         var fn = function(m, lbrace, name, format, args)
12579         {
12580             //Roo.log("ARGS");
12581             //Roo.log(arguments);
12582             args = args ? args.replace(/\\'/g,"'") : args;
12583             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12584             if (typeof(format) == 'undefined') {
12585                 format =  'htmlEncode'; 
12586             }
12587             if (format == 'raw' ) {
12588                 format = false;
12589             }
12590             
12591             if(name.substr(0, 6) == 'domtpl'){
12592                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12593             }
12594             
12595             // build an array of options to determine if value is undefined..
12596             
12597             // basically get 'xxxx.yyyy' then do
12598             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12599             //    (function () { Roo.log("Property not found"); return ''; })() :
12600             //    ......
12601             
12602             var udef_ar = [];
12603             var lookfor = '';
12604             Roo.each(name.split('.'), function(st) {
12605                 lookfor += (lookfor.length ? '.': '') + st;
12606                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12607             });
12608             
12609             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12610             
12611             
12612             if(format && useF){
12613                 
12614                 args = args ? ',' + args : "";
12615                  
12616                 if(format.substr(0, 5) != "this."){
12617                     format = "fm." + format + '(';
12618                 }else{
12619                     format = 'this.call("'+ format.substr(5) + '", ';
12620                     args = ", values";
12621                 }
12622                 
12623                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12624             }
12625              
12626             if (args && args.length) {
12627                 // called with xxyx.yuu:(test,test)
12628                 // change to ()
12629                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12630             }
12631             // raw.. - :raw modifier..
12632             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12633             
12634         };
12635         var body;
12636         // branched to use + in gecko and [].join() in others
12637         if(Roo.isGecko){
12638             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12639                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12640                     "';};};";
12641         }else{
12642             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12643             body.push(tpl.body.replace(/(\r\n|\n)/g,
12644                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12645             body.push("'].join('');};};");
12646             body = body.join('');
12647         }
12648         
12649         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12650        
12651         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12652         eval(body);
12653         
12654         return this;
12655     },
12656      
12657     /**
12658      * same as applyTemplate, except it's done to one of the subTemplates
12659      * when using named templates, you can do:
12660      *
12661      * var str = pl.applySubTemplate('your-name', values);
12662      *
12663      * 
12664      * @param {Number} id of the template
12665      * @param {Object} values to apply to template
12666      * @param {Object} parent (normaly the instance of this object)
12667      */
12668     applySubTemplate : function(id, values, parent)
12669     {
12670         
12671         
12672         var t = this.tpls[id];
12673         
12674         
12675         try { 
12676             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12677                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12678                 return '';
12679             }
12680         } catch(e) {
12681             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12682             Roo.log(values);
12683           
12684             return '';
12685         }
12686         try { 
12687             
12688             if(t.execCall && t.execCall.call(this, values, parent)){
12689                 return '';
12690             }
12691         } catch(e) {
12692             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12693             Roo.log(values);
12694             return '';
12695         }
12696         
12697         try {
12698             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12699             parent = t.target ? values : parent;
12700             if(t.forCall && vs instanceof Array){
12701                 var buf = [];
12702                 for(var i = 0, len = vs.length; i < len; i++){
12703                     try {
12704                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12705                     } catch (e) {
12706                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12707                         Roo.log(e.body);
12708                         //Roo.log(t.compiled);
12709                         Roo.log(vs[i]);
12710                     }   
12711                 }
12712                 return buf.join('');
12713             }
12714         } catch (e) {
12715             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12716             Roo.log(values);
12717             return '';
12718         }
12719         try {
12720             return t.compiled.call(this, vs, parent);
12721         } catch (e) {
12722             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12723             Roo.log(e.body);
12724             //Roo.log(t.compiled);
12725             Roo.log(values);
12726             return '';
12727         }
12728     },
12729
12730    
12731
12732     applyTemplate : function(values){
12733         return this.master.compiled.call(this, values, {});
12734         //var s = this.subs;
12735     },
12736
12737     apply : function(){
12738         return this.applyTemplate.apply(this, arguments);
12739     }
12740
12741  });
12742
12743 Roo.DomTemplate.from = function(el){
12744     el = Roo.getDom(el);
12745     return new Roo.Domtemplate(el.value || el.innerHTML);
12746 };/*
12747  * Based on:
12748  * Ext JS Library 1.1.1
12749  * Copyright(c) 2006-2007, Ext JS, LLC.
12750  *
12751  * Originally Released Under LGPL - original licence link has changed is not relivant.
12752  *
12753  * Fork - LGPL
12754  * <script type="text/javascript">
12755  */
12756
12757 /**
12758  * @class Roo.util.DelayedTask
12759  * Provides a convenient method of performing setTimeout where a new
12760  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12761  * You can use this class to buffer
12762  * the keypress events for a certain number of milliseconds, and perform only if they stop
12763  * for that amount of time.
12764  * @constructor The parameters to this constructor serve as defaults and are not required.
12765  * @param {Function} fn (optional) The default function to timeout
12766  * @param {Object} scope (optional) The default scope of that timeout
12767  * @param {Array} args (optional) The default Array of arguments
12768  */
12769 Roo.util.DelayedTask = function(fn, scope, args){
12770     var id = null, d, t;
12771
12772     var call = function(){
12773         var now = new Date().getTime();
12774         if(now - t >= d){
12775             clearInterval(id);
12776             id = null;
12777             fn.apply(scope, args || []);
12778         }
12779     };
12780     /**
12781      * Cancels any pending timeout and queues a new one
12782      * @param {Number} delay The milliseconds to delay
12783      * @param {Function} newFn (optional) Overrides function passed to constructor
12784      * @param {Object} newScope (optional) Overrides scope passed to constructor
12785      * @param {Array} newArgs (optional) Overrides args passed to constructor
12786      */
12787     this.delay = function(delay, newFn, newScope, newArgs){
12788         if(id && delay != d){
12789             this.cancel();
12790         }
12791         d = delay;
12792         t = new Date().getTime();
12793         fn = newFn || fn;
12794         scope = newScope || scope;
12795         args = newArgs || args;
12796         if(!id){
12797             id = setInterval(call, d);
12798         }
12799     };
12800
12801     /**
12802      * Cancel the last queued timeout
12803      */
12804     this.cancel = function(){
12805         if(id){
12806             clearInterval(id);
12807             id = null;
12808         }
12809     };
12810 };/*
12811  * Based on:
12812  * Ext JS Library 1.1.1
12813  * Copyright(c) 2006-2007, Ext JS, LLC.
12814  *
12815  * Originally Released Under LGPL - original licence link has changed is not relivant.
12816  *
12817  * Fork - LGPL
12818  * <script type="text/javascript">
12819  */
12820  
12821  
12822 Roo.util.TaskRunner = function(interval){
12823     interval = interval || 10;
12824     var tasks = [], removeQueue = [];
12825     var id = 0;
12826     var running = false;
12827
12828     var stopThread = function(){
12829         running = false;
12830         clearInterval(id);
12831         id = 0;
12832     };
12833
12834     var startThread = function(){
12835         if(!running){
12836             running = true;
12837             id = setInterval(runTasks, interval);
12838         }
12839     };
12840
12841     var removeTask = function(task){
12842         removeQueue.push(task);
12843         if(task.onStop){
12844             task.onStop();
12845         }
12846     };
12847
12848     var runTasks = function(){
12849         if(removeQueue.length > 0){
12850             for(var i = 0, len = removeQueue.length; i < len; i++){
12851                 tasks.remove(removeQueue[i]);
12852             }
12853             removeQueue = [];
12854             if(tasks.length < 1){
12855                 stopThread();
12856                 return;
12857             }
12858         }
12859         var now = new Date().getTime();
12860         for(var i = 0, len = tasks.length; i < len; ++i){
12861             var t = tasks[i];
12862             var itime = now - t.taskRunTime;
12863             if(t.interval <= itime){
12864                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12865                 t.taskRunTime = now;
12866                 if(rt === false || t.taskRunCount === t.repeat){
12867                     removeTask(t);
12868                     return;
12869                 }
12870             }
12871             if(t.duration && t.duration <= (now - t.taskStartTime)){
12872                 removeTask(t);
12873             }
12874         }
12875     };
12876
12877     /**
12878      * Queues a new task.
12879      * @param {Object} task
12880      */
12881     this.start = function(task){
12882         tasks.push(task);
12883         task.taskStartTime = new Date().getTime();
12884         task.taskRunTime = 0;
12885         task.taskRunCount = 0;
12886         startThread();
12887         return task;
12888     };
12889
12890     this.stop = function(task){
12891         removeTask(task);
12892         return task;
12893     };
12894
12895     this.stopAll = function(){
12896         stopThread();
12897         for(var i = 0, len = tasks.length; i < len; i++){
12898             if(tasks[i].onStop){
12899                 tasks[i].onStop();
12900             }
12901         }
12902         tasks = [];
12903         removeQueue = [];
12904     };
12905 };
12906
12907 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12908  * Based on:
12909  * Ext JS Library 1.1.1
12910  * Copyright(c) 2006-2007, Ext JS, LLC.
12911  *
12912  * Originally Released Under LGPL - original licence link has changed is not relivant.
12913  *
12914  * Fork - LGPL
12915  * <script type="text/javascript">
12916  */
12917
12918  
12919 /**
12920  * @class Roo.util.MixedCollection
12921  * @extends Roo.util.Observable
12922  * A Collection class that maintains both numeric indexes and keys and exposes events.
12923  * @constructor
12924  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12925  * collection (defaults to false)
12926  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12927  * and return the key value for that item.  This is used when available to look up the key on items that
12928  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12929  * equivalent to providing an implementation for the {@link #getKey} method.
12930  */
12931 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12932     this.items = [];
12933     this.map = {};
12934     this.keys = [];
12935     this.length = 0;
12936     this.addEvents({
12937         /**
12938          * @event clear
12939          * Fires when the collection is cleared.
12940          */
12941         "clear" : true,
12942         /**
12943          * @event add
12944          * Fires when an item is added to the collection.
12945          * @param {Number} index The index at which the item was added.
12946          * @param {Object} o The item added.
12947          * @param {String} key The key associated with the added item.
12948          */
12949         "add" : true,
12950         /**
12951          * @event replace
12952          * Fires when an item is replaced in the collection.
12953          * @param {String} key he key associated with the new added.
12954          * @param {Object} old The item being replaced.
12955          * @param {Object} new The new item.
12956          */
12957         "replace" : true,
12958         /**
12959          * @event remove
12960          * Fires when an item is removed from the collection.
12961          * @param {Object} o The item being removed.
12962          * @param {String} key (optional) The key associated with the removed item.
12963          */
12964         "remove" : true,
12965         "sort" : true
12966     });
12967     this.allowFunctions = allowFunctions === true;
12968     if(keyFn){
12969         this.getKey = keyFn;
12970     }
12971     Roo.util.MixedCollection.superclass.constructor.call(this);
12972 };
12973
12974 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12975     allowFunctions : false,
12976     
12977 /**
12978  * Adds an item to the collection.
12979  * @param {String} key The key to associate with the item
12980  * @param {Object} o The item to add.
12981  * @return {Object} The item added.
12982  */
12983     add : function(key, o){
12984         if(arguments.length == 1){
12985             o = arguments[0];
12986             key = this.getKey(o);
12987         }
12988         if(typeof key == "undefined" || key === null){
12989             this.length++;
12990             this.items.push(o);
12991             this.keys.push(null);
12992         }else{
12993             var old = this.map[key];
12994             if(old){
12995                 return this.replace(key, o);
12996             }
12997             this.length++;
12998             this.items.push(o);
12999             this.map[key] = o;
13000             this.keys.push(key);
13001         }
13002         this.fireEvent("add", this.length-1, o, key);
13003         return o;
13004     },
13005        
13006 /**
13007   * MixedCollection has a generic way to fetch keys if you implement getKey.
13008 <pre><code>
13009 // normal way
13010 var mc = new Roo.util.MixedCollection();
13011 mc.add(someEl.dom.id, someEl);
13012 mc.add(otherEl.dom.id, otherEl);
13013 //and so on
13014
13015 // using getKey
13016 var mc = new Roo.util.MixedCollection();
13017 mc.getKey = function(el){
13018    return el.dom.id;
13019 };
13020 mc.add(someEl);
13021 mc.add(otherEl);
13022
13023 // or via the constructor
13024 var mc = new Roo.util.MixedCollection(false, function(el){
13025    return el.dom.id;
13026 });
13027 mc.add(someEl);
13028 mc.add(otherEl);
13029 </code></pre>
13030  * @param o {Object} The item for which to find the key.
13031  * @return {Object} The key for the passed item.
13032  */
13033     getKey : function(o){
13034          return o.id; 
13035     },
13036    
13037 /**
13038  * Replaces an item in the collection.
13039  * @param {String} key The key associated with the item to replace, or the item to replace.
13040  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13041  * @return {Object}  The new item.
13042  */
13043     replace : function(key, o){
13044         if(arguments.length == 1){
13045             o = arguments[0];
13046             key = this.getKey(o);
13047         }
13048         var old = this.item(key);
13049         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13050              return this.add(key, o);
13051         }
13052         var index = this.indexOfKey(key);
13053         this.items[index] = o;
13054         this.map[key] = o;
13055         this.fireEvent("replace", key, old, o);
13056         return o;
13057     },
13058    
13059 /**
13060  * Adds all elements of an Array or an Object to the collection.
13061  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13062  * an Array of values, each of which are added to the collection.
13063  */
13064     addAll : function(objs){
13065         if(arguments.length > 1 || objs instanceof Array){
13066             var args = arguments.length > 1 ? arguments : objs;
13067             for(var i = 0, len = args.length; i < len; i++){
13068                 this.add(args[i]);
13069             }
13070         }else{
13071             for(var key in objs){
13072                 if(this.allowFunctions || typeof objs[key] != "function"){
13073                     this.add(key, objs[key]);
13074                 }
13075             }
13076         }
13077     },
13078    
13079 /**
13080  * Executes the specified function once for every item in the collection, passing each
13081  * item as the first and only parameter. returning false from the function will stop the iteration.
13082  * @param {Function} fn The function to execute for each item.
13083  * @param {Object} scope (optional) The scope in which to execute the function.
13084  */
13085     each : function(fn, scope){
13086         var items = [].concat(this.items); // each safe for removal
13087         for(var i = 0, len = items.length; i < len; i++){
13088             if(fn.call(scope || items[i], items[i], i, len) === false){
13089                 break;
13090             }
13091         }
13092     },
13093    
13094 /**
13095  * Executes the specified function once for every key in the collection, passing each
13096  * key, and its associated item as the first two parameters.
13097  * @param {Function} fn The function to execute for each item.
13098  * @param {Object} scope (optional) The scope in which to execute the function.
13099  */
13100     eachKey : function(fn, scope){
13101         for(var i = 0, len = this.keys.length; i < len; i++){
13102             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13103         }
13104     },
13105    
13106 /**
13107  * Returns the first item in the collection which elicits a true return value from the
13108  * passed selection function.
13109  * @param {Function} fn The selection function to execute for each item.
13110  * @param {Object} scope (optional) The scope in which to execute the function.
13111  * @return {Object} The first item in the collection which returned true from the selection function.
13112  */
13113     find : function(fn, scope){
13114         for(var i = 0, len = this.items.length; i < len; i++){
13115             if(fn.call(scope || window, this.items[i], this.keys[i])){
13116                 return this.items[i];
13117             }
13118         }
13119         return null;
13120     },
13121    
13122 /**
13123  * Inserts an item at the specified index in the collection.
13124  * @param {Number} index The index to insert the item at.
13125  * @param {String} key The key to associate with the new item, or the item itself.
13126  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13127  * @return {Object} The item inserted.
13128  */
13129     insert : function(index, key, o){
13130         if(arguments.length == 2){
13131             o = arguments[1];
13132             key = this.getKey(o);
13133         }
13134         if(index >= this.length){
13135             return this.add(key, o);
13136         }
13137         this.length++;
13138         this.items.splice(index, 0, o);
13139         if(typeof key != "undefined" && key != null){
13140             this.map[key] = o;
13141         }
13142         this.keys.splice(index, 0, key);
13143         this.fireEvent("add", index, o, key);
13144         return o;
13145     },
13146    
13147 /**
13148  * Removed an item from the collection.
13149  * @param {Object} o The item to remove.
13150  * @return {Object} The item removed.
13151  */
13152     remove : function(o){
13153         return this.removeAt(this.indexOf(o));
13154     },
13155    
13156 /**
13157  * Remove an item from a specified index in the collection.
13158  * @param {Number} index The index within the collection of the item to remove.
13159  */
13160     removeAt : function(index){
13161         if(index < this.length && index >= 0){
13162             this.length--;
13163             var o = this.items[index];
13164             this.items.splice(index, 1);
13165             var key = this.keys[index];
13166             if(typeof key != "undefined"){
13167                 delete this.map[key];
13168             }
13169             this.keys.splice(index, 1);
13170             this.fireEvent("remove", o, key);
13171         }
13172     },
13173    
13174 /**
13175  * Removed an item associated with the passed key fom the collection.
13176  * @param {String} key The key of the item to remove.
13177  */
13178     removeKey : function(key){
13179         return this.removeAt(this.indexOfKey(key));
13180     },
13181    
13182 /**
13183  * Returns the number of items in the collection.
13184  * @return {Number} the number of items in the collection.
13185  */
13186     getCount : function(){
13187         return this.length; 
13188     },
13189    
13190 /**
13191  * Returns index within the collection of the passed Object.
13192  * @param {Object} o The item to find the index of.
13193  * @return {Number} index of the item.
13194  */
13195     indexOf : function(o){
13196         if(!this.items.indexOf){
13197             for(var i = 0, len = this.items.length; i < len; i++){
13198                 if(this.items[i] == o) {
13199                     return i;
13200                 }
13201             }
13202             return -1;
13203         }else{
13204             return this.items.indexOf(o);
13205         }
13206     },
13207    
13208 /**
13209  * Returns index within the collection of the passed key.
13210  * @param {String} key The key to find the index of.
13211  * @return {Number} index of the key.
13212  */
13213     indexOfKey : function(key){
13214         if(!this.keys.indexOf){
13215             for(var i = 0, len = this.keys.length; i < len; i++){
13216                 if(this.keys[i] == key) {
13217                     return i;
13218                 }
13219             }
13220             return -1;
13221         }else{
13222             return this.keys.indexOf(key);
13223         }
13224     },
13225    
13226 /**
13227  * Returns the item associated with the passed key OR index. Key has priority over index.
13228  * @param {String/Number} key The key or index of the item.
13229  * @return {Object} The item associated with the passed key.
13230  */
13231     item : function(key){
13232         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13233         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13234     },
13235     
13236 /**
13237  * Returns the item at the specified index.
13238  * @param {Number} index The index of the item.
13239  * @return {Object}
13240  */
13241     itemAt : function(index){
13242         return this.items[index];
13243     },
13244     
13245 /**
13246  * Returns the item associated with the passed key.
13247  * @param {String/Number} key The key of the item.
13248  * @return {Object} The item associated with the passed key.
13249  */
13250     key : function(key){
13251         return this.map[key];
13252     },
13253    
13254 /**
13255  * Returns true if the collection contains the passed Object as an item.
13256  * @param {Object} o  The Object to look for in the collection.
13257  * @return {Boolean} True if the collection contains the Object as an item.
13258  */
13259     contains : function(o){
13260         return this.indexOf(o) != -1;
13261     },
13262    
13263 /**
13264  * Returns true if the collection contains the passed Object as a key.
13265  * @param {String} key The key to look for in the collection.
13266  * @return {Boolean} True if the collection contains the Object as a key.
13267  */
13268     containsKey : function(key){
13269         return typeof this.map[key] != "undefined";
13270     },
13271    
13272 /**
13273  * Removes all items from the collection.
13274  */
13275     clear : function(){
13276         this.length = 0;
13277         this.items = [];
13278         this.keys = [];
13279         this.map = {};
13280         this.fireEvent("clear");
13281     },
13282    
13283 /**
13284  * Returns the first item in the collection.
13285  * @return {Object} the first item in the collection..
13286  */
13287     first : function(){
13288         return this.items[0]; 
13289     },
13290    
13291 /**
13292  * Returns the last item in the collection.
13293  * @return {Object} the last item in the collection..
13294  */
13295     last : function(){
13296         return this.items[this.length-1];   
13297     },
13298     
13299     _sort : function(property, dir, fn){
13300         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13301         fn = fn || function(a, b){
13302             return a-b;
13303         };
13304         var c = [], k = this.keys, items = this.items;
13305         for(var i = 0, len = items.length; i < len; i++){
13306             c[c.length] = {key: k[i], value: items[i], index: i};
13307         }
13308         c.sort(function(a, b){
13309             var v = fn(a[property], b[property]) * dsc;
13310             if(v == 0){
13311                 v = (a.index < b.index ? -1 : 1);
13312             }
13313             return v;
13314         });
13315         for(var i = 0, len = c.length; i < len; i++){
13316             items[i] = c[i].value;
13317             k[i] = c[i].key;
13318         }
13319         this.fireEvent("sort", this);
13320     },
13321     
13322     /**
13323      * Sorts this collection with the passed comparison function
13324      * @param {String} direction (optional) "ASC" or "DESC"
13325      * @param {Function} fn (optional) comparison function
13326      */
13327     sort : function(dir, fn){
13328         this._sort("value", dir, fn);
13329     },
13330     
13331     /**
13332      * Sorts this collection by keys
13333      * @param {String} direction (optional) "ASC" or "DESC"
13334      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13335      */
13336     keySort : function(dir, fn){
13337         this._sort("key", dir, fn || function(a, b){
13338             return String(a).toUpperCase()-String(b).toUpperCase();
13339         });
13340     },
13341     
13342     /**
13343      * Returns a range of items in this collection
13344      * @param {Number} startIndex (optional) defaults to 0
13345      * @param {Number} endIndex (optional) default to the last item
13346      * @return {Array} An array of items
13347      */
13348     getRange : function(start, end){
13349         var items = this.items;
13350         if(items.length < 1){
13351             return [];
13352         }
13353         start = start || 0;
13354         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13355         var r = [];
13356         if(start <= end){
13357             for(var i = start; i <= end; i++) {
13358                     r[r.length] = items[i];
13359             }
13360         }else{
13361             for(var i = start; i >= end; i--) {
13362                     r[r.length] = items[i];
13363             }
13364         }
13365         return r;
13366     },
13367         
13368     /**
13369      * Filter the <i>objects</i> in this collection by a specific property. 
13370      * Returns a new collection that has been filtered.
13371      * @param {String} property A property on your objects
13372      * @param {String/RegExp} value Either string that the property values 
13373      * should start with or a RegExp to test against the property
13374      * @return {MixedCollection} The new filtered collection
13375      */
13376     filter : function(property, value){
13377         if(!value.exec){ // not a regex
13378             value = String(value);
13379             if(value.length == 0){
13380                 return this.clone();
13381             }
13382             value = new RegExp("^" + Roo.escapeRe(value), "i");
13383         }
13384         return this.filterBy(function(o){
13385             return o && value.test(o[property]);
13386         });
13387         },
13388     
13389     /**
13390      * Filter by a function. * Returns a new collection that has been filtered.
13391      * The passed function will be called with each 
13392      * object in the collection. If the function returns true, the value is included 
13393      * otherwise it is filtered.
13394      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13395      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13396      * @return {MixedCollection} The new filtered collection
13397      */
13398     filterBy : function(fn, scope){
13399         var r = new Roo.util.MixedCollection();
13400         r.getKey = this.getKey;
13401         var k = this.keys, it = this.items;
13402         for(var i = 0, len = it.length; i < len; i++){
13403             if(fn.call(scope||this, it[i], k[i])){
13404                                 r.add(k[i], it[i]);
13405                         }
13406         }
13407         return r;
13408     },
13409     
13410     /**
13411      * Creates a duplicate of this collection
13412      * @return {MixedCollection}
13413      */
13414     clone : function(){
13415         var r = new Roo.util.MixedCollection();
13416         var k = this.keys, it = this.items;
13417         for(var i = 0, len = it.length; i < len; i++){
13418             r.add(k[i], it[i]);
13419         }
13420         r.getKey = this.getKey;
13421         return r;
13422     }
13423 });
13424 /**
13425  * Returns the item associated with the passed key or index.
13426  * @method
13427  * @param {String/Number} key The key or index of the item.
13428  * @return {Object} The item associated with the passed key.
13429  */
13430 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13431  * Based on:
13432  * Ext JS Library 1.1.1
13433  * Copyright(c) 2006-2007, Ext JS, LLC.
13434  *
13435  * Originally Released Under LGPL - original licence link has changed is not relivant.
13436  *
13437  * Fork - LGPL
13438  * <script type="text/javascript">
13439  */
13440 /**
13441  * @class Roo.util.JSON
13442  * Modified version of Douglas Crockford"s json.js that doesn"t
13443  * mess with the Object prototype 
13444  * http://www.json.org/js.html
13445  * @singleton
13446  */
13447 Roo.util.JSON = new (function(){
13448     var useHasOwn = {}.hasOwnProperty ? true : false;
13449     
13450     // crashes Safari in some instances
13451     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13452     
13453     var pad = function(n) {
13454         return n < 10 ? "0" + n : n;
13455     };
13456     
13457     var m = {
13458         "\b": '\\b',
13459         "\t": '\\t',
13460         "\n": '\\n',
13461         "\f": '\\f',
13462         "\r": '\\r',
13463         '"' : '\\"',
13464         "\\": '\\\\'
13465     };
13466
13467     var encodeString = function(s){
13468         if (/["\\\x00-\x1f]/.test(s)) {
13469             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13470                 var c = m[b];
13471                 if(c){
13472                     return c;
13473                 }
13474                 c = b.charCodeAt();
13475                 return "\\u00" +
13476                     Math.floor(c / 16).toString(16) +
13477                     (c % 16).toString(16);
13478             }) + '"';
13479         }
13480         return '"' + s + '"';
13481     };
13482     
13483     var encodeArray = function(o){
13484         var a = ["["], b, i, l = o.length, v;
13485             for (i = 0; i < l; i += 1) {
13486                 v = o[i];
13487                 switch (typeof v) {
13488                     case "undefined":
13489                     case "function":
13490                     case "unknown":
13491                         break;
13492                     default:
13493                         if (b) {
13494                             a.push(',');
13495                         }
13496                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13497                         b = true;
13498                 }
13499             }
13500             a.push("]");
13501             return a.join("");
13502     };
13503     
13504     var encodeDate = function(o){
13505         return '"' + o.getFullYear() + "-" +
13506                 pad(o.getMonth() + 1) + "-" +
13507                 pad(o.getDate()) + "T" +
13508                 pad(o.getHours()) + ":" +
13509                 pad(o.getMinutes()) + ":" +
13510                 pad(o.getSeconds()) + '"';
13511     };
13512     
13513     /**
13514      * Encodes an Object, Array or other value
13515      * @param {Mixed} o The variable to encode
13516      * @return {String} The JSON string
13517      */
13518     this.encode = function(o)
13519     {
13520         // should this be extended to fully wrap stringify..
13521         
13522         if(typeof o == "undefined" || o === null){
13523             return "null";
13524         }else if(o instanceof Array){
13525             return encodeArray(o);
13526         }else if(o instanceof Date){
13527             return encodeDate(o);
13528         }else if(typeof o == "string"){
13529             return encodeString(o);
13530         }else if(typeof o == "number"){
13531             return isFinite(o) ? String(o) : "null";
13532         }else if(typeof o == "boolean"){
13533             return String(o);
13534         }else {
13535             var a = ["{"], b, i, v;
13536             for (i in o) {
13537                 if(!useHasOwn || o.hasOwnProperty(i)) {
13538                     v = o[i];
13539                     switch (typeof v) {
13540                     case "undefined":
13541                     case "function":
13542                     case "unknown":
13543                         break;
13544                     default:
13545                         if(b){
13546                             a.push(',');
13547                         }
13548                         a.push(this.encode(i), ":",
13549                                 v === null ? "null" : this.encode(v));
13550                         b = true;
13551                     }
13552                 }
13553             }
13554             a.push("}");
13555             return a.join("");
13556         }
13557     };
13558     
13559     /**
13560      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13561      * @param {String} json The JSON string
13562      * @return {Object} The resulting object
13563      */
13564     this.decode = function(json){
13565         
13566         return  /** eval:var:json */ eval("(" + json + ')');
13567     };
13568 })();
13569 /** 
13570  * Shorthand for {@link Roo.util.JSON#encode}
13571  * @member Roo encode 
13572  * @method */
13573 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13574 /** 
13575  * Shorthand for {@link Roo.util.JSON#decode}
13576  * @member Roo decode 
13577  * @method */
13578 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13579 /*
13580  * Based on:
13581  * Ext JS Library 1.1.1
13582  * Copyright(c) 2006-2007, Ext JS, LLC.
13583  *
13584  * Originally Released Under LGPL - original licence link has changed is not relivant.
13585  *
13586  * Fork - LGPL
13587  * <script type="text/javascript">
13588  */
13589  
13590 /**
13591  * @class Roo.util.Format
13592  * Reusable data formatting functions
13593  * @singleton
13594  */
13595 Roo.util.Format = function(){
13596     var trimRe = /^\s+|\s+$/g;
13597     return {
13598         /**
13599          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13600          * @param {String} value The string to truncate
13601          * @param {Number} length The maximum length to allow before truncating
13602          * @return {String} The converted text
13603          */
13604         ellipsis : function(value, len){
13605             if(value && value.length > len){
13606                 return value.substr(0, len-3)+"...";
13607             }
13608             return value;
13609         },
13610
13611         /**
13612          * Checks a reference and converts it to empty string if it is undefined
13613          * @param {Mixed} value Reference to check
13614          * @return {Mixed} Empty string if converted, otherwise the original value
13615          */
13616         undef : function(value){
13617             return typeof value != "undefined" ? value : "";
13618         },
13619
13620         /**
13621          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13622          * @param {String} value The string to encode
13623          * @return {String} The encoded text
13624          */
13625         htmlEncode : function(value){
13626             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13627         },
13628
13629         /**
13630          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13631          * @param {String} value The string to decode
13632          * @return {String} The decoded text
13633          */
13634         htmlDecode : function(value){
13635             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13636         },
13637
13638         /**
13639          * Trims any whitespace from either side of a string
13640          * @param {String} value The text to trim
13641          * @return {String} The trimmed text
13642          */
13643         trim : function(value){
13644             return String(value).replace(trimRe, "");
13645         },
13646
13647         /**
13648          * Returns a substring from within an original string
13649          * @param {String} value The original text
13650          * @param {Number} start The start index of the substring
13651          * @param {Number} length The length of the substring
13652          * @return {String} The substring
13653          */
13654         substr : function(value, start, length){
13655             return String(value).substr(start, length);
13656         },
13657
13658         /**
13659          * Converts a string to all lower case letters
13660          * @param {String} value The text to convert
13661          * @return {String} The converted text
13662          */
13663         lowercase : function(value){
13664             return String(value).toLowerCase();
13665         },
13666
13667         /**
13668          * Converts a string to all upper case letters
13669          * @param {String} value The text to convert
13670          * @return {String} The converted text
13671          */
13672         uppercase : function(value){
13673             return String(value).toUpperCase();
13674         },
13675
13676         /**
13677          * Converts the first character only of a string to upper case
13678          * @param {String} value The text to convert
13679          * @return {String} The converted text
13680          */
13681         capitalize : function(value){
13682             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13683         },
13684
13685         // private
13686         call : function(value, fn){
13687             if(arguments.length > 2){
13688                 var args = Array.prototype.slice.call(arguments, 2);
13689                 args.unshift(value);
13690                  
13691                 return /** eval:var:value */  eval(fn).apply(window, args);
13692             }else{
13693                 /** eval:var:value */
13694                 return /** eval:var:value */ eval(fn).call(window, value);
13695             }
13696         },
13697
13698        
13699         /**
13700          * safer version of Math.toFixed..??/
13701          * @param {Number/String} value The numeric value to format
13702          * @param {Number/String} value Decimal places 
13703          * @return {String} The formatted currency string
13704          */
13705         toFixed : function(v, n)
13706         {
13707             // why not use to fixed - precision is buggered???
13708             if (!n) {
13709                 return Math.round(v-0);
13710             }
13711             var fact = Math.pow(10,n+1);
13712             v = (Math.round((v-0)*fact))/fact;
13713             var z = (''+fact).substring(2);
13714             if (v == Math.floor(v)) {
13715                 return Math.floor(v) + '.' + z;
13716             }
13717             
13718             // now just padd decimals..
13719             var ps = String(v).split('.');
13720             var fd = (ps[1] + z);
13721             var r = fd.substring(0,n); 
13722             var rm = fd.substring(n); 
13723             if (rm < 5) {
13724                 return ps[0] + '.' + r;
13725             }
13726             r*=1; // turn it into a number;
13727             r++;
13728             if (String(r).length != n) {
13729                 ps[0]*=1;
13730                 ps[0]++;
13731                 r = String(r).substring(1); // chop the end off.
13732             }
13733             
13734             return ps[0] + '.' + r;
13735              
13736         },
13737         
13738         /**
13739          * Format a number as US currency
13740          * @param {Number/String} value The numeric value to format
13741          * @return {String} The formatted currency string
13742          */
13743         usMoney : function(v){
13744             return '$' + Roo.util.Format.number(v);
13745         },
13746         
13747         /**
13748          * Format a number
13749          * eventually this should probably emulate php's number_format
13750          * @param {Number/String} value The numeric value to format
13751          * @param {Number} decimals number of decimal places
13752          * @return {String} The formatted currency string
13753          */
13754         number : function(v,decimals)
13755         {
13756             // multiply and round.
13757             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13758             var mul = Math.pow(10, decimals);
13759             var zero = String(mul).substring(1);
13760             v = (Math.round((v-0)*mul))/mul;
13761             
13762             // if it's '0' number.. then
13763             
13764             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13765             v = String(v);
13766             var ps = v.split('.');
13767             var whole = ps[0];
13768             
13769             
13770             var r = /(\d+)(\d{3})/;
13771             // add comma's
13772             while (r.test(whole)) {
13773                 whole = whole.replace(r, '$1' + ',' + '$2');
13774             }
13775             
13776             
13777             var sub = ps[1] ?
13778                     // has decimals..
13779                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13780                     // does not have decimals
13781                     (decimals ? ('.' + zero) : '');
13782             
13783             
13784             return whole + sub ;
13785         },
13786         
13787         /**
13788          * Parse a value into a formatted date using the specified format pattern.
13789          * @param {Mixed} value The value to format
13790          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13791          * @return {String} The formatted date string
13792          */
13793         date : function(v, format){
13794             if(!v){
13795                 return "";
13796             }
13797             if(!(v instanceof Date)){
13798                 v = new Date(Date.parse(v));
13799             }
13800             return v.dateFormat(format || Roo.util.Format.defaults.date);
13801         },
13802
13803         /**
13804          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13805          * @param {String} format Any valid date format string
13806          * @return {Function} The date formatting function
13807          */
13808         dateRenderer : function(format){
13809             return function(v){
13810                 return Roo.util.Format.date(v, format);  
13811             };
13812         },
13813
13814         // private
13815         stripTagsRE : /<\/?[^>]+>/gi,
13816         
13817         /**
13818          * Strips all HTML tags
13819          * @param {Mixed} value The text from which to strip tags
13820          * @return {String} The stripped text
13821          */
13822         stripTags : function(v){
13823             return !v ? v : String(v).replace(this.stripTagsRE, "");
13824         }
13825     };
13826 }();
13827 Roo.util.Format.defaults = {
13828     date : 'd/M/Y'
13829 };/*
13830  * Based on:
13831  * Ext JS Library 1.1.1
13832  * Copyright(c) 2006-2007, Ext JS, LLC.
13833  *
13834  * Originally Released Under LGPL - original licence link has changed is not relivant.
13835  *
13836  * Fork - LGPL
13837  * <script type="text/javascript">
13838  */
13839
13840
13841  
13842
13843 /**
13844  * @class Roo.MasterTemplate
13845  * @extends Roo.Template
13846  * Provides a template that can have child templates. The syntax is:
13847 <pre><code>
13848 var t = new Roo.MasterTemplate(
13849         '&lt;select name="{name}"&gt;',
13850                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13851         '&lt;/select&gt;'
13852 );
13853 t.add('options', {value: 'foo', text: 'bar'});
13854 // or you can add multiple child elements in one shot
13855 t.addAll('options', [
13856     {value: 'foo', text: 'bar'},
13857     {value: 'foo2', text: 'bar2'},
13858     {value: 'foo3', text: 'bar3'}
13859 ]);
13860 // then append, applying the master template values
13861 t.append('my-form', {name: 'my-select'});
13862 </code></pre>
13863 * A name attribute for the child template is not required if you have only one child
13864 * template or you want to refer to them by index.
13865  */
13866 Roo.MasterTemplate = function(){
13867     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13868     this.originalHtml = this.html;
13869     var st = {};
13870     var m, re = this.subTemplateRe;
13871     re.lastIndex = 0;
13872     var subIndex = 0;
13873     while(m = re.exec(this.html)){
13874         var name = m[1], content = m[2];
13875         st[subIndex] = {
13876             name: name,
13877             index: subIndex,
13878             buffer: [],
13879             tpl : new Roo.Template(content)
13880         };
13881         if(name){
13882             st[name] = st[subIndex];
13883         }
13884         st[subIndex].tpl.compile();
13885         st[subIndex].tpl.call = this.call.createDelegate(this);
13886         subIndex++;
13887     }
13888     this.subCount = subIndex;
13889     this.subs = st;
13890 };
13891 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13892     /**
13893     * The regular expression used to match sub templates
13894     * @type RegExp
13895     * @property
13896     */
13897     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13898
13899     /**
13900      * Applies the passed values to a child template.
13901      * @param {String/Number} name (optional) The name or index of the child template
13902      * @param {Array/Object} values The values to be applied to the template
13903      * @return {MasterTemplate} this
13904      */
13905      add : function(name, values){
13906         if(arguments.length == 1){
13907             values = arguments[0];
13908             name = 0;
13909         }
13910         var s = this.subs[name];
13911         s.buffer[s.buffer.length] = s.tpl.apply(values);
13912         return this;
13913     },
13914
13915     /**
13916      * Applies all the passed values to a child template.
13917      * @param {String/Number} name (optional) The name or index of the child template
13918      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13919      * @param {Boolean} reset (optional) True to reset the template first
13920      * @return {MasterTemplate} this
13921      */
13922     fill : function(name, values, reset){
13923         var a = arguments;
13924         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13925             values = a[0];
13926             name = 0;
13927             reset = a[1];
13928         }
13929         if(reset){
13930             this.reset();
13931         }
13932         for(var i = 0, len = values.length; i < len; i++){
13933             this.add(name, values[i]);
13934         }
13935         return this;
13936     },
13937
13938     /**
13939      * Resets the template for reuse
13940      * @return {MasterTemplate} this
13941      */
13942      reset : function(){
13943         var s = this.subs;
13944         for(var i = 0; i < this.subCount; i++){
13945             s[i].buffer = [];
13946         }
13947         return this;
13948     },
13949
13950     applyTemplate : function(values){
13951         var s = this.subs;
13952         var replaceIndex = -1;
13953         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13954             return s[++replaceIndex].buffer.join("");
13955         });
13956         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13957     },
13958
13959     apply : function(){
13960         return this.applyTemplate.apply(this, arguments);
13961     },
13962
13963     compile : function(){return this;}
13964 });
13965
13966 /**
13967  * Alias for fill().
13968  * @method
13969  */
13970 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13971  /**
13972  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13973  * var tpl = Roo.MasterTemplate.from('element-id');
13974  * @param {String/HTMLElement} el
13975  * @param {Object} config
13976  * @static
13977  */
13978 Roo.MasterTemplate.from = function(el, config){
13979     el = Roo.getDom(el);
13980     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13981 };/*
13982  * Based on:
13983  * Ext JS Library 1.1.1
13984  * Copyright(c) 2006-2007, Ext JS, LLC.
13985  *
13986  * Originally Released Under LGPL - original licence link has changed is not relivant.
13987  *
13988  * Fork - LGPL
13989  * <script type="text/javascript">
13990  */
13991
13992  
13993 /**
13994  * @class Roo.util.CSS
13995  * Utility class for manipulating CSS rules
13996  * @singleton
13997  */
13998 Roo.util.CSS = function(){
13999         var rules = null;
14000         var doc = document;
14001
14002     var camelRe = /(-[a-z])/gi;
14003     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14004
14005    return {
14006    /**
14007     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14008     * tag and appended to the HEAD of the document.
14009     * @param {String|Object} cssText The text containing the css rules
14010     * @param {String} id An id to add to the stylesheet for later removal
14011     * @return {StyleSheet}
14012     */
14013     createStyleSheet : function(cssText, id){
14014         var ss;
14015         var head = doc.getElementsByTagName("head")[0];
14016         var nrules = doc.createElement("style");
14017         nrules.setAttribute("type", "text/css");
14018         if(id){
14019             nrules.setAttribute("id", id);
14020         }
14021         if (typeof(cssText) != 'string') {
14022             // support object maps..
14023             // not sure if this a good idea.. 
14024             // perhaps it should be merged with the general css handling
14025             // and handle js style props.
14026             var cssTextNew = [];
14027             for(var n in cssText) {
14028                 var citems = [];
14029                 for(var k in cssText[n]) {
14030                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14031                 }
14032                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14033                 
14034             }
14035             cssText = cssTextNew.join("\n");
14036             
14037         }
14038        
14039        
14040        if(Roo.isIE){
14041            head.appendChild(nrules);
14042            ss = nrules.styleSheet;
14043            ss.cssText = cssText;
14044        }else{
14045            try{
14046                 nrules.appendChild(doc.createTextNode(cssText));
14047            }catch(e){
14048                nrules.cssText = cssText; 
14049            }
14050            head.appendChild(nrules);
14051            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14052        }
14053        this.cacheStyleSheet(ss);
14054        return ss;
14055    },
14056
14057    /**
14058     * Removes a style or link tag by id
14059     * @param {String} id The id of the tag
14060     */
14061    removeStyleSheet : function(id){
14062        var existing = doc.getElementById(id);
14063        if(existing){
14064            existing.parentNode.removeChild(existing);
14065        }
14066    },
14067
14068    /**
14069     * Dynamically swaps an existing stylesheet reference for a new one
14070     * @param {String} id The id of an existing link tag to remove
14071     * @param {String} url The href of the new stylesheet to include
14072     */
14073    swapStyleSheet : function(id, url){
14074        this.removeStyleSheet(id);
14075        var ss = doc.createElement("link");
14076        ss.setAttribute("rel", "stylesheet");
14077        ss.setAttribute("type", "text/css");
14078        ss.setAttribute("id", id);
14079        ss.setAttribute("href", url);
14080        doc.getElementsByTagName("head")[0].appendChild(ss);
14081    },
14082    
14083    /**
14084     * Refresh the rule cache if you have dynamically added stylesheets
14085     * @return {Object} An object (hash) of rules indexed by selector
14086     */
14087    refreshCache : function(){
14088        return this.getRules(true);
14089    },
14090
14091    // private
14092    cacheStyleSheet : function(stylesheet){
14093        if(!rules){
14094            rules = {};
14095        }
14096        try{// try catch for cross domain access issue
14097            var ssRules = stylesheet.cssRules || stylesheet.rules;
14098            for(var j = ssRules.length-1; j >= 0; --j){
14099                rules[ssRules[j].selectorText] = ssRules[j];
14100            }
14101        }catch(e){}
14102    },
14103    
14104    /**
14105     * Gets all css rules for the document
14106     * @param {Boolean} refreshCache true to refresh the internal cache
14107     * @return {Object} An object (hash) of rules indexed by selector
14108     */
14109    getRules : function(refreshCache){
14110                 if(rules == null || refreshCache){
14111                         rules = {};
14112                         var ds = doc.styleSheets;
14113                         for(var i =0, len = ds.length; i < len; i++){
14114                             try{
14115                         this.cacheStyleSheet(ds[i]);
14116                     }catch(e){} 
14117                 }
14118                 }
14119                 return rules;
14120         },
14121         
14122         /**
14123     * Gets an an individual CSS rule by selector(s)
14124     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14125     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14126     * @return {CSSRule} The CSS rule or null if one is not found
14127     */
14128    getRule : function(selector, refreshCache){
14129                 var rs = this.getRules(refreshCache);
14130                 if(!(selector instanceof Array)){
14131                     return rs[selector];
14132                 }
14133                 for(var i = 0; i < selector.length; i++){
14134                         if(rs[selector[i]]){
14135                                 return rs[selector[i]];
14136                         }
14137                 }
14138                 return null;
14139         },
14140         
14141         
14142         /**
14143     * Updates a rule property
14144     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14145     * @param {String} property The css property
14146     * @param {String} value The new value for the property
14147     * @return {Boolean} true If a rule was found and updated
14148     */
14149    updateRule : function(selector, property, value){
14150                 if(!(selector instanceof Array)){
14151                         var rule = this.getRule(selector);
14152                         if(rule){
14153                                 rule.style[property.replace(camelRe, camelFn)] = value;
14154                                 return true;
14155                         }
14156                 }else{
14157                         for(var i = 0; i < selector.length; i++){
14158                                 if(this.updateRule(selector[i], property, value)){
14159                                         return true;
14160                                 }
14161                         }
14162                 }
14163                 return false;
14164         }
14165    };   
14166 }();/*
14167  * Based on:
14168  * Ext JS Library 1.1.1
14169  * Copyright(c) 2006-2007, Ext JS, LLC.
14170  *
14171  * Originally Released Under LGPL - original licence link has changed is not relivant.
14172  *
14173  * Fork - LGPL
14174  * <script type="text/javascript">
14175  */
14176
14177  
14178
14179 /**
14180  * @class Roo.util.ClickRepeater
14181  * @extends Roo.util.Observable
14182  * 
14183  * A wrapper class which can be applied to any element. Fires a "click" event while the
14184  * mouse is pressed. The interval between firings may be specified in the config but
14185  * defaults to 10 milliseconds.
14186  * 
14187  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14188  * 
14189  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14190  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14191  * Similar to an autorepeat key delay.
14192  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14193  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14194  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14195  *           "interval" and "delay" are ignored. "immediate" is honored.
14196  * @cfg {Boolean} preventDefault True to prevent the default click event
14197  * @cfg {Boolean} stopDefault True to stop the default click event
14198  * 
14199  * @history
14200  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14201  *     2007-02-02 jvs Renamed to ClickRepeater
14202  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14203  *
14204  *  @constructor
14205  * @param {String/HTMLElement/Element} el The element to listen on
14206  * @param {Object} config
14207  **/
14208 Roo.util.ClickRepeater = function(el, config)
14209 {
14210     this.el = Roo.get(el);
14211     this.el.unselectable();
14212
14213     Roo.apply(this, config);
14214
14215     this.addEvents({
14216     /**
14217      * @event mousedown
14218      * Fires when the mouse button is depressed.
14219      * @param {Roo.util.ClickRepeater} this
14220      */
14221         "mousedown" : true,
14222     /**
14223      * @event click
14224      * Fires on a specified interval during the time the element is pressed.
14225      * @param {Roo.util.ClickRepeater} this
14226      */
14227         "click" : true,
14228     /**
14229      * @event mouseup
14230      * Fires when the mouse key is released.
14231      * @param {Roo.util.ClickRepeater} this
14232      */
14233         "mouseup" : true
14234     });
14235
14236     this.el.on("mousedown", this.handleMouseDown, this);
14237     if(this.preventDefault || this.stopDefault){
14238         this.el.on("click", function(e){
14239             if(this.preventDefault){
14240                 e.preventDefault();
14241             }
14242             if(this.stopDefault){
14243                 e.stopEvent();
14244             }
14245         }, this);
14246     }
14247
14248     // allow inline handler
14249     if(this.handler){
14250         this.on("click", this.handler,  this.scope || this);
14251     }
14252
14253     Roo.util.ClickRepeater.superclass.constructor.call(this);
14254 };
14255
14256 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14257     interval : 20,
14258     delay: 250,
14259     preventDefault : true,
14260     stopDefault : false,
14261     timer : 0,
14262
14263     // private
14264     handleMouseDown : function(){
14265         clearTimeout(this.timer);
14266         this.el.blur();
14267         if(this.pressClass){
14268             this.el.addClass(this.pressClass);
14269         }
14270         this.mousedownTime = new Date();
14271
14272         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14273         this.el.on("mouseout", this.handleMouseOut, this);
14274
14275         this.fireEvent("mousedown", this);
14276         this.fireEvent("click", this);
14277         
14278         this.timer = this.click.defer(this.delay || this.interval, this);
14279     },
14280
14281     // private
14282     click : function(){
14283         this.fireEvent("click", this);
14284         this.timer = this.click.defer(this.getInterval(), this);
14285     },
14286
14287     // private
14288     getInterval: function(){
14289         if(!this.accelerate){
14290             return this.interval;
14291         }
14292         var pressTime = this.mousedownTime.getElapsed();
14293         if(pressTime < 500){
14294             return 400;
14295         }else if(pressTime < 1700){
14296             return 320;
14297         }else if(pressTime < 2600){
14298             return 250;
14299         }else if(pressTime < 3500){
14300             return 180;
14301         }else if(pressTime < 4400){
14302             return 140;
14303         }else if(pressTime < 5300){
14304             return 80;
14305         }else if(pressTime < 6200){
14306             return 50;
14307         }else{
14308             return 10;
14309         }
14310     },
14311
14312     // private
14313     handleMouseOut : function(){
14314         clearTimeout(this.timer);
14315         if(this.pressClass){
14316             this.el.removeClass(this.pressClass);
14317         }
14318         this.el.on("mouseover", this.handleMouseReturn, this);
14319     },
14320
14321     // private
14322     handleMouseReturn : function(){
14323         this.el.un("mouseover", this.handleMouseReturn);
14324         if(this.pressClass){
14325             this.el.addClass(this.pressClass);
14326         }
14327         this.click();
14328     },
14329
14330     // private
14331     handleMouseUp : function(){
14332         clearTimeout(this.timer);
14333         this.el.un("mouseover", this.handleMouseReturn);
14334         this.el.un("mouseout", this.handleMouseOut);
14335         Roo.get(document).un("mouseup", this.handleMouseUp);
14336         this.el.removeClass(this.pressClass);
14337         this.fireEvent("mouseup", this);
14338     }
14339 });/*
14340  * Based on:
14341  * Ext JS Library 1.1.1
14342  * Copyright(c) 2006-2007, Ext JS, LLC.
14343  *
14344  * Originally Released Under LGPL - original licence link has changed is not relivant.
14345  *
14346  * Fork - LGPL
14347  * <script type="text/javascript">
14348  */
14349
14350  
14351 /**
14352  * @class Roo.KeyNav
14353  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14354  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14355  * way to implement custom navigation schemes for any UI component.</p>
14356  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14357  * pageUp, pageDown, del, home, end.  Usage:</p>
14358  <pre><code>
14359 var nav = new Roo.KeyNav("my-element", {
14360     "left" : function(e){
14361         this.moveLeft(e.ctrlKey);
14362     },
14363     "right" : function(e){
14364         this.moveRight(e.ctrlKey);
14365     },
14366     "enter" : function(e){
14367         this.save();
14368     },
14369     scope : this
14370 });
14371 </code></pre>
14372  * @constructor
14373  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14374  * @param {Object} config The config
14375  */
14376 Roo.KeyNav = function(el, config){
14377     this.el = Roo.get(el);
14378     Roo.apply(this, config);
14379     if(!this.disabled){
14380         this.disabled = true;
14381         this.enable();
14382     }
14383 };
14384
14385 Roo.KeyNav.prototype = {
14386     /**
14387      * @cfg {Boolean} disabled
14388      * True to disable this KeyNav instance (defaults to false)
14389      */
14390     disabled : false,
14391     /**
14392      * @cfg {String} defaultEventAction
14393      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14394      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14395      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14396      */
14397     defaultEventAction: "stopEvent",
14398     /**
14399      * @cfg {Boolean} forceKeyDown
14400      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14401      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14402      * handle keydown instead of keypress.
14403      */
14404     forceKeyDown : false,
14405
14406     // private
14407     prepareEvent : function(e){
14408         var k = e.getKey();
14409         var h = this.keyToHandler[k];
14410         //if(h && this[h]){
14411         //    e.stopPropagation();
14412         //}
14413         if(Roo.isSafari && h && k >= 37 && k <= 40){
14414             e.stopEvent();
14415         }
14416     },
14417
14418     // private
14419     relay : function(e){
14420         var k = e.getKey();
14421         var h = this.keyToHandler[k];
14422         if(h && this[h]){
14423             if(this.doRelay(e, this[h], h) !== true){
14424                 e[this.defaultEventAction]();
14425             }
14426         }
14427     },
14428
14429     // private
14430     doRelay : function(e, h, hname){
14431         return h.call(this.scope || this, e);
14432     },
14433
14434     // possible handlers
14435     enter : false,
14436     left : false,
14437     right : false,
14438     up : false,
14439     down : false,
14440     tab : false,
14441     esc : false,
14442     pageUp : false,
14443     pageDown : false,
14444     del : false,
14445     home : false,
14446     end : false,
14447
14448     // quick lookup hash
14449     keyToHandler : {
14450         37 : "left",
14451         39 : "right",
14452         38 : "up",
14453         40 : "down",
14454         33 : "pageUp",
14455         34 : "pageDown",
14456         46 : "del",
14457         36 : "home",
14458         35 : "end",
14459         13 : "enter",
14460         27 : "esc",
14461         9  : "tab"
14462     },
14463
14464         /**
14465          * Enable this KeyNav
14466          */
14467         enable: function(){
14468                 if(this.disabled){
14469             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14470             // the EventObject will normalize Safari automatically
14471             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14472                 this.el.on("keydown", this.relay,  this);
14473             }else{
14474                 this.el.on("keydown", this.prepareEvent,  this);
14475                 this.el.on("keypress", this.relay,  this);
14476             }
14477                     this.disabled = false;
14478                 }
14479         },
14480
14481         /**
14482          * Disable this KeyNav
14483          */
14484         disable: function(){
14485                 if(!this.disabled){
14486                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14487                 this.el.un("keydown", this.relay);
14488             }else{
14489                 this.el.un("keydown", this.prepareEvent);
14490                 this.el.un("keypress", this.relay);
14491             }
14492                     this.disabled = true;
14493                 }
14494         }
14495 };/*
14496  * Based on:
14497  * Ext JS Library 1.1.1
14498  * Copyright(c) 2006-2007, Ext JS, LLC.
14499  *
14500  * Originally Released Under LGPL - original licence link has changed is not relivant.
14501  *
14502  * Fork - LGPL
14503  * <script type="text/javascript">
14504  */
14505
14506  
14507 /**
14508  * @class Roo.KeyMap
14509  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14510  * The constructor accepts the same config object as defined by {@link #addBinding}.
14511  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14512  * combination it will call the function with this signature (if the match is a multi-key
14513  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14514  * A KeyMap can also handle a string representation of keys.<br />
14515  * Usage:
14516  <pre><code>
14517 // map one key by key code
14518 var map = new Roo.KeyMap("my-element", {
14519     key: 13, // or Roo.EventObject.ENTER
14520     fn: myHandler,
14521     scope: myObject
14522 });
14523
14524 // map multiple keys to one action by string
14525 var map = new Roo.KeyMap("my-element", {
14526     key: "a\r\n\t",
14527     fn: myHandler,
14528     scope: myObject
14529 });
14530
14531 // map multiple keys to multiple actions by strings and array of codes
14532 var map = new Roo.KeyMap("my-element", [
14533     {
14534         key: [10,13],
14535         fn: function(){ alert("Return was pressed"); }
14536     }, {
14537         key: "abc",
14538         fn: function(){ alert('a, b or c was pressed'); }
14539     }, {
14540         key: "\t",
14541         ctrl:true,
14542         shift:true,
14543         fn: function(){ alert('Control + shift + tab was pressed.'); }
14544     }
14545 ]);
14546 </code></pre>
14547  * <b>Note: A KeyMap starts enabled</b>
14548  * @constructor
14549  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14550  * @param {Object} config The config (see {@link #addBinding})
14551  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14552  */
14553 Roo.KeyMap = function(el, config, eventName){
14554     this.el  = Roo.get(el);
14555     this.eventName = eventName || "keydown";
14556     this.bindings = [];
14557     if(config){
14558         this.addBinding(config);
14559     }
14560     this.enable();
14561 };
14562
14563 Roo.KeyMap.prototype = {
14564     /**
14565      * True to stop the event from bubbling and prevent the default browser action if the
14566      * key was handled by the KeyMap (defaults to false)
14567      * @type Boolean
14568      */
14569     stopEvent : false,
14570
14571     /**
14572      * Add a new binding to this KeyMap. The following config object properties are supported:
14573      * <pre>
14574 Property    Type             Description
14575 ----------  ---------------  ----------------------------------------------------------------------
14576 key         String/Array     A single keycode or an array of keycodes to handle
14577 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14578 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14579 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14580 fn          Function         The function to call when KeyMap finds the expected key combination
14581 scope       Object           The scope of the callback function
14582 </pre>
14583      *
14584      * Usage:
14585      * <pre><code>
14586 // Create a KeyMap
14587 var map = new Roo.KeyMap(document, {
14588     key: Roo.EventObject.ENTER,
14589     fn: handleKey,
14590     scope: this
14591 });
14592
14593 //Add a new binding to the existing KeyMap later
14594 map.addBinding({
14595     key: 'abc',
14596     shift: true,
14597     fn: handleKey,
14598     scope: this
14599 });
14600 </code></pre>
14601      * @param {Object/Array} config A single KeyMap config or an array of configs
14602      */
14603         addBinding : function(config){
14604         if(config instanceof Array){
14605             for(var i = 0, len = config.length; i < len; i++){
14606                 this.addBinding(config[i]);
14607             }
14608             return;
14609         }
14610         var keyCode = config.key,
14611             shift = config.shift, 
14612             ctrl = config.ctrl, 
14613             alt = config.alt,
14614             fn = config.fn,
14615             scope = config.scope;
14616         if(typeof keyCode == "string"){
14617             var ks = [];
14618             var keyString = keyCode.toUpperCase();
14619             for(var j = 0, len = keyString.length; j < len; j++){
14620                 ks.push(keyString.charCodeAt(j));
14621             }
14622             keyCode = ks;
14623         }
14624         var keyArray = keyCode instanceof Array;
14625         var handler = function(e){
14626             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14627                 var k = e.getKey();
14628                 if(keyArray){
14629                     for(var i = 0, len = keyCode.length; i < len; i++){
14630                         if(keyCode[i] == k){
14631                           if(this.stopEvent){
14632                               e.stopEvent();
14633                           }
14634                           fn.call(scope || window, k, e);
14635                           return;
14636                         }
14637                     }
14638                 }else{
14639                     if(k == keyCode){
14640                         if(this.stopEvent){
14641                            e.stopEvent();
14642                         }
14643                         fn.call(scope || window, k, e);
14644                     }
14645                 }
14646             }
14647         };
14648         this.bindings.push(handler);  
14649         },
14650
14651     /**
14652      * Shorthand for adding a single key listener
14653      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14654      * following options:
14655      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14656      * @param {Function} fn The function to call
14657      * @param {Object} scope (optional) The scope of the function
14658      */
14659     on : function(key, fn, scope){
14660         var keyCode, shift, ctrl, alt;
14661         if(typeof key == "object" && !(key instanceof Array)){
14662             keyCode = key.key;
14663             shift = key.shift;
14664             ctrl = key.ctrl;
14665             alt = key.alt;
14666         }else{
14667             keyCode = key;
14668         }
14669         this.addBinding({
14670             key: keyCode,
14671             shift: shift,
14672             ctrl: ctrl,
14673             alt: alt,
14674             fn: fn,
14675             scope: scope
14676         })
14677     },
14678
14679     // private
14680     handleKeyDown : function(e){
14681             if(this.enabled){ //just in case
14682             var b = this.bindings;
14683             for(var i = 0, len = b.length; i < len; i++){
14684                 b[i].call(this, e);
14685             }
14686             }
14687         },
14688         
14689         /**
14690          * Returns true if this KeyMap is enabled
14691          * @return {Boolean} 
14692          */
14693         isEnabled : function(){
14694             return this.enabled;  
14695         },
14696         
14697         /**
14698          * Enables this KeyMap
14699          */
14700         enable: function(){
14701                 if(!this.enabled){
14702                     this.el.on(this.eventName, this.handleKeyDown, this);
14703                     this.enabled = true;
14704                 }
14705         },
14706
14707         /**
14708          * Disable this KeyMap
14709          */
14710         disable: function(){
14711                 if(this.enabled){
14712                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14713                     this.enabled = false;
14714                 }
14715         }
14716 };/*
14717  * Based on:
14718  * Ext JS Library 1.1.1
14719  * Copyright(c) 2006-2007, Ext JS, LLC.
14720  *
14721  * Originally Released Under LGPL - original licence link has changed is not relivant.
14722  *
14723  * Fork - LGPL
14724  * <script type="text/javascript">
14725  */
14726
14727  
14728 /**
14729  * @class Roo.util.TextMetrics
14730  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14731  * wide, in pixels, a given block of text will be.
14732  * @singleton
14733  */
14734 Roo.util.TextMetrics = function(){
14735     var shared;
14736     return {
14737         /**
14738          * Measures the size of the specified text
14739          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14740          * that can affect the size of the rendered text
14741          * @param {String} text The text to measure
14742          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14743          * in order to accurately measure the text height
14744          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14745          */
14746         measure : function(el, text, fixedWidth){
14747             if(!shared){
14748                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14749             }
14750             shared.bind(el);
14751             shared.setFixedWidth(fixedWidth || 'auto');
14752             return shared.getSize(text);
14753         },
14754
14755         /**
14756          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14757          * the overhead of multiple calls to initialize the style properties on each measurement.
14758          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14759          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14760          * in order to accurately measure the text height
14761          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14762          */
14763         createInstance : function(el, fixedWidth){
14764             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14765         }
14766     };
14767 }();
14768
14769  
14770
14771 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14772     var ml = new Roo.Element(document.createElement('div'));
14773     document.body.appendChild(ml.dom);
14774     ml.position('absolute');
14775     ml.setLeftTop(-1000, -1000);
14776     ml.hide();
14777
14778     if(fixedWidth){
14779         ml.setWidth(fixedWidth);
14780     }
14781      
14782     var instance = {
14783         /**
14784          * Returns the size of the specified text based on the internal element's style and width properties
14785          * @memberOf Roo.util.TextMetrics.Instance#
14786          * @param {String} text The text to measure
14787          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14788          */
14789         getSize : function(text){
14790             ml.update(text);
14791             var s = ml.getSize();
14792             ml.update('');
14793             return s;
14794         },
14795
14796         /**
14797          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14798          * that can affect the size of the rendered text
14799          * @memberOf Roo.util.TextMetrics.Instance#
14800          * @param {String/HTMLElement} el The element, dom node or id
14801          */
14802         bind : function(el){
14803             ml.setStyle(
14804                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14805             );
14806         },
14807
14808         /**
14809          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14810          * to set a fixed width in order to accurately measure the text height.
14811          * @memberOf Roo.util.TextMetrics.Instance#
14812          * @param {Number} width The width to set on the element
14813          */
14814         setFixedWidth : function(width){
14815             ml.setWidth(width);
14816         },
14817
14818         /**
14819          * Returns the measured width of the specified text
14820          * @memberOf Roo.util.TextMetrics.Instance#
14821          * @param {String} text The text to measure
14822          * @return {Number} width The width in pixels
14823          */
14824         getWidth : function(text){
14825             ml.dom.style.width = 'auto';
14826             return this.getSize(text).width;
14827         },
14828
14829         /**
14830          * Returns the measured height of the specified text.  For multiline text, be sure to call
14831          * {@link #setFixedWidth} if necessary.
14832          * @memberOf Roo.util.TextMetrics.Instance#
14833          * @param {String} text The text to measure
14834          * @return {Number} height The height in pixels
14835          */
14836         getHeight : function(text){
14837             return this.getSize(text).height;
14838         }
14839     };
14840
14841     instance.bind(bindTo);
14842
14843     return instance;
14844 };
14845
14846 // backwards compat
14847 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14848  * Based on:
14849  * Ext JS Library 1.1.1
14850  * Copyright(c) 2006-2007, Ext JS, LLC.
14851  *
14852  * Originally Released Under LGPL - original licence link has changed is not relivant.
14853  *
14854  * Fork - LGPL
14855  * <script type="text/javascript">
14856  */
14857
14858 /**
14859  * @class Roo.state.Provider
14860  * Abstract base class for state provider implementations. This class provides methods
14861  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14862  * Provider interface.
14863  */
14864 Roo.state.Provider = function(){
14865     /**
14866      * @event statechange
14867      * Fires when a state change occurs.
14868      * @param {Provider} this This state provider
14869      * @param {String} key The state key which was changed
14870      * @param {String} value The encoded value for the state
14871      */
14872     this.addEvents({
14873         "statechange": true
14874     });
14875     this.state = {};
14876     Roo.state.Provider.superclass.constructor.call(this);
14877 };
14878 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14879     /**
14880      * Returns the current value for a key
14881      * @param {String} name The key name
14882      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14883      * @return {Mixed} The state data
14884      */
14885     get : function(name, defaultValue){
14886         return typeof this.state[name] == "undefined" ?
14887             defaultValue : this.state[name];
14888     },
14889     
14890     /**
14891      * Clears a value from the state
14892      * @param {String} name The key name
14893      */
14894     clear : function(name){
14895         delete this.state[name];
14896         this.fireEvent("statechange", this, name, null);
14897     },
14898     
14899     /**
14900      * Sets the value for a key
14901      * @param {String} name The key name
14902      * @param {Mixed} value The value to set
14903      */
14904     set : function(name, value){
14905         this.state[name] = value;
14906         this.fireEvent("statechange", this, name, value);
14907     },
14908     
14909     /**
14910      * Decodes a string previously encoded with {@link #encodeValue}.
14911      * @param {String} value The value to decode
14912      * @return {Mixed} The decoded value
14913      */
14914     decodeValue : function(cookie){
14915         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14916         var matches = re.exec(unescape(cookie));
14917         if(!matches || !matches[1]) {
14918             return; // non state cookie
14919         }
14920         var type = matches[1];
14921         var v = matches[2];
14922         switch(type){
14923             case "n":
14924                 return parseFloat(v);
14925             case "d":
14926                 return new Date(Date.parse(v));
14927             case "b":
14928                 return (v == "1");
14929             case "a":
14930                 var all = [];
14931                 var values = v.split("^");
14932                 for(var i = 0, len = values.length; i < len; i++){
14933                     all.push(this.decodeValue(values[i]));
14934                 }
14935                 return all;
14936            case "o":
14937                 var all = {};
14938                 var values = v.split("^");
14939                 for(var i = 0, len = values.length; i < len; i++){
14940                     var kv = values[i].split("=");
14941                     all[kv[0]] = this.decodeValue(kv[1]);
14942                 }
14943                 return all;
14944            default:
14945                 return v;
14946         }
14947     },
14948     
14949     /**
14950      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14951      * @param {Mixed} value The value to encode
14952      * @return {String} The encoded value
14953      */
14954     encodeValue : function(v){
14955         var enc;
14956         if(typeof v == "number"){
14957             enc = "n:" + v;
14958         }else if(typeof v == "boolean"){
14959             enc = "b:" + (v ? "1" : "0");
14960         }else if(v instanceof Date){
14961             enc = "d:" + v.toGMTString();
14962         }else if(v instanceof Array){
14963             var flat = "";
14964             for(var i = 0, len = v.length; i < len; i++){
14965                 flat += this.encodeValue(v[i]);
14966                 if(i != len-1) {
14967                     flat += "^";
14968                 }
14969             }
14970             enc = "a:" + flat;
14971         }else if(typeof v == "object"){
14972             var flat = "";
14973             for(var key in v){
14974                 if(typeof v[key] != "function"){
14975                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14976                 }
14977             }
14978             enc = "o:" + flat.substring(0, flat.length-1);
14979         }else{
14980             enc = "s:" + v;
14981         }
14982         return escape(enc);        
14983     }
14984 });
14985
14986 /*
14987  * Based on:
14988  * Ext JS Library 1.1.1
14989  * Copyright(c) 2006-2007, Ext JS, LLC.
14990  *
14991  * Originally Released Under LGPL - original licence link has changed is not relivant.
14992  *
14993  * Fork - LGPL
14994  * <script type="text/javascript">
14995  */
14996 /**
14997  * @class Roo.state.Manager
14998  * This is the global state manager. By default all components that are "state aware" check this class
14999  * for state information if you don't pass them a custom state provider. In order for this class
15000  * to be useful, it must be initialized with a provider when your application initializes.
15001  <pre><code>
15002 // in your initialization function
15003 init : function(){
15004    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15005    ...
15006    // supposed you have a {@link Roo.BorderLayout}
15007    var layout = new Roo.BorderLayout(...);
15008    layout.restoreState();
15009    // or a {Roo.BasicDialog}
15010    var dialog = new Roo.BasicDialog(...);
15011    dialog.restoreState();
15012  </code></pre>
15013  * @singleton
15014  */
15015 Roo.state.Manager = function(){
15016     var provider = new Roo.state.Provider();
15017     
15018     return {
15019         /**
15020          * Configures the default state provider for your application
15021          * @param {Provider} stateProvider The state provider to set
15022          */
15023         setProvider : function(stateProvider){
15024             provider = stateProvider;
15025         },
15026         
15027         /**
15028          * Returns the current value for a key
15029          * @param {String} name The key name
15030          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15031          * @return {Mixed} The state data
15032          */
15033         get : function(key, defaultValue){
15034             return provider.get(key, defaultValue);
15035         },
15036         
15037         /**
15038          * Sets the value for a key
15039          * @param {String} name The key name
15040          * @param {Mixed} value The state data
15041          */
15042          set : function(key, value){
15043             provider.set(key, value);
15044         },
15045         
15046         /**
15047          * Clears a value from the state
15048          * @param {String} name The key name
15049          */
15050         clear : function(key){
15051             provider.clear(key);
15052         },
15053         
15054         /**
15055          * Gets the currently configured state provider
15056          * @return {Provider} The state provider
15057          */
15058         getProvider : function(){
15059             return provider;
15060         }
15061     };
15062 }();
15063 /*
15064  * Based on:
15065  * Ext JS Library 1.1.1
15066  * Copyright(c) 2006-2007, Ext JS, LLC.
15067  *
15068  * Originally Released Under LGPL - original licence link has changed is not relivant.
15069  *
15070  * Fork - LGPL
15071  * <script type="text/javascript">
15072  */
15073 /**
15074  * @class Roo.state.CookieProvider
15075  * @extends Roo.state.Provider
15076  * The default Provider implementation which saves state via cookies.
15077  * <br />Usage:
15078  <pre><code>
15079    var cp = new Roo.state.CookieProvider({
15080        path: "/cgi-bin/",
15081        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15082        domain: "roojs.com"
15083    })
15084    Roo.state.Manager.setProvider(cp);
15085  </code></pre>
15086  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15087  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15088  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15089  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15090  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15091  * domain the page is running on including the 'www' like 'www.roojs.com')
15092  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15093  * @constructor
15094  * Create a new CookieProvider
15095  * @param {Object} config The configuration object
15096  */
15097 Roo.state.CookieProvider = function(config){
15098     Roo.state.CookieProvider.superclass.constructor.call(this);
15099     this.path = "/";
15100     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15101     this.domain = null;
15102     this.secure = false;
15103     Roo.apply(this, config);
15104     this.state = this.readCookies();
15105 };
15106
15107 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15108     // private
15109     set : function(name, value){
15110         if(typeof value == "undefined" || value === null){
15111             this.clear(name);
15112             return;
15113         }
15114         this.setCookie(name, value);
15115         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15116     },
15117
15118     // private
15119     clear : function(name){
15120         this.clearCookie(name);
15121         Roo.state.CookieProvider.superclass.clear.call(this, name);
15122     },
15123
15124     // private
15125     readCookies : function(){
15126         var cookies = {};
15127         var c = document.cookie + ";";
15128         var re = /\s?(.*?)=(.*?);/g;
15129         var matches;
15130         while((matches = re.exec(c)) != null){
15131             var name = matches[1];
15132             var value = matches[2];
15133             if(name && name.substring(0,3) == "ys-"){
15134                 cookies[name.substr(3)] = this.decodeValue(value);
15135             }
15136         }
15137         return cookies;
15138     },
15139
15140     // private
15141     setCookie : function(name, value){
15142         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15143            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15144            ((this.path == null) ? "" : ("; path=" + this.path)) +
15145            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15146            ((this.secure == true) ? "; secure" : "");
15147     },
15148
15149     // private
15150     clearCookie : function(name){
15151         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15152            ((this.path == null) ? "" : ("; path=" + this.path)) +
15153            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15154            ((this.secure == true) ? "; secure" : "");
15155     }
15156 });/*
15157  * Based on:
15158  * Ext JS Library 1.1.1
15159  * Copyright(c) 2006-2007, Ext JS, LLC.
15160  *
15161  * Originally Released Under LGPL - original licence link has changed is not relivant.
15162  *
15163  * Fork - LGPL
15164  * <script type="text/javascript">
15165  */
15166  
15167
15168 /**
15169  * @class Roo.ComponentMgr
15170  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15171  * @singleton
15172  */
15173 Roo.ComponentMgr = function(){
15174     var all = new Roo.util.MixedCollection();
15175
15176     return {
15177         /**
15178          * Registers a component.
15179          * @param {Roo.Component} c The component
15180          */
15181         register : function(c){
15182             all.add(c);
15183         },
15184
15185         /**
15186          * Unregisters a component.
15187          * @param {Roo.Component} c The component
15188          */
15189         unregister : function(c){
15190             all.remove(c);
15191         },
15192
15193         /**
15194          * Returns a component by id
15195          * @param {String} id The component id
15196          */
15197         get : function(id){
15198             return all.get(id);
15199         },
15200
15201         /**
15202          * Registers a function that will be called when a specified component is added to ComponentMgr
15203          * @param {String} id The component id
15204          * @param {Funtction} fn The callback function
15205          * @param {Object} scope The scope of the callback
15206          */
15207         onAvailable : function(id, fn, scope){
15208             all.on("add", function(index, o){
15209                 if(o.id == id){
15210                     fn.call(scope || o, o);
15211                     all.un("add", fn, scope);
15212                 }
15213             });
15214         }
15215     };
15216 }();/*
15217  * Based on:
15218  * Ext JS Library 1.1.1
15219  * Copyright(c) 2006-2007, Ext JS, LLC.
15220  *
15221  * Originally Released Under LGPL - original licence link has changed is not relivant.
15222  *
15223  * Fork - LGPL
15224  * <script type="text/javascript">
15225  */
15226  
15227 /**
15228  * @class Roo.Component
15229  * @extends Roo.util.Observable
15230  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15231  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15232  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15233  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15234  * All visual components (widgets) that require rendering into a layout should subclass Component.
15235  * @constructor
15236  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15237  * 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
15238  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15239  */
15240 Roo.Component = function(config){
15241     config = config || {};
15242     if(config.tagName || config.dom || typeof config == "string"){ // element object
15243         config = {el: config, id: config.id || config};
15244     }
15245     this.initialConfig = config;
15246
15247     Roo.apply(this, config);
15248     this.addEvents({
15249         /**
15250          * @event disable
15251          * Fires after the component is disabled.
15252              * @param {Roo.Component} this
15253              */
15254         disable : true,
15255         /**
15256          * @event enable
15257          * Fires after the component is enabled.
15258              * @param {Roo.Component} this
15259              */
15260         enable : true,
15261         /**
15262          * @event beforeshow
15263          * Fires before the component is shown.  Return false to stop the show.
15264              * @param {Roo.Component} this
15265              */
15266         beforeshow : true,
15267         /**
15268          * @event show
15269          * Fires after the component is shown.
15270              * @param {Roo.Component} this
15271              */
15272         show : true,
15273         /**
15274          * @event beforehide
15275          * Fires before the component is hidden. Return false to stop the hide.
15276              * @param {Roo.Component} this
15277              */
15278         beforehide : true,
15279         /**
15280          * @event hide
15281          * Fires after the component is hidden.
15282              * @param {Roo.Component} this
15283              */
15284         hide : true,
15285         /**
15286          * @event beforerender
15287          * Fires before the component is rendered. Return false to stop the render.
15288              * @param {Roo.Component} this
15289              */
15290         beforerender : true,
15291         /**
15292          * @event render
15293          * Fires after the component is rendered.
15294              * @param {Roo.Component} this
15295              */
15296         render : true,
15297         /**
15298          * @event beforedestroy
15299          * Fires before the component is destroyed. Return false to stop the destroy.
15300              * @param {Roo.Component} this
15301              */
15302         beforedestroy : true,
15303         /**
15304          * @event destroy
15305          * Fires after the component is destroyed.
15306              * @param {Roo.Component} this
15307              */
15308         destroy : true
15309     });
15310     if(!this.id){
15311         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15312     }
15313     Roo.ComponentMgr.register(this);
15314     Roo.Component.superclass.constructor.call(this);
15315     this.initComponent();
15316     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15317         this.render(this.renderTo);
15318         delete this.renderTo;
15319     }
15320 };
15321
15322 /** @private */
15323 Roo.Component.AUTO_ID = 1000;
15324
15325 Roo.extend(Roo.Component, Roo.util.Observable, {
15326     /**
15327      * @scope Roo.Component.prototype
15328      * @type {Boolean}
15329      * true if this component is hidden. Read-only.
15330      */
15331     hidden : false,
15332     /**
15333      * @type {Boolean}
15334      * true if this component is disabled. Read-only.
15335      */
15336     disabled : false,
15337     /**
15338      * @type {Boolean}
15339      * true if this component has been rendered. Read-only.
15340      */
15341     rendered : false,
15342     
15343     /** @cfg {String} disableClass
15344      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15345      */
15346     disabledClass : "x-item-disabled",
15347         /** @cfg {Boolean} allowDomMove
15348          * Whether the component can move the Dom node when rendering (defaults to true).
15349          */
15350     allowDomMove : true,
15351     /** @cfg {String} hideMode (display|visibility)
15352      * How this component should hidden. Supported values are
15353      * "visibility" (css visibility), "offsets" (negative offset position) and
15354      * "display" (css display) - defaults to "display".
15355      */
15356     hideMode: 'display',
15357
15358     /** @private */
15359     ctype : "Roo.Component",
15360
15361     /**
15362      * @cfg {String} actionMode 
15363      * which property holds the element that used for  hide() / show() / disable() / enable()
15364      * default is 'el' 
15365      */
15366     actionMode : "el",
15367
15368     /** @private */
15369     getActionEl : function(){
15370         return this[this.actionMode];
15371     },
15372
15373     initComponent : Roo.emptyFn,
15374     /**
15375      * If this is a lazy rendering component, render it to its container element.
15376      * @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.
15377      */
15378     render : function(container, position){
15379         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15380             if(!container && this.el){
15381                 this.el = Roo.get(this.el);
15382                 container = this.el.dom.parentNode;
15383                 this.allowDomMove = false;
15384             }
15385             this.container = Roo.get(container);
15386             this.rendered = true;
15387             if(position !== undefined){
15388                 if(typeof position == 'number'){
15389                     position = this.container.dom.childNodes[position];
15390                 }else{
15391                     position = Roo.getDom(position);
15392                 }
15393             }
15394             this.onRender(this.container, position || null);
15395             if(this.cls){
15396                 this.el.addClass(this.cls);
15397                 delete this.cls;
15398             }
15399             if(this.style){
15400                 this.el.applyStyles(this.style);
15401                 delete this.style;
15402             }
15403             this.fireEvent("render", this);
15404             this.afterRender(this.container);
15405             if(this.hidden){
15406                 this.hide();
15407             }
15408             if(this.disabled){
15409                 this.disable();
15410             }
15411         }
15412         return this;
15413     },
15414
15415     /** @private */
15416     // default function is not really useful
15417     onRender : function(ct, position){
15418         if(this.el){
15419             this.el = Roo.get(this.el);
15420             if(this.allowDomMove !== false){
15421                 ct.dom.insertBefore(this.el.dom, position);
15422             }
15423         }
15424     },
15425
15426     /** @private */
15427     getAutoCreate : function(){
15428         var cfg = typeof this.autoCreate == "object" ?
15429                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15430         if(this.id && !cfg.id){
15431             cfg.id = this.id;
15432         }
15433         return cfg;
15434     },
15435
15436     /** @private */
15437     afterRender : Roo.emptyFn,
15438
15439     /**
15440      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15441      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15442      */
15443     destroy : function(){
15444         if(this.fireEvent("beforedestroy", this) !== false){
15445             this.purgeListeners();
15446             this.beforeDestroy();
15447             if(this.rendered){
15448                 this.el.removeAllListeners();
15449                 this.el.remove();
15450                 if(this.actionMode == "container"){
15451                     this.container.remove();
15452                 }
15453             }
15454             this.onDestroy();
15455             Roo.ComponentMgr.unregister(this);
15456             this.fireEvent("destroy", this);
15457         }
15458     },
15459
15460         /** @private */
15461     beforeDestroy : function(){
15462
15463     },
15464
15465         /** @private */
15466         onDestroy : function(){
15467
15468     },
15469
15470     /**
15471      * Returns the underlying {@link Roo.Element}.
15472      * @return {Roo.Element} The element
15473      */
15474     getEl : function(){
15475         return this.el;
15476     },
15477
15478     /**
15479      * Returns the id of this component.
15480      * @return {String}
15481      */
15482     getId : function(){
15483         return this.id;
15484     },
15485
15486     /**
15487      * Try to focus this component.
15488      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15489      * @return {Roo.Component} this
15490      */
15491     focus : function(selectText){
15492         if(this.rendered){
15493             this.el.focus();
15494             if(selectText === true){
15495                 this.el.dom.select();
15496             }
15497         }
15498         return this;
15499     },
15500
15501     /** @private */
15502     blur : function(){
15503         if(this.rendered){
15504             this.el.blur();
15505         }
15506         return this;
15507     },
15508
15509     /**
15510      * Disable this component.
15511      * @return {Roo.Component} this
15512      */
15513     disable : function(){
15514         if(this.rendered){
15515             this.onDisable();
15516         }
15517         this.disabled = true;
15518         this.fireEvent("disable", this);
15519         return this;
15520     },
15521
15522         // private
15523     onDisable : function(){
15524         this.getActionEl().addClass(this.disabledClass);
15525         this.el.dom.disabled = true;
15526     },
15527
15528     /**
15529      * Enable this component.
15530      * @return {Roo.Component} this
15531      */
15532     enable : function(){
15533         if(this.rendered){
15534             this.onEnable();
15535         }
15536         this.disabled = false;
15537         this.fireEvent("enable", this);
15538         return this;
15539     },
15540
15541         // private
15542     onEnable : function(){
15543         this.getActionEl().removeClass(this.disabledClass);
15544         this.el.dom.disabled = false;
15545     },
15546
15547     /**
15548      * Convenience function for setting disabled/enabled by boolean.
15549      * @param {Boolean} disabled
15550      */
15551     setDisabled : function(disabled){
15552         this[disabled ? "disable" : "enable"]();
15553     },
15554
15555     /**
15556      * Show this component.
15557      * @return {Roo.Component} this
15558      */
15559     show: function(){
15560         if(this.fireEvent("beforeshow", this) !== false){
15561             this.hidden = false;
15562             if(this.rendered){
15563                 this.onShow();
15564             }
15565             this.fireEvent("show", this);
15566         }
15567         return this;
15568     },
15569
15570     // private
15571     onShow : function(){
15572         var ae = this.getActionEl();
15573         if(this.hideMode == 'visibility'){
15574             ae.dom.style.visibility = "visible";
15575         }else if(this.hideMode == 'offsets'){
15576             ae.removeClass('x-hidden');
15577         }else{
15578             ae.dom.style.display = "";
15579         }
15580     },
15581
15582     /**
15583      * Hide this component.
15584      * @return {Roo.Component} this
15585      */
15586     hide: function(){
15587         if(this.fireEvent("beforehide", this) !== false){
15588             this.hidden = true;
15589             if(this.rendered){
15590                 this.onHide();
15591             }
15592             this.fireEvent("hide", this);
15593         }
15594         return this;
15595     },
15596
15597     // private
15598     onHide : function(){
15599         var ae = this.getActionEl();
15600         if(this.hideMode == 'visibility'){
15601             ae.dom.style.visibility = "hidden";
15602         }else if(this.hideMode == 'offsets'){
15603             ae.addClass('x-hidden');
15604         }else{
15605             ae.dom.style.display = "none";
15606         }
15607     },
15608
15609     /**
15610      * Convenience function to hide or show this component by boolean.
15611      * @param {Boolean} visible True to show, false to hide
15612      * @return {Roo.Component} this
15613      */
15614     setVisible: function(visible){
15615         if(visible) {
15616             this.show();
15617         }else{
15618             this.hide();
15619         }
15620         return this;
15621     },
15622
15623     /**
15624      * Returns true if this component is visible.
15625      */
15626     isVisible : function(){
15627         return this.getActionEl().isVisible();
15628     },
15629
15630     cloneConfig : function(overrides){
15631         overrides = overrides || {};
15632         var id = overrides.id || Roo.id();
15633         var cfg = Roo.applyIf(overrides, this.initialConfig);
15634         cfg.id = id; // prevent dup id
15635         return new this.constructor(cfg);
15636     }
15637 });/*
15638  * Based on:
15639  * Ext JS Library 1.1.1
15640  * Copyright(c) 2006-2007, Ext JS, LLC.
15641  *
15642  * Originally Released Under LGPL - original licence link has changed is not relivant.
15643  *
15644  * Fork - LGPL
15645  * <script type="text/javascript">
15646  */
15647
15648 /**
15649  * @class Roo.BoxComponent
15650  * @extends Roo.Component
15651  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15652  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15653  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15654  * layout containers.
15655  * @constructor
15656  * @param {Roo.Element/String/Object} config The configuration options.
15657  */
15658 Roo.BoxComponent = function(config){
15659     Roo.Component.call(this, config);
15660     this.addEvents({
15661         /**
15662          * @event resize
15663          * Fires after the component is resized.
15664              * @param {Roo.Component} this
15665              * @param {Number} adjWidth The box-adjusted width that was set
15666              * @param {Number} adjHeight The box-adjusted height that was set
15667              * @param {Number} rawWidth The width that was originally specified
15668              * @param {Number} rawHeight The height that was originally specified
15669              */
15670         resize : true,
15671         /**
15672          * @event move
15673          * Fires after the component is moved.
15674              * @param {Roo.Component} this
15675              * @param {Number} x The new x position
15676              * @param {Number} y The new y position
15677              */
15678         move : true
15679     });
15680 };
15681
15682 Roo.extend(Roo.BoxComponent, Roo.Component, {
15683     // private, set in afterRender to signify that the component has been rendered
15684     boxReady : false,
15685     // private, used to defer height settings to subclasses
15686     deferHeight: false,
15687     /** @cfg {Number} width
15688      * width (optional) size of component
15689      */
15690      /** @cfg {Number} height
15691      * height (optional) size of component
15692      */
15693      
15694     /**
15695      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15696      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15697      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15698      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15699      * @return {Roo.BoxComponent} this
15700      */
15701     setSize : function(w, h){
15702         // support for standard size objects
15703         if(typeof w == 'object'){
15704             h = w.height;
15705             w = w.width;
15706         }
15707         // not rendered
15708         if(!this.boxReady){
15709             this.width = w;
15710             this.height = h;
15711             return this;
15712         }
15713
15714         // prevent recalcs when not needed
15715         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15716             return this;
15717         }
15718         this.lastSize = {width: w, height: h};
15719
15720         var adj = this.adjustSize(w, h);
15721         var aw = adj.width, ah = adj.height;
15722         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15723             var rz = this.getResizeEl();
15724             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15725                 rz.setSize(aw, ah);
15726             }else if(!this.deferHeight && ah !== undefined){
15727                 rz.setHeight(ah);
15728             }else if(aw !== undefined){
15729                 rz.setWidth(aw);
15730             }
15731             this.onResize(aw, ah, w, h);
15732             this.fireEvent('resize', this, aw, ah, w, h);
15733         }
15734         return this;
15735     },
15736
15737     /**
15738      * Gets the current size of the component's underlying element.
15739      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15740      */
15741     getSize : function(){
15742         return this.el.getSize();
15743     },
15744
15745     /**
15746      * Gets the current XY position of the component's underlying element.
15747      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15748      * @return {Array} The XY position of the element (e.g., [100, 200])
15749      */
15750     getPosition : function(local){
15751         if(local === true){
15752             return [this.el.getLeft(true), this.el.getTop(true)];
15753         }
15754         return this.xy || this.el.getXY();
15755     },
15756
15757     /**
15758      * Gets the current box measurements of the component's underlying element.
15759      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15760      * @returns {Object} box An object in the format {x, y, width, height}
15761      */
15762     getBox : function(local){
15763         var s = this.el.getSize();
15764         if(local){
15765             s.x = this.el.getLeft(true);
15766             s.y = this.el.getTop(true);
15767         }else{
15768             var xy = this.xy || this.el.getXY();
15769             s.x = xy[0];
15770             s.y = xy[1];
15771         }
15772         return s;
15773     },
15774
15775     /**
15776      * Sets the current box measurements of the component's underlying element.
15777      * @param {Object} box An object in the format {x, y, width, height}
15778      * @returns {Roo.BoxComponent} this
15779      */
15780     updateBox : function(box){
15781         this.setSize(box.width, box.height);
15782         this.setPagePosition(box.x, box.y);
15783         return this;
15784     },
15785
15786     // protected
15787     getResizeEl : function(){
15788         return this.resizeEl || this.el;
15789     },
15790
15791     // protected
15792     getPositionEl : function(){
15793         return this.positionEl || this.el;
15794     },
15795
15796     /**
15797      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15798      * This method fires the move event.
15799      * @param {Number} left The new left
15800      * @param {Number} top The new top
15801      * @returns {Roo.BoxComponent} this
15802      */
15803     setPosition : function(x, y){
15804         this.x = x;
15805         this.y = y;
15806         if(!this.boxReady){
15807             return this;
15808         }
15809         var adj = this.adjustPosition(x, y);
15810         var ax = adj.x, ay = adj.y;
15811
15812         var el = this.getPositionEl();
15813         if(ax !== undefined || ay !== undefined){
15814             if(ax !== undefined && ay !== undefined){
15815                 el.setLeftTop(ax, ay);
15816             }else if(ax !== undefined){
15817                 el.setLeft(ax);
15818             }else if(ay !== undefined){
15819                 el.setTop(ay);
15820             }
15821             this.onPosition(ax, ay);
15822             this.fireEvent('move', this, ax, ay);
15823         }
15824         return this;
15825     },
15826
15827     /**
15828      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15829      * This method fires the move event.
15830      * @param {Number} x The new x position
15831      * @param {Number} y The new y position
15832      * @returns {Roo.BoxComponent} this
15833      */
15834     setPagePosition : function(x, y){
15835         this.pageX = x;
15836         this.pageY = y;
15837         if(!this.boxReady){
15838             return;
15839         }
15840         if(x === undefined || y === undefined){ // cannot translate undefined points
15841             return;
15842         }
15843         var p = this.el.translatePoints(x, y);
15844         this.setPosition(p.left, p.top);
15845         return this;
15846     },
15847
15848     // private
15849     onRender : function(ct, position){
15850         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15851         if(this.resizeEl){
15852             this.resizeEl = Roo.get(this.resizeEl);
15853         }
15854         if(this.positionEl){
15855             this.positionEl = Roo.get(this.positionEl);
15856         }
15857     },
15858
15859     // private
15860     afterRender : function(){
15861         Roo.BoxComponent.superclass.afterRender.call(this);
15862         this.boxReady = true;
15863         this.setSize(this.width, this.height);
15864         if(this.x || this.y){
15865             this.setPosition(this.x, this.y);
15866         }
15867         if(this.pageX || this.pageY){
15868             this.setPagePosition(this.pageX, this.pageY);
15869         }
15870     },
15871
15872     /**
15873      * Force the component's size to recalculate based on the underlying element's current height and width.
15874      * @returns {Roo.BoxComponent} this
15875      */
15876     syncSize : function(){
15877         delete this.lastSize;
15878         this.setSize(this.el.getWidth(), this.el.getHeight());
15879         return this;
15880     },
15881
15882     /**
15883      * Called after the component is resized, this method is empty by default but can be implemented by any
15884      * subclass that needs to perform custom logic after a resize occurs.
15885      * @param {Number} adjWidth The box-adjusted width that was set
15886      * @param {Number} adjHeight The box-adjusted height that was set
15887      * @param {Number} rawWidth The width that was originally specified
15888      * @param {Number} rawHeight The height that was originally specified
15889      */
15890     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15891
15892     },
15893
15894     /**
15895      * Called after the component is moved, this method is empty by default but can be implemented by any
15896      * subclass that needs to perform custom logic after a move occurs.
15897      * @param {Number} x The new x position
15898      * @param {Number} y The new y position
15899      */
15900     onPosition : function(x, y){
15901
15902     },
15903
15904     // private
15905     adjustSize : function(w, h){
15906         if(this.autoWidth){
15907             w = 'auto';
15908         }
15909         if(this.autoHeight){
15910             h = 'auto';
15911         }
15912         return {width : w, height: h};
15913     },
15914
15915     // private
15916     adjustPosition : function(x, y){
15917         return {x : x, y: y};
15918     }
15919 });/*
15920  * Original code for Roojs - LGPL
15921  * <script type="text/javascript">
15922  */
15923  
15924 /**
15925  * @class Roo.XComponent
15926  * A delayed Element creator...
15927  * Or a way to group chunks of interface together.
15928  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15929  *  used in conjunction with XComponent.build() it will create an instance of each element,
15930  *  then call addxtype() to build the User interface.
15931  * 
15932  * Mypart.xyx = new Roo.XComponent({
15933
15934     parent : 'Mypart.xyz', // empty == document.element.!!
15935     order : '001',
15936     name : 'xxxx'
15937     region : 'xxxx'
15938     disabled : function() {} 
15939      
15940     tree : function() { // return an tree of xtype declared components
15941         var MODULE = this;
15942         return 
15943         {
15944             xtype : 'NestedLayoutPanel',
15945             // technicall
15946         }
15947      ]
15948  *})
15949  *
15950  *
15951  * It can be used to build a big heiracy, with parent etc.
15952  * or you can just use this to render a single compoent to a dom element
15953  * MYPART.render(Roo.Element | String(id) | dom_element )
15954  *
15955  *
15956  * Usage patterns.
15957  *
15958  * Classic Roo
15959  *
15960  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15961  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15962  *
15963  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15964  *
15965  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15966  * - if mulitple topModules exist, the last one is defined as the top module.
15967  *
15968  * Embeded Roo
15969  * 
15970  * When the top level or multiple modules are to embedded into a existing HTML page,
15971  * the parent element can container '#id' of the element where the module will be drawn.
15972  *
15973  * Bootstrap Roo
15974  *
15975  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15976  * it relies more on a include mechanism, where sub modules are included into an outer page.
15977  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15978  * 
15979  * Bootstrap Roo Included elements
15980  *
15981  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15982  * hence confusing the component builder as it thinks there are multiple top level elements. 
15983  *
15984  * 
15985  * 
15986  * @extends Roo.util.Observable
15987  * @constructor
15988  * @param cfg {Object} configuration of component
15989  * 
15990  */
15991 Roo.XComponent = function(cfg) {
15992     Roo.apply(this, cfg);
15993     this.addEvents({ 
15994         /**
15995              * @event built
15996              * Fires when this the componnt is built
15997              * @param {Roo.XComponent} c the component
15998              */
15999         'built' : true
16000         
16001     });
16002     this.region = this.region || 'center'; // default..
16003     Roo.XComponent.register(this);
16004     this.modules = false;
16005     this.el = false; // where the layout goes..
16006     
16007     
16008 }
16009 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16010     /**
16011      * @property el
16012      * The created element (with Roo.factory())
16013      * @type {Roo.Layout}
16014      */
16015     el  : false,
16016     
16017     /**
16018      * @property el
16019      * for BC  - use el in new code
16020      * @type {Roo.Layout}
16021      */
16022     panel : false,
16023     
16024     /**
16025      * @property layout
16026      * for BC  - use el in new code
16027      * @type {Roo.Layout}
16028      */
16029     layout : false,
16030     
16031      /**
16032      * @cfg {Function|boolean} disabled
16033      * If this module is disabled by some rule, return true from the funtion
16034      */
16035     disabled : false,
16036     
16037     /**
16038      * @cfg {String} parent 
16039      * Name of parent element which it get xtype added to..
16040      */
16041     parent: false,
16042     
16043     /**
16044      * @cfg {String} order
16045      * Used to set the order in which elements are created (usefull for multiple tabs)
16046      */
16047     
16048     order : false,
16049     /**
16050      * @cfg {String} name
16051      * String to display while loading.
16052      */
16053     name : false,
16054     /**
16055      * @cfg {String} region
16056      * Region to render component to (defaults to center)
16057      */
16058     region : 'center',
16059     
16060     /**
16061      * @cfg {Array} items
16062      * A single item array - the first element is the root of the tree..
16063      * It's done this way to stay compatible with the Xtype system...
16064      */
16065     items : false,
16066     
16067     /**
16068      * @property _tree
16069      * The method that retuns the tree of parts that make up this compoennt 
16070      * @type {function}
16071      */
16072     _tree  : false,
16073     
16074      /**
16075      * render
16076      * render element to dom or tree
16077      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16078      */
16079     
16080     render : function(el)
16081     {
16082         
16083         el = el || false;
16084         var hp = this.parent ? 1 : 0;
16085         Roo.debug &&  Roo.log(this);
16086         
16087         var tree = this._tree ? this._tree() : this.tree();
16088
16089         
16090         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16091             // if parent is a '#.....' string, then let's use that..
16092             var ename = this.parent.substr(1);
16093             this.parent = false;
16094             Roo.debug && Roo.log(ename);
16095             switch (ename) {
16096                 case 'bootstrap-body':
16097                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16098                         // this is the BorderLayout standard?
16099                        this.parent = { el : true };
16100                        break;
16101                     }
16102                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16103                         // need to insert stuff...
16104                         this.parent =  {
16105                              el : new Roo.bootstrap.layout.Border({
16106                                  el : document.body, 
16107                      
16108                                  center: {
16109                                     titlebar: false,
16110                                     autoScroll:false,
16111                                     closeOnTab: true,
16112                                     tabPosition: 'top',
16113                                       //resizeTabs: true,
16114                                     alwaysShowTabs: true,
16115                                     hideTabs: false
16116                                      //minTabWidth: 140
16117                                  }
16118                              })
16119                         
16120                          };
16121                          break;
16122                     }
16123                          
16124                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16125                         this.parent = { el :  new  Roo.bootstrap.Body() };
16126                         Roo.debug && Roo.log("setting el to doc body");
16127                          
16128                     } else {
16129                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16130                     }
16131                     break;
16132                 case 'bootstrap':
16133                     this.parent = { el : true};
16134                     // fall through
16135                 default:
16136                     el = Roo.get(ename);
16137                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16138                         this.parent = { el : true};
16139                     }
16140                     
16141                     break;
16142             }
16143                 
16144             
16145             if (!el && !this.parent) {
16146                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16147                 return;
16148             }
16149         }
16150         
16151         Roo.debug && Roo.log("EL:");
16152         Roo.debug && Roo.log(el);
16153         Roo.debug && Roo.log("this.parent.el:");
16154         Roo.debug && Roo.log(this.parent.el);
16155         
16156
16157         // altertive root elements ??? - we need a better way to indicate these.
16158         var is_alt = Roo.XComponent.is_alt ||
16159                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16160                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16161                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16162         
16163         
16164         
16165         if (!this.parent && is_alt) {
16166             //el = Roo.get(document.body);
16167             this.parent = { el : true };
16168         }
16169             
16170             
16171         
16172         if (!this.parent) {
16173             
16174             Roo.debug && Roo.log("no parent - creating one");
16175             
16176             el = el ? Roo.get(el) : false;      
16177             
16178             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16179                 
16180                 this.parent =  {
16181                     el : new Roo.bootstrap.layout.Border({
16182                         el: el || document.body,
16183                     
16184                         center: {
16185                             titlebar: false,
16186                             autoScroll:false,
16187                             closeOnTab: true,
16188                             tabPosition: 'top',
16189                              //resizeTabs: true,
16190                             alwaysShowTabs: false,
16191                             hideTabs: true,
16192                             minTabWidth: 140,
16193                             overflow: 'visible'
16194                          }
16195                      })
16196                 };
16197             } else {
16198             
16199                 // it's a top level one..
16200                 this.parent =  {
16201                     el : new Roo.BorderLayout(el || document.body, {
16202                         center: {
16203                             titlebar: false,
16204                             autoScroll:false,
16205                             closeOnTab: true,
16206                             tabPosition: 'top',
16207                              //resizeTabs: true,
16208                             alwaysShowTabs: el && hp? false :  true,
16209                             hideTabs: el || !hp ? true :  false,
16210                             minTabWidth: 140
16211                          }
16212                     })
16213                 };
16214             }
16215         }
16216         
16217         if (!this.parent.el) {
16218                 // probably an old style ctor, which has been disabled.
16219                 return;
16220
16221         }
16222                 // The 'tree' method is  '_tree now' 
16223             
16224         tree.region = tree.region || this.region;
16225         var is_body = false;
16226         if (this.parent.el === true) {
16227             // bootstrap... - body..
16228             if (el) {
16229                 tree.el = el;
16230             }
16231             this.parent.el = Roo.factory(tree);
16232             is_body = true;
16233         }
16234         
16235         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16236         this.fireEvent('built', this);
16237         
16238         this.panel = this.el;
16239         this.layout = this.panel.layout;
16240         this.parentLayout = this.parent.layout  || false;  
16241          
16242     }
16243     
16244 });
16245
16246 Roo.apply(Roo.XComponent, {
16247     /**
16248      * @property  hideProgress
16249      * true to disable the building progress bar.. usefull on single page renders.
16250      * @type Boolean
16251      */
16252     hideProgress : false,
16253     /**
16254      * @property  buildCompleted
16255      * True when the builder has completed building the interface.
16256      * @type Boolean
16257      */
16258     buildCompleted : false,
16259      
16260     /**
16261      * @property  topModule
16262      * the upper most module - uses document.element as it's constructor.
16263      * @type Object
16264      */
16265      
16266     topModule  : false,
16267       
16268     /**
16269      * @property  modules
16270      * array of modules to be created by registration system.
16271      * @type {Array} of Roo.XComponent
16272      */
16273     
16274     modules : [],
16275     /**
16276      * @property  elmodules
16277      * array of modules to be created by which use #ID 
16278      * @type {Array} of Roo.XComponent
16279      */
16280      
16281     elmodules : [],
16282
16283      /**
16284      * @property  is_alt
16285      * Is an alternative Root - normally used by bootstrap or other systems,
16286      *    where the top element in the tree can wrap 'body' 
16287      * @type {boolean}  (default false)
16288      */
16289      
16290     is_alt : false,
16291     /**
16292      * @property  build_from_html
16293      * Build elements from html - used by bootstrap HTML stuff 
16294      *    - this is cleared after build is completed
16295      * @type {boolean}    (default false)
16296      */
16297      
16298     build_from_html : false,
16299     /**
16300      * Register components to be built later.
16301      *
16302      * This solves the following issues
16303      * - Building is not done on page load, but after an authentication process has occured.
16304      * - Interface elements are registered on page load
16305      * - Parent Interface elements may not be loaded before child, so this handles that..
16306      * 
16307      *
16308      * example:
16309      * 
16310      * MyApp.register({
16311           order : '000001',
16312           module : 'Pman.Tab.projectMgr',
16313           region : 'center',
16314           parent : 'Pman.layout',
16315           disabled : false,  // or use a function..
16316         })
16317      
16318      * * @param {Object} details about module
16319      */
16320     register : function(obj) {
16321                 
16322         Roo.XComponent.event.fireEvent('register', obj);
16323         switch(typeof(obj.disabled) ) {
16324                 
16325             case 'undefined':
16326                 break;
16327             
16328             case 'function':
16329                 if ( obj.disabled() ) {
16330                         return;
16331                 }
16332                 break;
16333             
16334             default:
16335                 if (obj.disabled) {
16336                         return;
16337                 }
16338                 break;
16339         }
16340                 
16341         this.modules.push(obj);
16342          
16343     },
16344     /**
16345      * convert a string to an object..
16346      * eg. 'AAA.BBB' -> finds AAA.BBB
16347
16348      */
16349     
16350     toObject : function(str)
16351     {
16352         if (!str || typeof(str) == 'object') {
16353             return str;
16354         }
16355         if (str.substring(0,1) == '#') {
16356             return str;
16357         }
16358
16359         var ar = str.split('.');
16360         var rt, o;
16361         rt = ar.shift();
16362             /** eval:var:o */
16363         try {
16364             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16365         } catch (e) {
16366             throw "Module not found : " + str;
16367         }
16368         
16369         if (o === false) {
16370             throw "Module not found : " + str;
16371         }
16372         Roo.each(ar, function(e) {
16373             if (typeof(o[e]) == 'undefined') {
16374                 throw "Module not found : " + str;
16375             }
16376             o = o[e];
16377         });
16378         
16379         return o;
16380         
16381     },
16382     
16383     
16384     /**
16385      * move modules into their correct place in the tree..
16386      * 
16387      */
16388     preBuild : function ()
16389     {
16390         var _t = this;
16391         Roo.each(this.modules , function (obj)
16392         {
16393             Roo.XComponent.event.fireEvent('beforebuild', obj);
16394             
16395             var opar = obj.parent;
16396             try { 
16397                 obj.parent = this.toObject(opar);
16398             } catch(e) {
16399                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16400                 return;
16401             }
16402             
16403             if (!obj.parent) {
16404                 Roo.debug && Roo.log("GOT top level module");
16405                 Roo.debug && Roo.log(obj);
16406                 obj.modules = new Roo.util.MixedCollection(false, 
16407                     function(o) { return o.order + '' }
16408                 );
16409                 this.topModule = obj;
16410                 return;
16411             }
16412                         // parent is a string (usually a dom element name..)
16413             if (typeof(obj.parent) == 'string') {
16414                 this.elmodules.push(obj);
16415                 return;
16416             }
16417             if (obj.parent.constructor != Roo.XComponent) {
16418                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16419             }
16420             if (!obj.parent.modules) {
16421                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16422                     function(o) { return o.order + '' }
16423                 );
16424             }
16425             if (obj.parent.disabled) {
16426                 obj.disabled = true;
16427             }
16428             obj.parent.modules.add(obj);
16429         }, this);
16430     },
16431     
16432      /**
16433      * make a list of modules to build.
16434      * @return {Array} list of modules. 
16435      */ 
16436     
16437     buildOrder : function()
16438     {
16439         var _this = this;
16440         var cmp = function(a,b) {   
16441             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16442         };
16443         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16444             throw "No top level modules to build";
16445         }
16446         
16447         // make a flat list in order of modules to build.
16448         var mods = this.topModule ? [ this.topModule ] : [];
16449                 
16450         
16451         // elmodules (is a list of DOM based modules )
16452         Roo.each(this.elmodules, function(e) {
16453             mods.push(e);
16454             if (!this.topModule &&
16455                 typeof(e.parent) == 'string' &&
16456                 e.parent.substring(0,1) == '#' &&
16457                 Roo.get(e.parent.substr(1))
16458                ) {
16459                 
16460                 _this.topModule = e;
16461             }
16462             
16463         });
16464
16465         
16466         // add modules to their parents..
16467         var addMod = function(m) {
16468             Roo.debug && Roo.log("build Order: add: " + m.name);
16469                 
16470             mods.push(m);
16471             if (m.modules && !m.disabled) {
16472                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16473                 m.modules.keySort('ASC',  cmp );
16474                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16475     
16476                 m.modules.each(addMod);
16477             } else {
16478                 Roo.debug && Roo.log("build Order: no child modules");
16479             }
16480             // not sure if this is used any more..
16481             if (m.finalize) {
16482                 m.finalize.name = m.name + " (clean up) ";
16483                 mods.push(m.finalize);
16484             }
16485             
16486         }
16487         if (this.topModule && this.topModule.modules) { 
16488             this.topModule.modules.keySort('ASC',  cmp );
16489             this.topModule.modules.each(addMod);
16490         } 
16491         return mods;
16492     },
16493     
16494      /**
16495      * Build the registered modules.
16496      * @param {Object} parent element.
16497      * @param {Function} optional method to call after module has been added.
16498      * 
16499      */ 
16500    
16501     build : function(opts) 
16502     {
16503         
16504         if (typeof(opts) != 'undefined') {
16505             Roo.apply(this,opts);
16506         }
16507         
16508         this.preBuild();
16509         var mods = this.buildOrder();
16510       
16511         //this.allmods = mods;
16512         //Roo.debug && Roo.log(mods);
16513         //return;
16514         if (!mods.length) { // should not happen
16515             throw "NO modules!!!";
16516         }
16517         
16518         
16519         var msg = "Building Interface...";
16520         // flash it up as modal - so we store the mask!?
16521         if (!this.hideProgress && Roo.MessageBox) {
16522             Roo.MessageBox.show({ title: 'loading' });
16523             Roo.MessageBox.show({
16524                title: "Please wait...",
16525                msg: msg,
16526                width:450,
16527                progress:true,
16528                closable:false,
16529                modal: false
16530               
16531             });
16532         }
16533         var total = mods.length;
16534         
16535         var _this = this;
16536         var progressRun = function() {
16537             if (!mods.length) {
16538                 Roo.debug && Roo.log('hide?');
16539                 if (!this.hideProgress && Roo.MessageBox) {
16540                     Roo.MessageBox.hide();
16541                 }
16542                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16543                 
16544                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16545                 
16546                 // THE END...
16547                 return false;   
16548             }
16549             
16550             var m = mods.shift();
16551             
16552             
16553             Roo.debug && Roo.log(m);
16554             // not sure if this is supported any more.. - modules that are are just function
16555             if (typeof(m) == 'function') { 
16556                 m.call(this);
16557                 return progressRun.defer(10, _this);
16558             } 
16559             
16560             
16561             msg = "Building Interface " + (total  - mods.length) + 
16562                     " of " + total + 
16563                     (m.name ? (' - ' + m.name) : '');
16564                         Roo.debug && Roo.log(msg);
16565             if (!_this.hideProgress &&  Roo.MessageBox) { 
16566                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16567             }
16568             
16569          
16570             // is the module disabled?
16571             var disabled = (typeof(m.disabled) == 'function') ?
16572                 m.disabled.call(m.module.disabled) : m.disabled;    
16573             
16574             
16575             if (disabled) {
16576                 return progressRun(); // we do not update the display!
16577             }
16578             
16579             // now build 
16580             
16581                         
16582                         
16583             m.render();
16584             // it's 10 on top level, and 1 on others??? why...
16585             return progressRun.defer(10, _this);
16586              
16587         }
16588         progressRun.defer(1, _this);
16589      
16590         
16591         
16592     },
16593         
16594         
16595         /**
16596          * Event Object.
16597          *
16598          *
16599          */
16600         event: false, 
16601     /**
16602          * wrapper for event.on - aliased later..  
16603          * Typically use to register a event handler for register:
16604          *
16605          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16606          *
16607          */
16608     on : false
16609    
16610     
16611     
16612 });
16613
16614 Roo.XComponent.event = new Roo.util.Observable({
16615                 events : { 
16616                         /**
16617                          * @event register
16618                          * Fires when an Component is registered,
16619                          * set the disable property on the Component to stop registration.
16620                          * @param {Roo.XComponent} c the component being registerd.
16621                          * 
16622                          */
16623                         'register' : true,
16624             /**
16625                          * @event beforebuild
16626                          * Fires before each Component is built
16627                          * can be used to apply permissions.
16628                          * @param {Roo.XComponent} c the component being registerd.
16629                          * 
16630                          */
16631                         'beforebuild' : true,
16632                         /**
16633                          * @event buildcomplete
16634                          * Fires on the top level element when all elements have been built
16635                          * @param {Roo.XComponent} the top level component.
16636                          */
16637                         'buildcomplete' : true
16638                         
16639                 }
16640 });
16641
16642 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16643  //
16644  /**
16645  * marked - a markdown parser
16646  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16647  * https://github.com/chjj/marked
16648  */
16649
16650
16651 /**
16652  *
16653  * Roo.Markdown - is a very crude wrapper around marked..
16654  *
16655  * usage:
16656  * 
16657  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16658  * 
16659  * Note: move the sample code to the bottom of this
16660  * file before uncommenting it.
16661  *
16662  */
16663
16664 Roo.Markdown = {};
16665 Roo.Markdown.toHtml = function(text) {
16666     
16667     var c = new Roo.Markdown.marked.setOptions({
16668             renderer: new Roo.Markdown.marked.Renderer(),
16669             gfm: true,
16670             tables: true,
16671             breaks: false,
16672             pedantic: false,
16673             sanitize: false,
16674             smartLists: true,
16675             smartypants: false
16676           });
16677     // A FEW HACKS!!?
16678     
16679     text = text.replace(/\\\n/g,' ');
16680     return Roo.Markdown.marked(text);
16681 };
16682 //
16683 // converter
16684 //
16685 // Wraps all "globals" so that the only thing
16686 // exposed is makeHtml().
16687 //
16688 (function() {
16689     
16690     /**
16691      * Block-Level Grammar
16692      */
16693     
16694     var block = {
16695       newline: /^\n+/,
16696       code: /^( {4}[^\n]+\n*)+/,
16697       fences: noop,
16698       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16699       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16700       nptable: noop,
16701       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16702       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16703       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16704       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16705       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16706       table: noop,
16707       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16708       text: /^[^\n]+/
16709     };
16710     
16711     block.bullet = /(?:[*+-]|\d+\.)/;
16712     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16713     block.item = replace(block.item, 'gm')
16714       (/bull/g, block.bullet)
16715       ();
16716     
16717     block.list = replace(block.list)
16718       (/bull/g, block.bullet)
16719       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16720       ('def', '\\n+(?=' + block.def.source + ')')
16721       ();
16722     
16723     block.blockquote = replace(block.blockquote)
16724       ('def', block.def)
16725       ();
16726     
16727     block._tag = '(?!(?:'
16728       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16729       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16730       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16731     
16732     block.html = replace(block.html)
16733       ('comment', /<!--[\s\S]*?-->/)
16734       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16735       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16736       (/tag/g, block._tag)
16737       ();
16738     
16739     block.paragraph = replace(block.paragraph)
16740       ('hr', block.hr)
16741       ('heading', block.heading)
16742       ('lheading', block.lheading)
16743       ('blockquote', block.blockquote)
16744       ('tag', '<' + block._tag)
16745       ('def', block.def)
16746       ();
16747     
16748     /**
16749      * Normal Block Grammar
16750      */
16751     
16752     block.normal = merge({}, block);
16753     
16754     /**
16755      * GFM Block Grammar
16756      */
16757     
16758     block.gfm = merge({}, block.normal, {
16759       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16760       paragraph: /^/,
16761       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16762     });
16763     
16764     block.gfm.paragraph = replace(block.paragraph)
16765       ('(?!', '(?!'
16766         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16767         + block.list.source.replace('\\1', '\\3') + '|')
16768       ();
16769     
16770     /**
16771      * GFM + Tables Block Grammar
16772      */
16773     
16774     block.tables = merge({}, block.gfm, {
16775       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16776       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16777     });
16778     
16779     /**
16780      * Block Lexer
16781      */
16782     
16783     function Lexer(options) {
16784       this.tokens = [];
16785       this.tokens.links = {};
16786       this.options = options || marked.defaults;
16787       this.rules = block.normal;
16788     
16789       if (this.options.gfm) {
16790         if (this.options.tables) {
16791           this.rules = block.tables;
16792         } else {
16793           this.rules = block.gfm;
16794         }
16795       }
16796     }
16797     
16798     /**
16799      * Expose Block Rules
16800      */
16801     
16802     Lexer.rules = block;
16803     
16804     /**
16805      * Static Lex Method
16806      */
16807     
16808     Lexer.lex = function(src, options) {
16809       var lexer = new Lexer(options);
16810       return lexer.lex(src);
16811     };
16812     
16813     /**
16814      * Preprocessing
16815      */
16816     
16817     Lexer.prototype.lex = function(src) {
16818       src = src
16819         .replace(/\r\n|\r/g, '\n')
16820         .replace(/\t/g, '    ')
16821         .replace(/\u00a0/g, ' ')
16822         .replace(/\u2424/g, '\n');
16823     
16824       return this.token(src, true);
16825     };
16826     
16827     /**
16828      * Lexing
16829      */
16830     
16831     Lexer.prototype.token = function(src, top, bq) {
16832       var src = src.replace(/^ +$/gm, '')
16833         , next
16834         , loose
16835         , cap
16836         , bull
16837         , b
16838         , item
16839         , space
16840         , i
16841         , l;
16842     
16843       while (src) {
16844         // newline
16845         if (cap = this.rules.newline.exec(src)) {
16846           src = src.substring(cap[0].length);
16847           if (cap[0].length > 1) {
16848             this.tokens.push({
16849               type: 'space'
16850             });
16851           }
16852         }
16853     
16854         // code
16855         if (cap = this.rules.code.exec(src)) {
16856           src = src.substring(cap[0].length);
16857           cap = cap[0].replace(/^ {4}/gm, '');
16858           this.tokens.push({
16859             type: 'code',
16860             text: !this.options.pedantic
16861               ? cap.replace(/\n+$/, '')
16862               : cap
16863           });
16864           continue;
16865         }
16866     
16867         // fences (gfm)
16868         if (cap = this.rules.fences.exec(src)) {
16869           src = src.substring(cap[0].length);
16870           this.tokens.push({
16871             type: 'code',
16872             lang: cap[2],
16873             text: cap[3] || ''
16874           });
16875           continue;
16876         }
16877     
16878         // heading
16879         if (cap = this.rules.heading.exec(src)) {
16880           src = src.substring(cap[0].length);
16881           this.tokens.push({
16882             type: 'heading',
16883             depth: cap[1].length,
16884             text: cap[2]
16885           });
16886           continue;
16887         }
16888     
16889         // table no leading pipe (gfm)
16890         if (top && (cap = this.rules.nptable.exec(src))) {
16891           src = src.substring(cap[0].length);
16892     
16893           item = {
16894             type: 'table',
16895             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16896             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16897             cells: cap[3].replace(/\n$/, '').split('\n')
16898           };
16899     
16900           for (i = 0; i < item.align.length; i++) {
16901             if (/^ *-+: *$/.test(item.align[i])) {
16902               item.align[i] = 'right';
16903             } else if (/^ *:-+: *$/.test(item.align[i])) {
16904               item.align[i] = 'center';
16905             } else if (/^ *:-+ *$/.test(item.align[i])) {
16906               item.align[i] = 'left';
16907             } else {
16908               item.align[i] = null;
16909             }
16910           }
16911     
16912           for (i = 0; i < item.cells.length; i++) {
16913             item.cells[i] = item.cells[i].split(/ *\| */);
16914           }
16915     
16916           this.tokens.push(item);
16917     
16918           continue;
16919         }
16920     
16921         // lheading
16922         if (cap = this.rules.lheading.exec(src)) {
16923           src = src.substring(cap[0].length);
16924           this.tokens.push({
16925             type: 'heading',
16926             depth: cap[2] === '=' ? 1 : 2,
16927             text: cap[1]
16928           });
16929           continue;
16930         }
16931     
16932         // hr
16933         if (cap = this.rules.hr.exec(src)) {
16934           src = src.substring(cap[0].length);
16935           this.tokens.push({
16936             type: 'hr'
16937           });
16938           continue;
16939         }
16940     
16941         // blockquote
16942         if (cap = this.rules.blockquote.exec(src)) {
16943           src = src.substring(cap[0].length);
16944     
16945           this.tokens.push({
16946             type: 'blockquote_start'
16947           });
16948     
16949           cap = cap[0].replace(/^ *> ?/gm, '');
16950     
16951           // Pass `top` to keep the current
16952           // "toplevel" state. This is exactly
16953           // how markdown.pl works.
16954           this.token(cap, top, true);
16955     
16956           this.tokens.push({
16957             type: 'blockquote_end'
16958           });
16959     
16960           continue;
16961         }
16962     
16963         // list
16964         if (cap = this.rules.list.exec(src)) {
16965           src = src.substring(cap[0].length);
16966           bull = cap[2];
16967     
16968           this.tokens.push({
16969             type: 'list_start',
16970             ordered: bull.length > 1
16971           });
16972     
16973           // Get each top-level item.
16974           cap = cap[0].match(this.rules.item);
16975     
16976           next = false;
16977           l = cap.length;
16978           i = 0;
16979     
16980           for (; i < l; i++) {
16981             item = cap[i];
16982     
16983             // Remove the list item's bullet
16984             // so it is seen as the next token.
16985             space = item.length;
16986             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16987     
16988             // Outdent whatever the
16989             // list item contains. Hacky.
16990             if (~item.indexOf('\n ')) {
16991               space -= item.length;
16992               item = !this.options.pedantic
16993                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16994                 : item.replace(/^ {1,4}/gm, '');
16995             }
16996     
16997             // Determine whether the next list item belongs here.
16998             // Backpedal if it does not belong in this list.
16999             if (this.options.smartLists && i !== l - 1) {
17000               b = block.bullet.exec(cap[i + 1])[0];
17001               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17002                 src = cap.slice(i + 1).join('\n') + src;
17003                 i = l - 1;
17004               }
17005             }
17006     
17007             // Determine whether item is loose or not.
17008             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17009             // for discount behavior.
17010             loose = next || /\n\n(?!\s*$)/.test(item);
17011             if (i !== l - 1) {
17012               next = item.charAt(item.length - 1) === '\n';
17013               if (!loose) { loose = next; }
17014             }
17015     
17016             this.tokens.push({
17017               type: loose
17018                 ? 'loose_item_start'
17019                 : 'list_item_start'
17020             });
17021     
17022             // Recurse.
17023             this.token(item, false, bq);
17024     
17025             this.tokens.push({
17026               type: 'list_item_end'
17027             });
17028           }
17029     
17030           this.tokens.push({
17031             type: 'list_end'
17032           });
17033     
17034           continue;
17035         }
17036     
17037         // html
17038         if (cap = this.rules.html.exec(src)) {
17039           src = src.substring(cap[0].length);
17040           this.tokens.push({
17041             type: this.options.sanitize
17042               ? 'paragraph'
17043               : 'html',
17044             pre: !this.options.sanitizer
17045               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17046             text: cap[0]
17047           });
17048           continue;
17049         }
17050     
17051         // def
17052         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17053           src = src.substring(cap[0].length);
17054           this.tokens.links[cap[1].toLowerCase()] = {
17055             href: cap[2],
17056             title: cap[3]
17057           };
17058           continue;
17059         }
17060     
17061         // table (gfm)
17062         if (top && (cap = this.rules.table.exec(src))) {
17063           src = src.substring(cap[0].length);
17064     
17065           item = {
17066             type: 'table',
17067             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17068             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17069             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17070           };
17071     
17072           for (i = 0; i < item.align.length; i++) {
17073             if (/^ *-+: *$/.test(item.align[i])) {
17074               item.align[i] = 'right';
17075             } else if (/^ *:-+: *$/.test(item.align[i])) {
17076               item.align[i] = 'center';
17077             } else if (/^ *:-+ *$/.test(item.align[i])) {
17078               item.align[i] = 'left';
17079             } else {
17080               item.align[i] = null;
17081             }
17082           }
17083     
17084           for (i = 0; i < item.cells.length; i++) {
17085             item.cells[i] = item.cells[i]
17086               .replace(/^ *\| *| *\| *$/g, '')
17087               .split(/ *\| */);
17088           }
17089     
17090           this.tokens.push(item);
17091     
17092           continue;
17093         }
17094     
17095         // top-level paragraph
17096         if (top && (cap = this.rules.paragraph.exec(src))) {
17097           src = src.substring(cap[0].length);
17098           this.tokens.push({
17099             type: 'paragraph',
17100             text: cap[1].charAt(cap[1].length - 1) === '\n'
17101               ? cap[1].slice(0, -1)
17102               : cap[1]
17103           });
17104           continue;
17105         }
17106     
17107         // text
17108         if (cap = this.rules.text.exec(src)) {
17109           // Top-level should never reach here.
17110           src = src.substring(cap[0].length);
17111           this.tokens.push({
17112             type: 'text',
17113             text: cap[0]
17114           });
17115           continue;
17116         }
17117     
17118         if (src) {
17119           throw new
17120             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17121         }
17122       }
17123     
17124       return this.tokens;
17125     };
17126     
17127     /**
17128      * Inline-Level Grammar
17129      */
17130     
17131     var inline = {
17132       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17133       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17134       url: noop,
17135       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17136       link: /^!?\[(inside)\]\(href\)/,
17137       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17138       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17139       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17140       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17141       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17142       br: /^ {2,}\n(?!\s*$)/,
17143       del: noop,
17144       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17145     };
17146     
17147     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17148     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17149     
17150     inline.link = replace(inline.link)
17151       ('inside', inline._inside)
17152       ('href', inline._href)
17153       ();
17154     
17155     inline.reflink = replace(inline.reflink)
17156       ('inside', inline._inside)
17157       ();
17158     
17159     /**
17160      * Normal Inline Grammar
17161      */
17162     
17163     inline.normal = merge({}, inline);
17164     
17165     /**
17166      * Pedantic Inline Grammar
17167      */
17168     
17169     inline.pedantic = merge({}, inline.normal, {
17170       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17171       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17172     });
17173     
17174     /**
17175      * GFM Inline Grammar
17176      */
17177     
17178     inline.gfm = merge({}, inline.normal, {
17179       escape: replace(inline.escape)('])', '~|])')(),
17180       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17181       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17182       text: replace(inline.text)
17183         (']|', '~]|')
17184         ('|', '|https?://|')
17185         ()
17186     });
17187     
17188     /**
17189      * GFM + Line Breaks Inline Grammar
17190      */
17191     
17192     inline.breaks = merge({}, inline.gfm, {
17193       br: replace(inline.br)('{2,}', '*')(),
17194       text: replace(inline.gfm.text)('{2,}', '*')()
17195     });
17196     
17197     /**
17198      * Inline Lexer & Compiler
17199      */
17200     
17201     function InlineLexer(links, options) {
17202       this.options = options || marked.defaults;
17203       this.links = links;
17204       this.rules = inline.normal;
17205       this.renderer = this.options.renderer || new Renderer;
17206       this.renderer.options = this.options;
17207     
17208       if (!this.links) {
17209         throw new
17210           Error('Tokens array requires a `links` property.');
17211       }
17212     
17213       if (this.options.gfm) {
17214         if (this.options.breaks) {
17215           this.rules = inline.breaks;
17216         } else {
17217           this.rules = inline.gfm;
17218         }
17219       } else if (this.options.pedantic) {
17220         this.rules = inline.pedantic;
17221       }
17222     }
17223     
17224     /**
17225      * Expose Inline Rules
17226      */
17227     
17228     InlineLexer.rules = inline;
17229     
17230     /**
17231      * Static Lexing/Compiling Method
17232      */
17233     
17234     InlineLexer.output = function(src, links, options) {
17235       var inline = new InlineLexer(links, options);
17236       return inline.output(src);
17237     };
17238     
17239     /**
17240      * Lexing/Compiling
17241      */
17242     
17243     InlineLexer.prototype.output = function(src) {
17244       var out = ''
17245         , link
17246         , text
17247         , href
17248         , cap;
17249     
17250       while (src) {
17251         // escape
17252         if (cap = this.rules.escape.exec(src)) {
17253           src = src.substring(cap[0].length);
17254           out += cap[1];
17255           continue;
17256         }
17257     
17258         // autolink
17259         if (cap = this.rules.autolink.exec(src)) {
17260           src = src.substring(cap[0].length);
17261           if (cap[2] === '@') {
17262             text = cap[1].charAt(6) === ':'
17263               ? this.mangle(cap[1].substring(7))
17264               : this.mangle(cap[1]);
17265             href = this.mangle('mailto:') + text;
17266           } else {
17267             text = escape(cap[1]);
17268             href = text;
17269           }
17270           out += this.renderer.link(href, null, text);
17271           continue;
17272         }
17273     
17274         // url (gfm)
17275         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17276           src = src.substring(cap[0].length);
17277           text = escape(cap[1]);
17278           href = text;
17279           out += this.renderer.link(href, null, text);
17280           continue;
17281         }
17282     
17283         // tag
17284         if (cap = this.rules.tag.exec(src)) {
17285           if (!this.inLink && /^<a /i.test(cap[0])) {
17286             this.inLink = true;
17287           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17288             this.inLink = false;
17289           }
17290           src = src.substring(cap[0].length);
17291           out += this.options.sanitize
17292             ? this.options.sanitizer
17293               ? this.options.sanitizer(cap[0])
17294               : escape(cap[0])
17295             : cap[0];
17296           continue;
17297         }
17298     
17299         // link
17300         if (cap = this.rules.link.exec(src)) {
17301           src = src.substring(cap[0].length);
17302           this.inLink = true;
17303           out += this.outputLink(cap, {
17304             href: cap[2],
17305             title: cap[3]
17306           });
17307           this.inLink = false;
17308           continue;
17309         }
17310     
17311         // reflink, nolink
17312         if ((cap = this.rules.reflink.exec(src))
17313             || (cap = this.rules.nolink.exec(src))) {
17314           src = src.substring(cap[0].length);
17315           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17316           link = this.links[link.toLowerCase()];
17317           if (!link || !link.href) {
17318             out += cap[0].charAt(0);
17319             src = cap[0].substring(1) + src;
17320             continue;
17321           }
17322           this.inLink = true;
17323           out += this.outputLink(cap, link);
17324           this.inLink = false;
17325           continue;
17326         }
17327     
17328         // strong
17329         if (cap = this.rules.strong.exec(src)) {
17330           src = src.substring(cap[0].length);
17331           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17332           continue;
17333         }
17334     
17335         // em
17336         if (cap = this.rules.em.exec(src)) {
17337           src = src.substring(cap[0].length);
17338           out += this.renderer.em(this.output(cap[2] || cap[1]));
17339           continue;
17340         }
17341     
17342         // code
17343         if (cap = this.rules.code.exec(src)) {
17344           src = src.substring(cap[0].length);
17345           out += this.renderer.codespan(escape(cap[2], true));
17346           continue;
17347         }
17348     
17349         // br
17350         if (cap = this.rules.br.exec(src)) {
17351           src = src.substring(cap[0].length);
17352           out += this.renderer.br();
17353           continue;
17354         }
17355     
17356         // del (gfm)
17357         if (cap = this.rules.del.exec(src)) {
17358           src = src.substring(cap[0].length);
17359           out += this.renderer.del(this.output(cap[1]));
17360           continue;
17361         }
17362     
17363         // text
17364         if (cap = this.rules.text.exec(src)) {
17365           src = src.substring(cap[0].length);
17366           out += this.renderer.text(escape(this.smartypants(cap[0])));
17367           continue;
17368         }
17369     
17370         if (src) {
17371           throw new
17372             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17373         }
17374       }
17375     
17376       return out;
17377     };
17378     
17379     /**
17380      * Compile Link
17381      */
17382     
17383     InlineLexer.prototype.outputLink = function(cap, link) {
17384       var href = escape(link.href)
17385         , title = link.title ? escape(link.title) : null;
17386     
17387       return cap[0].charAt(0) !== '!'
17388         ? this.renderer.link(href, title, this.output(cap[1]))
17389         : this.renderer.image(href, title, escape(cap[1]));
17390     };
17391     
17392     /**
17393      * Smartypants Transformations
17394      */
17395     
17396     InlineLexer.prototype.smartypants = function(text) {
17397       if (!this.options.smartypants)  { return text; }
17398       return text
17399         // em-dashes
17400         .replace(/---/g, '\u2014')
17401         // en-dashes
17402         .replace(/--/g, '\u2013')
17403         // opening singles
17404         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17405         // closing singles & apostrophes
17406         .replace(/'/g, '\u2019')
17407         // opening doubles
17408         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17409         // closing doubles
17410         .replace(/"/g, '\u201d')
17411         // ellipses
17412         .replace(/\.{3}/g, '\u2026');
17413     };
17414     
17415     /**
17416      * Mangle Links
17417      */
17418     
17419     InlineLexer.prototype.mangle = function(text) {
17420       if (!this.options.mangle) { return text; }
17421       var out = ''
17422         , l = text.length
17423         , i = 0
17424         , ch;
17425     
17426       for (; i < l; i++) {
17427         ch = text.charCodeAt(i);
17428         if (Math.random() > 0.5) {
17429           ch = 'x' + ch.toString(16);
17430         }
17431         out += '&#' + ch + ';';
17432       }
17433     
17434       return out;
17435     };
17436     
17437     /**
17438      * Renderer
17439      */
17440     
17441     function Renderer(options) {
17442       this.options = options || {};
17443     }
17444     
17445     Renderer.prototype.code = function(code, lang, escaped) {
17446       if (this.options.highlight) {
17447         var out = this.options.highlight(code, lang);
17448         if (out != null && out !== code) {
17449           escaped = true;
17450           code = out;
17451         }
17452       } else {
17453             // hack!!! - it's already escapeD?
17454             escaped = true;
17455       }
17456     
17457       if (!lang) {
17458         return '<pre><code>'
17459           + (escaped ? code : escape(code, true))
17460           + '\n</code></pre>';
17461       }
17462     
17463       return '<pre><code class="'
17464         + this.options.langPrefix
17465         + escape(lang, true)
17466         + '">'
17467         + (escaped ? code : escape(code, true))
17468         + '\n</code></pre>\n';
17469     };
17470     
17471     Renderer.prototype.blockquote = function(quote) {
17472       return '<blockquote>\n' + quote + '</blockquote>\n';
17473     };
17474     
17475     Renderer.prototype.html = function(html) {
17476       return html;
17477     };
17478     
17479     Renderer.prototype.heading = function(text, level, raw) {
17480       return '<h'
17481         + level
17482         + ' id="'
17483         + this.options.headerPrefix
17484         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17485         + '">'
17486         + text
17487         + '</h'
17488         + level
17489         + '>\n';
17490     };
17491     
17492     Renderer.prototype.hr = function() {
17493       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17494     };
17495     
17496     Renderer.prototype.list = function(body, ordered) {
17497       var type = ordered ? 'ol' : 'ul';
17498       return '<' + type + '>\n' + body + '</' + type + '>\n';
17499     };
17500     
17501     Renderer.prototype.listitem = function(text) {
17502       return '<li>' + text + '</li>\n';
17503     };
17504     
17505     Renderer.prototype.paragraph = function(text) {
17506       return '<p>' + text + '</p>\n';
17507     };
17508     
17509     Renderer.prototype.table = function(header, body) {
17510       return '<table class="table table-striped">\n'
17511         + '<thead>\n'
17512         + header
17513         + '</thead>\n'
17514         + '<tbody>\n'
17515         + body
17516         + '</tbody>\n'
17517         + '</table>\n';
17518     };
17519     
17520     Renderer.prototype.tablerow = function(content) {
17521       return '<tr>\n' + content + '</tr>\n';
17522     };
17523     
17524     Renderer.prototype.tablecell = function(content, flags) {
17525       var type = flags.header ? 'th' : 'td';
17526       var tag = flags.align
17527         ? '<' + type + ' style="text-align:' + flags.align + '">'
17528         : '<' + type + '>';
17529       return tag + content + '</' + type + '>\n';
17530     };
17531     
17532     // span level renderer
17533     Renderer.prototype.strong = function(text) {
17534       return '<strong>' + text + '</strong>';
17535     };
17536     
17537     Renderer.prototype.em = function(text) {
17538       return '<em>' + text + '</em>';
17539     };
17540     
17541     Renderer.prototype.codespan = function(text) {
17542       return '<code>' + text + '</code>';
17543     };
17544     
17545     Renderer.prototype.br = function() {
17546       return this.options.xhtml ? '<br/>' : '<br>';
17547     };
17548     
17549     Renderer.prototype.del = function(text) {
17550       return '<del>' + text + '</del>';
17551     };
17552     
17553     Renderer.prototype.link = function(href, title, text) {
17554       if (this.options.sanitize) {
17555         try {
17556           var prot = decodeURIComponent(unescape(href))
17557             .replace(/[^\w:]/g, '')
17558             .toLowerCase();
17559         } catch (e) {
17560           return '';
17561         }
17562         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17563           return '';
17564         }
17565       }
17566       var out = '<a href="' + href + '"';
17567       if (title) {
17568         out += ' title="' + title + '"';
17569       }
17570       out += '>' + text + '</a>';
17571       return out;
17572     };
17573     
17574     Renderer.prototype.image = function(href, title, text) {
17575       var out = '<img src="' + href + '" alt="' + text + '"';
17576       if (title) {
17577         out += ' title="' + title + '"';
17578       }
17579       out += this.options.xhtml ? '/>' : '>';
17580       return out;
17581     };
17582     
17583     Renderer.prototype.text = function(text) {
17584       return text;
17585     };
17586     
17587     /**
17588      * Parsing & Compiling
17589      */
17590     
17591     function Parser(options) {
17592       this.tokens = [];
17593       this.token = null;
17594       this.options = options || marked.defaults;
17595       this.options.renderer = this.options.renderer || new Renderer;
17596       this.renderer = this.options.renderer;
17597       this.renderer.options = this.options;
17598     }
17599     
17600     /**
17601      * Static Parse Method
17602      */
17603     
17604     Parser.parse = function(src, options, renderer) {
17605       var parser = new Parser(options, renderer);
17606       return parser.parse(src);
17607     };
17608     
17609     /**
17610      * Parse Loop
17611      */
17612     
17613     Parser.prototype.parse = function(src) {
17614       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17615       this.tokens = src.reverse();
17616     
17617       var out = '';
17618       while (this.next()) {
17619         out += this.tok();
17620       }
17621     
17622       return out;
17623     };
17624     
17625     /**
17626      * Next Token
17627      */
17628     
17629     Parser.prototype.next = function() {
17630       return this.token = this.tokens.pop();
17631     };
17632     
17633     /**
17634      * Preview Next Token
17635      */
17636     
17637     Parser.prototype.peek = function() {
17638       return this.tokens[this.tokens.length - 1] || 0;
17639     };
17640     
17641     /**
17642      * Parse Text Tokens
17643      */
17644     
17645     Parser.prototype.parseText = function() {
17646       var body = this.token.text;
17647     
17648       while (this.peek().type === 'text') {
17649         body += '\n' + this.next().text;
17650       }
17651     
17652       return this.inline.output(body);
17653     };
17654     
17655     /**
17656      * Parse Current Token
17657      */
17658     
17659     Parser.prototype.tok = function() {
17660       switch (this.token.type) {
17661         case 'space': {
17662           return '';
17663         }
17664         case 'hr': {
17665           return this.renderer.hr();
17666         }
17667         case 'heading': {
17668           return this.renderer.heading(
17669             this.inline.output(this.token.text),
17670             this.token.depth,
17671             this.token.text);
17672         }
17673         case 'code': {
17674           return this.renderer.code(this.token.text,
17675             this.token.lang,
17676             this.token.escaped);
17677         }
17678         case 'table': {
17679           var header = ''
17680             , body = ''
17681             , i
17682             , row
17683             , cell
17684             , flags
17685             , j;
17686     
17687           // header
17688           cell = '';
17689           for (i = 0; i < this.token.header.length; i++) {
17690             flags = { header: true, align: this.token.align[i] };
17691             cell += this.renderer.tablecell(
17692               this.inline.output(this.token.header[i]),
17693               { header: true, align: this.token.align[i] }
17694             );
17695           }
17696           header += this.renderer.tablerow(cell);
17697     
17698           for (i = 0; i < this.token.cells.length; i++) {
17699             row = this.token.cells[i];
17700     
17701             cell = '';
17702             for (j = 0; j < row.length; j++) {
17703               cell += this.renderer.tablecell(
17704                 this.inline.output(row[j]),
17705                 { header: false, align: this.token.align[j] }
17706               );
17707             }
17708     
17709             body += this.renderer.tablerow(cell);
17710           }
17711           return this.renderer.table(header, body);
17712         }
17713         case 'blockquote_start': {
17714           var body = '';
17715     
17716           while (this.next().type !== 'blockquote_end') {
17717             body += this.tok();
17718           }
17719     
17720           return this.renderer.blockquote(body);
17721         }
17722         case 'list_start': {
17723           var body = ''
17724             , ordered = this.token.ordered;
17725     
17726           while (this.next().type !== 'list_end') {
17727             body += this.tok();
17728           }
17729     
17730           return this.renderer.list(body, ordered);
17731         }
17732         case 'list_item_start': {
17733           var body = '';
17734     
17735           while (this.next().type !== 'list_item_end') {
17736             body += this.token.type === 'text'
17737               ? this.parseText()
17738               : this.tok();
17739           }
17740     
17741           return this.renderer.listitem(body);
17742         }
17743         case 'loose_item_start': {
17744           var body = '';
17745     
17746           while (this.next().type !== 'list_item_end') {
17747             body += this.tok();
17748           }
17749     
17750           return this.renderer.listitem(body);
17751         }
17752         case 'html': {
17753           var html = !this.token.pre && !this.options.pedantic
17754             ? this.inline.output(this.token.text)
17755             : this.token.text;
17756           return this.renderer.html(html);
17757         }
17758         case 'paragraph': {
17759           return this.renderer.paragraph(this.inline.output(this.token.text));
17760         }
17761         case 'text': {
17762           return this.renderer.paragraph(this.parseText());
17763         }
17764       }
17765     };
17766     
17767     /**
17768      * Helpers
17769      */
17770     
17771     function escape(html, encode) {
17772       return html
17773         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17774         .replace(/</g, '&lt;')
17775         .replace(/>/g, '&gt;')
17776         .replace(/"/g, '&quot;')
17777         .replace(/'/g, '&#39;');
17778     }
17779     
17780     function unescape(html) {
17781         // explicitly match decimal, hex, and named HTML entities 
17782       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17783         n = n.toLowerCase();
17784         if (n === 'colon') { return ':'; }
17785         if (n.charAt(0) === '#') {
17786           return n.charAt(1) === 'x'
17787             ? String.fromCharCode(parseInt(n.substring(2), 16))
17788             : String.fromCharCode(+n.substring(1));
17789         }
17790         return '';
17791       });
17792     }
17793     
17794     function replace(regex, opt) {
17795       regex = regex.source;
17796       opt = opt || '';
17797       return function self(name, val) {
17798         if (!name) { return new RegExp(regex, opt); }
17799         val = val.source || val;
17800         val = val.replace(/(^|[^\[])\^/g, '$1');
17801         regex = regex.replace(name, val);
17802         return self;
17803       };
17804     }
17805     
17806     function noop() {}
17807     noop.exec = noop;
17808     
17809     function merge(obj) {
17810       var i = 1
17811         , target
17812         , key;
17813     
17814       for (; i < arguments.length; i++) {
17815         target = arguments[i];
17816         for (key in target) {
17817           if (Object.prototype.hasOwnProperty.call(target, key)) {
17818             obj[key] = target[key];
17819           }
17820         }
17821       }
17822     
17823       return obj;
17824     }
17825     
17826     
17827     /**
17828      * Marked
17829      */
17830     
17831     function marked(src, opt, callback) {
17832       if (callback || typeof opt === 'function') {
17833         if (!callback) {
17834           callback = opt;
17835           opt = null;
17836         }
17837     
17838         opt = merge({}, marked.defaults, opt || {});
17839     
17840         var highlight = opt.highlight
17841           , tokens
17842           , pending
17843           , i = 0;
17844     
17845         try {
17846           tokens = Lexer.lex(src, opt)
17847         } catch (e) {
17848           return callback(e);
17849         }
17850     
17851         pending = tokens.length;
17852     
17853         var done = function(err) {
17854           if (err) {
17855             opt.highlight = highlight;
17856             return callback(err);
17857           }
17858     
17859           var out;
17860     
17861           try {
17862             out = Parser.parse(tokens, opt);
17863           } catch (e) {
17864             err = e;
17865           }
17866     
17867           opt.highlight = highlight;
17868     
17869           return err
17870             ? callback(err)
17871             : callback(null, out);
17872         };
17873     
17874         if (!highlight || highlight.length < 3) {
17875           return done();
17876         }
17877     
17878         delete opt.highlight;
17879     
17880         if (!pending) { return done(); }
17881     
17882         for (; i < tokens.length; i++) {
17883           (function(token) {
17884             if (token.type !== 'code') {
17885               return --pending || done();
17886             }
17887             return highlight(token.text, token.lang, function(err, code) {
17888               if (err) { return done(err); }
17889               if (code == null || code === token.text) {
17890                 return --pending || done();
17891               }
17892               token.text = code;
17893               token.escaped = true;
17894               --pending || done();
17895             });
17896           })(tokens[i]);
17897         }
17898     
17899         return;
17900       }
17901       try {
17902         if (opt) { opt = merge({}, marked.defaults, opt); }
17903         return Parser.parse(Lexer.lex(src, opt), opt);
17904       } catch (e) {
17905         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17906         if ((opt || marked.defaults).silent) {
17907           return '<p>An error occured:</p><pre>'
17908             + escape(e.message + '', true)
17909             + '</pre>';
17910         }
17911         throw e;
17912       }
17913     }
17914     
17915     /**
17916      * Options
17917      */
17918     
17919     marked.options =
17920     marked.setOptions = function(opt) {
17921       merge(marked.defaults, opt);
17922       return marked;
17923     };
17924     
17925     marked.defaults = {
17926       gfm: true,
17927       tables: true,
17928       breaks: false,
17929       pedantic: false,
17930       sanitize: false,
17931       sanitizer: null,
17932       mangle: true,
17933       smartLists: false,
17934       silent: false,
17935       highlight: null,
17936       langPrefix: 'lang-',
17937       smartypants: false,
17938       headerPrefix: '',
17939       renderer: new Renderer,
17940       xhtml: false
17941     };
17942     
17943     /**
17944      * Expose
17945      */
17946     
17947     marked.Parser = Parser;
17948     marked.parser = Parser.parse;
17949     
17950     marked.Renderer = Renderer;
17951     
17952     marked.Lexer = Lexer;
17953     marked.lexer = Lexer.lex;
17954     
17955     marked.InlineLexer = InlineLexer;
17956     marked.inlineLexer = InlineLexer.output;
17957     
17958     marked.parse = marked;
17959     
17960     Roo.Markdown.marked = marked;
17961
17962 })();/*
17963  * Based on:
17964  * Ext JS Library 1.1.1
17965  * Copyright(c) 2006-2007, Ext JS, LLC.
17966  *
17967  * Originally Released Under LGPL - original licence link has changed is not relivant.
17968  *
17969  * Fork - LGPL
17970  * <script type="text/javascript">
17971  */
17972
17973
17974
17975 /*
17976  * These classes are derivatives of the similarly named classes in the YUI Library.
17977  * The original license:
17978  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17979  * Code licensed under the BSD License:
17980  * http://developer.yahoo.net/yui/license.txt
17981  */
17982
17983 (function() {
17984
17985 var Event=Roo.EventManager;
17986 var Dom=Roo.lib.Dom;
17987
17988 /**
17989  * @class Roo.dd.DragDrop
17990  * @extends Roo.util.Observable
17991  * Defines the interface and base operation of items that that can be
17992  * dragged or can be drop targets.  It was designed to be extended, overriding
17993  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17994  * Up to three html elements can be associated with a DragDrop instance:
17995  * <ul>
17996  * <li>linked element: the element that is passed into the constructor.
17997  * This is the element which defines the boundaries for interaction with
17998  * other DragDrop objects.</li>
17999  * <li>handle element(s): The drag operation only occurs if the element that
18000  * was clicked matches a handle element.  By default this is the linked
18001  * element, but there are times that you will want only a portion of the
18002  * linked element to initiate the drag operation, and the setHandleElId()
18003  * method provides a way to define this.</li>
18004  * <li>drag element: this represents the element that would be moved along
18005  * with the cursor during a drag operation.  By default, this is the linked
18006  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
18007  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18008  * </li>
18009  * </ul>
18010  * This class should not be instantiated until the onload event to ensure that
18011  * the associated elements are available.
18012  * The following would define a DragDrop obj that would interact with any
18013  * other DragDrop obj in the "group1" group:
18014  * <pre>
18015  *  dd = new Roo.dd.DragDrop("div1", "group1");
18016  * </pre>
18017  * Since none of the event handlers have been implemented, nothing would
18018  * actually happen if you were to run the code above.  Normally you would
18019  * override this class or one of the default implementations, but you can
18020  * also override the methods you want on an instance of the class...
18021  * <pre>
18022  *  dd.onDragDrop = function(e, id) {
18023  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18024  *  }
18025  * </pre>
18026  * @constructor
18027  * @param {String} id of the element that is linked to this instance
18028  * @param {String} sGroup the group of related DragDrop objects
18029  * @param {object} config an object containing configurable attributes
18030  *                Valid properties for DragDrop:
18031  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18032  */
18033 Roo.dd.DragDrop = function(id, sGroup, config) {
18034     if (id) {
18035         this.init(id, sGroup, config);
18036     }
18037     
18038 };
18039
18040 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18041
18042     /**
18043      * The id of the element associated with this object.  This is what we
18044      * refer to as the "linked element" because the size and position of
18045      * this element is used to determine when the drag and drop objects have
18046      * interacted.
18047      * @property id
18048      * @type String
18049      */
18050     id: null,
18051
18052     /**
18053      * Configuration attributes passed into the constructor
18054      * @property config
18055      * @type object
18056      */
18057     config: null,
18058
18059     /**
18060      * The id of the element that will be dragged.  By default this is same
18061      * as the linked element , but could be changed to another element. Ex:
18062      * Roo.dd.DDProxy
18063      * @property dragElId
18064      * @type String
18065      * @private
18066      */
18067     dragElId: null,
18068
18069     /**
18070      * the id of the element that initiates the drag operation.  By default
18071      * this is the linked element, but could be changed to be a child of this
18072      * element.  This lets us do things like only starting the drag when the
18073      * header element within the linked html element is clicked.
18074      * @property handleElId
18075      * @type String
18076      * @private
18077      */
18078     handleElId: null,
18079
18080     /**
18081      * An associative array of HTML tags that will be ignored if clicked.
18082      * @property invalidHandleTypes
18083      * @type {string: string}
18084      */
18085     invalidHandleTypes: null,
18086
18087     /**
18088      * An associative array of ids for elements that will be ignored if clicked
18089      * @property invalidHandleIds
18090      * @type {string: string}
18091      */
18092     invalidHandleIds: null,
18093
18094     /**
18095      * An indexted array of css class names for elements that will be ignored
18096      * if clicked.
18097      * @property invalidHandleClasses
18098      * @type string[]
18099      */
18100     invalidHandleClasses: null,
18101
18102     /**
18103      * The linked element's absolute X position at the time the drag was
18104      * started
18105      * @property startPageX
18106      * @type int
18107      * @private
18108      */
18109     startPageX: 0,
18110
18111     /**
18112      * The linked element's absolute X position at the time the drag was
18113      * started
18114      * @property startPageY
18115      * @type int
18116      * @private
18117      */
18118     startPageY: 0,
18119
18120     /**
18121      * The group defines a logical collection of DragDrop objects that are
18122      * related.  Instances only get events when interacting with other
18123      * DragDrop object in the same group.  This lets us define multiple
18124      * groups using a single DragDrop subclass if we want.
18125      * @property groups
18126      * @type {string: string}
18127      */
18128     groups: null,
18129
18130     /**
18131      * Individual drag/drop instances can be locked.  This will prevent
18132      * onmousedown start drag.
18133      * @property locked
18134      * @type boolean
18135      * @private
18136      */
18137     locked: false,
18138
18139     /**
18140      * Lock this instance
18141      * @method lock
18142      */
18143     lock: function() { this.locked = true; },
18144
18145     /**
18146      * Unlock this instace
18147      * @method unlock
18148      */
18149     unlock: function() { this.locked = false; },
18150
18151     /**
18152      * By default, all insances can be a drop target.  This can be disabled by
18153      * setting isTarget to false.
18154      * @method isTarget
18155      * @type boolean
18156      */
18157     isTarget: true,
18158
18159     /**
18160      * The padding configured for this drag and drop object for calculating
18161      * the drop zone intersection with this object.
18162      * @method padding
18163      * @type int[]
18164      */
18165     padding: null,
18166
18167     /**
18168      * Cached reference to the linked element
18169      * @property _domRef
18170      * @private
18171      */
18172     _domRef: null,
18173
18174     /**
18175      * Internal typeof flag
18176      * @property __ygDragDrop
18177      * @private
18178      */
18179     __ygDragDrop: true,
18180
18181     /**
18182      * Set to true when horizontal contraints are applied
18183      * @property constrainX
18184      * @type boolean
18185      * @private
18186      */
18187     constrainX: false,
18188
18189     /**
18190      * Set to true when vertical contraints are applied
18191      * @property constrainY
18192      * @type boolean
18193      * @private
18194      */
18195     constrainY: false,
18196
18197     /**
18198      * The left constraint
18199      * @property minX
18200      * @type int
18201      * @private
18202      */
18203     minX: 0,
18204
18205     /**
18206      * The right constraint
18207      * @property maxX
18208      * @type int
18209      * @private
18210      */
18211     maxX: 0,
18212
18213     /**
18214      * The up constraint
18215      * @property minY
18216      * @type int
18217      * @type int
18218      * @private
18219      */
18220     minY: 0,
18221
18222     /**
18223      * The down constraint
18224      * @property maxY
18225      * @type int
18226      * @private
18227      */
18228     maxY: 0,
18229
18230     /**
18231      * Maintain offsets when we resetconstraints.  Set to true when you want
18232      * the position of the element relative to its parent to stay the same
18233      * when the page changes
18234      *
18235      * @property maintainOffset
18236      * @type boolean
18237      */
18238     maintainOffset: false,
18239
18240     /**
18241      * Array of pixel locations the element will snap to if we specified a
18242      * horizontal graduation/interval.  This array is generated automatically
18243      * when you define a tick interval.
18244      * @property xTicks
18245      * @type int[]
18246      */
18247     xTicks: null,
18248
18249     /**
18250      * Array of pixel locations the element will snap to if we specified a
18251      * vertical graduation/interval.  This array is generated automatically
18252      * when you define a tick interval.
18253      * @property yTicks
18254      * @type int[]
18255      */
18256     yTicks: null,
18257
18258     /**
18259      * By default the drag and drop instance will only respond to the primary
18260      * button click (left button for a right-handed mouse).  Set to true to
18261      * allow drag and drop to start with any mouse click that is propogated
18262      * by the browser
18263      * @property primaryButtonOnly
18264      * @type boolean
18265      */
18266     primaryButtonOnly: true,
18267
18268     /**
18269      * The availabe property is false until the linked dom element is accessible.
18270      * @property available
18271      * @type boolean
18272      */
18273     available: false,
18274
18275     /**
18276      * By default, drags can only be initiated if the mousedown occurs in the
18277      * region the linked element is.  This is done in part to work around a
18278      * bug in some browsers that mis-report the mousedown if the previous
18279      * mouseup happened outside of the window.  This property is set to true
18280      * if outer handles are defined.
18281      *
18282      * @property hasOuterHandles
18283      * @type boolean
18284      * @default false
18285      */
18286     hasOuterHandles: false,
18287
18288     /**
18289      * Code that executes immediately before the startDrag event
18290      * @method b4StartDrag
18291      * @private
18292      */
18293     b4StartDrag: function(x, y) { },
18294
18295     /**
18296      * Abstract method called after a drag/drop object is clicked
18297      * and the drag or mousedown time thresholds have beeen met.
18298      * @method startDrag
18299      * @param {int} X click location
18300      * @param {int} Y click location
18301      */
18302     startDrag: function(x, y) { /* override this */ },
18303
18304     /**
18305      * Code that executes immediately before the onDrag event
18306      * @method b4Drag
18307      * @private
18308      */
18309     b4Drag: function(e) { },
18310
18311     /**
18312      * Abstract method called during the onMouseMove event while dragging an
18313      * object.
18314      * @method onDrag
18315      * @param {Event} e the mousemove event
18316      */
18317     onDrag: function(e) { /* override this */ },
18318
18319     /**
18320      * Abstract method called when this element fist begins hovering over
18321      * another DragDrop obj
18322      * @method onDragEnter
18323      * @param {Event} e the mousemove event
18324      * @param {String|DragDrop[]} id In POINT mode, the element
18325      * id this is hovering over.  In INTERSECT mode, an array of one or more
18326      * dragdrop items being hovered over.
18327      */
18328     onDragEnter: function(e, id) { /* override this */ },
18329
18330     /**
18331      * Code that executes immediately before the onDragOver event
18332      * @method b4DragOver
18333      * @private
18334      */
18335     b4DragOver: function(e) { },
18336
18337     /**
18338      * Abstract method called when this element is hovering over another
18339      * DragDrop obj
18340      * @method onDragOver
18341      * @param {Event} e the mousemove event
18342      * @param {String|DragDrop[]} id In POINT mode, the element
18343      * id this is hovering over.  In INTERSECT mode, an array of dd items
18344      * being hovered over.
18345      */
18346     onDragOver: function(e, id) { /* override this */ },
18347
18348     /**
18349      * Code that executes immediately before the onDragOut event
18350      * @method b4DragOut
18351      * @private
18352      */
18353     b4DragOut: function(e) { },
18354
18355     /**
18356      * Abstract method called when we are no longer hovering over an element
18357      * @method onDragOut
18358      * @param {Event} e the mousemove event
18359      * @param {String|DragDrop[]} id In POINT mode, the element
18360      * id this was hovering over.  In INTERSECT mode, an array of dd items
18361      * that the mouse is no longer over.
18362      */
18363     onDragOut: function(e, id) { /* override this */ },
18364
18365     /**
18366      * Code that executes immediately before the onDragDrop event
18367      * @method b4DragDrop
18368      * @private
18369      */
18370     b4DragDrop: function(e) { },
18371
18372     /**
18373      * Abstract method called when this item is dropped on another DragDrop
18374      * obj
18375      * @method onDragDrop
18376      * @param {Event} e the mouseup event
18377      * @param {String|DragDrop[]} id In POINT mode, the element
18378      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18379      * was dropped on.
18380      */
18381     onDragDrop: function(e, id) { /* override this */ },
18382
18383     /**
18384      * Abstract method called when this item is dropped on an area with no
18385      * drop target
18386      * @method onInvalidDrop
18387      * @param {Event} e the mouseup event
18388      */
18389     onInvalidDrop: function(e) { /* override this */ },
18390
18391     /**
18392      * Code that executes immediately before the endDrag event
18393      * @method b4EndDrag
18394      * @private
18395      */
18396     b4EndDrag: function(e) { },
18397
18398     /**
18399      * Fired when we are done dragging the object
18400      * @method endDrag
18401      * @param {Event} e the mouseup event
18402      */
18403     endDrag: function(e) { /* override this */ },
18404
18405     /**
18406      * Code executed immediately before the onMouseDown event
18407      * @method b4MouseDown
18408      * @param {Event} e the mousedown event
18409      * @private
18410      */
18411     b4MouseDown: function(e) {  },
18412
18413     /**
18414      * Event handler that fires when a drag/drop obj gets a mousedown
18415      * @method onMouseDown
18416      * @param {Event} e the mousedown event
18417      */
18418     onMouseDown: function(e) { /* override this */ },
18419
18420     /**
18421      * Event handler that fires when a drag/drop obj gets a mouseup
18422      * @method onMouseUp
18423      * @param {Event} e the mouseup event
18424      */
18425     onMouseUp: function(e) { /* override this */ },
18426
18427     /**
18428      * Override the onAvailable method to do what is needed after the initial
18429      * position was determined.
18430      * @method onAvailable
18431      */
18432     onAvailable: function () {
18433     },
18434
18435     /*
18436      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18437      * @type Object
18438      */
18439     defaultPadding : {left:0, right:0, top:0, bottom:0},
18440
18441     /*
18442      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18443  *
18444  * Usage:
18445  <pre><code>
18446  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18447                 { dragElId: "existingProxyDiv" });
18448  dd.startDrag = function(){
18449      this.constrainTo("parent-id");
18450  };
18451  </code></pre>
18452  * Or you can initalize it using the {@link Roo.Element} object:
18453  <pre><code>
18454  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18455      startDrag : function(){
18456          this.constrainTo("parent-id");
18457      }
18458  });
18459  </code></pre>
18460      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18461      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18462      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18463      * an object containing the sides to pad. For example: {right:10, bottom:10}
18464      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18465      */
18466     constrainTo : function(constrainTo, pad, inContent){
18467         if(typeof pad == "number"){
18468             pad = {left: pad, right:pad, top:pad, bottom:pad};
18469         }
18470         pad = pad || this.defaultPadding;
18471         var b = Roo.get(this.getEl()).getBox();
18472         var ce = Roo.get(constrainTo);
18473         var s = ce.getScroll();
18474         var c, cd = ce.dom;
18475         if(cd == document.body){
18476             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18477         }else{
18478             xy = ce.getXY();
18479             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18480         }
18481
18482
18483         var topSpace = b.y - c.y;
18484         var leftSpace = b.x - c.x;
18485
18486         this.resetConstraints();
18487         this.setXConstraint(leftSpace - (pad.left||0), // left
18488                 c.width - leftSpace - b.width - (pad.right||0) //right
18489         );
18490         this.setYConstraint(topSpace - (pad.top||0), //top
18491                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18492         );
18493     },
18494
18495     /**
18496      * Returns a reference to the linked element
18497      * @method getEl
18498      * @return {HTMLElement} the html element
18499      */
18500     getEl: function() {
18501         if (!this._domRef) {
18502             this._domRef = Roo.getDom(this.id);
18503         }
18504
18505         return this._domRef;
18506     },
18507
18508     /**
18509      * Returns a reference to the actual element to drag.  By default this is
18510      * the same as the html element, but it can be assigned to another
18511      * element. An example of this can be found in Roo.dd.DDProxy
18512      * @method getDragEl
18513      * @return {HTMLElement} the html element
18514      */
18515     getDragEl: function() {
18516         return Roo.getDom(this.dragElId);
18517     },
18518
18519     /**
18520      * Sets up the DragDrop object.  Must be called in the constructor of any
18521      * Roo.dd.DragDrop subclass
18522      * @method init
18523      * @param id the id of the linked element
18524      * @param {String} sGroup the group of related items
18525      * @param {object} config configuration attributes
18526      */
18527     init: function(id, sGroup, config) {
18528         this.initTarget(id, sGroup, config);
18529         if (!Roo.isTouch) {
18530             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18531         }
18532         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18533         // Event.on(this.id, "selectstart", Event.preventDefault);
18534     },
18535
18536     /**
18537      * Initializes Targeting functionality only... the object does not
18538      * get a mousedown handler.
18539      * @method initTarget
18540      * @param id the id of the linked element
18541      * @param {String} sGroup the group of related items
18542      * @param {object} config configuration attributes
18543      */
18544     initTarget: function(id, sGroup, config) {
18545
18546         // configuration attributes
18547         this.config = config || {};
18548
18549         // create a local reference to the drag and drop manager
18550         this.DDM = Roo.dd.DDM;
18551         // initialize the groups array
18552         this.groups = {};
18553
18554         // assume that we have an element reference instead of an id if the
18555         // parameter is not a string
18556         if (typeof id !== "string") {
18557             id = Roo.id(id);
18558         }
18559
18560         // set the id
18561         this.id = id;
18562
18563         // add to an interaction group
18564         this.addToGroup((sGroup) ? sGroup : "default");
18565
18566         // We don't want to register this as the handle with the manager
18567         // so we just set the id rather than calling the setter.
18568         this.handleElId = id;
18569
18570         // the linked element is the element that gets dragged by default
18571         this.setDragElId(id);
18572
18573         // by default, clicked anchors will not start drag operations.
18574         this.invalidHandleTypes = { A: "A" };
18575         this.invalidHandleIds = {};
18576         this.invalidHandleClasses = [];
18577
18578         this.applyConfig();
18579
18580         this.handleOnAvailable();
18581     },
18582
18583     /**
18584      * Applies the configuration parameters that were passed into the constructor.
18585      * This is supposed to happen at each level through the inheritance chain.  So
18586      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18587      * DragDrop in order to get all of the parameters that are available in
18588      * each object.
18589      * @method applyConfig
18590      */
18591     applyConfig: function() {
18592
18593         // configurable properties:
18594         //    padding, isTarget, maintainOffset, primaryButtonOnly
18595         this.padding           = this.config.padding || [0, 0, 0, 0];
18596         this.isTarget          = (this.config.isTarget !== false);
18597         this.maintainOffset    = (this.config.maintainOffset);
18598         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18599
18600     },
18601
18602     /**
18603      * Executed when the linked element is available
18604      * @method handleOnAvailable
18605      * @private
18606      */
18607     handleOnAvailable: function() {
18608         this.available = true;
18609         this.resetConstraints();
18610         this.onAvailable();
18611     },
18612
18613      /**
18614      * Configures the padding for the target zone in px.  Effectively expands
18615      * (or reduces) the virtual object size for targeting calculations.
18616      * Supports css-style shorthand; if only one parameter is passed, all sides
18617      * will have that padding, and if only two are passed, the top and bottom
18618      * will have the first param, the left and right the second.
18619      * @method setPadding
18620      * @param {int} iTop    Top pad
18621      * @param {int} iRight  Right pad
18622      * @param {int} iBot    Bot pad
18623      * @param {int} iLeft   Left pad
18624      */
18625     setPadding: function(iTop, iRight, iBot, iLeft) {
18626         // this.padding = [iLeft, iRight, iTop, iBot];
18627         if (!iRight && 0 !== iRight) {
18628             this.padding = [iTop, iTop, iTop, iTop];
18629         } else if (!iBot && 0 !== iBot) {
18630             this.padding = [iTop, iRight, iTop, iRight];
18631         } else {
18632             this.padding = [iTop, iRight, iBot, iLeft];
18633         }
18634     },
18635
18636     /**
18637      * Stores the initial placement of the linked element.
18638      * @method setInitialPosition
18639      * @param {int} diffX   the X offset, default 0
18640      * @param {int} diffY   the Y offset, default 0
18641      */
18642     setInitPosition: function(diffX, diffY) {
18643         var el = this.getEl();
18644
18645         if (!this.DDM.verifyEl(el)) {
18646             return;
18647         }
18648
18649         var dx = diffX || 0;
18650         var dy = diffY || 0;
18651
18652         var p = Dom.getXY( el );
18653
18654         this.initPageX = p[0] - dx;
18655         this.initPageY = p[1] - dy;
18656
18657         this.lastPageX = p[0];
18658         this.lastPageY = p[1];
18659
18660
18661         this.setStartPosition(p);
18662     },
18663
18664     /**
18665      * Sets the start position of the element.  This is set when the obj
18666      * is initialized, the reset when a drag is started.
18667      * @method setStartPosition
18668      * @param pos current position (from previous lookup)
18669      * @private
18670      */
18671     setStartPosition: function(pos) {
18672         var p = pos || Dom.getXY( this.getEl() );
18673         this.deltaSetXY = null;
18674
18675         this.startPageX = p[0];
18676         this.startPageY = p[1];
18677     },
18678
18679     /**
18680      * Add this instance to a group of related drag/drop objects.  All
18681      * instances belong to at least one group, and can belong to as many
18682      * groups as needed.
18683      * @method addToGroup
18684      * @param sGroup {string} the name of the group
18685      */
18686     addToGroup: function(sGroup) {
18687         this.groups[sGroup] = true;
18688         this.DDM.regDragDrop(this, sGroup);
18689     },
18690
18691     /**
18692      * Remove's this instance from the supplied interaction group
18693      * @method removeFromGroup
18694      * @param {string}  sGroup  The group to drop
18695      */
18696     removeFromGroup: function(sGroup) {
18697         if (this.groups[sGroup]) {
18698             delete this.groups[sGroup];
18699         }
18700
18701         this.DDM.removeDDFromGroup(this, sGroup);
18702     },
18703
18704     /**
18705      * Allows you to specify that an element other than the linked element
18706      * will be moved with the cursor during a drag
18707      * @method setDragElId
18708      * @param id {string} the id of the element that will be used to initiate the drag
18709      */
18710     setDragElId: function(id) {
18711         this.dragElId = id;
18712     },
18713
18714     /**
18715      * Allows you to specify a child of the linked element that should be
18716      * used to initiate the drag operation.  An example of this would be if
18717      * you have a content div with text and links.  Clicking anywhere in the
18718      * content area would normally start the drag operation.  Use this method
18719      * to specify that an element inside of the content div is the element
18720      * that starts the drag operation.
18721      * @method setHandleElId
18722      * @param id {string} the id of the element that will be used to
18723      * initiate the drag.
18724      */
18725     setHandleElId: function(id) {
18726         if (typeof id !== "string") {
18727             id = Roo.id(id);
18728         }
18729         this.handleElId = id;
18730         this.DDM.regHandle(this.id, id);
18731     },
18732
18733     /**
18734      * Allows you to set an element outside of the linked element as a drag
18735      * handle
18736      * @method setOuterHandleElId
18737      * @param id the id of the element that will be used to initiate the drag
18738      */
18739     setOuterHandleElId: function(id) {
18740         if (typeof id !== "string") {
18741             id = Roo.id(id);
18742         }
18743         Event.on(id, "mousedown",
18744                 this.handleMouseDown, this);
18745         this.setHandleElId(id);
18746
18747         this.hasOuterHandles = true;
18748     },
18749
18750     /**
18751      * Remove all drag and drop hooks for this element
18752      * @method unreg
18753      */
18754     unreg: function() {
18755         Event.un(this.id, "mousedown",
18756                 this.handleMouseDown);
18757         Event.un(this.id, "touchstart",
18758                 this.handleMouseDown);
18759         this._domRef = null;
18760         this.DDM._remove(this);
18761     },
18762
18763     destroy : function(){
18764         this.unreg();
18765     },
18766
18767     /**
18768      * Returns true if this instance is locked, or the drag drop mgr is locked
18769      * (meaning that all drag/drop is disabled on the page.)
18770      * @method isLocked
18771      * @return {boolean} true if this obj or all drag/drop is locked, else
18772      * false
18773      */
18774     isLocked: function() {
18775         return (this.DDM.isLocked() || this.locked);
18776     },
18777
18778     /**
18779      * Fired when this object is clicked
18780      * @method handleMouseDown
18781      * @param {Event} e
18782      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18783      * @private
18784      */
18785     handleMouseDown: function(e, oDD){
18786      
18787         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18788             //Roo.log('not touch/ button !=0');
18789             return;
18790         }
18791         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18792             return; // double touch..
18793         }
18794         
18795
18796         if (this.isLocked()) {
18797             //Roo.log('locked');
18798             return;
18799         }
18800
18801         this.DDM.refreshCache(this.groups);
18802 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18803         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18804         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18805             //Roo.log('no outer handes or not over target');
18806                 // do nothing.
18807         } else {
18808 //            Roo.log('check validator');
18809             if (this.clickValidator(e)) {
18810 //                Roo.log('validate success');
18811                 // set the initial element position
18812                 this.setStartPosition();
18813
18814
18815                 this.b4MouseDown(e);
18816                 this.onMouseDown(e);
18817
18818                 this.DDM.handleMouseDown(e, this);
18819
18820                 this.DDM.stopEvent(e);
18821             } else {
18822
18823
18824             }
18825         }
18826     },
18827
18828     clickValidator: function(e) {
18829         var target = e.getTarget();
18830         return ( this.isValidHandleChild(target) &&
18831                     (this.id == this.handleElId ||
18832                         this.DDM.handleWasClicked(target, this.id)) );
18833     },
18834
18835     /**
18836      * Allows you to specify a tag name that should not start a drag operation
18837      * when clicked.  This is designed to facilitate embedding links within a
18838      * drag handle that do something other than start the drag.
18839      * @method addInvalidHandleType
18840      * @param {string} tagName the type of element to exclude
18841      */
18842     addInvalidHandleType: function(tagName) {
18843         var type = tagName.toUpperCase();
18844         this.invalidHandleTypes[type] = type;
18845     },
18846
18847     /**
18848      * Lets you to specify an element id for a child of a drag handle
18849      * that should not initiate a drag
18850      * @method addInvalidHandleId
18851      * @param {string} id the element id of the element you wish to ignore
18852      */
18853     addInvalidHandleId: function(id) {
18854         if (typeof id !== "string") {
18855             id = Roo.id(id);
18856         }
18857         this.invalidHandleIds[id] = id;
18858     },
18859
18860     /**
18861      * Lets you specify a css class of elements that will not initiate a drag
18862      * @method addInvalidHandleClass
18863      * @param {string} cssClass the class of the elements you wish to ignore
18864      */
18865     addInvalidHandleClass: function(cssClass) {
18866         this.invalidHandleClasses.push(cssClass);
18867     },
18868
18869     /**
18870      * Unsets an excluded tag name set by addInvalidHandleType
18871      * @method removeInvalidHandleType
18872      * @param {string} tagName the type of element to unexclude
18873      */
18874     removeInvalidHandleType: function(tagName) {
18875         var type = tagName.toUpperCase();
18876         // this.invalidHandleTypes[type] = null;
18877         delete this.invalidHandleTypes[type];
18878     },
18879
18880     /**
18881      * Unsets an invalid handle id
18882      * @method removeInvalidHandleId
18883      * @param {string} id the id of the element to re-enable
18884      */
18885     removeInvalidHandleId: function(id) {
18886         if (typeof id !== "string") {
18887             id = Roo.id(id);
18888         }
18889         delete this.invalidHandleIds[id];
18890     },
18891
18892     /**
18893      * Unsets an invalid css class
18894      * @method removeInvalidHandleClass
18895      * @param {string} cssClass the class of the element(s) you wish to
18896      * re-enable
18897      */
18898     removeInvalidHandleClass: function(cssClass) {
18899         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18900             if (this.invalidHandleClasses[i] == cssClass) {
18901                 delete this.invalidHandleClasses[i];
18902             }
18903         }
18904     },
18905
18906     /**
18907      * Checks the tag exclusion list to see if this click should be ignored
18908      * @method isValidHandleChild
18909      * @param {HTMLElement} node the HTMLElement to evaluate
18910      * @return {boolean} true if this is a valid tag type, false if not
18911      */
18912     isValidHandleChild: function(node) {
18913
18914         var valid = true;
18915         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18916         var nodeName;
18917         try {
18918             nodeName = node.nodeName.toUpperCase();
18919         } catch(e) {
18920             nodeName = node.nodeName;
18921         }
18922         valid = valid && !this.invalidHandleTypes[nodeName];
18923         valid = valid && !this.invalidHandleIds[node.id];
18924
18925         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18926             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18927         }
18928
18929
18930         return valid;
18931
18932     },
18933
18934     /**
18935      * Create the array of horizontal tick marks if an interval was specified
18936      * in setXConstraint().
18937      * @method setXTicks
18938      * @private
18939      */
18940     setXTicks: function(iStartX, iTickSize) {
18941         this.xTicks = [];
18942         this.xTickSize = iTickSize;
18943
18944         var tickMap = {};
18945
18946         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18947             if (!tickMap[i]) {
18948                 this.xTicks[this.xTicks.length] = i;
18949                 tickMap[i] = true;
18950             }
18951         }
18952
18953         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18954             if (!tickMap[i]) {
18955                 this.xTicks[this.xTicks.length] = i;
18956                 tickMap[i] = true;
18957             }
18958         }
18959
18960         this.xTicks.sort(this.DDM.numericSort) ;
18961     },
18962
18963     /**
18964      * Create the array of vertical tick marks if an interval was specified in
18965      * setYConstraint().
18966      * @method setYTicks
18967      * @private
18968      */
18969     setYTicks: function(iStartY, iTickSize) {
18970         this.yTicks = [];
18971         this.yTickSize = iTickSize;
18972
18973         var tickMap = {};
18974
18975         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18976             if (!tickMap[i]) {
18977                 this.yTicks[this.yTicks.length] = i;
18978                 tickMap[i] = true;
18979             }
18980         }
18981
18982         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18983             if (!tickMap[i]) {
18984                 this.yTicks[this.yTicks.length] = i;
18985                 tickMap[i] = true;
18986             }
18987         }
18988
18989         this.yTicks.sort(this.DDM.numericSort) ;
18990     },
18991
18992     /**
18993      * By default, the element can be dragged any place on the screen.  Use
18994      * this method to limit the horizontal travel of the element.  Pass in
18995      * 0,0 for the parameters if you want to lock the drag to the y axis.
18996      * @method setXConstraint
18997      * @param {int} iLeft the number of pixels the element can move to the left
18998      * @param {int} iRight the number of pixels the element can move to the
18999      * right
19000      * @param {int} iTickSize optional parameter for specifying that the
19001      * element
19002      * should move iTickSize pixels at a time.
19003      */
19004     setXConstraint: function(iLeft, iRight, iTickSize) {
19005         this.leftConstraint = iLeft;
19006         this.rightConstraint = iRight;
19007
19008         this.minX = this.initPageX - iLeft;
19009         this.maxX = this.initPageX + iRight;
19010         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19011
19012         this.constrainX = true;
19013     },
19014
19015     /**
19016      * Clears any constraints applied to this instance.  Also clears ticks
19017      * since they can't exist independent of a constraint at this time.
19018      * @method clearConstraints
19019      */
19020     clearConstraints: function() {
19021         this.constrainX = false;
19022         this.constrainY = false;
19023         this.clearTicks();
19024     },
19025
19026     /**
19027      * Clears any tick interval defined for this instance
19028      * @method clearTicks
19029      */
19030     clearTicks: function() {
19031         this.xTicks = null;
19032         this.yTicks = null;
19033         this.xTickSize = 0;
19034         this.yTickSize = 0;
19035     },
19036
19037     /**
19038      * By default, the element can be dragged any place on the screen.  Set
19039      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19040      * parameters if you want to lock the drag to the x axis.
19041      * @method setYConstraint
19042      * @param {int} iUp the number of pixels the element can move up
19043      * @param {int} iDown the number of pixels the element can move down
19044      * @param {int} iTickSize optional parameter for specifying that the
19045      * element should move iTickSize pixels at a time.
19046      */
19047     setYConstraint: function(iUp, iDown, iTickSize) {
19048         this.topConstraint = iUp;
19049         this.bottomConstraint = iDown;
19050
19051         this.minY = this.initPageY - iUp;
19052         this.maxY = this.initPageY + iDown;
19053         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19054
19055         this.constrainY = true;
19056
19057     },
19058
19059     /**
19060      * resetConstraints must be called if you manually reposition a dd element.
19061      * @method resetConstraints
19062      * @param {boolean} maintainOffset
19063      */
19064     resetConstraints: function() {
19065
19066
19067         // Maintain offsets if necessary
19068         if (this.initPageX || this.initPageX === 0) {
19069             // figure out how much this thing has moved
19070             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19071             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19072
19073             this.setInitPosition(dx, dy);
19074
19075         // This is the first time we have detected the element's position
19076         } else {
19077             this.setInitPosition();
19078         }
19079
19080         if (this.constrainX) {
19081             this.setXConstraint( this.leftConstraint,
19082                                  this.rightConstraint,
19083                                  this.xTickSize        );
19084         }
19085
19086         if (this.constrainY) {
19087             this.setYConstraint( this.topConstraint,
19088                                  this.bottomConstraint,
19089                                  this.yTickSize         );
19090         }
19091     },
19092
19093     /**
19094      * Normally the drag element is moved pixel by pixel, but we can specify
19095      * that it move a number of pixels at a time.  This method resolves the
19096      * location when we have it set up like this.
19097      * @method getTick
19098      * @param {int} val where we want to place the object
19099      * @param {int[]} tickArray sorted array of valid points
19100      * @return {int} the closest tick
19101      * @private
19102      */
19103     getTick: function(val, tickArray) {
19104
19105         if (!tickArray) {
19106             // If tick interval is not defined, it is effectively 1 pixel,
19107             // so we return the value passed to us.
19108             return val;
19109         } else if (tickArray[0] >= val) {
19110             // The value is lower than the first tick, so we return the first
19111             // tick.
19112             return tickArray[0];
19113         } else {
19114             for (var i=0, len=tickArray.length; i<len; ++i) {
19115                 var next = i + 1;
19116                 if (tickArray[next] && tickArray[next] >= val) {
19117                     var diff1 = val - tickArray[i];
19118                     var diff2 = tickArray[next] - val;
19119                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19120                 }
19121             }
19122
19123             // The value is larger than the last tick, so we return the last
19124             // tick.
19125             return tickArray[tickArray.length - 1];
19126         }
19127     },
19128
19129     /**
19130      * toString method
19131      * @method toString
19132      * @return {string} string representation of the dd obj
19133      */
19134     toString: function() {
19135         return ("DragDrop " + this.id);
19136     }
19137
19138 });
19139
19140 })();
19141 /*
19142  * Based on:
19143  * Ext JS Library 1.1.1
19144  * Copyright(c) 2006-2007, Ext JS, LLC.
19145  *
19146  * Originally Released Under LGPL - original licence link has changed is not relivant.
19147  *
19148  * Fork - LGPL
19149  * <script type="text/javascript">
19150  */
19151
19152
19153 /**
19154  * The drag and drop utility provides a framework for building drag and drop
19155  * applications.  In addition to enabling drag and drop for specific elements,
19156  * the drag and drop elements are tracked by the manager class, and the
19157  * interactions between the various elements are tracked during the drag and
19158  * the implementing code is notified about these important moments.
19159  */
19160
19161 // Only load the library once.  Rewriting the manager class would orphan
19162 // existing drag and drop instances.
19163 if (!Roo.dd.DragDropMgr) {
19164
19165 /**
19166  * @class Roo.dd.DragDropMgr
19167  * DragDropMgr is a singleton that tracks the element interaction for
19168  * all DragDrop items in the window.  Generally, you will not call
19169  * this class directly, but it does have helper methods that could
19170  * be useful in your DragDrop implementations.
19171  * @singleton
19172  */
19173 Roo.dd.DragDropMgr = function() {
19174
19175     var Event = Roo.EventManager;
19176
19177     return {
19178
19179         /**
19180          * Two dimensional Array of registered DragDrop objects.  The first
19181          * dimension is the DragDrop item group, the second the DragDrop
19182          * object.
19183          * @property ids
19184          * @type {string: string}
19185          * @private
19186          * @static
19187          */
19188         ids: {},
19189
19190         /**
19191          * Array of element ids defined as drag handles.  Used to determine
19192          * if the element that generated the mousedown event is actually the
19193          * handle and not the html element itself.
19194          * @property handleIds
19195          * @type {string: string}
19196          * @private
19197          * @static
19198          */
19199         handleIds: {},
19200
19201         /**
19202          * the DragDrop object that is currently being dragged
19203          * @property dragCurrent
19204          * @type DragDrop
19205          * @private
19206          * @static
19207          **/
19208         dragCurrent: null,
19209
19210         /**
19211          * the DragDrop object(s) that are being hovered over
19212          * @property dragOvers
19213          * @type Array
19214          * @private
19215          * @static
19216          */
19217         dragOvers: {},
19218
19219         /**
19220          * the X distance between the cursor and the object being dragged
19221          * @property deltaX
19222          * @type int
19223          * @private
19224          * @static
19225          */
19226         deltaX: 0,
19227
19228         /**
19229          * the Y distance between the cursor and the object being dragged
19230          * @property deltaY
19231          * @type int
19232          * @private
19233          * @static
19234          */
19235         deltaY: 0,
19236
19237         /**
19238          * Flag to determine if we should prevent the default behavior of the
19239          * events we define. By default this is true, but this can be set to
19240          * false if you need the default behavior (not recommended)
19241          * @property preventDefault
19242          * @type boolean
19243          * @static
19244          */
19245         preventDefault: true,
19246
19247         /**
19248          * Flag to determine if we should stop the propagation of the events
19249          * we generate. This is true by default but you may want to set it to
19250          * false if the html element contains other features that require the
19251          * mouse click.
19252          * @property stopPropagation
19253          * @type boolean
19254          * @static
19255          */
19256         stopPropagation: true,
19257
19258         /**
19259          * Internal flag that is set to true when drag and drop has been
19260          * intialized
19261          * @property initialized
19262          * @private
19263          * @static
19264          */
19265         initalized: false,
19266
19267         /**
19268          * All drag and drop can be disabled.
19269          * @property locked
19270          * @private
19271          * @static
19272          */
19273         locked: false,
19274
19275         /**
19276          * Called the first time an element is registered.
19277          * @method init
19278          * @private
19279          * @static
19280          */
19281         init: function() {
19282             this.initialized = true;
19283         },
19284
19285         /**
19286          * In point mode, drag and drop interaction is defined by the
19287          * location of the cursor during the drag/drop
19288          * @property POINT
19289          * @type int
19290          * @static
19291          */
19292         POINT: 0,
19293
19294         /**
19295          * In intersect mode, drag and drop interactio nis defined by the
19296          * overlap of two or more drag and drop objects.
19297          * @property INTERSECT
19298          * @type int
19299          * @static
19300          */
19301         INTERSECT: 1,
19302
19303         /**
19304          * The current drag and drop mode.  Default: POINT
19305          * @property mode
19306          * @type int
19307          * @static
19308          */
19309         mode: 0,
19310
19311         /**
19312          * Runs method on all drag and drop objects
19313          * @method _execOnAll
19314          * @private
19315          * @static
19316          */
19317         _execOnAll: function(sMethod, args) {
19318             for (var i in this.ids) {
19319                 for (var j in this.ids[i]) {
19320                     var oDD = this.ids[i][j];
19321                     if (! this.isTypeOfDD(oDD)) {
19322                         continue;
19323                     }
19324                     oDD[sMethod].apply(oDD, args);
19325                 }
19326             }
19327         },
19328
19329         /**
19330          * Drag and drop initialization.  Sets up the global event handlers
19331          * @method _onLoad
19332          * @private
19333          * @static
19334          */
19335         _onLoad: function() {
19336
19337             this.init();
19338
19339             if (!Roo.isTouch) {
19340                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19341                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19342             }
19343             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19344             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19345             
19346             Event.on(window,   "unload",    this._onUnload, this, true);
19347             Event.on(window,   "resize",    this._onResize, this, true);
19348             // Event.on(window,   "mouseout",    this._test);
19349
19350         },
19351
19352         /**
19353          * Reset constraints on all drag and drop objs
19354          * @method _onResize
19355          * @private
19356          * @static
19357          */
19358         _onResize: function(e) {
19359             this._execOnAll("resetConstraints", []);
19360         },
19361
19362         /**
19363          * Lock all drag and drop functionality
19364          * @method lock
19365          * @static
19366          */
19367         lock: function() { this.locked = true; },
19368
19369         /**
19370          * Unlock all drag and drop functionality
19371          * @method unlock
19372          * @static
19373          */
19374         unlock: function() { this.locked = false; },
19375
19376         /**
19377          * Is drag and drop locked?
19378          * @method isLocked
19379          * @return {boolean} True if drag and drop is locked, false otherwise.
19380          * @static
19381          */
19382         isLocked: function() { return this.locked; },
19383
19384         /**
19385          * Location cache that is set for all drag drop objects when a drag is
19386          * initiated, cleared when the drag is finished.
19387          * @property locationCache
19388          * @private
19389          * @static
19390          */
19391         locationCache: {},
19392
19393         /**
19394          * Set useCache to false if you want to force object the lookup of each
19395          * drag and drop linked element constantly during a drag.
19396          * @property useCache
19397          * @type boolean
19398          * @static
19399          */
19400         useCache: true,
19401
19402         /**
19403          * The number of pixels that the mouse needs to move after the
19404          * mousedown before the drag is initiated.  Default=3;
19405          * @property clickPixelThresh
19406          * @type int
19407          * @static
19408          */
19409         clickPixelThresh: 3,
19410
19411         /**
19412          * The number of milliseconds after the mousedown event to initiate the
19413          * drag if we don't get a mouseup event. Default=1000
19414          * @property clickTimeThresh
19415          * @type int
19416          * @static
19417          */
19418         clickTimeThresh: 350,
19419
19420         /**
19421          * Flag that indicates that either the drag pixel threshold or the
19422          * mousdown time threshold has been met
19423          * @property dragThreshMet
19424          * @type boolean
19425          * @private
19426          * @static
19427          */
19428         dragThreshMet: false,
19429
19430         /**
19431          * Timeout used for the click time threshold
19432          * @property clickTimeout
19433          * @type Object
19434          * @private
19435          * @static
19436          */
19437         clickTimeout: null,
19438
19439         /**
19440          * The X position of the mousedown event stored for later use when a
19441          * drag threshold is met.
19442          * @property startX
19443          * @type int
19444          * @private
19445          * @static
19446          */
19447         startX: 0,
19448
19449         /**
19450          * The Y position of the mousedown event stored for later use when a
19451          * drag threshold is met.
19452          * @property startY
19453          * @type int
19454          * @private
19455          * @static
19456          */
19457         startY: 0,
19458
19459         /**
19460          * Each DragDrop instance must be registered with the DragDropMgr.
19461          * This is executed in DragDrop.init()
19462          * @method regDragDrop
19463          * @param {DragDrop} oDD the DragDrop object to register
19464          * @param {String} sGroup the name of the group this element belongs to
19465          * @static
19466          */
19467         regDragDrop: function(oDD, sGroup) {
19468             if (!this.initialized) { this.init(); }
19469
19470             if (!this.ids[sGroup]) {
19471                 this.ids[sGroup] = {};
19472             }
19473             this.ids[sGroup][oDD.id] = oDD;
19474         },
19475
19476         /**
19477          * Removes the supplied dd instance from the supplied group. Executed
19478          * by DragDrop.removeFromGroup, so don't call this function directly.
19479          * @method removeDDFromGroup
19480          * @private
19481          * @static
19482          */
19483         removeDDFromGroup: function(oDD, sGroup) {
19484             if (!this.ids[sGroup]) {
19485                 this.ids[sGroup] = {};
19486             }
19487
19488             var obj = this.ids[sGroup];
19489             if (obj && obj[oDD.id]) {
19490                 delete obj[oDD.id];
19491             }
19492         },
19493
19494         /**
19495          * Unregisters a drag and drop item.  This is executed in
19496          * DragDrop.unreg, use that method instead of calling this directly.
19497          * @method _remove
19498          * @private
19499          * @static
19500          */
19501         _remove: function(oDD) {
19502             for (var g in oDD.groups) {
19503                 if (g && this.ids[g][oDD.id]) {
19504                     delete this.ids[g][oDD.id];
19505                 }
19506             }
19507             delete this.handleIds[oDD.id];
19508         },
19509
19510         /**
19511          * Each DragDrop handle element must be registered.  This is done
19512          * automatically when executing DragDrop.setHandleElId()
19513          * @method regHandle
19514          * @param {String} sDDId the DragDrop id this element is a handle for
19515          * @param {String} sHandleId the id of the element that is the drag
19516          * handle
19517          * @static
19518          */
19519         regHandle: function(sDDId, sHandleId) {
19520             if (!this.handleIds[sDDId]) {
19521                 this.handleIds[sDDId] = {};
19522             }
19523             this.handleIds[sDDId][sHandleId] = sHandleId;
19524         },
19525
19526         /**
19527          * Utility function to determine if a given element has been
19528          * registered as a drag drop item.
19529          * @method isDragDrop
19530          * @param {String} id the element id to check
19531          * @return {boolean} true if this element is a DragDrop item,
19532          * false otherwise
19533          * @static
19534          */
19535         isDragDrop: function(id) {
19536             return ( this.getDDById(id) ) ? true : false;
19537         },
19538
19539         /**
19540          * Returns the drag and drop instances that are in all groups the
19541          * passed in instance belongs to.
19542          * @method getRelated
19543          * @param {DragDrop} p_oDD the obj to get related data for
19544          * @param {boolean} bTargetsOnly if true, only return targetable objs
19545          * @return {DragDrop[]} the related instances
19546          * @static
19547          */
19548         getRelated: function(p_oDD, bTargetsOnly) {
19549             var oDDs = [];
19550             for (var i in p_oDD.groups) {
19551                 for (j in this.ids[i]) {
19552                     var dd = this.ids[i][j];
19553                     if (! this.isTypeOfDD(dd)) {
19554                         continue;
19555                     }
19556                     if (!bTargetsOnly || dd.isTarget) {
19557                         oDDs[oDDs.length] = dd;
19558                     }
19559                 }
19560             }
19561
19562             return oDDs;
19563         },
19564
19565         /**
19566          * Returns true if the specified dd target is a legal target for
19567          * the specifice drag obj
19568          * @method isLegalTarget
19569          * @param {DragDrop} the drag obj
19570          * @param {DragDrop} the target
19571          * @return {boolean} true if the target is a legal target for the
19572          * dd obj
19573          * @static
19574          */
19575         isLegalTarget: function (oDD, oTargetDD) {
19576             var targets = this.getRelated(oDD, true);
19577             for (var i=0, len=targets.length;i<len;++i) {
19578                 if (targets[i].id == oTargetDD.id) {
19579                     return true;
19580                 }
19581             }
19582
19583             return false;
19584         },
19585
19586         /**
19587          * My goal is to be able to transparently determine if an object is
19588          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19589          * returns "object", oDD.constructor.toString() always returns
19590          * "DragDrop" and not the name of the subclass.  So for now it just
19591          * evaluates a well-known variable in DragDrop.
19592          * @method isTypeOfDD
19593          * @param {Object} the object to evaluate
19594          * @return {boolean} true if typeof oDD = DragDrop
19595          * @static
19596          */
19597         isTypeOfDD: function (oDD) {
19598             return (oDD && oDD.__ygDragDrop);
19599         },
19600
19601         /**
19602          * Utility function to determine if a given element has been
19603          * registered as a drag drop handle for the given Drag Drop object.
19604          * @method isHandle
19605          * @param {String} id the element id to check
19606          * @return {boolean} true if this element is a DragDrop handle, false
19607          * otherwise
19608          * @static
19609          */
19610         isHandle: function(sDDId, sHandleId) {
19611             return ( this.handleIds[sDDId] &&
19612                             this.handleIds[sDDId][sHandleId] );
19613         },
19614
19615         /**
19616          * Returns the DragDrop instance for a given id
19617          * @method getDDById
19618          * @param {String} id the id of the DragDrop object
19619          * @return {DragDrop} the drag drop object, null if it is not found
19620          * @static
19621          */
19622         getDDById: function(id) {
19623             for (var i in this.ids) {
19624                 if (this.ids[i][id]) {
19625                     return this.ids[i][id];
19626                 }
19627             }
19628             return null;
19629         },
19630
19631         /**
19632          * Fired after a registered DragDrop object gets the mousedown event.
19633          * Sets up the events required to track the object being dragged
19634          * @method handleMouseDown
19635          * @param {Event} e the event
19636          * @param oDD the DragDrop object being dragged
19637          * @private
19638          * @static
19639          */
19640         handleMouseDown: function(e, oDD) {
19641             if(Roo.QuickTips){
19642                 Roo.QuickTips.disable();
19643             }
19644             this.currentTarget = e.getTarget();
19645
19646             this.dragCurrent = oDD;
19647
19648             var el = oDD.getEl();
19649
19650             // track start position
19651             this.startX = e.getPageX();
19652             this.startY = e.getPageY();
19653
19654             this.deltaX = this.startX - el.offsetLeft;
19655             this.deltaY = this.startY - el.offsetTop;
19656
19657             this.dragThreshMet = false;
19658
19659             this.clickTimeout = setTimeout(
19660                     function() {
19661                         var DDM = Roo.dd.DDM;
19662                         DDM.startDrag(DDM.startX, DDM.startY);
19663                     },
19664                     this.clickTimeThresh );
19665         },
19666
19667         /**
19668          * Fired when either the drag pixel threshol or the mousedown hold
19669          * time threshold has been met.
19670          * @method startDrag
19671          * @param x {int} the X position of the original mousedown
19672          * @param y {int} the Y position of the original mousedown
19673          * @static
19674          */
19675         startDrag: function(x, y) {
19676             clearTimeout(this.clickTimeout);
19677             if (this.dragCurrent) {
19678                 this.dragCurrent.b4StartDrag(x, y);
19679                 this.dragCurrent.startDrag(x, y);
19680             }
19681             this.dragThreshMet = true;
19682         },
19683
19684         /**
19685          * Internal function to handle the mouseup event.  Will be invoked
19686          * from the context of the document.
19687          * @method handleMouseUp
19688          * @param {Event} e the event
19689          * @private
19690          * @static
19691          */
19692         handleMouseUp: function(e) {
19693
19694             if(Roo.QuickTips){
19695                 Roo.QuickTips.enable();
19696             }
19697             if (! this.dragCurrent) {
19698                 return;
19699             }
19700
19701             clearTimeout(this.clickTimeout);
19702
19703             if (this.dragThreshMet) {
19704                 this.fireEvents(e, true);
19705             } else {
19706             }
19707
19708             this.stopDrag(e);
19709
19710             this.stopEvent(e);
19711         },
19712
19713         /**
19714          * Utility to stop event propagation and event default, if these
19715          * features are turned on.
19716          * @method stopEvent
19717          * @param {Event} e the event as returned by this.getEvent()
19718          * @static
19719          */
19720         stopEvent: function(e){
19721             if(this.stopPropagation) {
19722                 e.stopPropagation();
19723             }
19724
19725             if (this.preventDefault) {
19726                 e.preventDefault();
19727             }
19728         },
19729
19730         /**
19731          * Internal function to clean up event handlers after the drag
19732          * operation is complete
19733          * @method stopDrag
19734          * @param {Event} e the event
19735          * @private
19736          * @static
19737          */
19738         stopDrag: function(e) {
19739             // Fire the drag end event for the item that was dragged
19740             if (this.dragCurrent) {
19741                 if (this.dragThreshMet) {
19742                     this.dragCurrent.b4EndDrag(e);
19743                     this.dragCurrent.endDrag(e);
19744                 }
19745
19746                 this.dragCurrent.onMouseUp(e);
19747             }
19748
19749             this.dragCurrent = null;
19750             this.dragOvers = {};
19751         },
19752
19753         /**
19754          * Internal function to handle the mousemove event.  Will be invoked
19755          * from the context of the html element.
19756          *
19757          * @TODO figure out what we can do about mouse events lost when the
19758          * user drags objects beyond the window boundary.  Currently we can
19759          * detect this in internet explorer by verifying that the mouse is
19760          * down during the mousemove event.  Firefox doesn't give us the
19761          * button state on the mousemove event.
19762          * @method handleMouseMove
19763          * @param {Event} e the event
19764          * @private
19765          * @static
19766          */
19767         handleMouseMove: function(e) {
19768             if (! this.dragCurrent) {
19769                 return true;
19770             }
19771
19772             // var button = e.which || e.button;
19773
19774             // check for IE mouseup outside of page boundary
19775             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19776                 this.stopEvent(e);
19777                 return this.handleMouseUp(e);
19778             }
19779
19780             if (!this.dragThreshMet) {
19781                 var diffX = Math.abs(this.startX - e.getPageX());
19782                 var diffY = Math.abs(this.startY - e.getPageY());
19783                 if (diffX > this.clickPixelThresh ||
19784                             diffY > this.clickPixelThresh) {
19785                     this.startDrag(this.startX, this.startY);
19786                 }
19787             }
19788
19789             if (this.dragThreshMet) {
19790                 this.dragCurrent.b4Drag(e);
19791                 this.dragCurrent.onDrag(e);
19792                 if(!this.dragCurrent.moveOnly){
19793                     this.fireEvents(e, false);
19794                 }
19795             }
19796
19797             this.stopEvent(e);
19798
19799             return true;
19800         },
19801
19802         /**
19803          * Iterates over all of the DragDrop elements to find ones we are
19804          * hovering over or dropping on
19805          * @method fireEvents
19806          * @param {Event} e the event
19807          * @param {boolean} isDrop is this a drop op or a mouseover op?
19808          * @private
19809          * @static
19810          */
19811         fireEvents: function(e, isDrop) {
19812             var dc = this.dragCurrent;
19813
19814             // If the user did the mouse up outside of the window, we could
19815             // get here even though we have ended the drag.
19816             if (!dc || dc.isLocked()) {
19817                 return;
19818             }
19819
19820             var pt = e.getPoint();
19821
19822             // cache the previous dragOver array
19823             var oldOvers = [];
19824
19825             var outEvts   = [];
19826             var overEvts  = [];
19827             var dropEvts  = [];
19828             var enterEvts = [];
19829
19830             // Check to see if the object(s) we were hovering over is no longer
19831             // being hovered over so we can fire the onDragOut event
19832             for (var i in this.dragOvers) {
19833
19834                 var ddo = this.dragOvers[i];
19835
19836                 if (! this.isTypeOfDD(ddo)) {
19837                     continue;
19838                 }
19839
19840                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19841                     outEvts.push( ddo );
19842                 }
19843
19844                 oldOvers[i] = true;
19845                 delete this.dragOvers[i];
19846             }
19847
19848             for (var sGroup in dc.groups) {
19849
19850                 if ("string" != typeof sGroup) {
19851                     continue;
19852                 }
19853
19854                 for (i in this.ids[sGroup]) {
19855                     var oDD = this.ids[sGroup][i];
19856                     if (! this.isTypeOfDD(oDD)) {
19857                         continue;
19858                     }
19859
19860                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19861                         if (this.isOverTarget(pt, oDD, this.mode)) {
19862                             // look for drop interactions
19863                             if (isDrop) {
19864                                 dropEvts.push( oDD );
19865                             // look for drag enter and drag over interactions
19866                             } else {
19867
19868                                 // initial drag over: dragEnter fires
19869                                 if (!oldOvers[oDD.id]) {
19870                                     enterEvts.push( oDD );
19871                                 // subsequent drag overs: dragOver fires
19872                                 } else {
19873                                     overEvts.push( oDD );
19874                                 }
19875
19876                                 this.dragOvers[oDD.id] = oDD;
19877                             }
19878                         }
19879                     }
19880                 }
19881             }
19882
19883             if (this.mode) {
19884                 if (outEvts.length) {
19885                     dc.b4DragOut(e, outEvts);
19886                     dc.onDragOut(e, outEvts);
19887                 }
19888
19889                 if (enterEvts.length) {
19890                     dc.onDragEnter(e, enterEvts);
19891                 }
19892
19893                 if (overEvts.length) {
19894                     dc.b4DragOver(e, overEvts);
19895                     dc.onDragOver(e, overEvts);
19896                 }
19897
19898                 if (dropEvts.length) {
19899                     dc.b4DragDrop(e, dropEvts);
19900                     dc.onDragDrop(e, dropEvts);
19901                 }
19902
19903             } else {
19904                 // fire dragout events
19905                 var len = 0;
19906                 for (i=0, len=outEvts.length; i<len; ++i) {
19907                     dc.b4DragOut(e, outEvts[i].id);
19908                     dc.onDragOut(e, outEvts[i].id);
19909                 }
19910
19911                 // fire enter events
19912                 for (i=0,len=enterEvts.length; i<len; ++i) {
19913                     // dc.b4DragEnter(e, oDD.id);
19914                     dc.onDragEnter(e, enterEvts[i].id);
19915                 }
19916
19917                 // fire over events
19918                 for (i=0,len=overEvts.length; i<len; ++i) {
19919                     dc.b4DragOver(e, overEvts[i].id);
19920                     dc.onDragOver(e, overEvts[i].id);
19921                 }
19922
19923                 // fire drop events
19924                 for (i=0, len=dropEvts.length; i<len; ++i) {
19925                     dc.b4DragDrop(e, dropEvts[i].id);
19926                     dc.onDragDrop(e, dropEvts[i].id);
19927                 }
19928
19929             }
19930
19931             // notify about a drop that did not find a target
19932             if (isDrop && !dropEvts.length) {
19933                 dc.onInvalidDrop(e);
19934             }
19935
19936         },
19937
19938         /**
19939          * Helper function for getting the best match from the list of drag
19940          * and drop objects returned by the drag and drop events when we are
19941          * in INTERSECT mode.  It returns either the first object that the
19942          * cursor is over, or the object that has the greatest overlap with
19943          * the dragged element.
19944          * @method getBestMatch
19945          * @param  {DragDrop[]} dds The array of drag and drop objects
19946          * targeted
19947          * @return {DragDrop}       The best single match
19948          * @static
19949          */
19950         getBestMatch: function(dds) {
19951             var winner = null;
19952             // Return null if the input is not what we expect
19953             //if (!dds || !dds.length || dds.length == 0) {
19954                // winner = null;
19955             // If there is only one item, it wins
19956             //} else if (dds.length == 1) {
19957
19958             var len = dds.length;
19959
19960             if (len == 1) {
19961                 winner = dds[0];
19962             } else {
19963                 // Loop through the targeted items
19964                 for (var i=0; i<len; ++i) {
19965                     var dd = dds[i];
19966                     // If the cursor is over the object, it wins.  If the
19967                     // cursor is over multiple matches, the first one we come
19968                     // to wins.
19969                     if (dd.cursorIsOver) {
19970                         winner = dd;
19971                         break;
19972                     // Otherwise the object with the most overlap wins
19973                     } else {
19974                         if (!winner ||
19975                             winner.overlap.getArea() < dd.overlap.getArea()) {
19976                             winner = dd;
19977                         }
19978                     }
19979                 }
19980             }
19981
19982             return winner;
19983         },
19984
19985         /**
19986          * Refreshes the cache of the top-left and bottom-right points of the
19987          * drag and drop objects in the specified group(s).  This is in the
19988          * format that is stored in the drag and drop instance, so typical
19989          * usage is:
19990          * <code>
19991          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19992          * </code>
19993          * Alternatively:
19994          * <code>
19995          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19996          * </code>
19997          * @TODO this really should be an indexed array.  Alternatively this
19998          * method could accept both.
19999          * @method refreshCache
20000          * @param {Object} groups an associative array of groups to refresh
20001          * @static
20002          */
20003         refreshCache: function(groups) {
20004             for (var sGroup in groups) {
20005                 if ("string" != typeof sGroup) {
20006                     continue;
20007                 }
20008                 for (var i in this.ids[sGroup]) {
20009                     var oDD = this.ids[sGroup][i];
20010
20011                     if (this.isTypeOfDD(oDD)) {
20012                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20013                         var loc = this.getLocation(oDD);
20014                         if (loc) {
20015                             this.locationCache[oDD.id] = loc;
20016                         } else {
20017                             delete this.locationCache[oDD.id];
20018                             // this will unregister the drag and drop object if
20019                             // the element is not in a usable state
20020                             // oDD.unreg();
20021                         }
20022                     }
20023                 }
20024             }
20025         },
20026
20027         /**
20028          * This checks to make sure an element exists and is in the DOM.  The
20029          * main purpose is to handle cases where innerHTML is used to remove
20030          * drag and drop objects from the DOM.  IE provides an 'unspecified
20031          * error' when trying to access the offsetParent of such an element
20032          * @method verifyEl
20033          * @param {HTMLElement} el the element to check
20034          * @return {boolean} true if the element looks usable
20035          * @static
20036          */
20037         verifyEl: function(el) {
20038             if (el) {
20039                 var parent;
20040                 if(Roo.isIE){
20041                     try{
20042                         parent = el.offsetParent;
20043                     }catch(e){}
20044                 }else{
20045                     parent = el.offsetParent;
20046                 }
20047                 if (parent) {
20048                     return true;
20049                 }
20050             }
20051
20052             return false;
20053         },
20054
20055         /**
20056          * Returns a Region object containing the drag and drop element's position
20057          * and size, including the padding configured for it
20058          * @method getLocation
20059          * @param {DragDrop} oDD the drag and drop object to get the
20060          *                       location for
20061          * @return {Roo.lib.Region} a Region object representing the total area
20062          *                             the element occupies, including any padding
20063          *                             the instance is configured for.
20064          * @static
20065          */
20066         getLocation: function(oDD) {
20067             if (! this.isTypeOfDD(oDD)) {
20068                 return null;
20069             }
20070
20071             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20072
20073             try {
20074                 pos= Roo.lib.Dom.getXY(el);
20075             } catch (e) { }
20076
20077             if (!pos) {
20078                 return null;
20079             }
20080
20081             x1 = pos[0];
20082             x2 = x1 + el.offsetWidth;
20083             y1 = pos[1];
20084             y2 = y1 + el.offsetHeight;
20085
20086             t = y1 - oDD.padding[0];
20087             r = x2 + oDD.padding[1];
20088             b = y2 + oDD.padding[2];
20089             l = x1 - oDD.padding[3];
20090
20091             return new Roo.lib.Region( t, r, b, l );
20092         },
20093
20094         /**
20095          * Checks the cursor location to see if it over the target
20096          * @method isOverTarget
20097          * @param {Roo.lib.Point} pt The point to evaluate
20098          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20099          * @return {boolean} true if the mouse is over the target
20100          * @private
20101          * @static
20102          */
20103         isOverTarget: function(pt, oTarget, intersect) {
20104             // use cache if available
20105             var loc = this.locationCache[oTarget.id];
20106             if (!loc || !this.useCache) {
20107                 loc = this.getLocation(oTarget);
20108                 this.locationCache[oTarget.id] = loc;
20109
20110             }
20111
20112             if (!loc) {
20113                 return false;
20114             }
20115
20116             oTarget.cursorIsOver = loc.contains( pt );
20117
20118             // DragDrop is using this as a sanity check for the initial mousedown
20119             // in this case we are done.  In POINT mode, if the drag obj has no
20120             // contraints, we are also done. Otherwise we need to evaluate the
20121             // location of the target as related to the actual location of the
20122             // dragged element.
20123             var dc = this.dragCurrent;
20124             if (!dc || !dc.getTargetCoord ||
20125                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20126                 return oTarget.cursorIsOver;
20127             }
20128
20129             oTarget.overlap = null;
20130
20131             // Get the current location of the drag element, this is the
20132             // location of the mouse event less the delta that represents
20133             // where the original mousedown happened on the element.  We
20134             // need to consider constraints and ticks as well.
20135             var pos = dc.getTargetCoord(pt.x, pt.y);
20136
20137             var el = dc.getDragEl();
20138             var curRegion = new Roo.lib.Region( pos.y,
20139                                                    pos.x + el.offsetWidth,
20140                                                    pos.y + el.offsetHeight,
20141                                                    pos.x );
20142
20143             var overlap = curRegion.intersect(loc);
20144
20145             if (overlap) {
20146                 oTarget.overlap = overlap;
20147                 return (intersect) ? true : oTarget.cursorIsOver;
20148             } else {
20149                 return false;
20150             }
20151         },
20152
20153         /**
20154          * unload event handler
20155          * @method _onUnload
20156          * @private
20157          * @static
20158          */
20159         _onUnload: function(e, me) {
20160             Roo.dd.DragDropMgr.unregAll();
20161         },
20162
20163         /**
20164          * Cleans up the drag and drop events and objects.
20165          * @method unregAll
20166          * @private
20167          * @static
20168          */
20169         unregAll: function() {
20170
20171             if (this.dragCurrent) {
20172                 this.stopDrag();
20173                 this.dragCurrent = null;
20174             }
20175
20176             this._execOnAll("unreg", []);
20177
20178             for (i in this.elementCache) {
20179                 delete this.elementCache[i];
20180             }
20181
20182             this.elementCache = {};
20183             this.ids = {};
20184         },
20185
20186         /**
20187          * A cache of DOM elements
20188          * @property elementCache
20189          * @private
20190          * @static
20191          */
20192         elementCache: {},
20193
20194         /**
20195          * Get the wrapper for the DOM element specified
20196          * @method getElWrapper
20197          * @param {String} id the id of the element to get
20198          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20199          * @private
20200          * @deprecated This wrapper isn't that useful
20201          * @static
20202          */
20203         getElWrapper: function(id) {
20204             var oWrapper = this.elementCache[id];
20205             if (!oWrapper || !oWrapper.el) {
20206                 oWrapper = this.elementCache[id] =
20207                     new this.ElementWrapper(Roo.getDom(id));
20208             }
20209             return oWrapper;
20210         },
20211
20212         /**
20213          * Returns the actual DOM element
20214          * @method getElement
20215          * @param {String} id the id of the elment to get
20216          * @return {Object} The element
20217          * @deprecated use Roo.getDom instead
20218          * @static
20219          */
20220         getElement: function(id) {
20221             return Roo.getDom(id);
20222         },
20223
20224         /**
20225          * Returns the style property for the DOM element (i.e.,
20226          * document.getElById(id).style)
20227          * @method getCss
20228          * @param {String} id the id of the elment to get
20229          * @return {Object} The style property of the element
20230          * @deprecated use Roo.getDom instead
20231          * @static
20232          */
20233         getCss: function(id) {
20234             var el = Roo.getDom(id);
20235             return (el) ? el.style : null;
20236         },
20237
20238         /**
20239          * Inner class for cached elements
20240          * @class DragDropMgr.ElementWrapper
20241          * @for DragDropMgr
20242          * @private
20243          * @deprecated
20244          */
20245         ElementWrapper: function(el) {
20246                 /**
20247                  * The element
20248                  * @property el
20249                  */
20250                 this.el = el || null;
20251                 /**
20252                  * The element id
20253                  * @property id
20254                  */
20255                 this.id = this.el && el.id;
20256                 /**
20257                  * A reference to the style property
20258                  * @property css
20259                  */
20260                 this.css = this.el && el.style;
20261             },
20262
20263         /**
20264          * Returns the X position of an html element
20265          * @method getPosX
20266          * @param el the element for which to get the position
20267          * @return {int} the X coordinate
20268          * @for DragDropMgr
20269          * @deprecated use Roo.lib.Dom.getX instead
20270          * @static
20271          */
20272         getPosX: function(el) {
20273             return Roo.lib.Dom.getX(el);
20274         },
20275
20276         /**
20277          * Returns the Y position of an html element
20278          * @method getPosY
20279          * @param el the element for which to get the position
20280          * @return {int} the Y coordinate
20281          * @deprecated use Roo.lib.Dom.getY instead
20282          * @static
20283          */
20284         getPosY: function(el) {
20285             return Roo.lib.Dom.getY(el);
20286         },
20287
20288         /**
20289          * Swap two nodes.  In IE, we use the native method, for others we
20290          * emulate the IE behavior
20291          * @method swapNode
20292          * @param n1 the first node to swap
20293          * @param n2 the other node to swap
20294          * @static
20295          */
20296         swapNode: function(n1, n2) {
20297             if (n1.swapNode) {
20298                 n1.swapNode(n2);
20299             } else {
20300                 var p = n2.parentNode;
20301                 var s = n2.nextSibling;
20302
20303                 if (s == n1) {
20304                     p.insertBefore(n1, n2);
20305                 } else if (n2 == n1.nextSibling) {
20306                     p.insertBefore(n2, n1);
20307                 } else {
20308                     n1.parentNode.replaceChild(n2, n1);
20309                     p.insertBefore(n1, s);
20310                 }
20311             }
20312         },
20313
20314         /**
20315          * Returns the current scroll position
20316          * @method getScroll
20317          * @private
20318          * @static
20319          */
20320         getScroll: function () {
20321             var t, l, dde=document.documentElement, db=document.body;
20322             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20323                 t = dde.scrollTop;
20324                 l = dde.scrollLeft;
20325             } else if (db) {
20326                 t = db.scrollTop;
20327                 l = db.scrollLeft;
20328             } else {
20329
20330             }
20331             return { top: t, left: l };
20332         },
20333
20334         /**
20335          * Returns the specified element style property
20336          * @method getStyle
20337          * @param {HTMLElement} el          the element
20338          * @param {string}      styleProp   the style property
20339          * @return {string} The value of the style property
20340          * @deprecated use Roo.lib.Dom.getStyle
20341          * @static
20342          */
20343         getStyle: function(el, styleProp) {
20344             return Roo.fly(el).getStyle(styleProp);
20345         },
20346
20347         /**
20348          * Gets the scrollTop
20349          * @method getScrollTop
20350          * @return {int} the document's scrollTop
20351          * @static
20352          */
20353         getScrollTop: function () { return this.getScroll().top; },
20354
20355         /**
20356          * Gets the scrollLeft
20357          * @method getScrollLeft
20358          * @return {int} the document's scrollTop
20359          * @static
20360          */
20361         getScrollLeft: function () { return this.getScroll().left; },
20362
20363         /**
20364          * Sets the x/y position of an element to the location of the
20365          * target element.
20366          * @method moveToEl
20367          * @param {HTMLElement} moveEl      The element to move
20368          * @param {HTMLElement} targetEl    The position reference element
20369          * @static
20370          */
20371         moveToEl: function (moveEl, targetEl) {
20372             var aCoord = Roo.lib.Dom.getXY(targetEl);
20373             Roo.lib.Dom.setXY(moveEl, aCoord);
20374         },
20375
20376         /**
20377          * Numeric array sort function
20378          * @method numericSort
20379          * @static
20380          */
20381         numericSort: function(a, b) { return (a - b); },
20382
20383         /**
20384          * Internal counter
20385          * @property _timeoutCount
20386          * @private
20387          * @static
20388          */
20389         _timeoutCount: 0,
20390
20391         /**
20392          * Trying to make the load order less important.  Without this we get
20393          * an error if this file is loaded before the Event Utility.
20394          * @method _addListeners
20395          * @private
20396          * @static
20397          */
20398         _addListeners: function() {
20399             var DDM = Roo.dd.DDM;
20400             if ( Roo.lib.Event && document ) {
20401                 DDM._onLoad();
20402             } else {
20403                 if (DDM._timeoutCount > 2000) {
20404                 } else {
20405                     setTimeout(DDM._addListeners, 10);
20406                     if (document && document.body) {
20407                         DDM._timeoutCount += 1;
20408                     }
20409                 }
20410             }
20411         },
20412
20413         /**
20414          * Recursively searches the immediate parent and all child nodes for
20415          * the handle element in order to determine wheter or not it was
20416          * clicked.
20417          * @method handleWasClicked
20418          * @param node the html element to inspect
20419          * @static
20420          */
20421         handleWasClicked: function(node, id) {
20422             if (this.isHandle(id, node.id)) {
20423                 return true;
20424             } else {
20425                 // check to see if this is a text node child of the one we want
20426                 var p = node.parentNode;
20427
20428                 while (p) {
20429                     if (this.isHandle(id, p.id)) {
20430                         return true;
20431                     } else {
20432                         p = p.parentNode;
20433                     }
20434                 }
20435             }
20436
20437             return false;
20438         }
20439
20440     };
20441
20442 }();
20443
20444 // shorter alias, save a few bytes
20445 Roo.dd.DDM = Roo.dd.DragDropMgr;
20446 Roo.dd.DDM._addListeners();
20447
20448 }/*
20449  * Based on:
20450  * Ext JS Library 1.1.1
20451  * Copyright(c) 2006-2007, Ext JS, LLC.
20452  *
20453  * Originally Released Under LGPL - original licence link has changed is not relivant.
20454  *
20455  * Fork - LGPL
20456  * <script type="text/javascript">
20457  */
20458
20459 /**
20460  * @class Roo.dd.DD
20461  * A DragDrop implementation where the linked element follows the
20462  * mouse cursor during a drag.
20463  * @extends Roo.dd.DragDrop
20464  * @constructor
20465  * @param {String} id the id of the linked element
20466  * @param {String} sGroup the group of related DragDrop items
20467  * @param {object} config an object containing configurable attributes
20468  *                Valid properties for DD:
20469  *                    scroll
20470  */
20471 Roo.dd.DD = function(id, sGroup, config) {
20472     if (id) {
20473         this.init(id, sGroup, config);
20474     }
20475 };
20476
20477 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20478
20479     /**
20480      * When set to true, the utility automatically tries to scroll the browser
20481      * window wehn a drag and drop element is dragged near the viewport boundary.
20482      * Defaults to true.
20483      * @property scroll
20484      * @type boolean
20485      */
20486     scroll: true,
20487
20488     /**
20489      * Sets the pointer offset to the distance between the linked element's top
20490      * left corner and the location the element was clicked
20491      * @method autoOffset
20492      * @param {int} iPageX the X coordinate of the click
20493      * @param {int} iPageY the Y coordinate of the click
20494      */
20495     autoOffset: function(iPageX, iPageY) {
20496         var x = iPageX - this.startPageX;
20497         var y = iPageY - this.startPageY;
20498         this.setDelta(x, y);
20499     },
20500
20501     /**
20502      * Sets the pointer offset.  You can call this directly to force the
20503      * offset to be in a particular location (e.g., pass in 0,0 to set it
20504      * to the center of the object)
20505      * @method setDelta
20506      * @param {int} iDeltaX the distance from the left
20507      * @param {int} iDeltaY the distance from the top
20508      */
20509     setDelta: function(iDeltaX, iDeltaY) {
20510         this.deltaX = iDeltaX;
20511         this.deltaY = iDeltaY;
20512     },
20513
20514     /**
20515      * Sets the drag element to the location of the mousedown or click event,
20516      * maintaining the cursor location relative to the location on the element
20517      * that was clicked.  Override this if you want to place the element in a
20518      * location other than where the cursor is.
20519      * @method setDragElPos
20520      * @param {int} iPageX the X coordinate of the mousedown or drag event
20521      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20522      */
20523     setDragElPos: function(iPageX, iPageY) {
20524         // the first time we do this, we are going to check to make sure
20525         // the element has css positioning
20526
20527         var el = this.getDragEl();
20528         this.alignElWithMouse(el, iPageX, iPageY);
20529     },
20530
20531     /**
20532      * Sets the element to the location of the mousedown or click event,
20533      * maintaining the cursor location relative to the location on the element
20534      * that was clicked.  Override this if you want to place the element in a
20535      * location other than where the cursor is.
20536      * @method alignElWithMouse
20537      * @param {HTMLElement} el the element to move
20538      * @param {int} iPageX the X coordinate of the mousedown or drag event
20539      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20540      */
20541     alignElWithMouse: function(el, iPageX, iPageY) {
20542         var oCoord = this.getTargetCoord(iPageX, iPageY);
20543         var fly = el.dom ? el : Roo.fly(el);
20544         if (!this.deltaSetXY) {
20545             var aCoord = [oCoord.x, oCoord.y];
20546             fly.setXY(aCoord);
20547             var newLeft = fly.getLeft(true);
20548             var newTop  = fly.getTop(true);
20549             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20550         } else {
20551             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20552         }
20553
20554         this.cachePosition(oCoord.x, oCoord.y);
20555         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20556         return oCoord;
20557     },
20558
20559     /**
20560      * Saves the most recent position so that we can reset the constraints and
20561      * tick marks on-demand.  We need to know this so that we can calculate the
20562      * number of pixels the element is offset from its original position.
20563      * @method cachePosition
20564      * @param iPageX the current x position (optional, this just makes it so we
20565      * don't have to look it up again)
20566      * @param iPageY the current y position (optional, this just makes it so we
20567      * don't have to look it up again)
20568      */
20569     cachePosition: function(iPageX, iPageY) {
20570         if (iPageX) {
20571             this.lastPageX = iPageX;
20572             this.lastPageY = iPageY;
20573         } else {
20574             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20575             this.lastPageX = aCoord[0];
20576             this.lastPageY = aCoord[1];
20577         }
20578     },
20579
20580     /**
20581      * Auto-scroll the window if the dragged object has been moved beyond the
20582      * visible window boundary.
20583      * @method autoScroll
20584      * @param {int} x the drag element's x position
20585      * @param {int} y the drag element's y position
20586      * @param {int} h the height of the drag element
20587      * @param {int} w the width of the drag element
20588      * @private
20589      */
20590     autoScroll: function(x, y, h, w) {
20591
20592         if (this.scroll) {
20593             // The client height
20594             var clientH = Roo.lib.Dom.getViewWidth();
20595
20596             // The client width
20597             var clientW = Roo.lib.Dom.getViewHeight();
20598
20599             // The amt scrolled down
20600             var st = this.DDM.getScrollTop();
20601
20602             // The amt scrolled right
20603             var sl = this.DDM.getScrollLeft();
20604
20605             // Location of the bottom of the element
20606             var bot = h + y;
20607
20608             // Location of the right of the element
20609             var right = w + x;
20610
20611             // The distance from the cursor to the bottom of the visible area,
20612             // adjusted so that we don't scroll if the cursor is beyond the
20613             // element drag constraints
20614             var toBot = (clientH + st - y - this.deltaY);
20615
20616             // The distance from the cursor to the right of the visible area
20617             var toRight = (clientW + sl - x - this.deltaX);
20618
20619
20620             // How close to the edge the cursor must be before we scroll
20621             // var thresh = (document.all) ? 100 : 40;
20622             var thresh = 40;
20623
20624             // How many pixels to scroll per autoscroll op.  This helps to reduce
20625             // clunky scrolling. IE is more sensitive about this ... it needs this
20626             // value to be higher.
20627             var scrAmt = (document.all) ? 80 : 30;
20628
20629             // Scroll down if we are near the bottom of the visible page and the
20630             // obj extends below the crease
20631             if ( bot > clientH && toBot < thresh ) {
20632                 window.scrollTo(sl, st + scrAmt);
20633             }
20634
20635             // Scroll up if the window is scrolled down and the top of the object
20636             // goes above the top border
20637             if ( y < st && st > 0 && y - st < thresh ) {
20638                 window.scrollTo(sl, st - scrAmt);
20639             }
20640
20641             // Scroll right if the obj is beyond the right border and the cursor is
20642             // near the border.
20643             if ( right > clientW && toRight < thresh ) {
20644                 window.scrollTo(sl + scrAmt, st);
20645             }
20646
20647             // Scroll left if the window has been scrolled to the right and the obj
20648             // extends past the left border
20649             if ( x < sl && sl > 0 && x - sl < thresh ) {
20650                 window.scrollTo(sl - scrAmt, st);
20651             }
20652         }
20653     },
20654
20655     /**
20656      * Finds the location the element should be placed if we want to move
20657      * it to where the mouse location less the click offset would place us.
20658      * @method getTargetCoord
20659      * @param {int} iPageX the X coordinate of the click
20660      * @param {int} iPageY the Y coordinate of the click
20661      * @return an object that contains the coordinates (Object.x and Object.y)
20662      * @private
20663      */
20664     getTargetCoord: function(iPageX, iPageY) {
20665
20666
20667         var x = iPageX - this.deltaX;
20668         var y = iPageY - this.deltaY;
20669
20670         if (this.constrainX) {
20671             if (x < this.minX) { x = this.minX; }
20672             if (x > this.maxX) { x = this.maxX; }
20673         }
20674
20675         if (this.constrainY) {
20676             if (y < this.minY) { y = this.minY; }
20677             if (y > this.maxY) { y = this.maxY; }
20678         }
20679
20680         x = this.getTick(x, this.xTicks);
20681         y = this.getTick(y, this.yTicks);
20682
20683
20684         return {x:x, y:y};
20685     },
20686
20687     /*
20688      * Sets up config options specific to this class. Overrides
20689      * Roo.dd.DragDrop, but all versions of this method through the
20690      * inheritance chain are called
20691      */
20692     applyConfig: function() {
20693         Roo.dd.DD.superclass.applyConfig.call(this);
20694         this.scroll = (this.config.scroll !== false);
20695     },
20696
20697     /*
20698      * Event that fires prior to the onMouseDown event.  Overrides
20699      * Roo.dd.DragDrop.
20700      */
20701     b4MouseDown: function(e) {
20702         // this.resetConstraints();
20703         this.autoOffset(e.getPageX(),
20704                             e.getPageY());
20705     },
20706
20707     /*
20708      * Event that fires prior to the onDrag event.  Overrides
20709      * Roo.dd.DragDrop.
20710      */
20711     b4Drag: function(e) {
20712         this.setDragElPos(e.getPageX(),
20713                             e.getPageY());
20714     },
20715
20716     toString: function() {
20717         return ("DD " + this.id);
20718     }
20719
20720     //////////////////////////////////////////////////////////////////////////
20721     // Debugging ygDragDrop events that can be overridden
20722     //////////////////////////////////////////////////////////////////////////
20723     /*
20724     startDrag: function(x, y) {
20725     },
20726
20727     onDrag: function(e) {
20728     },
20729
20730     onDragEnter: function(e, id) {
20731     },
20732
20733     onDragOver: function(e, id) {
20734     },
20735
20736     onDragOut: function(e, id) {
20737     },
20738
20739     onDragDrop: function(e, id) {
20740     },
20741
20742     endDrag: function(e) {
20743     }
20744
20745     */
20746
20747 });/*
20748  * Based on:
20749  * Ext JS Library 1.1.1
20750  * Copyright(c) 2006-2007, Ext JS, LLC.
20751  *
20752  * Originally Released Under LGPL - original licence link has changed is not relivant.
20753  *
20754  * Fork - LGPL
20755  * <script type="text/javascript">
20756  */
20757
20758 /**
20759  * @class Roo.dd.DDProxy
20760  * A DragDrop implementation that inserts an empty, bordered div into
20761  * the document that follows the cursor during drag operations.  At the time of
20762  * the click, the frame div is resized to the dimensions of the linked html
20763  * element, and moved to the exact location of the linked element.
20764  *
20765  * References to the "frame" element refer to the single proxy element that
20766  * was created to be dragged in place of all DDProxy elements on the
20767  * page.
20768  *
20769  * @extends Roo.dd.DD
20770  * @constructor
20771  * @param {String} id the id of the linked html element
20772  * @param {String} sGroup the group of related DragDrop objects
20773  * @param {object} config an object containing configurable attributes
20774  *                Valid properties for DDProxy in addition to those in DragDrop:
20775  *                   resizeFrame, centerFrame, dragElId
20776  */
20777 Roo.dd.DDProxy = function(id, sGroup, config) {
20778     if (id) {
20779         this.init(id, sGroup, config);
20780         this.initFrame();
20781     }
20782 };
20783
20784 /**
20785  * The default drag frame div id
20786  * @property Roo.dd.DDProxy.dragElId
20787  * @type String
20788  * @static
20789  */
20790 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20791
20792 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20793
20794     /**
20795      * By default we resize the drag frame to be the same size as the element
20796      * we want to drag (this is to get the frame effect).  We can turn it off
20797      * if we want a different behavior.
20798      * @property resizeFrame
20799      * @type boolean
20800      */
20801     resizeFrame: true,
20802
20803     /**
20804      * By default the frame is positioned exactly where the drag element is, so
20805      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20806      * you do not have constraints on the obj is to have the drag frame centered
20807      * around the cursor.  Set centerFrame to true for this effect.
20808      * @property centerFrame
20809      * @type boolean
20810      */
20811     centerFrame: false,
20812
20813     /**
20814      * Creates the proxy element if it does not yet exist
20815      * @method createFrame
20816      */
20817     createFrame: function() {
20818         var self = this;
20819         var body = document.body;
20820
20821         if (!body || !body.firstChild) {
20822             setTimeout( function() { self.createFrame(); }, 50 );
20823             return;
20824         }
20825
20826         var div = this.getDragEl();
20827
20828         if (!div) {
20829             div    = document.createElement("div");
20830             div.id = this.dragElId;
20831             var s  = div.style;
20832
20833             s.position   = "absolute";
20834             s.visibility = "hidden";
20835             s.cursor     = "move";
20836             s.border     = "2px solid #aaa";
20837             s.zIndex     = 999;
20838
20839             // appendChild can blow up IE if invoked prior to the window load event
20840             // while rendering a table.  It is possible there are other scenarios
20841             // that would cause this to happen as well.
20842             body.insertBefore(div, body.firstChild);
20843         }
20844     },
20845
20846     /**
20847      * Initialization for the drag frame element.  Must be called in the
20848      * constructor of all subclasses
20849      * @method initFrame
20850      */
20851     initFrame: function() {
20852         this.createFrame();
20853     },
20854
20855     applyConfig: function() {
20856         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20857
20858         this.resizeFrame = (this.config.resizeFrame !== false);
20859         this.centerFrame = (this.config.centerFrame);
20860         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20861     },
20862
20863     /**
20864      * Resizes the drag frame to the dimensions of the clicked object, positions
20865      * it over the object, and finally displays it
20866      * @method showFrame
20867      * @param {int} iPageX X click position
20868      * @param {int} iPageY Y click position
20869      * @private
20870      */
20871     showFrame: function(iPageX, iPageY) {
20872         var el = this.getEl();
20873         var dragEl = this.getDragEl();
20874         var s = dragEl.style;
20875
20876         this._resizeProxy();
20877
20878         if (this.centerFrame) {
20879             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20880                            Math.round(parseInt(s.height, 10)/2) );
20881         }
20882
20883         this.setDragElPos(iPageX, iPageY);
20884
20885         Roo.fly(dragEl).show();
20886     },
20887
20888     /**
20889      * The proxy is automatically resized to the dimensions of the linked
20890      * element when a drag is initiated, unless resizeFrame is set to false
20891      * @method _resizeProxy
20892      * @private
20893      */
20894     _resizeProxy: function() {
20895         if (this.resizeFrame) {
20896             var el = this.getEl();
20897             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20898         }
20899     },
20900
20901     // overrides Roo.dd.DragDrop
20902     b4MouseDown: function(e) {
20903         var x = e.getPageX();
20904         var y = e.getPageY();
20905         this.autoOffset(x, y);
20906         this.setDragElPos(x, y);
20907     },
20908
20909     // overrides Roo.dd.DragDrop
20910     b4StartDrag: function(x, y) {
20911         // show the drag frame
20912         this.showFrame(x, y);
20913     },
20914
20915     // overrides Roo.dd.DragDrop
20916     b4EndDrag: function(e) {
20917         Roo.fly(this.getDragEl()).hide();
20918     },
20919
20920     // overrides Roo.dd.DragDrop
20921     // By default we try to move the element to the last location of the frame.
20922     // This is so that the default behavior mirrors that of Roo.dd.DD.
20923     endDrag: function(e) {
20924
20925         var lel = this.getEl();
20926         var del = this.getDragEl();
20927
20928         // Show the drag frame briefly so we can get its position
20929         del.style.visibility = "";
20930
20931         this.beforeMove();
20932         // Hide the linked element before the move to get around a Safari
20933         // rendering bug.
20934         lel.style.visibility = "hidden";
20935         Roo.dd.DDM.moveToEl(lel, del);
20936         del.style.visibility = "hidden";
20937         lel.style.visibility = "";
20938
20939         this.afterDrag();
20940     },
20941
20942     beforeMove : function(){
20943
20944     },
20945
20946     afterDrag : function(){
20947
20948     },
20949
20950     toString: function() {
20951         return ("DDProxy " + this.id);
20952     }
20953
20954 });
20955 /*
20956  * Based on:
20957  * Ext JS Library 1.1.1
20958  * Copyright(c) 2006-2007, Ext JS, LLC.
20959  *
20960  * Originally Released Under LGPL - original licence link has changed is not relivant.
20961  *
20962  * Fork - LGPL
20963  * <script type="text/javascript">
20964  */
20965
20966  /**
20967  * @class Roo.dd.DDTarget
20968  * A DragDrop implementation that does not move, but can be a drop
20969  * target.  You would get the same result by simply omitting implementation
20970  * for the event callbacks, but this way we reduce the processing cost of the
20971  * event listener and the callbacks.
20972  * @extends Roo.dd.DragDrop
20973  * @constructor
20974  * @param {String} id the id of the element that is a drop target
20975  * @param {String} sGroup the group of related DragDrop objects
20976  * @param {object} config an object containing configurable attributes
20977  *                 Valid properties for DDTarget in addition to those in
20978  *                 DragDrop:
20979  *                    none
20980  */
20981 Roo.dd.DDTarget = function(id, sGroup, config) {
20982     if (id) {
20983         this.initTarget(id, sGroup, config);
20984     }
20985     if (config.listeners || config.events) { 
20986        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20987             listeners : config.listeners || {}, 
20988             events : config.events || {} 
20989         });    
20990     }
20991 };
20992
20993 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20994 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20995     toString: function() {
20996         return ("DDTarget " + this.id);
20997     }
20998 });
20999 /*
21000  * Based on:
21001  * Ext JS Library 1.1.1
21002  * Copyright(c) 2006-2007, Ext JS, LLC.
21003  *
21004  * Originally Released Under LGPL - original licence link has changed is not relivant.
21005  *
21006  * Fork - LGPL
21007  * <script type="text/javascript">
21008  */
21009  
21010
21011 /**
21012  * @class Roo.dd.ScrollManager
21013  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21014  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21015  * @singleton
21016  */
21017 Roo.dd.ScrollManager = function(){
21018     var ddm = Roo.dd.DragDropMgr;
21019     var els = {};
21020     var dragEl = null;
21021     var proc = {};
21022     
21023     
21024     
21025     var onStop = function(e){
21026         dragEl = null;
21027         clearProc();
21028     };
21029     
21030     var triggerRefresh = function(){
21031         if(ddm.dragCurrent){
21032              ddm.refreshCache(ddm.dragCurrent.groups);
21033         }
21034     };
21035     
21036     var doScroll = function(){
21037         if(ddm.dragCurrent){
21038             var dds = Roo.dd.ScrollManager;
21039             if(!dds.animate){
21040                 if(proc.el.scroll(proc.dir, dds.increment)){
21041                     triggerRefresh();
21042                 }
21043             }else{
21044                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21045             }
21046         }
21047     };
21048     
21049     var clearProc = function(){
21050         if(proc.id){
21051             clearInterval(proc.id);
21052         }
21053         proc.id = 0;
21054         proc.el = null;
21055         proc.dir = "";
21056     };
21057     
21058     var startProc = function(el, dir){
21059          Roo.log('scroll startproc');
21060         clearProc();
21061         proc.el = el;
21062         proc.dir = dir;
21063         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21064     };
21065     
21066     var onFire = function(e, isDrop){
21067        
21068         if(isDrop || !ddm.dragCurrent){ return; }
21069         var dds = Roo.dd.ScrollManager;
21070         if(!dragEl || dragEl != ddm.dragCurrent){
21071             dragEl = ddm.dragCurrent;
21072             // refresh regions on drag start
21073             dds.refreshCache();
21074         }
21075         
21076         var xy = Roo.lib.Event.getXY(e);
21077         var pt = new Roo.lib.Point(xy[0], xy[1]);
21078         for(var id in els){
21079             var el = els[id], r = el._region;
21080             if(r && r.contains(pt) && el.isScrollable()){
21081                 if(r.bottom - pt.y <= dds.thresh){
21082                     if(proc.el != el){
21083                         startProc(el, "down");
21084                     }
21085                     return;
21086                 }else if(r.right - pt.x <= dds.thresh){
21087                     if(proc.el != el){
21088                         startProc(el, "left");
21089                     }
21090                     return;
21091                 }else if(pt.y - r.top <= dds.thresh){
21092                     if(proc.el != el){
21093                         startProc(el, "up");
21094                     }
21095                     return;
21096                 }else if(pt.x - r.left <= dds.thresh){
21097                     if(proc.el != el){
21098                         startProc(el, "right");
21099                     }
21100                     return;
21101                 }
21102             }
21103         }
21104         clearProc();
21105     };
21106     
21107     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21108     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21109     
21110     return {
21111         /**
21112          * Registers new overflow element(s) to auto scroll
21113          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21114          */
21115         register : function(el){
21116             if(el instanceof Array){
21117                 for(var i = 0, len = el.length; i < len; i++) {
21118                         this.register(el[i]);
21119                 }
21120             }else{
21121                 el = Roo.get(el);
21122                 els[el.id] = el;
21123             }
21124             Roo.dd.ScrollManager.els = els;
21125         },
21126         
21127         /**
21128          * Unregisters overflow element(s) so they are no longer scrolled
21129          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21130          */
21131         unregister : function(el){
21132             if(el instanceof Array){
21133                 for(var i = 0, len = el.length; i < len; i++) {
21134                         this.unregister(el[i]);
21135                 }
21136             }else{
21137                 el = Roo.get(el);
21138                 delete els[el.id];
21139             }
21140         },
21141         
21142         /**
21143          * The number of pixels from the edge of a container the pointer needs to be to 
21144          * trigger scrolling (defaults to 25)
21145          * @type Number
21146          */
21147         thresh : 25,
21148         
21149         /**
21150          * The number of pixels to scroll in each scroll increment (defaults to 50)
21151          * @type Number
21152          */
21153         increment : 100,
21154         
21155         /**
21156          * The frequency of scrolls in milliseconds (defaults to 500)
21157          * @type Number
21158          */
21159         frequency : 500,
21160         
21161         /**
21162          * True to animate the scroll (defaults to true)
21163          * @type Boolean
21164          */
21165         animate: true,
21166         
21167         /**
21168          * The animation duration in seconds - 
21169          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21170          * @type Number
21171          */
21172         animDuration: .4,
21173         
21174         /**
21175          * Manually trigger a cache refresh.
21176          */
21177         refreshCache : function(){
21178             for(var id in els){
21179                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21180                     els[id]._region = els[id].getRegion();
21181                 }
21182             }
21183         }
21184     };
21185 }();/*
21186  * Based on:
21187  * Ext JS Library 1.1.1
21188  * Copyright(c) 2006-2007, Ext JS, LLC.
21189  *
21190  * Originally Released Under LGPL - original licence link has changed is not relivant.
21191  *
21192  * Fork - LGPL
21193  * <script type="text/javascript">
21194  */
21195  
21196
21197 /**
21198  * @class Roo.dd.Registry
21199  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21200  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21201  * @singleton
21202  */
21203 Roo.dd.Registry = function(){
21204     var elements = {}; 
21205     var handles = {}; 
21206     var autoIdSeed = 0;
21207
21208     var getId = function(el, autogen){
21209         if(typeof el == "string"){
21210             return el;
21211         }
21212         var id = el.id;
21213         if(!id && autogen !== false){
21214             id = "roodd-" + (++autoIdSeed);
21215             el.id = id;
21216         }
21217         return id;
21218     };
21219     
21220     return {
21221     /**
21222      * Register a drag drop element
21223      * @param {String|HTMLElement} element The id or DOM node to register
21224      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21225      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21226      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21227      * populated in the data object (if applicable):
21228      * <pre>
21229 Value      Description<br />
21230 ---------  ------------------------------------------<br />
21231 handles    Array of DOM nodes that trigger dragging<br />
21232            for the element being registered<br />
21233 isHandle   True if the element passed in triggers<br />
21234            dragging itself, else false
21235 </pre>
21236      */
21237         register : function(el, data){
21238             data = data || {};
21239             if(typeof el == "string"){
21240                 el = document.getElementById(el);
21241             }
21242             data.ddel = el;
21243             elements[getId(el)] = data;
21244             if(data.isHandle !== false){
21245                 handles[data.ddel.id] = data;
21246             }
21247             if(data.handles){
21248                 var hs = data.handles;
21249                 for(var i = 0, len = hs.length; i < len; i++){
21250                         handles[getId(hs[i])] = data;
21251                 }
21252             }
21253         },
21254
21255     /**
21256      * Unregister a drag drop element
21257      * @param {String|HTMLElement}  element The id or DOM node to unregister
21258      */
21259         unregister : function(el){
21260             var id = getId(el, false);
21261             var data = elements[id];
21262             if(data){
21263                 delete elements[id];
21264                 if(data.handles){
21265                     var hs = data.handles;
21266                     for(var i = 0, len = hs.length; i < len; i++){
21267                         delete handles[getId(hs[i], false)];
21268                     }
21269                 }
21270             }
21271         },
21272
21273     /**
21274      * Returns the handle registered for a DOM Node by id
21275      * @param {String|HTMLElement} id The DOM node or id to look up
21276      * @return {Object} handle The custom handle data
21277      */
21278         getHandle : function(id){
21279             if(typeof id != "string"){ // must be element?
21280                 id = id.id;
21281             }
21282             return handles[id];
21283         },
21284
21285     /**
21286      * Returns the handle that is registered for the DOM node that is the target of the event
21287      * @param {Event} e The event
21288      * @return {Object} handle The custom handle data
21289      */
21290         getHandleFromEvent : function(e){
21291             var t = Roo.lib.Event.getTarget(e);
21292             return t ? handles[t.id] : null;
21293         },
21294
21295     /**
21296      * Returns a custom data object that is registered for a DOM node by id
21297      * @param {String|HTMLElement} id The DOM node or id to look up
21298      * @return {Object} data The custom data
21299      */
21300         getTarget : function(id){
21301             if(typeof id != "string"){ // must be element?
21302                 id = id.id;
21303             }
21304             return elements[id];
21305         },
21306
21307     /**
21308      * Returns a custom data object that is registered for the DOM node that is the target of the event
21309      * @param {Event} e The event
21310      * @return {Object} data The custom data
21311      */
21312         getTargetFromEvent : function(e){
21313             var t = Roo.lib.Event.getTarget(e);
21314             return t ? elements[t.id] || handles[t.id] : null;
21315         }
21316     };
21317 }();/*
21318  * Based on:
21319  * Ext JS Library 1.1.1
21320  * Copyright(c) 2006-2007, Ext JS, LLC.
21321  *
21322  * Originally Released Under LGPL - original licence link has changed is not relivant.
21323  *
21324  * Fork - LGPL
21325  * <script type="text/javascript">
21326  */
21327  
21328
21329 /**
21330  * @class Roo.dd.StatusProxy
21331  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21332  * default drag proxy used by all Roo.dd components.
21333  * @constructor
21334  * @param {Object} config
21335  */
21336 Roo.dd.StatusProxy = function(config){
21337     Roo.apply(this, config);
21338     this.id = this.id || Roo.id();
21339     this.el = new Roo.Layer({
21340         dh: {
21341             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21342                 {tag: "div", cls: "x-dd-drop-icon"},
21343                 {tag: "div", cls: "x-dd-drag-ghost"}
21344             ]
21345         }, 
21346         shadow: !config || config.shadow !== false
21347     });
21348     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21349     this.dropStatus = this.dropNotAllowed;
21350 };
21351
21352 Roo.dd.StatusProxy.prototype = {
21353     /**
21354      * @cfg {String} dropAllowed
21355      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21356      */
21357     dropAllowed : "x-dd-drop-ok",
21358     /**
21359      * @cfg {String} dropNotAllowed
21360      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21361      */
21362     dropNotAllowed : "x-dd-drop-nodrop",
21363
21364     /**
21365      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21366      * over the current target element.
21367      * @param {String} cssClass The css class for the new drop status indicator image
21368      */
21369     setStatus : function(cssClass){
21370         cssClass = cssClass || this.dropNotAllowed;
21371         if(this.dropStatus != cssClass){
21372             this.el.replaceClass(this.dropStatus, cssClass);
21373             this.dropStatus = cssClass;
21374         }
21375     },
21376
21377     /**
21378      * Resets the status indicator to the default dropNotAllowed value
21379      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21380      */
21381     reset : function(clearGhost){
21382         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21383         this.dropStatus = this.dropNotAllowed;
21384         if(clearGhost){
21385             this.ghost.update("");
21386         }
21387     },
21388
21389     /**
21390      * Updates the contents of the ghost element
21391      * @param {String} html The html that will replace the current innerHTML of the ghost element
21392      */
21393     update : function(html){
21394         if(typeof html == "string"){
21395             this.ghost.update(html);
21396         }else{
21397             this.ghost.update("");
21398             html.style.margin = "0";
21399             this.ghost.dom.appendChild(html);
21400         }
21401         // ensure float = none set?? cant remember why though.
21402         var el = this.ghost.dom.firstChild;
21403                 if(el){
21404                         Roo.fly(el).setStyle('float', 'none');
21405                 }
21406     },
21407     
21408     /**
21409      * Returns the underlying proxy {@link Roo.Layer}
21410      * @return {Roo.Layer} el
21411     */
21412     getEl : function(){
21413         return this.el;
21414     },
21415
21416     /**
21417      * Returns the ghost element
21418      * @return {Roo.Element} el
21419      */
21420     getGhost : function(){
21421         return this.ghost;
21422     },
21423
21424     /**
21425      * Hides the proxy
21426      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21427      */
21428     hide : function(clear){
21429         this.el.hide();
21430         if(clear){
21431             this.reset(true);
21432         }
21433     },
21434
21435     /**
21436      * Stops the repair animation if it's currently running
21437      */
21438     stop : function(){
21439         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21440             this.anim.stop();
21441         }
21442     },
21443
21444     /**
21445      * Displays this proxy
21446      */
21447     show : function(){
21448         this.el.show();
21449     },
21450
21451     /**
21452      * Force the Layer to sync its shadow and shim positions to the element
21453      */
21454     sync : function(){
21455         this.el.sync();
21456     },
21457
21458     /**
21459      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21460      * invalid drop operation by the item being dragged.
21461      * @param {Array} xy The XY position of the element ([x, y])
21462      * @param {Function} callback The function to call after the repair is complete
21463      * @param {Object} scope The scope in which to execute the callback
21464      */
21465     repair : function(xy, callback, scope){
21466         this.callback = callback;
21467         this.scope = scope;
21468         if(xy && this.animRepair !== false){
21469             this.el.addClass("x-dd-drag-repair");
21470             this.el.hideUnders(true);
21471             this.anim = this.el.shift({
21472                 duration: this.repairDuration || .5,
21473                 easing: 'easeOut',
21474                 xy: xy,
21475                 stopFx: true,
21476                 callback: this.afterRepair,
21477                 scope: this
21478             });
21479         }else{
21480             this.afterRepair();
21481         }
21482     },
21483
21484     // private
21485     afterRepair : function(){
21486         this.hide(true);
21487         if(typeof this.callback == "function"){
21488             this.callback.call(this.scope || this);
21489         }
21490         this.callback = null;
21491         this.scope = null;
21492     }
21493 };/*
21494  * Based on:
21495  * Ext JS Library 1.1.1
21496  * Copyright(c) 2006-2007, Ext JS, LLC.
21497  *
21498  * Originally Released Under LGPL - original licence link has changed is not relivant.
21499  *
21500  * Fork - LGPL
21501  * <script type="text/javascript">
21502  */
21503
21504 /**
21505  * @class Roo.dd.DragSource
21506  * @extends Roo.dd.DDProxy
21507  * A simple class that provides the basic implementation needed to make any element draggable.
21508  * @constructor
21509  * @param {String/HTMLElement/Element} el The container element
21510  * @param {Object} config
21511  */
21512 Roo.dd.DragSource = function(el, config){
21513     this.el = Roo.get(el);
21514     this.dragData = {};
21515     
21516     Roo.apply(this, config);
21517     
21518     if(!this.proxy){
21519         this.proxy = new Roo.dd.StatusProxy();
21520     }
21521
21522     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21523           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21524     
21525     this.dragging = false;
21526 };
21527
21528 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21529     /**
21530      * @cfg {String} dropAllowed
21531      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21532      */
21533     dropAllowed : "x-dd-drop-ok",
21534     /**
21535      * @cfg {String} dropNotAllowed
21536      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21537      */
21538     dropNotAllowed : "x-dd-drop-nodrop",
21539
21540     /**
21541      * Returns the data object associated with this drag source
21542      * @return {Object} data An object containing arbitrary data
21543      */
21544     getDragData : function(e){
21545         return this.dragData;
21546     },
21547
21548     // private
21549     onDragEnter : function(e, id){
21550         var target = Roo.dd.DragDropMgr.getDDById(id);
21551         this.cachedTarget = target;
21552         if(this.beforeDragEnter(target, e, id) !== false){
21553             if(target.isNotifyTarget){
21554                 var status = target.notifyEnter(this, e, this.dragData);
21555                 this.proxy.setStatus(status);
21556             }else{
21557                 this.proxy.setStatus(this.dropAllowed);
21558             }
21559             
21560             if(this.afterDragEnter){
21561                 /**
21562                  * An empty function by default, but provided so that you can perform a custom action
21563                  * when the dragged item enters the drop target by providing an implementation.
21564                  * @param {Roo.dd.DragDrop} target The drop target
21565                  * @param {Event} e The event object
21566                  * @param {String} id The id of the dragged element
21567                  * @method afterDragEnter
21568                  */
21569                 this.afterDragEnter(target, e, id);
21570             }
21571         }
21572     },
21573
21574     /**
21575      * An empty function by default, but provided so that you can perform a custom action
21576      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21577      * @param {Roo.dd.DragDrop} target The drop target
21578      * @param {Event} e The event object
21579      * @param {String} id The id of the dragged element
21580      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21581      */
21582     beforeDragEnter : function(target, e, id){
21583         return true;
21584     },
21585
21586     // private
21587     alignElWithMouse: function() {
21588         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21589         this.proxy.sync();
21590     },
21591
21592     // private
21593     onDragOver : function(e, id){
21594         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21595         if(this.beforeDragOver(target, e, id) !== false){
21596             if(target.isNotifyTarget){
21597                 var status = target.notifyOver(this, e, this.dragData);
21598                 this.proxy.setStatus(status);
21599             }
21600
21601             if(this.afterDragOver){
21602                 /**
21603                  * An empty function by default, but provided so that you can perform a custom action
21604                  * while the dragged item is over the drop target by providing an implementation.
21605                  * @param {Roo.dd.DragDrop} target The drop target
21606                  * @param {Event} e The event object
21607                  * @param {String} id The id of the dragged element
21608                  * @method afterDragOver
21609                  */
21610                 this.afterDragOver(target, e, id);
21611             }
21612         }
21613     },
21614
21615     /**
21616      * An empty function by default, but provided so that you can perform a custom action
21617      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21618      * @param {Roo.dd.DragDrop} target The drop target
21619      * @param {Event} e The event object
21620      * @param {String} id The id of the dragged element
21621      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21622      */
21623     beforeDragOver : function(target, e, id){
21624         return true;
21625     },
21626
21627     // private
21628     onDragOut : function(e, id){
21629         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21630         if(this.beforeDragOut(target, e, id) !== false){
21631             if(target.isNotifyTarget){
21632                 target.notifyOut(this, e, this.dragData);
21633             }
21634             this.proxy.reset();
21635             if(this.afterDragOut){
21636                 /**
21637                  * An empty function by default, but provided so that you can perform a custom action
21638                  * after the dragged item is dragged out of the target without dropping.
21639                  * @param {Roo.dd.DragDrop} target The drop target
21640                  * @param {Event} e The event object
21641                  * @param {String} id The id of the dragged element
21642                  * @method afterDragOut
21643                  */
21644                 this.afterDragOut(target, e, id);
21645             }
21646         }
21647         this.cachedTarget = null;
21648     },
21649
21650     /**
21651      * An empty function by default, but provided so that you can perform a custom action before the dragged
21652      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21653      * @param {Roo.dd.DragDrop} target The drop target
21654      * @param {Event} e The event object
21655      * @param {String} id The id of the dragged element
21656      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21657      */
21658     beforeDragOut : function(target, e, id){
21659         return true;
21660     },
21661     
21662     // private
21663     onDragDrop : function(e, id){
21664         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21665         if(this.beforeDragDrop(target, e, id) !== false){
21666             if(target.isNotifyTarget){
21667                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21668                     this.onValidDrop(target, e, id);
21669                 }else{
21670                     this.onInvalidDrop(target, e, id);
21671                 }
21672             }else{
21673                 this.onValidDrop(target, e, id);
21674             }
21675             
21676             if(this.afterDragDrop){
21677                 /**
21678                  * An empty function by default, but provided so that you can perform a custom action
21679                  * after a valid drag drop has occurred by providing an implementation.
21680                  * @param {Roo.dd.DragDrop} target The drop target
21681                  * @param {Event} e The event object
21682                  * @param {String} id The id of the dropped element
21683                  * @method afterDragDrop
21684                  */
21685                 this.afterDragDrop(target, e, id);
21686             }
21687         }
21688         delete this.cachedTarget;
21689     },
21690
21691     /**
21692      * An empty function by default, but provided so that you can perform a custom action before the dragged
21693      * item is dropped onto the target and optionally cancel the onDragDrop.
21694      * @param {Roo.dd.DragDrop} target The drop target
21695      * @param {Event} e The event object
21696      * @param {String} id The id of the dragged element
21697      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21698      */
21699     beforeDragDrop : function(target, e, id){
21700         return true;
21701     },
21702
21703     // private
21704     onValidDrop : function(target, e, id){
21705         this.hideProxy();
21706         if(this.afterValidDrop){
21707             /**
21708              * An empty function by default, but provided so that you can perform a custom action
21709              * after a valid drop has occurred by providing an implementation.
21710              * @param {Object} target The target DD 
21711              * @param {Event} e The event object
21712              * @param {String} id The id of the dropped element
21713              * @method afterInvalidDrop
21714              */
21715             this.afterValidDrop(target, e, id);
21716         }
21717     },
21718
21719     // private
21720     getRepairXY : function(e, data){
21721         return this.el.getXY();  
21722     },
21723
21724     // private
21725     onInvalidDrop : function(target, e, id){
21726         this.beforeInvalidDrop(target, e, id);
21727         if(this.cachedTarget){
21728             if(this.cachedTarget.isNotifyTarget){
21729                 this.cachedTarget.notifyOut(this, e, this.dragData);
21730             }
21731             this.cacheTarget = null;
21732         }
21733         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21734
21735         if(this.afterInvalidDrop){
21736             /**
21737              * An empty function by default, but provided so that you can perform a custom action
21738              * after an invalid drop has occurred by providing an implementation.
21739              * @param {Event} e The event object
21740              * @param {String} id The id of the dropped element
21741              * @method afterInvalidDrop
21742              */
21743             this.afterInvalidDrop(e, id);
21744         }
21745     },
21746
21747     // private
21748     afterRepair : function(){
21749         if(Roo.enableFx){
21750             this.el.highlight(this.hlColor || "c3daf9");
21751         }
21752         this.dragging = false;
21753     },
21754
21755     /**
21756      * An empty function by default, but provided so that you can perform a custom action after an invalid
21757      * drop has occurred.
21758      * @param {Roo.dd.DragDrop} target The drop target
21759      * @param {Event} e The event object
21760      * @param {String} id The id of the dragged element
21761      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21762      */
21763     beforeInvalidDrop : function(target, e, id){
21764         return true;
21765     },
21766
21767     // private
21768     handleMouseDown : function(e){
21769         if(this.dragging) {
21770             return;
21771         }
21772         var data = this.getDragData(e);
21773         if(data && this.onBeforeDrag(data, e) !== false){
21774             this.dragData = data;
21775             this.proxy.stop();
21776             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21777         } 
21778     },
21779
21780     /**
21781      * An empty function by default, but provided so that you can perform a custom action before the initial
21782      * drag event begins and optionally cancel it.
21783      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21784      * @param {Event} e The event object
21785      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21786      */
21787     onBeforeDrag : function(data, e){
21788         return true;
21789     },
21790
21791     /**
21792      * An empty function by default, but provided so that you can perform a custom action once the initial
21793      * drag event has begun.  The drag cannot be canceled from this function.
21794      * @param {Number} x The x position of the click on the dragged object
21795      * @param {Number} y The y position of the click on the dragged object
21796      */
21797     onStartDrag : Roo.emptyFn,
21798
21799     // private - YUI override
21800     startDrag : function(x, y){
21801         this.proxy.reset();
21802         this.dragging = true;
21803         this.proxy.update("");
21804         this.onInitDrag(x, y);
21805         this.proxy.show();
21806     },
21807
21808     // private
21809     onInitDrag : function(x, y){
21810         var clone = this.el.dom.cloneNode(true);
21811         clone.id = Roo.id(); // prevent duplicate ids
21812         this.proxy.update(clone);
21813         this.onStartDrag(x, y);
21814         return true;
21815     },
21816
21817     /**
21818      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21819      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21820      */
21821     getProxy : function(){
21822         return this.proxy;  
21823     },
21824
21825     /**
21826      * Hides the drag source's {@link Roo.dd.StatusProxy}
21827      */
21828     hideProxy : function(){
21829         this.proxy.hide();  
21830         this.proxy.reset(true);
21831         this.dragging = false;
21832     },
21833
21834     // private
21835     triggerCacheRefresh : function(){
21836         Roo.dd.DDM.refreshCache(this.groups);
21837     },
21838
21839     // private - override to prevent hiding
21840     b4EndDrag: function(e) {
21841     },
21842
21843     // private - override to prevent moving
21844     endDrag : function(e){
21845         this.onEndDrag(this.dragData, e);
21846     },
21847
21848     // private
21849     onEndDrag : function(data, e){
21850     },
21851     
21852     // private - pin to cursor
21853     autoOffset : function(x, y) {
21854         this.setDelta(-12, -20);
21855     }    
21856 });/*
21857  * Based on:
21858  * Ext JS Library 1.1.1
21859  * Copyright(c) 2006-2007, Ext JS, LLC.
21860  *
21861  * Originally Released Under LGPL - original licence link has changed is not relivant.
21862  *
21863  * Fork - LGPL
21864  * <script type="text/javascript">
21865  */
21866
21867
21868 /**
21869  * @class Roo.dd.DropTarget
21870  * @extends Roo.dd.DDTarget
21871  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21872  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21873  * @constructor
21874  * @param {String/HTMLElement/Element} el The container element
21875  * @param {Object} config
21876  */
21877 Roo.dd.DropTarget = function(el, config){
21878     this.el = Roo.get(el);
21879     
21880     var listeners = false; ;
21881     if (config && config.listeners) {
21882         listeners= config.listeners;
21883         delete config.listeners;
21884     }
21885     Roo.apply(this, config);
21886     
21887     if(this.containerScroll){
21888         Roo.dd.ScrollManager.register(this.el);
21889     }
21890     this.addEvents( {
21891          /**
21892          * @scope Roo.dd.DropTarget
21893          */
21894          
21895          /**
21896          * @event enter
21897          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21898          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21899          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21900          * 
21901          * IMPORTANT : it should set this.overClass and this.dropAllowed
21902          * 
21903          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21904          * @param {Event} e The event
21905          * @param {Object} data An object containing arbitrary data supplied by the drag source
21906          */
21907         "enter" : true,
21908         
21909          /**
21910          * @event over
21911          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21912          * This method will be called on every mouse movement while the drag source is over the drop target.
21913          * This default implementation simply returns the dropAllowed config value.
21914          * 
21915          * IMPORTANT : it should set this.dropAllowed
21916          * 
21917          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21918          * @param {Event} e The event
21919          * @param {Object} data An object containing arbitrary data supplied by the drag source
21920          
21921          */
21922         "over" : true,
21923         /**
21924          * @event out
21925          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21926          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21927          * overClass (if any) from the drop element.
21928          * 
21929          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21930          * @param {Event} e The event
21931          * @param {Object} data An object containing arbitrary data supplied by the drag source
21932          */
21933          "out" : true,
21934          
21935         /**
21936          * @event drop
21937          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21938          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21939          * implementation that does something to process the drop event and returns true so that the drag source's
21940          * repair action does not run.
21941          * 
21942          * IMPORTANT : it should set this.success
21943          * 
21944          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21945          * @param {Event} e The event
21946          * @param {Object} data An object containing arbitrary data supplied by the drag source
21947         */
21948          "drop" : true
21949     });
21950             
21951      
21952     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21953         this.el.dom, 
21954         this.ddGroup || this.group,
21955         {
21956             isTarget: true,
21957             listeners : listeners || {} 
21958            
21959         
21960         }
21961     );
21962
21963 };
21964
21965 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21966     /**
21967      * @cfg {String} overClass
21968      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21969      */
21970      /**
21971      * @cfg {String} ddGroup
21972      * The drag drop group to handle drop events for
21973      */
21974      
21975     /**
21976      * @cfg {String} dropAllowed
21977      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21978      */
21979     dropAllowed : "x-dd-drop-ok",
21980     /**
21981      * @cfg {String} dropNotAllowed
21982      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21983      */
21984     dropNotAllowed : "x-dd-drop-nodrop",
21985     /**
21986      * @cfg {boolean} success
21987      * set this after drop listener.. 
21988      */
21989     success : false,
21990     /**
21991      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21992      * if the drop point is valid for over/enter..
21993      */
21994     valid : false,
21995     // private
21996     isTarget : true,
21997
21998     // private
21999     isNotifyTarget : true,
22000     
22001     /**
22002      * @hide
22003      */
22004     notifyEnter : function(dd, e, data)
22005     {
22006         this.valid = true;
22007         this.fireEvent('enter', dd, e, data);
22008         if(this.overClass){
22009             this.el.addClass(this.overClass);
22010         }
22011         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22012             this.valid ? this.dropAllowed : this.dropNotAllowed
22013         );
22014     },
22015
22016     /**
22017      * @hide
22018      */
22019     notifyOver : function(dd, e, data)
22020     {
22021         this.valid = true;
22022         this.fireEvent('over', dd, e, data);
22023         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22024             this.valid ? this.dropAllowed : this.dropNotAllowed
22025         );
22026     },
22027
22028     /**
22029      * @hide
22030      */
22031     notifyOut : function(dd, e, data)
22032     {
22033         this.fireEvent('out', dd, e, data);
22034         if(this.overClass){
22035             this.el.removeClass(this.overClass);
22036         }
22037     },
22038
22039     /**
22040      * @hide
22041      */
22042     notifyDrop : function(dd, e, data)
22043     {
22044         this.success = false;
22045         this.fireEvent('drop', dd, e, data);
22046         return this.success;
22047     }
22048 });/*
22049  * Based on:
22050  * Ext JS Library 1.1.1
22051  * Copyright(c) 2006-2007, Ext JS, LLC.
22052  *
22053  * Originally Released Under LGPL - original licence link has changed is not relivant.
22054  *
22055  * Fork - LGPL
22056  * <script type="text/javascript">
22057  */
22058
22059
22060 /**
22061  * @class Roo.dd.DragZone
22062  * @extends Roo.dd.DragSource
22063  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22064  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22065  * @constructor
22066  * @param {String/HTMLElement/Element} el The container element
22067  * @param {Object} config
22068  */
22069 Roo.dd.DragZone = function(el, config){
22070     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22071     if(this.containerScroll){
22072         Roo.dd.ScrollManager.register(this.el);
22073     }
22074 };
22075
22076 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22077     /**
22078      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22079      * for auto scrolling during drag operations.
22080      */
22081     /**
22082      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22083      * method after a failed drop (defaults to "c3daf9" - light blue)
22084      */
22085
22086     /**
22087      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22088      * for a valid target to drag based on the mouse down. Override this method
22089      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22090      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22091      * @param {EventObject} e The mouse down event
22092      * @return {Object} The dragData
22093      */
22094     getDragData : function(e){
22095         return Roo.dd.Registry.getHandleFromEvent(e);
22096     },
22097     
22098     /**
22099      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22100      * this.dragData.ddel
22101      * @param {Number} x The x position of the click on the dragged object
22102      * @param {Number} y The y position of the click on the dragged object
22103      * @return {Boolean} true to continue the drag, false to cancel
22104      */
22105     onInitDrag : function(x, y){
22106         this.proxy.update(this.dragData.ddel.cloneNode(true));
22107         this.onStartDrag(x, y);
22108         return true;
22109     },
22110     
22111     /**
22112      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22113      */
22114     afterRepair : function(){
22115         if(Roo.enableFx){
22116             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22117         }
22118         this.dragging = false;
22119     },
22120
22121     /**
22122      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22123      * the XY of this.dragData.ddel
22124      * @param {EventObject} e The mouse up event
22125      * @return {Array} The xy location (e.g. [100, 200])
22126      */
22127     getRepairXY : function(e){
22128         return Roo.Element.fly(this.dragData.ddel).getXY();  
22129     }
22130 });/*
22131  * Based on:
22132  * Ext JS Library 1.1.1
22133  * Copyright(c) 2006-2007, Ext JS, LLC.
22134  *
22135  * Originally Released Under LGPL - original licence link has changed is not relivant.
22136  *
22137  * Fork - LGPL
22138  * <script type="text/javascript">
22139  */
22140 /**
22141  * @class Roo.dd.DropZone
22142  * @extends Roo.dd.DropTarget
22143  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22144  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22145  * @constructor
22146  * @param {String/HTMLElement/Element} el The container element
22147  * @param {Object} config
22148  */
22149 Roo.dd.DropZone = function(el, config){
22150     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22151 };
22152
22153 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22154     /**
22155      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22156      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22157      * provide your own custom lookup.
22158      * @param {Event} e The event
22159      * @return {Object} data The custom data
22160      */
22161     getTargetFromEvent : function(e){
22162         return Roo.dd.Registry.getTargetFromEvent(e);
22163     },
22164
22165     /**
22166      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22167      * that it has registered.  This method has no default implementation and should be overridden to provide
22168      * node-specific processing if necessary.
22169      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22170      * {@link #getTargetFromEvent} for this node)
22171      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22172      * @param {Event} e The event
22173      * @param {Object} data An object containing arbitrary data supplied by the drag source
22174      */
22175     onNodeEnter : function(n, dd, e, data){
22176         
22177     },
22178
22179     /**
22180      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22181      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22182      * overridden to provide the proper feedback.
22183      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22184      * {@link #getTargetFromEvent} for this node)
22185      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22186      * @param {Event} e The event
22187      * @param {Object} data An object containing arbitrary data supplied by the drag source
22188      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22189      * underlying {@link Roo.dd.StatusProxy} can be updated
22190      */
22191     onNodeOver : function(n, dd, e, data){
22192         return this.dropAllowed;
22193     },
22194
22195     /**
22196      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22197      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22198      * node-specific processing if necessary.
22199      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22200      * {@link #getTargetFromEvent} for this node)
22201      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22202      * @param {Event} e The event
22203      * @param {Object} data An object containing arbitrary data supplied by the drag source
22204      */
22205     onNodeOut : function(n, dd, e, data){
22206         
22207     },
22208
22209     /**
22210      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22211      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22212      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22213      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22214      * {@link #getTargetFromEvent} for this node)
22215      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22216      * @param {Event} e The event
22217      * @param {Object} data An object containing arbitrary data supplied by the drag source
22218      * @return {Boolean} True if the drop was valid, else false
22219      */
22220     onNodeDrop : function(n, dd, e, data){
22221         return false;
22222     },
22223
22224     /**
22225      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22226      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22227      * it should be overridden to provide the proper feedback if necessary.
22228      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22229      * @param {Event} e The event
22230      * @param {Object} data An object containing arbitrary data supplied by the drag source
22231      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22232      * underlying {@link Roo.dd.StatusProxy} can be updated
22233      */
22234     onContainerOver : function(dd, e, data){
22235         return this.dropNotAllowed;
22236     },
22237
22238     /**
22239      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22240      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22241      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22242      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22243      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22244      * @param {Event} e The event
22245      * @param {Object} data An object containing arbitrary data supplied by the drag source
22246      * @return {Boolean} True if the drop was valid, else false
22247      */
22248     onContainerDrop : function(dd, e, data){
22249         return false;
22250     },
22251
22252     /**
22253      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22254      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22255      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22256      * you should override this method and provide a custom implementation.
22257      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22258      * @param {Event} e The event
22259      * @param {Object} data An object containing arbitrary data supplied by the drag source
22260      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22261      * underlying {@link Roo.dd.StatusProxy} can be updated
22262      */
22263     notifyEnter : function(dd, e, data){
22264         return this.dropNotAllowed;
22265     },
22266
22267     /**
22268      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22269      * This method will be called on every mouse movement while the drag source is over the drop zone.
22270      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22271      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22272      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22273      * registered node, it will call {@link #onContainerOver}.
22274      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22275      * @param {Event} e The event
22276      * @param {Object} data An object containing arbitrary data supplied by the drag source
22277      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22278      * underlying {@link Roo.dd.StatusProxy} can be updated
22279      */
22280     notifyOver : function(dd, e, data){
22281         var n = this.getTargetFromEvent(e);
22282         if(!n){ // not over valid drop target
22283             if(this.lastOverNode){
22284                 this.onNodeOut(this.lastOverNode, dd, e, data);
22285                 this.lastOverNode = null;
22286             }
22287             return this.onContainerOver(dd, e, data);
22288         }
22289         if(this.lastOverNode != n){
22290             if(this.lastOverNode){
22291                 this.onNodeOut(this.lastOverNode, dd, e, data);
22292             }
22293             this.onNodeEnter(n, dd, e, data);
22294             this.lastOverNode = n;
22295         }
22296         return this.onNodeOver(n, dd, e, data);
22297     },
22298
22299     /**
22300      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22301      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22302      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22303      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22304      * @param {Event} e The event
22305      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22306      */
22307     notifyOut : function(dd, e, data){
22308         if(this.lastOverNode){
22309             this.onNodeOut(this.lastOverNode, dd, e, data);
22310             this.lastOverNode = null;
22311         }
22312     },
22313
22314     /**
22315      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22316      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22317      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22318      * otherwise it will call {@link #onContainerDrop}.
22319      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22320      * @param {Event} e The event
22321      * @param {Object} data An object containing arbitrary data supplied by the drag source
22322      * @return {Boolean} True if the drop was valid, else false
22323      */
22324     notifyDrop : function(dd, e, data){
22325         if(this.lastOverNode){
22326             this.onNodeOut(this.lastOverNode, dd, e, data);
22327             this.lastOverNode = null;
22328         }
22329         var n = this.getTargetFromEvent(e);
22330         return n ?
22331             this.onNodeDrop(n, dd, e, data) :
22332             this.onContainerDrop(dd, e, data);
22333     },
22334
22335     // private
22336     triggerCacheRefresh : function(){
22337         Roo.dd.DDM.refreshCache(this.groups);
22338     }  
22339 });