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.isIE11 ? "roo-ie11"
6632             : Roo.isGecko ? "roo-gecko"
6633             : Roo.isOpera ? "roo-opera"
6634             : Roo.isSafari ? "roo-safari" : ""];
6635
6636     if(Roo.isMac){
6637         cls.push("roo-mac");
6638     }
6639     if(Roo.isLinux){
6640         cls.push("roo-linux");
6641     }
6642     if(Roo.isIOS){
6643         cls.push("roo-ios");
6644     }
6645     if(Roo.isTouch){
6646         cls.push("roo-touch");
6647     }
6648     if(Roo.isBorderBox){
6649         cls.push('roo-border-box');
6650     }
6651     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6652         var p = bd.dom.parentNode;
6653         if(p){
6654             p.className += ' roo-strict';
6655         }
6656     }
6657     bd.addClass(cls.join(' '));
6658 });
6659
6660 /**
6661  * @class Roo.EventObject
6662  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6663  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6664  * Example:
6665  * <pre><code>
6666  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6667     e.preventDefault();
6668     var target = e.getTarget();
6669     ...
6670  }
6671  var myDiv = Roo.get("myDiv");
6672  myDiv.on("click", handleClick);
6673  //or
6674  Roo.EventManager.on("myDiv", 'click', handleClick);
6675  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6676  </code></pre>
6677  * @singleton
6678  */
6679 Roo.EventObject = function(){
6680     
6681     var E = Roo.lib.Event;
6682     
6683     // safari keypress events for special keys return bad keycodes
6684     var safariKeys = {
6685         63234 : 37, // left
6686         63235 : 39, // right
6687         63232 : 38, // up
6688         63233 : 40, // down
6689         63276 : 33, // page up
6690         63277 : 34, // page down
6691         63272 : 46, // delete
6692         63273 : 36, // home
6693         63275 : 35  // end
6694     };
6695
6696     // normalize button clicks
6697     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6698                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6699
6700     Roo.EventObjectImpl = function(e){
6701         if(e){
6702             this.setEvent(e.browserEvent || e);
6703         }
6704     };
6705     Roo.EventObjectImpl.prototype = {
6706         /**
6707          * Used to fix doc tools.
6708          * @scope Roo.EventObject.prototype
6709          */
6710             
6711
6712         
6713         
6714         /** The normal browser event */
6715         browserEvent : null,
6716         /** The button pressed in a mouse event */
6717         button : -1,
6718         /** True if the shift key was down during the event */
6719         shiftKey : false,
6720         /** True if the control key was down during the event */
6721         ctrlKey : false,
6722         /** True if the alt key was down during the event */
6723         altKey : false,
6724
6725         /** Key constant 
6726         * @type Number */
6727         BACKSPACE : 8,
6728         /** Key constant 
6729         * @type Number */
6730         TAB : 9,
6731         /** Key constant 
6732         * @type Number */
6733         RETURN : 13,
6734         /** Key constant 
6735         * @type Number */
6736         ENTER : 13,
6737         /** Key constant 
6738         * @type Number */
6739         SHIFT : 16,
6740         /** Key constant 
6741         * @type Number */
6742         CONTROL : 17,
6743         /** Key constant 
6744         * @type Number */
6745         ESC : 27,
6746         /** Key constant 
6747         * @type Number */
6748         SPACE : 32,
6749         /** Key constant 
6750         * @type Number */
6751         PAGEUP : 33,
6752         /** Key constant 
6753         * @type Number */
6754         PAGEDOWN : 34,
6755         /** Key constant 
6756         * @type Number */
6757         END : 35,
6758         /** Key constant 
6759         * @type Number */
6760         HOME : 36,
6761         /** Key constant 
6762         * @type Number */
6763         LEFT : 37,
6764         /** Key constant 
6765         * @type Number */
6766         UP : 38,
6767         /** Key constant 
6768         * @type Number */
6769         RIGHT : 39,
6770         /** Key constant 
6771         * @type Number */
6772         DOWN : 40,
6773         /** Key constant 
6774         * @type Number */
6775         DELETE : 46,
6776         /** Key constant 
6777         * @type Number */
6778         F5 : 116,
6779
6780            /** @private */
6781         setEvent : function(e){
6782             if(e == this || (e && e.browserEvent)){ // already wrapped
6783                 return e;
6784             }
6785             this.browserEvent = e;
6786             if(e){
6787                 // normalize buttons
6788                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6789                 if(e.type == 'click' && this.button == -1){
6790                     this.button = 0;
6791                 }
6792                 this.type = e.type;
6793                 this.shiftKey = e.shiftKey;
6794                 // mac metaKey behaves like ctrlKey
6795                 this.ctrlKey = e.ctrlKey || e.metaKey;
6796                 this.altKey = e.altKey;
6797                 // in getKey these will be normalized for the mac
6798                 this.keyCode = e.keyCode;
6799                 // keyup warnings on firefox.
6800                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6801                 // cache the target for the delayed and or buffered events
6802                 this.target = E.getTarget(e);
6803                 // same for XY
6804                 this.xy = E.getXY(e);
6805             }else{
6806                 this.button = -1;
6807                 this.shiftKey = false;
6808                 this.ctrlKey = false;
6809                 this.altKey = false;
6810                 this.keyCode = 0;
6811                 this.charCode =0;
6812                 this.target = null;
6813                 this.xy = [0, 0];
6814             }
6815             return this;
6816         },
6817
6818         /**
6819          * Stop the event (preventDefault and stopPropagation)
6820          */
6821         stopEvent : function(){
6822             if(this.browserEvent){
6823                 if(this.browserEvent.type == 'mousedown'){
6824                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6825                 }
6826                 E.stopEvent(this.browserEvent);
6827             }
6828         },
6829
6830         /**
6831          * Prevents the browsers default handling of the event.
6832          */
6833         preventDefault : function(){
6834             if(this.browserEvent){
6835                 E.preventDefault(this.browserEvent);
6836             }
6837         },
6838
6839         /** @private */
6840         isNavKeyPress : function(){
6841             var k = this.keyCode;
6842             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6843             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6844         },
6845
6846         isSpecialKey : function(){
6847             var k = this.keyCode;
6848             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6849             (k == 16) || (k == 17) ||
6850             (k >= 18 && k <= 20) ||
6851             (k >= 33 && k <= 35) ||
6852             (k >= 36 && k <= 39) ||
6853             (k >= 44 && k <= 45);
6854         },
6855         /**
6856          * Cancels bubbling of the event.
6857          */
6858         stopPropagation : function(){
6859             if(this.browserEvent){
6860                 if(this.type == 'mousedown'){
6861                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6862                 }
6863                 E.stopPropagation(this.browserEvent);
6864             }
6865         },
6866
6867         /**
6868          * Gets the key code for the event.
6869          * @return {Number}
6870          */
6871         getCharCode : function(){
6872             return this.charCode || this.keyCode;
6873         },
6874
6875         /**
6876          * Returns a normalized keyCode for the event.
6877          * @return {Number} The key code
6878          */
6879         getKey : function(){
6880             var k = this.keyCode || this.charCode;
6881             return Roo.isSafari ? (safariKeys[k] || k) : k;
6882         },
6883
6884         /**
6885          * Gets the x coordinate of the event.
6886          * @return {Number}
6887          */
6888         getPageX : function(){
6889             return this.xy[0];
6890         },
6891
6892         /**
6893          * Gets the y coordinate of the event.
6894          * @return {Number}
6895          */
6896         getPageY : function(){
6897             return this.xy[1];
6898         },
6899
6900         /**
6901          * Gets the time of the event.
6902          * @return {Number}
6903          */
6904         getTime : function(){
6905             if(this.browserEvent){
6906                 return E.getTime(this.browserEvent);
6907             }
6908             return null;
6909         },
6910
6911         /**
6912          * Gets the page coordinates of the event.
6913          * @return {Array} The xy values like [x, y]
6914          */
6915         getXY : function(){
6916             return this.xy;
6917         },
6918
6919         /**
6920          * Gets the target for the event.
6921          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6922          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6923                 search as a number or element (defaults to 10 || document.body)
6924          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6925          * @return {HTMLelement}
6926          */
6927         getTarget : function(selector, maxDepth, returnEl){
6928             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6929         },
6930         /**
6931          * Gets the related target.
6932          * @return {HTMLElement}
6933          */
6934         getRelatedTarget : function(){
6935             if(this.browserEvent){
6936                 return E.getRelatedTarget(this.browserEvent);
6937             }
6938             return null;
6939         },
6940
6941         /**
6942          * Normalizes mouse wheel delta across browsers
6943          * @return {Number} The delta
6944          */
6945         getWheelDelta : function(){
6946             var e = this.browserEvent;
6947             var delta = 0;
6948             if(e.wheelDelta){ /* IE/Opera. */
6949                 delta = e.wheelDelta/120;
6950             }else if(e.detail){ /* Mozilla case. */
6951                 delta = -e.detail/3;
6952             }
6953             return delta;
6954         },
6955
6956         /**
6957          * Returns true if the control, meta, shift or alt key was pressed during this event.
6958          * @return {Boolean}
6959          */
6960         hasModifier : function(){
6961             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6962         },
6963
6964         /**
6965          * Returns true if the target of this event equals el or is a child of el
6966          * @param {String/HTMLElement/Element} el
6967          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6968          * @return {Boolean}
6969          */
6970         within : function(el, related){
6971             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6972             return t && Roo.fly(el).contains(t);
6973         },
6974
6975         getPoint : function(){
6976             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6977         }
6978     };
6979
6980     return new Roo.EventObjectImpl();
6981 }();
6982             
6983     /*
6984  * Based on:
6985  * Ext JS Library 1.1.1
6986  * Copyright(c) 2006-2007, Ext JS, LLC.
6987  *
6988  * Originally Released Under LGPL - original licence link has changed is not relivant.
6989  *
6990  * Fork - LGPL
6991  * <script type="text/javascript">
6992  */
6993
6994  
6995 // was in Composite Element!??!?!
6996  
6997 (function(){
6998     var D = Roo.lib.Dom;
6999     var E = Roo.lib.Event;
7000     var A = Roo.lib.Anim;
7001
7002     // local style camelizing for speed
7003     var propCache = {};
7004     var camelRe = /(-[a-z])/gi;
7005     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7006     var view = document.defaultView;
7007
7008 /**
7009  * @class Roo.Element
7010  * Represents an Element in the DOM.<br><br>
7011  * Usage:<br>
7012 <pre><code>
7013 var el = Roo.get("my-div");
7014
7015 // or with getEl
7016 var el = getEl("my-div");
7017
7018 // or with a DOM element
7019 var el = Roo.get(myDivElement);
7020 </code></pre>
7021  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7022  * each call instead of constructing a new one.<br><br>
7023  * <b>Animations</b><br />
7024  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7025  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7026 <pre>
7027 Option    Default   Description
7028 --------- --------  ---------------------------------------------
7029 duration  .35       The duration of the animation in seconds
7030 easing    easeOut   The YUI easing method
7031 callback  none      A function to execute when the anim completes
7032 scope     this      The scope (this) of the callback function
7033 </pre>
7034 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7035 * manipulate the animation. Here's an example:
7036 <pre><code>
7037 var el = Roo.get("my-div");
7038
7039 // no animation
7040 el.setWidth(100);
7041
7042 // default animation
7043 el.setWidth(100, true);
7044
7045 // animation with some options set
7046 el.setWidth(100, {
7047     duration: 1,
7048     callback: this.foo,
7049     scope: this
7050 });
7051
7052 // using the "anim" property to get the Anim object
7053 var opt = {
7054     duration: 1,
7055     callback: this.foo,
7056     scope: this
7057 };
7058 el.setWidth(100, opt);
7059 ...
7060 if(opt.anim.isAnimated()){
7061     opt.anim.stop();
7062 }
7063 </code></pre>
7064 * <b> Composite (Collections of) Elements</b><br />
7065  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7066  * @constructor Create a new Element directly.
7067  * @param {String/HTMLElement} element
7068  * @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).
7069  */
7070     Roo.Element = function(element, forceNew){
7071         var dom = typeof element == "string" ?
7072                 document.getElementById(element) : element;
7073         if(!dom){ // invalid id/element
7074             return null;
7075         }
7076         var id = dom.id;
7077         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7078             return Roo.Element.cache[id];
7079         }
7080
7081         /**
7082          * The DOM element
7083          * @type HTMLElement
7084          */
7085         this.dom = dom;
7086
7087         /**
7088          * The DOM element ID
7089          * @type String
7090          */
7091         this.id = id || Roo.id(dom);
7092     };
7093
7094     var El = Roo.Element;
7095
7096     El.prototype = {
7097         /**
7098          * The element's default display mode  (defaults to "")
7099          * @type String
7100          */
7101         originalDisplay : "",
7102
7103         visibilityMode : 1,
7104         /**
7105          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7106          * @type String
7107          */
7108         defaultUnit : "px",
7109         
7110         /**
7111          * Sets the element's visibility mode. When setVisible() is called it
7112          * will use this to determine whether to set the visibility or the display property.
7113          * @param visMode Element.VISIBILITY or Element.DISPLAY
7114          * @return {Roo.Element} this
7115          */
7116         setVisibilityMode : function(visMode){
7117             this.visibilityMode = visMode;
7118             return this;
7119         },
7120         /**
7121          * Convenience method for setVisibilityMode(Element.DISPLAY)
7122          * @param {String} display (optional) What to set display to when visible
7123          * @return {Roo.Element} this
7124          */
7125         enableDisplayMode : function(display){
7126             this.setVisibilityMode(El.DISPLAY);
7127             if(typeof display != "undefined") { this.originalDisplay = display; }
7128             return this;
7129         },
7130
7131         /**
7132          * 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)
7133          * @param {String} selector The simple selector to test
7134          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7135                 search as a number or element (defaults to 10 || document.body)
7136          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7137          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7138          */
7139         findParent : function(simpleSelector, maxDepth, returnEl){
7140             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7141             maxDepth = maxDepth || 50;
7142             if(typeof maxDepth != "number"){
7143                 stopEl = Roo.getDom(maxDepth);
7144                 maxDepth = 10;
7145             }
7146             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7147                 if(dq.is(p, simpleSelector)){
7148                     return returnEl ? Roo.get(p) : p;
7149                 }
7150                 depth++;
7151                 p = p.parentNode;
7152             }
7153             return null;
7154         },
7155
7156
7157         /**
7158          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7159          * @param {String} selector The simple selector to test
7160          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7161                 search as a number or element (defaults to 10 || document.body)
7162          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7163          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7164          */
7165         findParentNode : function(simpleSelector, maxDepth, returnEl){
7166             var p = Roo.fly(this.dom.parentNode, '_internal');
7167             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7168         },
7169         
7170         /**
7171          * Looks at  the scrollable parent element
7172          */
7173         findScrollableParent : function()
7174         {
7175             var overflowRegex = /(auto|scroll)/;
7176             
7177             if(this.getStyle('position') === 'fixed'){
7178                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7179             }
7180             
7181             var excludeStaticParent = this.getStyle('position') === "absolute";
7182             
7183             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7184                 
7185                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7186                     continue;
7187                 }
7188                 
7189                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7190                     return parent;
7191                 }
7192                 
7193                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7194                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7195                 }
7196             }
7197             
7198             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7199         },
7200
7201         /**
7202          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7203          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7204          * @param {String} selector The simple selector to test
7205          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7206                 search as a number or element (defaults to 10 || document.body)
7207          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7208          */
7209         up : function(simpleSelector, maxDepth){
7210             return this.findParentNode(simpleSelector, maxDepth, true);
7211         },
7212
7213
7214
7215         /**
7216          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7217          * @param {String} selector The simple selector to test
7218          * @return {Boolean} True if this element matches the selector, else false
7219          */
7220         is : function(simpleSelector){
7221             return Roo.DomQuery.is(this.dom, simpleSelector);
7222         },
7223
7224         /**
7225          * Perform animation on this element.
7226          * @param {Object} args The YUI animation control args
7227          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7228          * @param {Function} onComplete (optional) Function to call when animation completes
7229          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7230          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7231          * @return {Roo.Element} this
7232          */
7233         animate : function(args, duration, onComplete, easing, animType){
7234             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7235             return this;
7236         },
7237
7238         /*
7239          * @private Internal animation call
7240          */
7241         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7242             animType = animType || 'run';
7243             opt = opt || {};
7244             var anim = Roo.lib.Anim[animType](
7245                 this.dom, args,
7246                 (opt.duration || defaultDur) || .35,
7247                 (opt.easing || defaultEase) || 'easeOut',
7248                 function(){
7249                     Roo.callback(cb, this);
7250                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7251                 },
7252                 this
7253             );
7254             opt.anim = anim;
7255             return anim;
7256         },
7257
7258         // private legacy anim prep
7259         preanim : function(a, i){
7260             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7261         },
7262
7263         /**
7264          * Removes worthless text nodes
7265          * @param {Boolean} forceReclean (optional) By default the element
7266          * keeps track if it has been cleaned already so
7267          * you can call this over and over. However, if you update the element and
7268          * need to force a reclean, you can pass true.
7269          */
7270         clean : function(forceReclean){
7271             if(this.isCleaned && forceReclean !== true){
7272                 return this;
7273             }
7274             var ns = /\S/;
7275             var d = this.dom, n = d.firstChild, ni = -1;
7276             while(n){
7277                 var nx = n.nextSibling;
7278                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7279                     d.removeChild(n);
7280                 }else{
7281                     n.nodeIndex = ++ni;
7282                 }
7283                 n = nx;
7284             }
7285             this.isCleaned = true;
7286             return this;
7287         },
7288
7289         // private
7290         calcOffsetsTo : function(el){
7291             el = Roo.get(el);
7292             var d = el.dom;
7293             var restorePos = false;
7294             if(el.getStyle('position') == 'static'){
7295                 el.position('relative');
7296                 restorePos = true;
7297             }
7298             var x = 0, y =0;
7299             var op = this.dom;
7300             while(op && op != d && op.tagName != 'HTML'){
7301                 x+= op.offsetLeft;
7302                 y+= op.offsetTop;
7303                 op = op.offsetParent;
7304             }
7305             if(restorePos){
7306                 el.position('static');
7307             }
7308             return [x, y];
7309         },
7310
7311         /**
7312          * Scrolls this element into view within the passed container.
7313          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7314          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7315          * @return {Roo.Element} this
7316          */
7317         scrollIntoView : function(container, hscroll){
7318             var c = Roo.getDom(container) || document.body;
7319             var el = this.dom;
7320
7321             var o = this.calcOffsetsTo(c),
7322                 l = o[0],
7323                 t = o[1],
7324                 b = t+el.offsetHeight,
7325                 r = l+el.offsetWidth;
7326
7327             var ch = c.clientHeight;
7328             var ct = parseInt(c.scrollTop, 10);
7329             var cl = parseInt(c.scrollLeft, 10);
7330             var cb = ct + ch;
7331             var cr = cl + c.clientWidth;
7332
7333             if(t < ct){
7334                 c.scrollTop = t;
7335             }else if(b > cb){
7336                 c.scrollTop = b-ch;
7337             }
7338
7339             if(hscroll !== false){
7340                 if(l < cl){
7341                     c.scrollLeft = l;
7342                 }else if(r > cr){
7343                     c.scrollLeft = r-c.clientWidth;
7344                 }
7345             }
7346             return this;
7347         },
7348
7349         // private
7350         scrollChildIntoView : function(child, hscroll){
7351             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7352         },
7353
7354         /**
7355          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7356          * the new height may not be available immediately.
7357          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7358          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7359          * @param {Function} onComplete (optional) Function to call when animation completes
7360          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7361          * @return {Roo.Element} this
7362          */
7363         autoHeight : function(animate, duration, onComplete, easing){
7364             var oldHeight = this.getHeight();
7365             this.clip();
7366             this.setHeight(1); // force clipping
7367             setTimeout(function(){
7368                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7369                 if(!animate){
7370                     this.setHeight(height);
7371                     this.unclip();
7372                     if(typeof onComplete == "function"){
7373                         onComplete();
7374                     }
7375                 }else{
7376                     this.setHeight(oldHeight); // restore original height
7377                     this.setHeight(height, animate, duration, function(){
7378                         this.unclip();
7379                         if(typeof onComplete == "function") { onComplete(); }
7380                     }.createDelegate(this), easing);
7381                 }
7382             }.createDelegate(this), 0);
7383             return this;
7384         },
7385
7386         /**
7387          * Returns true if this element is an ancestor of the passed element
7388          * @param {HTMLElement/String} el The element to check
7389          * @return {Boolean} True if this element is an ancestor of el, else false
7390          */
7391         contains : function(el){
7392             if(!el){return false;}
7393             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7394         },
7395
7396         /**
7397          * Checks whether the element is currently visible using both visibility and display properties.
7398          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7399          * @return {Boolean} True if the element is currently visible, else false
7400          */
7401         isVisible : function(deep) {
7402             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7403             if(deep !== true || !vis){
7404                 return vis;
7405             }
7406             var p = this.dom.parentNode;
7407             while(p && p.tagName.toLowerCase() != "body"){
7408                 if(!Roo.fly(p, '_isVisible').isVisible()){
7409                     return false;
7410                 }
7411                 p = p.parentNode;
7412             }
7413             return true;
7414         },
7415
7416         /**
7417          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7418          * @param {String} selector The CSS selector
7419          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7420          * @return {CompositeElement/CompositeElementLite} The composite element
7421          */
7422         select : function(selector, unique){
7423             return El.select(selector, unique, this.dom);
7424         },
7425
7426         /**
7427          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7428          * @param {String} selector The CSS selector
7429          * @return {Array} An array of the matched nodes
7430          */
7431         query : function(selector, unique){
7432             return Roo.DomQuery.select(selector, this.dom);
7433         },
7434
7435         /**
7436          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7437          * @param {String} selector The CSS selector
7438          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7439          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7440          */
7441         child : function(selector, returnDom){
7442             var n = Roo.DomQuery.selectNode(selector, this.dom);
7443             return returnDom ? n : Roo.get(n);
7444         },
7445
7446         /**
7447          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7448          * @param {String} selector The CSS selector
7449          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7450          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7451          */
7452         down : function(selector, returnDom){
7453             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7454             return returnDom ? n : Roo.get(n);
7455         },
7456
7457         /**
7458          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7459          * @param {String} group The group the DD object is member of
7460          * @param {Object} config The DD config object
7461          * @param {Object} overrides An object containing methods to override/implement on the DD object
7462          * @return {Roo.dd.DD} The DD object
7463          */
7464         initDD : function(group, config, overrides){
7465             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7466             return Roo.apply(dd, overrides);
7467         },
7468
7469         /**
7470          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7471          * @param {String} group The group the DDProxy object is member of
7472          * @param {Object} config The DDProxy config object
7473          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7474          * @return {Roo.dd.DDProxy} The DDProxy object
7475          */
7476         initDDProxy : function(group, config, overrides){
7477             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7478             return Roo.apply(dd, overrides);
7479         },
7480
7481         /**
7482          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7483          * @param {String} group The group the DDTarget object is member of
7484          * @param {Object} config The DDTarget config object
7485          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7486          * @return {Roo.dd.DDTarget} The DDTarget object
7487          */
7488         initDDTarget : function(group, config, overrides){
7489             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7490             return Roo.apply(dd, overrides);
7491         },
7492
7493         /**
7494          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7495          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7496          * @param {Boolean} visible Whether the element is visible
7497          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7498          * @return {Roo.Element} this
7499          */
7500          setVisible : function(visible, animate){
7501             if(!animate || !A){
7502                 if(this.visibilityMode == El.DISPLAY){
7503                     this.setDisplayed(visible);
7504                 }else{
7505                     this.fixDisplay();
7506                     this.dom.style.visibility = visible ? "visible" : "hidden";
7507                 }
7508             }else{
7509                 // closure for composites
7510                 var dom = this.dom;
7511                 var visMode = this.visibilityMode;
7512                 if(visible){
7513                     this.setOpacity(.01);
7514                     this.setVisible(true);
7515                 }
7516                 this.anim({opacity: { to: (visible?1:0) }},
7517                       this.preanim(arguments, 1),
7518                       null, .35, 'easeIn', function(){
7519                          if(!visible){
7520                              if(visMode == El.DISPLAY){
7521                                  dom.style.display = "none";
7522                              }else{
7523                                  dom.style.visibility = "hidden";
7524                              }
7525                              Roo.get(dom).setOpacity(1);
7526                          }
7527                      });
7528             }
7529             return this;
7530         },
7531
7532         /**
7533          * Returns true if display is not "none"
7534          * @return {Boolean}
7535          */
7536         isDisplayed : function() {
7537             return this.getStyle("display") != "none";
7538         },
7539
7540         /**
7541          * Toggles the element's visibility or display, depending on visibility mode.
7542          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7543          * @return {Roo.Element} this
7544          */
7545         toggle : function(animate){
7546             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7547             return this;
7548         },
7549
7550         /**
7551          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7552          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7553          * @return {Roo.Element} this
7554          */
7555         setDisplayed : function(value) {
7556             if(typeof value == "boolean"){
7557                value = value ? this.originalDisplay : "none";
7558             }
7559             this.setStyle("display", value);
7560             return this;
7561         },
7562
7563         /**
7564          * Tries to focus the element. Any exceptions are caught and ignored.
7565          * @return {Roo.Element} this
7566          */
7567         focus : function() {
7568             try{
7569                 this.dom.focus();
7570             }catch(e){}
7571             return this;
7572         },
7573
7574         /**
7575          * Tries to blur the element. Any exceptions are caught and ignored.
7576          * @return {Roo.Element} this
7577          */
7578         blur : function() {
7579             try{
7580                 this.dom.blur();
7581             }catch(e){}
7582             return this;
7583         },
7584
7585         /**
7586          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7587          * @param {String/Array} className The CSS class to add, or an array of classes
7588          * @return {Roo.Element} this
7589          */
7590         addClass : function(className){
7591             if(className instanceof Array){
7592                 for(var i = 0, len = className.length; i < len; i++) {
7593                     this.addClass(className[i]);
7594                 }
7595             }else{
7596                 if(className && !this.hasClass(className)){
7597                     this.dom.className = this.dom.className + " " + className;
7598                 }
7599             }
7600             return this;
7601         },
7602
7603         /**
7604          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7605          * @param {String/Array} className The CSS class to add, or an array of classes
7606          * @return {Roo.Element} this
7607          */
7608         radioClass : function(className){
7609             var siblings = this.dom.parentNode.childNodes;
7610             for(var i = 0; i < siblings.length; i++) {
7611                 var s = siblings[i];
7612                 if(s.nodeType == 1){
7613                     Roo.get(s).removeClass(className);
7614                 }
7615             }
7616             this.addClass(className);
7617             return this;
7618         },
7619
7620         /**
7621          * Removes one or more CSS classes from the element.
7622          * @param {String/Array} className The CSS class to remove, or an array of classes
7623          * @return {Roo.Element} this
7624          */
7625         removeClass : function(className){
7626             if(!className || !this.dom.className){
7627                 return this;
7628             }
7629             if(className instanceof Array){
7630                 for(var i = 0, len = className.length; i < len; i++) {
7631                     this.removeClass(className[i]);
7632                 }
7633             }else{
7634                 if(this.hasClass(className)){
7635                     var re = this.classReCache[className];
7636                     if (!re) {
7637                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7638                        this.classReCache[className] = re;
7639                     }
7640                     this.dom.className =
7641                         this.dom.className.replace(re, " ");
7642                 }
7643             }
7644             return this;
7645         },
7646
7647         // private
7648         classReCache: {},
7649
7650         /**
7651          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7652          * @param {String} className The CSS class to toggle
7653          * @return {Roo.Element} this
7654          */
7655         toggleClass : function(className){
7656             if(this.hasClass(className)){
7657                 this.removeClass(className);
7658             }else{
7659                 this.addClass(className);
7660             }
7661             return this;
7662         },
7663
7664         /**
7665          * Checks if the specified CSS class exists on this element's DOM node.
7666          * @param {String} className The CSS class to check for
7667          * @return {Boolean} True if the class exists, else false
7668          */
7669         hasClass : function(className){
7670             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7671         },
7672
7673         /**
7674          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7675          * @param {String} oldClassName The CSS class to replace
7676          * @param {String} newClassName The replacement CSS class
7677          * @return {Roo.Element} this
7678          */
7679         replaceClass : function(oldClassName, newClassName){
7680             this.removeClass(oldClassName);
7681             this.addClass(newClassName);
7682             return this;
7683         },
7684
7685         /**
7686          * Returns an object with properties matching the styles requested.
7687          * For example, el.getStyles('color', 'font-size', 'width') might return
7688          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7689          * @param {String} style1 A style name
7690          * @param {String} style2 A style name
7691          * @param {String} etc.
7692          * @return {Object} The style object
7693          */
7694         getStyles : function(){
7695             var a = arguments, len = a.length, r = {};
7696             for(var i = 0; i < len; i++){
7697                 r[a[i]] = this.getStyle(a[i]);
7698             }
7699             return r;
7700         },
7701
7702         /**
7703          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7704          * @param {String} property The style property whose value is returned.
7705          * @return {String} The current value of the style property for this element.
7706          */
7707         getStyle : function(){
7708             return view && view.getComputedStyle ?
7709                 function(prop){
7710                     var el = this.dom, v, cs, camel;
7711                     if(prop == 'float'){
7712                         prop = "cssFloat";
7713                     }
7714                     if(el.style && (v = el.style[prop])){
7715                         return v;
7716                     }
7717                     if(cs = view.getComputedStyle(el, "")){
7718                         if(!(camel = propCache[prop])){
7719                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7720                         }
7721                         return cs[camel];
7722                     }
7723                     return null;
7724                 } :
7725                 function(prop){
7726                     var el = this.dom, v, cs, camel;
7727                     if(prop == 'opacity'){
7728                         if(typeof el.style.filter == 'string'){
7729                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7730                             if(m){
7731                                 var fv = parseFloat(m[1]);
7732                                 if(!isNaN(fv)){
7733                                     return fv ? fv / 100 : 0;
7734                                 }
7735                             }
7736                         }
7737                         return 1;
7738                     }else if(prop == 'float'){
7739                         prop = "styleFloat";
7740                     }
7741                     if(!(camel = propCache[prop])){
7742                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7743                     }
7744                     if(v = el.style[camel]){
7745                         return v;
7746                     }
7747                     if(cs = el.currentStyle){
7748                         return cs[camel];
7749                     }
7750                     return null;
7751                 };
7752         }(),
7753
7754         /**
7755          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7756          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7757          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7758          * @return {Roo.Element} this
7759          */
7760         setStyle : function(prop, value){
7761             if(typeof prop == "string"){
7762                 
7763                 if (prop == 'float') {
7764                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7765                     return this;
7766                 }
7767                 
7768                 var camel;
7769                 if(!(camel = propCache[prop])){
7770                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7771                 }
7772                 
7773                 if(camel == 'opacity') {
7774                     this.setOpacity(value);
7775                 }else{
7776                     this.dom.style[camel] = value;
7777                 }
7778             }else{
7779                 for(var style in prop){
7780                     if(typeof prop[style] != "function"){
7781                        this.setStyle(style, prop[style]);
7782                     }
7783                 }
7784             }
7785             return this;
7786         },
7787
7788         /**
7789          * More flexible version of {@link #setStyle} for setting style properties.
7790          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7791          * a function which returns such a specification.
7792          * @return {Roo.Element} this
7793          */
7794         applyStyles : function(style){
7795             Roo.DomHelper.applyStyles(this.dom, style);
7796             return this;
7797         },
7798
7799         /**
7800           * 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).
7801           * @return {Number} The X position of the element
7802           */
7803         getX : function(){
7804             return D.getX(this.dom);
7805         },
7806
7807         /**
7808           * 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).
7809           * @return {Number} The Y position of the element
7810           */
7811         getY : function(){
7812             return D.getY(this.dom);
7813         },
7814
7815         /**
7816           * 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).
7817           * @return {Array} The XY position of the element
7818           */
7819         getXY : function(){
7820             return D.getXY(this.dom);
7821         },
7822
7823         /**
7824          * 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).
7825          * @param {Number} The X position of the element
7826          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7827          * @return {Roo.Element} this
7828          */
7829         setX : function(x, animate){
7830             if(!animate || !A){
7831                 D.setX(this.dom, x);
7832             }else{
7833                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7834             }
7835             return this;
7836         },
7837
7838         /**
7839          * 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).
7840          * @param {Number} The Y position of the element
7841          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7842          * @return {Roo.Element} this
7843          */
7844         setY : function(y, animate){
7845             if(!animate || !A){
7846                 D.setY(this.dom, y);
7847             }else{
7848                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7849             }
7850             return this;
7851         },
7852
7853         /**
7854          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7855          * @param {String} left The left CSS property value
7856          * @return {Roo.Element} this
7857          */
7858         setLeft : function(left){
7859             this.setStyle("left", this.addUnits(left));
7860             return this;
7861         },
7862
7863         /**
7864          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7865          * @param {String} top The top CSS property value
7866          * @return {Roo.Element} this
7867          */
7868         setTop : function(top){
7869             this.setStyle("top", this.addUnits(top));
7870             return this;
7871         },
7872
7873         /**
7874          * Sets the element's CSS right style.
7875          * @param {String} right The right CSS property value
7876          * @return {Roo.Element} this
7877          */
7878         setRight : function(right){
7879             this.setStyle("right", this.addUnits(right));
7880             return this;
7881         },
7882
7883         /**
7884          * Sets the element's CSS bottom style.
7885          * @param {String} bottom The bottom CSS property value
7886          * @return {Roo.Element} this
7887          */
7888         setBottom : function(bottom){
7889             this.setStyle("bottom", this.addUnits(bottom));
7890             return this;
7891         },
7892
7893         /**
7894          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7895          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7896          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7897          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7898          * @return {Roo.Element} this
7899          */
7900         setXY : function(pos, animate){
7901             if(!animate || !A){
7902                 D.setXY(this.dom, pos);
7903             }else{
7904                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7905             }
7906             return this;
7907         },
7908
7909         /**
7910          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7911          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7912          * @param {Number} x X value for new position (coordinates are page-based)
7913          * @param {Number} y Y value for new position (coordinates are page-based)
7914          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7915          * @return {Roo.Element} this
7916          */
7917         setLocation : function(x, y, animate){
7918             this.setXY([x, y], this.preanim(arguments, 2));
7919             return this;
7920         },
7921
7922         /**
7923          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7924          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7925          * @param {Number} x X value for new position (coordinates are page-based)
7926          * @param {Number} y Y value for new position (coordinates are page-based)
7927          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7928          * @return {Roo.Element} this
7929          */
7930         moveTo : function(x, y, animate){
7931             this.setXY([x, y], this.preanim(arguments, 2));
7932             return this;
7933         },
7934
7935         /**
7936          * Returns the region of the given element.
7937          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7938          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7939          */
7940         getRegion : function(){
7941             return D.getRegion(this.dom);
7942         },
7943
7944         /**
7945          * Returns the offset height of the element
7946          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7947          * @return {Number} The element's height
7948          */
7949         getHeight : function(contentHeight){
7950             var h = this.dom.offsetHeight || 0;
7951             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7952         },
7953
7954         /**
7955          * Returns the offset width of the element
7956          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7957          * @return {Number} The element's width
7958          */
7959         getWidth : function(contentWidth){
7960             var w = this.dom.offsetWidth || 0;
7961             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7962         },
7963
7964         /**
7965          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7966          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7967          * if a height has not been set using CSS.
7968          * @return {Number}
7969          */
7970         getComputedHeight : function(){
7971             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7972             if(!h){
7973                 h = parseInt(this.getStyle('height'), 10) || 0;
7974                 if(!this.isBorderBox()){
7975                     h += this.getFrameWidth('tb');
7976                 }
7977             }
7978             return h;
7979         },
7980
7981         /**
7982          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7983          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7984          * if a width has not been set using CSS.
7985          * @return {Number}
7986          */
7987         getComputedWidth : function(){
7988             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7989             if(!w){
7990                 w = parseInt(this.getStyle('width'), 10) || 0;
7991                 if(!this.isBorderBox()){
7992                     w += this.getFrameWidth('lr');
7993                 }
7994             }
7995             return w;
7996         },
7997
7998         /**
7999          * Returns the size of the element.
8000          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8001          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8002          */
8003         getSize : function(contentSize){
8004             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8005         },
8006
8007         /**
8008          * Returns the width and height of the viewport.
8009          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8010          */
8011         getViewSize : function(){
8012             var d = this.dom, doc = document, aw = 0, ah = 0;
8013             if(d == doc || d == doc.body){
8014                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8015             }else{
8016                 return {
8017                     width : d.clientWidth,
8018                     height: d.clientHeight
8019                 };
8020             }
8021         },
8022
8023         /**
8024          * Returns the value of the "value" attribute
8025          * @param {Boolean} asNumber true to parse the value as a number
8026          * @return {String/Number}
8027          */
8028         getValue : function(asNumber){
8029             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8030         },
8031
8032         // private
8033         adjustWidth : function(width){
8034             if(typeof width == "number"){
8035                 if(this.autoBoxAdjust && !this.isBorderBox()){
8036                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8037                 }
8038                 if(width < 0){
8039                     width = 0;
8040                 }
8041             }
8042             return width;
8043         },
8044
8045         // private
8046         adjustHeight : function(height){
8047             if(typeof height == "number"){
8048                if(this.autoBoxAdjust && !this.isBorderBox()){
8049                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8050                }
8051                if(height < 0){
8052                    height = 0;
8053                }
8054             }
8055             return height;
8056         },
8057
8058         /**
8059          * Set the width of the element
8060          * @param {Number} width The new width
8061          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8062          * @return {Roo.Element} this
8063          */
8064         setWidth : function(width, animate){
8065             width = this.adjustWidth(width);
8066             if(!animate || !A){
8067                 this.dom.style.width = this.addUnits(width);
8068             }else{
8069                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8070             }
8071             return this;
8072         },
8073
8074         /**
8075          * Set the height of the element
8076          * @param {Number} height The new height
8077          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8078          * @return {Roo.Element} this
8079          */
8080          setHeight : function(height, animate){
8081             height = this.adjustHeight(height);
8082             if(!animate || !A){
8083                 this.dom.style.height = this.addUnits(height);
8084             }else{
8085                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8086             }
8087             return this;
8088         },
8089
8090         /**
8091          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8092          * @param {Number} width The new width
8093          * @param {Number} height The new height
8094          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8095          * @return {Roo.Element} this
8096          */
8097          setSize : function(width, height, animate){
8098             if(typeof width == "object"){ // in case of object from getSize()
8099                 height = width.height; width = width.width;
8100             }
8101             width = this.adjustWidth(width); height = this.adjustHeight(height);
8102             if(!animate || !A){
8103                 this.dom.style.width = this.addUnits(width);
8104                 this.dom.style.height = this.addUnits(height);
8105             }else{
8106                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8107             }
8108             return this;
8109         },
8110
8111         /**
8112          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8113          * @param {Number} x X value for new position (coordinates are page-based)
8114          * @param {Number} y Y value for new position (coordinates are page-based)
8115          * @param {Number} width The new width
8116          * @param {Number} height The new height
8117          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8118          * @return {Roo.Element} this
8119          */
8120         setBounds : function(x, y, width, height, animate){
8121             if(!animate || !A){
8122                 this.setSize(width, height);
8123                 this.setLocation(x, y);
8124             }else{
8125                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8126                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8127                               this.preanim(arguments, 4), 'motion');
8128             }
8129             return this;
8130         },
8131
8132         /**
8133          * 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.
8134          * @param {Roo.lib.Region} region The region to fill
8135          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8136          * @return {Roo.Element} this
8137          */
8138         setRegion : function(region, animate){
8139             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8140             return this;
8141         },
8142
8143         /**
8144          * Appends an event handler
8145          *
8146          * @param {String}   eventName     The type of event to append
8147          * @param {Function} fn        The method the event invokes
8148          * @param {Object} scope       (optional) The scope (this object) of the fn
8149          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8150          */
8151         addListener : function(eventName, fn, scope, options){
8152             if (this.dom) {
8153                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8154             }
8155         },
8156
8157         /**
8158          * Removes an event handler from this element
8159          * @param {String} eventName the type of event to remove
8160          * @param {Function} fn the method the event invokes
8161          * @return {Roo.Element} this
8162          */
8163         removeListener : function(eventName, fn){
8164             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8165             return this;
8166         },
8167
8168         /**
8169          * Removes all previous added listeners from this element
8170          * @return {Roo.Element} this
8171          */
8172         removeAllListeners : function(){
8173             E.purgeElement(this.dom);
8174             return this;
8175         },
8176
8177         relayEvent : function(eventName, observable){
8178             this.on(eventName, function(e){
8179                 observable.fireEvent(eventName, e);
8180             });
8181         },
8182
8183         /**
8184          * Set the opacity of the element
8185          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8186          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8187          * @return {Roo.Element} this
8188          */
8189          setOpacity : function(opacity, animate){
8190             if(!animate || !A){
8191                 var s = this.dom.style;
8192                 if(Roo.isIE){
8193                     s.zoom = 1;
8194                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8195                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8196                 }else{
8197                     s.opacity = opacity;
8198                 }
8199             }else{
8200                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8201             }
8202             return this;
8203         },
8204
8205         /**
8206          * Gets the left X coordinate
8207          * @param {Boolean} local True to get the local css position instead of page coordinate
8208          * @return {Number}
8209          */
8210         getLeft : function(local){
8211             if(!local){
8212                 return this.getX();
8213             }else{
8214                 return parseInt(this.getStyle("left"), 10) || 0;
8215             }
8216         },
8217
8218         /**
8219          * Gets the right X coordinate of the element (element X position + element width)
8220          * @param {Boolean} local True to get the local css position instead of page coordinate
8221          * @return {Number}
8222          */
8223         getRight : function(local){
8224             if(!local){
8225                 return this.getX() + this.getWidth();
8226             }else{
8227                 return (this.getLeft(true) + this.getWidth()) || 0;
8228             }
8229         },
8230
8231         /**
8232          * Gets the top Y coordinate
8233          * @param {Boolean} local True to get the local css position instead of page coordinate
8234          * @return {Number}
8235          */
8236         getTop : function(local) {
8237             if(!local){
8238                 return this.getY();
8239             }else{
8240                 return parseInt(this.getStyle("top"), 10) || 0;
8241             }
8242         },
8243
8244         /**
8245          * Gets the bottom Y coordinate of the element (element Y position + element height)
8246          * @param {Boolean} local True to get the local css position instead of page coordinate
8247          * @return {Number}
8248          */
8249         getBottom : function(local){
8250             if(!local){
8251                 return this.getY() + this.getHeight();
8252             }else{
8253                 return (this.getTop(true) + this.getHeight()) || 0;
8254             }
8255         },
8256
8257         /**
8258         * Initializes positioning on this element. If a desired position is not passed, it will make the
8259         * the element positioned relative IF it is not already positioned.
8260         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8261         * @param {Number} zIndex (optional) The zIndex to apply
8262         * @param {Number} x (optional) Set the page X position
8263         * @param {Number} y (optional) Set the page Y position
8264         */
8265         position : function(pos, zIndex, x, y){
8266             if(!pos){
8267                if(this.getStyle('position') == 'static'){
8268                    this.setStyle('position', 'relative');
8269                }
8270             }else{
8271                 this.setStyle("position", pos);
8272             }
8273             if(zIndex){
8274                 this.setStyle("z-index", zIndex);
8275             }
8276             if(x !== undefined && y !== undefined){
8277                 this.setXY([x, y]);
8278             }else if(x !== undefined){
8279                 this.setX(x);
8280             }else if(y !== undefined){
8281                 this.setY(y);
8282             }
8283         },
8284
8285         /**
8286         * Clear positioning back to the default when the document was loaded
8287         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8288         * @return {Roo.Element} this
8289          */
8290         clearPositioning : function(value){
8291             value = value ||'';
8292             this.setStyle({
8293                 "left": value,
8294                 "right": value,
8295                 "top": value,
8296                 "bottom": value,
8297                 "z-index": "",
8298                 "position" : "static"
8299             });
8300             return this;
8301         },
8302
8303         /**
8304         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8305         * snapshot before performing an update and then restoring the element.
8306         * @return {Object}
8307         */
8308         getPositioning : function(){
8309             var l = this.getStyle("left");
8310             var t = this.getStyle("top");
8311             return {
8312                 "position" : this.getStyle("position"),
8313                 "left" : l,
8314                 "right" : l ? "" : this.getStyle("right"),
8315                 "top" : t,
8316                 "bottom" : t ? "" : this.getStyle("bottom"),
8317                 "z-index" : this.getStyle("z-index")
8318             };
8319         },
8320
8321         /**
8322          * Gets the width of the border(s) for the specified side(s)
8323          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8324          * passing lr would get the border (l)eft width + the border (r)ight width.
8325          * @return {Number} The width of the sides passed added together
8326          */
8327         getBorderWidth : function(side){
8328             return this.addStyles(side, El.borders);
8329         },
8330
8331         /**
8332          * Gets the width of the padding(s) for the specified side(s)
8333          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8334          * passing lr would get the padding (l)eft + the padding (r)ight.
8335          * @return {Number} The padding of the sides passed added together
8336          */
8337         getPadding : function(side){
8338             return this.addStyles(side, El.paddings);
8339         },
8340
8341         /**
8342         * Set positioning with an object returned by getPositioning().
8343         * @param {Object} posCfg
8344         * @return {Roo.Element} this
8345          */
8346         setPositioning : function(pc){
8347             this.applyStyles(pc);
8348             if(pc.right == "auto"){
8349                 this.dom.style.right = "";
8350             }
8351             if(pc.bottom == "auto"){
8352                 this.dom.style.bottom = "";
8353             }
8354             return this;
8355         },
8356
8357         // private
8358         fixDisplay : function(){
8359             if(this.getStyle("display") == "none"){
8360                 this.setStyle("visibility", "hidden");
8361                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8362                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8363                     this.setStyle("display", "block");
8364                 }
8365             }
8366         },
8367
8368         /**
8369          * Quick set left and top adding default units
8370          * @param {String} left The left CSS property value
8371          * @param {String} top The top CSS property value
8372          * @return {Roo.Element} this
8373          */
8374          setLeftTop : function(left, top){
8375             this.dom.style.left = this.addUnits(left);
8376             this.dom.style.top = this.addUnits(top);
8377             return this;
8378         },
8379
8380         /**
8381          * Move this element relative to its current position.
8382          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8383          * @param {Number} distance How far to move the element in pixels
8384          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8385          * @return {Roo.Element} this
8386          */
8387          move : function(direction, distance, animate){
8388             var xy = this.getXY();
8389             direction = direction.toLowerCase();
8390             switch(direction){
8391                 case "l":
8392                 case "left":
8393                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8394                     break;
8395                case "r":
8396                case "right":
8397                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8398                     break;
8399                case "t":
8400                case "top":
8401                case "up":
8402                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8403                     break;
8404                case "b":
8405                case "bottom":
8406                case "down":
8407                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8408                     break;
8409             }
8410             return this;
8411         },
8412
8413         /**
8414          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8415          * @return {Roo.Element} this
8416          */
8417         clip : function(){
8418             if(!this.isClipped){
8419                this.isClipped = true;
8420                this.originalClip = {
8421                    "o": this.getStyle("overflow"),
8422                    "x": this.getStyle("overflow-x"),
8423                    "y": this.getStyle("overflow-y")
8424                };
8425                this.setStyle("overflow", "hidden");
8426                this.setStyle("overflow-x", "hidden");
8427                this.setStyle("overflow-y", "hidden");
8428             }
8429             return this;
8430         },
8431
8432         /**
8433          *  Return clipping (overflow) to original clipping before clip() was called
8434          * @return {Roo.Element} this
8435          */
8436         unclip : function(){
8437             if(this.isClipped){
8438                 this.isClipped = false;
8439                 var o = this.originalClip;
8440                 if(o.o){this.setStyle("overflow", o.o);}
8441                 if(o.x){this.setStyle("overflow-x", o.x);}
8442                 if(o.y){this.setStyle("overflow-y", o.y);}
8443             }
8444             return this;
8445         },
8446
8447
8448         /**
8449          * Gets the x,y coordinates specified by the anchor position on the element.
8450          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8451          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8452          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8453          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8454          * @return {Array} [x, y] An array containing the element's x and y coordinates
8455          */
8456         getAnchorXY : function(anchor, local, s){
8457             //Passing a different size is useful for pre-calculating anchors,
8458             //especially for anchored animations that change the el size.
8459
8460             var w, h, vp = false;
8461             if(!s){
8462                 var d = this.dom;
8463                 if(d == document.body || d == document){
8464                     vp = true;
8465                     w = D.getViewWidth(); h = D.getViewHeight();
8466                 }else{
8467                     w = this.getWidth(); h = this.getHeight();
8468                 }
8469             }else{
8470                 w = s.width;  h = s.height;
8471             }
8472             var x = 0, y = 0, r = Math.round;
8473             switch((anchor || "tl").toLowerCase()){
8474                 case "c":
8475                     x = r(w*.5);
8476                     y = r(h*.5);
8477                 break;
8478                 case "t":
8479                     x = r(w*.5);
8480                     y = 0;
8481                 break;
8482                 case "l":
8483                     x = 0;
8484                     y = r(h*.5);
8485                 break;
8486                 case "r":
8487                     x = w;
8488                     y = r(h*.5);
8489                 break;
8490                 case "b":
8491                     x = r(w*.5);
8492                     y = h;
8493                 break;
8494                 case "tl":
8495                     x = 0;
8496                     y = 0;
8497                 break;
8498                 case "bl":
8499                     x = 0;
8500                     y = h;
8501                 break;
8502                 case "br":
8503                     x = w;
8504                     y = h;
8505                 break;
8506                 case "tr":
8507                     x = w;
8508                     y = 0;
8509                 break;
8510             }
8511             if(local === true){
8512                 return [x, y];
8513             }
8514             if(vp){
8515                 var sc = this.getScroll();
8516                 return [x + sc.left, y + sc.top];
8517             }
8518             //Add the element's offset xy
8519             var o = this.getXY();
8520             return [x+o[0], y+o[1]];
8521         },
8522
8523         /**
8524          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8525          * supported position values.
8526          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8527          * @param {String} position The position to align to.
8528          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8529          * @return {Array} [x, y]
8530          */
8531         getAlignToXY : function(el, p, o){
8532             el = Roo.get(el);
8533             var d = this.dom;
8534             if(!el.dom){
8535                 throw "Element.alignTo with an element that doesn't exist";
8536             }
8537             var c = false; //constrain to viewport
8538             var p1 = "", p2 = "";
8539             o = o || [0,0];
8540
8541             if(!p){
8542                 p = "tl-bl";
8543             }else if(p == "?"){
8544                 p = "tl-bl?";
8545             }else if(p.indexOf("-") == -1){
8546                 p = "tl-" + p;
8547             }
8548             p = p.toLowerCase();
8549             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8550             if(!m){
8551                throw "Element.alignTo with an invalid alignment " + p;
8552             }
8553             p1 = m[1]; p2 = m[2]; c = !!m[3];
8554
8555             //Subtract the aligned el's internal xy from the target's offset xy
8556             //plus custom offset to get the aligned el's new offset xy
8557             var a1 = this.getAnchorXY(p1, true);
8558             var a2 = el.getAnchorXY(p2, false);
8559             var x = a2[0] - a1[0] + o[0];
8560             var y = a2[1] - a1[1] + o[1];
8561             if(c){
8562                 //constrain the aligned el to viewport if necessary
8563                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8564                 // 5px of margin for ie
8565                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8566
8567                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8568                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8569                 //otherwise swap the aligned el to the opposite border of the target.
8570                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8571                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8572                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8573                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8574
8575                var doc = document;
8576                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8577                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8578
8579                if((x+w) > dw + scrollX){
8580                     x = swapX ? r.left-w : dw+scrollX-w;
8581                 }
8582                if(x < scrollX){
8583                    x = swapX ? r.right : scrollX;
8584                }
8585                if((y+h) > dh + scrollY){
8586                     y = swapY ? r.top-h : dh+scrollY-h;
8587                 }
8588                if (y < scrollY){
8589                    y = swapY ? r.bottom : scrollY;
8590                }
8591             }
8592             return [x,y];
8593         },
8594
8595         // private
8596         getConstrainToXY : function(){
8597             var os = {top:0, left:0, bottom:0, right: 0};
8598
8599             return function(el, local, offsets, proposedXY){
8600                 el = Roo.get(el);
8601                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8602
8603                 var vw, vh, vx = 0, vy = 0;
8604                 if(el.dom == document.body || el.dom == document){
8605                     vw = Roo.lib.Dom.getViewWidth();
8606                     vh = Roo.lib.Dom.getViewHeight();
8607                 }else{
8608                     vw = el.dom.clientWidth;
8609                     vh = el.dom.clientHeight;
8610                     if(!local){
8611                         var vxy = el.getXY();
8612                         vx = vxy[0];
8613                         vy = vxy[1];
8614                     }
8615                 }
8616
8617                 var s = el.getScroll();
8618
8619                 vx += offsets.left + s.left;
8620                 vy += offsets.top + s.top;
8621
8622                 vw -= offsets.right;
8623                 vh -= offsets.bottom;
8624
8625                 var vr = vx+vw;
8626                 var vb = vy+vh;
8627
8628                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8629                 var x = xy[0], y = xy[1];
8630                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8631
8632                 // only move it if it needs it
8633                 var moved = false;
8634
8635                 // first validate right/bottom
8636                 if((x + w) > vr){
8637                     x = vr - w;
8638                     moved = true;
8639                 }
8640                 if((y + h) > vb){
8641                     y = vb - h;
8642                     moved = true;
8643                 }
8644                 // then make sure top/left isn't negative
8645                 if(x < vx){
8646                     x = vx;
8647                     moved = true;
8648                 }
8649                 if(y < vy){
8650                     y = vy;
8651                     moved = true;
8652                 }
8653                 return moved ? [x, y] : false;
8654             };
8655         }(),
8656
8657         // private
8658         adjustForConstraints : function(xy, parent, offsets){
8659             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8660         },
8661
8662         /**
8663          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8664          * document it aligns it to the viewport.
8665          * The position parameter is optional, and can be specified in any one of the following formats:
8666          * <ul>
8667          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8668          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8669          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8670          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8671          *   <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
8672          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8673          * </ul>
8674          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8675          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8676          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8677          * that specified in order to enforce the viewport constraints.
8678          * Following are all of the supported anchor positions:
8679     <pre>
8680     Value  Description
8681     -----  -----------------------------
8682     tl     The top left corner (default)
8683     t      The center of the top edge
8684     tr     The top right corner
8685     l      The center of the left edge
8686     c      In the center of the element
8687     r      The center of the right edge
8688     bl     The bottom left corner
8689     b      The center of the bottom edge
8690     br     The bottom right corner
8691     </pre>
8692     Example Usage:
8693     <pre><code>
8694     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8695     el.alignTo("other-el");
8696
8697     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8698     el.alignTo("other-el", "tr?");
8699
8700     // align the bottom right corner of el with the center left edge of other-el
8701     el.alignTo("other-el", "br-l?");
8702
8703     // align the center of el with the bottom left corner of other-el and
8704     // adjust the x position by -6 pixels (and the y position by 0)
8705     el.alignTo("other-el", "c-bl", [-6, 0]);
8706     </code></pre>
8707          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8708          * @param {String} position The position to align to.
8709          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8710          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8711          * @return {Roo.Element} this
8712          */
8713         alignTo : function(element, position, offsets, animate){
8714             var xy = this.getAlignToXY(element, position, offsets);
8715             this.setXY(xy, this.preanim(arguments, 3));
8716             return this;
8717         },
8718
8719         /**
8720          * Anchors an element to another element and realigns it when the window is resized.
8721          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8722          * @param {String} position The position to align to.
8723          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8724          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8725          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8726          * is a number, it is used as the buffer delay (defaults to 50ms).
8727          * @param {Function} callback The function to call after the animation finishes
8728          * @return {Roo.Element} this
8729          */
8730         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8731             var action = function(){
8732                 this.alignTo(el, alignment, offsets, animate);
8733                 Roo.callback(callback, this);
8734             };
8735             Roo.EventManager.onWindowResize(action, this);
8736             var tm = typeof monitorScroll;
8737             if(tm != 'undefined'){
8738                 Roo.EventManager.on(window, 'scroll', action, this,
8739                     {buffer: tm == 'number' ? monitorScroll : 50});
8740             }
8741             action.call(this); // align immediately
8742             return this;
8743         },
8744         /**
8745          * Clears any opacity settings from this element. Required in some cases for IE.
8746          * @return {Roo.Element} this
8747          */
8748         clearOpacity : function(){
8749             if (window.ActiveXObject) {
8750                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8751                     this.dom.style.filter = "";
8752                 }
8753             } else {
8754                 this.dom.style.opacity = "";
8755                 this.dom.style["-moz-opacity"] = "";
8756                 this.dom.style["-khtml-opacity"] = "";
8757             }
8758             return this;
8759         },
8760
8761         /**
8762          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8763          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8764          * @return {Roo.Element} this
8765          */
8766         hide : function(animate){
8767             this.setVisible(false, this.preanim(arguments, 0));
8768             return this;
8769         },
8770
8771         /**
8772         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8773         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8774          * @return {Roo.Element} this
8775          */
8776         show : function(animate){
8777             this.setVisible(true, this.preanim(arguments, 0));
8778             return this;
8779         },
8780
8781         /**
8782          * @private Test if size has a unit, otherwise appends the default
8783          */
8784         addUnits : function(size){
8785             return Roo.Element.addUnits(size, this.defaultUnit);
8786         },
8787
8788         /**
8789          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8790          * @return {Roo.Element} this
8791          */
8792         beginMeasure : function(){
8793             var el = this.dom;
8794             if(el.offsetWidth || el.offsetHeight){
8795                 return this; // offsets work already
8796             }
8797             var changed = [];
8798             var p = this.dom, b = document.body; // start with this element
8799             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8800                 var pe = Roo.get(p);
8801                 if(pe.getStyle('display') == 'none'){
8802                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8803                     p.style.visibility = "hidden";
8804                     p.style.display = "block";
8805                 }
8806                 p = p.parentNode;
8807             }
8808             this._measureChanged = changed;
8809             return this;
8810
8811         },
8812
8813         /**
8814          * Restores displays to before beginMeasure was called
8815          * @return {Roo.Element} this
8816          */
8817         endMeasure : function(){
8818             var changed = this._measureChanged;
8819             if(changed){
8820                 for(var i = 0, len = changed.length; i < len; i++) {
8821                     var r = changed[i];
8822                     r.el.style.visibility = r.visibility;
8823                     r.el.style.display = "none";
8824                 }
8825                 this._measureChanged = null;
8826             }
8827             return this;
8828         },
8829
8830         /**
8831         * Update the innerHTML of this element, optionally searching for and processing scripts
8832         * @param {String} html The new HTML
8833         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8834         * @param {Function} callback For async script loading you can be noticed when the update completes
8835         * @return {Roo.Element} this
8836          */
8837         update : function(html, loadScripts, callback){
8838             if(typeof html == "undefined"){
8839                 html = "";
8840             }
8841             if(loadScripts !== true){
8842                 this.dom.innerHTML = html;
8843                 if(typeof callback == "function"){
8844                     callback();
8845                 }
8846                 return this;
8847             }
8848             var id = Roo.id();
8849             var dom = this.dom;
8850
8851             html += '<span id="' + id + '"></span>';
8852
8853             E.onAvailable(id, function(){
8854                 var hd = document.getElementsByTagName("head")[0];
8855                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8856                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8857                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8858
8859                 var match;
8860                 while(match = re.exec(html)){
8861                     var attrs = match[1];
8862                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8863                     if(srcMatch && srcMatch[2]){
8864                        var s = document.createElement("script");
8865                        s.src = srcMatch[2];
8866                        var typeMatch = attrs.match(typeRe);
8867                        if(typeMatch && typeMatch[2]){
8868                            s.type = typeMatch[2];
8869                        }
8870                        hd.appendChild(s);
8871                     }else if(match[2] && match[2].length > 0){
8872                         if(window.execScript) {
8873                            window.execScript(match[2]);
8874                         } else {
8875                             /**
8876                              * eval:var:id
8877                              * eval:var:dom
8878                              * eval:var:html
8879                              * 
8880                              */
8881                            window.eval(match[2]);
8882                         }
8883                     }
8884                 }
8885                 var el = document.getElementById(id);
8886                 if(el){el.parentNode.removeChild(el);}
8887                 if(typeof callback == "function"){
8888                     callback();
8889                 }
8890             });
8891             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8892             return this;
8893         },
8894
8895         /**
8896          * Direct access to the UpdateManager update() method (takes the same parameters).
8897          * @param {String/Function} url The url for this request or a function to call to get the url
8898          * @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}
8899          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8900          * @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.
8901          * @return {Roo.Element} this
8902          */
8903         load : function(){
8904             var um = this.getUpdateManager();
8905             um.update.apply(um, arguments);
8906             return this;
8907         },
8908
8909         /**
8910         * Gets this element's UpdateManager
8911         * @return {Roo.UpdateManager} The UpdateManager
8912         */
8913         getUpdateManager : function(){
8914             if(!this.updateManager){
8915                 this.updateManager = new Roo.UpdateManager(this);
8916             }
8917             return this.updateManager;
8918         },
8919
8920         /**
8921          * Disables text selection for this element (normalized across browsers)
8922          * @return {Roo.Element} this
8923          */
8924         unselectable : function(){
8925             this.dom.unselectable = "on";
8926             this.swallowEvent("selectstart", true);
8927             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8928             this.addClass("x-unselectable");
8929             return this;
8930         },
8931
8932         /**
8933         * Calculates the x, y to center this element on the screen
8934         * @return {Array} The x, y values [x, y]
8935         */
8936         getCenterXY : function(){
8937             return this.getAlignToXY(document, 'c-c');
8938         },
8939
8940         /**
8941         * Centers the Element in either the viewport, or another Element.
8942         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8943         */
8944         center : function(centerIn){
8945             this.alignTo(centerIn || document, 'c-c');
8946             return this;
8947         },
8948
8949         /**
8950          * Tests various css rules/browsers to determine if this element uses a border box
8951          * @return {Boolean}
8952          */
8953         isBorderBox : function(){
8954             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8955         },
8956
8957         /**
8958          * Return a box {x, y, width, height} that can be used to set another elements
8959          * size/location to match this element.
8960          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8961          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8962          * @return {Object} box An object in the format {x, y, width, height}
8963          */
8964         getBox : function(contentBox, local){
8965             var xy;
8966             if(!local){
8967                 xy = this.getXY();
8968             }else{
8969                 var left = parseInt(this.getStyle("left"), 10) || 0;
8970                 var top = parseInt(this.getStyle("top"), 10) || 0;
8971                 xy = [left, top];
8972             }
8973             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8974             if(!contentBox){
8975                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8976             }else{
8977                 var l = this.getBorderWidth("l")+this.getPadding("l");
8978                 var r = this.getBorderWidth("r")+this.getPadding("r");
8979                 var t = this.getBorderWidth("t")+this.getPadding("t");
8980                 var b = this.getBorderWidth("b")+this.getPadding("b");
8981                 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)};
8982             }
8983             bx.right = bx.x + bx.width;
8984             bx.bottom = bx.y + bx.height;
8985             return bx;
8986         },
8987
8988         /**
8989          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8990          for more information about the sides.
8991          * @param {String} sides
8992          * @return {Number}
8993          */
8994         getFrameWidth : function(sides, onlyContentBox){
8995             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8996         },
8997
8998         /**
8999          * 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.
9000          * @param {Object} box The box to fill {x, y, width, height}
9001          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9002          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9003          * @return {Roo.Element} this
9004          */
9005         setBox : function(box, adjust, animate){
9006             var w = box.width, h = box.height;
9007             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9008                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9009                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9010             }
9011             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9012             return this;
9013         },
9014
9015         /**
9016          * Forces the browser to repaint this element
9017          * @return {Roo.Element} this
9018          */
9019          repaint : function(){
9020             var dom = this.dom;
9021             this.addClass("x-repaint");
9022             setTimeout(function(){
9023                 Roo.get(dom).removeClass("x-repaint");
9024             }, 1);
9025             return this;
9026         },
9027
9028         /**
9029          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9030          * then it returns the calculated width of the sides (see getPadding)
9031          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9032          * @return {Object/Number}
9033          */
9034         getMargins : function(side){
9035             if(!side){
9036                 return {
9037                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9038                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9039                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9040                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9041                 };
9042             }else{
9043                 return this.addStyles(side, El.margins);
9044              }
9045         },
9046
9047         // private
9048         addStyles : function(sides, styles){
9049             var val = 0, v, w;
9050             for(var i = 0, len = sides.length; i < len; i++){
9051                 v = this.getStyle(styles[sides.charAt(i)]);
9052                 if(v){
9053                      w = parseInt(v, 10);
9054                      if(w){ val += w; }
9055                 }
9056             }
9057             return val;
9058         },
9059
9060         /**
9061          * Creates a proxy element of this element
9062          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9063          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9064          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9065          * @return {Roo.Element} The new proxy element
9066          */
9067         createProxy : function(config, renderTo, matchBox){
9068             if(renderTo){
9069                 renderTo = Roo.getDom(renderTo);
9070             }else{
9071                 renderTo = document.body;
9072             }
9073             config = typeof config == "object" ?
9074                 config : {tag : "div", cls: config};
9075             var proxy = Roo.DomHelper.append(renderTo, config, true);
9076             if(matchBox){
9077                proxy.setBox(this.getBox());
9078             }
9079             return proxy;
9080         },
9081
9082         /**
9083          * Puts a mask over this element to disable user interaction. Requires core.css.
9084          * This method can only be applied to elements which accept child nodes.
9085          * @param {String} msg (optional) A message to display in the mask
9086          * @param {String} msgCls (optional) A css class to apply to the msg element
9087          * @return {Element} The mask  element
9088          */
9089         mask : function(msg, msgCls)
9090         {
9091             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9092                 this.setStyle("position", "relative");
9093             }
9094             if(!this._mask){
9095                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9096             }
9097             this.addClass("x-masked");
9098             this._mask.setDisplayed(true);
9099             
9100             // we wander
9101             var z = 0;
9102             var dom = this.dom;
9103             while (dom && dom.style) {
9104                 if (!isNaN(parseInt(dom.style.zIndex))) {
9105                     z = Math.max(z, parseInt(dom.style.zIndex));
9106                 }
9107                 dom = dom.parentNode;
9108             }
9109             // if we are masking the body - then it hides everything..
9110             if (this.dom == document.body) {
9111                 z = 1000000;
9112                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9113                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9114             }
9115            
9116             if(typeof msg == 'string'){
9117                 if(!this._maskMsg){
9118                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9119                 }
9120                 var mm = this._maskMsg;
9121                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9122                 if (mm.dom.firstChild) { // weird IE issue?
9123                     mm.dom.firstChild.innerHTML = msg;
9124                 }
9125                 mm.setDisplayed(true);
9126                 mm.center(this);
9127                 mm.setStyle('z-index', z + 102);
9128             }
9129             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9130                 this._mask.setHeight(this.getHeight());
9131             }
9132             this._mask.setStyle('z-index', z + 100);
9133             
9134             return this._mask;
9135         },
9136
9137         /**
9138          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9139          * it is cached for reuse.
9140          */
9141         unmask : function(removeEl){
9142             if(this._mask){
9143                 if(removeEl === true){
9144                     this._mask.remove();
9145                     delete this._mask;
9146                     if(this._maskMsg){
9147                         this._maskMsg.remove();
9148                         delete this._maskMsg;
9149                     }
9150                 }else{
9151                     this._mask.setDisplayed(false);
9152                     if(this._maskMsg){
9153                         this._maskMsg.setDisplayed(false);
9154                     }
9155                 }
9156             }
9157             this.removeClass("x-masked");
9158         },
9159
9160         /**
9161          * Returns true if this element is masked
9162          * @return {Boolean}
9163          */
9164         isMasked : function(){
9165             return this._mask && this._mask.isVisible();
9166         },
9167
9168         /**
9169          * Creates an iframe shim for this element to keep selects and other windowed objects from
9170          * showing through.
9171          * @return {Roo.Element} The new shim element
9172          */
9173         createShim : function(){
9174             var el = document.createElement('iframe');
9175             el.frameBorder = 'no';
9176             el.className = 'roo-shim';
9177             if(Roo.isIE && Roo.isSecure){
9178                 el.src = Roo.SSL_SECURE_URL;
9179             }
9180             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9181             shim.autoBoxAdjust = false;
9182             return shim;
9183         },
9184
9185         /**
9186          * Removes this element from the DOM and deletes it from the cache
9187          */
9188         remove : function(){
9189             if(this.dom.parentNode){
9190                 this.dom.parentNode.removeChild(this.dom);
9191             }
9192             delete El.cache[this.dom.id];
9193         },
9194
9195         /**
9196          * Sets up event handlers to add and remove a css class when the mouse is over this element
9197          * @param {String} className
9198          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9199          * mouseout events for children elements
9200          * @return {Roo.Element} this
9201          */
9202         addClassOnOver : function(className, preventFlicker){
9203             this.on("mouseover", function(){
9204                 Roo.fly(this, '_internal').addClass(className);
9205             }, this.dom);
9206             var removeFn = function(e){
9207                 if(preventFlicker !== true || !e.within(this, true)){
9208                     Roo.fly(this, '_internal').removeClass(className);
9209                 }
9210             };
9211             this.on("mouseout", removeFn, this.dom);
9212             return this;
9213         },
9214
9215         /**
9216          * Sets up event handlers to add and remove a css class when this element has the focus
9217          * @param {String} className
9218          * @return {Roo.Element} this
9219          */
9220         addClassOnFocus : function(className){
9221             this.on("focus", function(){
9222                 Roo.fly(this, '_internal').addClass(className);
9223             }, this.dom);
9224             this.on("blur", function(){
9225                 Roo.fly(this, '_internal').removeClass(className);
9226             }, this.dom);
9227             return this;
9228         },
9229         /**
9230          * 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)
9231          * @param {String} className
9232          * @return {Roo.Element} this
9233          */
9234         addClassOnClick : function(className){
9235             var dom = this.dom;
9236             this.on("mousedown", function(){
9237                 Roo.fly(dom, '_internal').addClass(className);
9238                 var d = Roo.get(document);
9239                 var fn = function(){
9240                     Roo.fly(dom, '_internal').removeClass(className);
9241                     d.removeListener("mouseup", fn);
9242                 };
9243                 d.on("mouseup", fn);
9244             });
9245             return this;
9246         },
9247
9248         /**
9249          * Stops the specified event from bubbling and optionally prevents the default action
9250          * @param {String} eventName
9251          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9252          * @return {Roo.Element} this
9253          */
9254         swallowEvent : function(eventName, preventDefault){
9255             var fn = function(e){
9256                 e.stopPropagation();
9257                 if(preventDefault){
9258                     e.preventDefault();
9259                 }
9260             };
9261             if(eventName instanceof Array){
9262                 for(var i = 0, len = eventName.length; i < len; i++){
9263                      this.on(eventName[i], fn);
9264                 }
9265                 return this;
9266             }
9267             this.on(eventName, fn);
9268             return this;
9269         },
9270
9271         /**
9272          * @private
9273          */
9274       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9275
9276         /**
9277          * Sizes this element to its parent element's dimensions performing
9278          * neccessary box adjustments.
9279          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9280          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9281          * @return {Roo.Element} this
9282          */
9283         fitToParent : function(monitorResize, targetParent) {
9284           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9285           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9286           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9287             return;
9288           }
9289           var p = Roo.get(targetParent || this.dom.parentNode);
9290           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9291           if (monitorResize === true) {
9292             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9293             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9294           }
9295           return this;
9296         },
9297
9298         /**
9299          * Gets the next sibling, skipping text nodes
9300          * @return {HTMLElement} The next sibling or null
9301          */
9302         getNextSibling : function(){
9303             var n = this.dom.nextSibling;
9304             while(n && n.nodeType != 1){
9305                 n = n.nextSibling;
9306             }
9307             return n;
9308         },
9309
9310         /**
9311          * Gets the previous sibling, skipping text nodes
9312          * @return {HTMLElement} The previous sibling or null
9313          */
9314         getPrevSibling : function(){
9315             var n = this.dom.previousSibling;
9316             while(n && n.nodeType != 1){
9317                 n = n.previousSibling;
9318             }
9319             return n;
9320         },
9321
9322
9323         /**
9324          * Appends the passed element(s) to this element
9325          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9326          * @return {Roo.Element} this
9327          */
9328         appendChild: function(el){
9329             el = Roo.get(el);
9330             el.appendTo(this);
9331             return this;
9332         },
9333
9334         /**
9335          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9336          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9337          * automatically generated with the specified attributes.
9338          * @param {HTMLElement} insertBefore (optional) a child element of this element
9339          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9340          * @return {Roo.Element} The new child element
9341          */
9342         createChild: function(config, insertBefore, returnDom){
9343             config = config || {tag:'div'};
9344             if(insertBefore){
9345                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9346             }
9347             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9348         },
9349
9350         /**
9351          * Appends this element to the passed element
9352          * @param {String/HTMLElement/Element} el The new parent element
9353          * @return {Roo.Element} this
9354          */
9355         appendTo: function(el){
9356             el = Roo.getDom(el);
9357             el.appendChild(this.dom);
9358             return this;
9359         },
9360
9361         /**
9362          * Inserts this element before the passed element in the DOM
9363          * @param {String/HTMLElement/Element} el The element to insert before
9364          * @return {Roo.Element} this
9365          */
9366         insertBefore: function(el){
9367             el = Roo.getDom(el);
9368             el.parentNode.insertBefore(this.dom, el);
9369             return this;
9370         },
9371
9372         /**
9373          * Inserts this element after the passed element in the DOM
9374          * @param {String/HTMLElement/Element} el The element to insert after
9375          * @return {Roo.Element} this
9376          */
9377         insertAfter: function(el){
9378             el = Roo.getDom(el);
9379             el.parentNode.insertBefore(this.dom, el.nextSibling);
9380             return this;
9381         },
9382
9383         /**
9384          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9385          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9386          * @return {Roo.Element} The new child
9387          */
9388         insertFirst: function(el, returnDom){
9389             el = el || {};
9390             if(typeof el == 'object' && !el.nodeType){ // dh config
9391                 return this.createChild(el, this.dom.firstChild, returnDom);
9392             }else{
9393                 el = Roo.getDom(el);
9394                 this.dom.insertBefore(el, this.dom.firstChild);
9395                 return !returnDom ? Roo.get(el) : el;
9396             }
9397         },
9398
9399         /**
9400          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9401          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9402          * @param {String} where (optional) 'before' or 'after' defaults to before
9403          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9404          * @return {Roo.Element} the inserted Element
9405          */
9406         insertSibling: function(el, where, returnDom){
9407             where = where ? where.toLowerCase() : 'before';
9408             el = el || {};
9409             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9410
9411             if(typeof el == 'object' && !el.nodeType){ // dh config
9412                 if(where == 'after' && !this.dom.nextSibling){
9413                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9414                 }else{
9415                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9416                 }
9417
9418             }else{
9419                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9420                             where == 'before' ? this.dom : this.dom.nextSibling);
9421                 if(!returnDom){
9422                     rt = Roo.get(rt);
9423                 }
9424             }
9425             return rt;
9426         },
9427
9428         /**
9429          * Creates and wraps this element with another element
9430          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9431          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9432          * @return {HTMLElement/Element} The newly created wrapper element
9433          */
9434         wrap: function(config, returnDom){
9435             if(!config){
9436                 config = {tag: "div"};
9437             }
9438             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9439             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9440             return newEl;
9441         },
9442
9443         /**
9444          * Replaces the passed element with this element
9445          * @param {String/HTMLElement/Element} el The element to replace
9446          * @return {Roo.Element} this
9447          */
9448         replace: function(el){
9449             el = Roo.get(el);
9450             this.insertBefore(el);
9451             el.remove();
9452             return this;
9453         },
9454
9455         /**
9456          * Inserts an html fragment into this element
9457          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9458          * @param {String} html The HTML fragment
9459          * @param {Boolean} returnEl True to return an Roo.Element
9460          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9461          */
9462         insertHtml : function(where, html, returnEl){
9463             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9464             return returnEl ? Roo.get(el) : el;
9465         },
9466
9467         /**
9468          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9469          * @param {Object} o The object with the attributes
9470          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9471          * @return {Roo.Element} this
9472          */
9473         set : function(o, useSet){
9474             var el = this.dom;
9475             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9476             for(var attr in o){
9477                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9478                 if(attr=="cls"){
9479                     el.className = o["cls"];
9480                 }else{
9481                     if(useSet) {
9482                         el.setAttribute(attr, o[attr]);
9483                     } else {
9484                         el[attr] = o[attr];
9485                     }
9486                 }
9487             }
9488             if(o.style){
9489                 Roo.DomHelper.applyStyles(el, o.style);
9490             }
9491             return this;
9492         },
9493
9494         /**
9495          * Convenience method for constructing a KeyMap
9496          * @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:
9497          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9498          * @param {Function} fn The function to call
9499          * @param {Object} scope (optional) The scope of the function
9500          * @return {Roo.KeyMap} The KeyMap created
9501          */
9502         addKeyListener : function(key, fn, scope){
9503             var config;
9504             if(typeof key != "object" || key instanceof Array){
9505                 config = {
9506                     key: key,
9507                     fn: fn,
9508                     scope: scope
9509                 };
9510             }else{
9511                 config = {
9512                     key : key.key,
9513                     shift : key.shift,
9514                     ctrl : key.ctrl,
9515                     alt : key.alt,
9516                     fn: fn,
9517                     scope: scope
9518                 };
9519             }
9520             return new Roo.KeyMap(this, config);
9521         },
9522
9523         /**
9524          * Creates a KeyMap for this element
9525          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9526          * @return {Roo.KeyMap} The KeyMap created
9527          */
9528         addKeyMap : function(config){
9529             return new Roo.KeyMap(this, config);
9530         },
9531
9532         /**
9533          * Returns true if this element is scrollable.
9534          * @return {Boolean}
9535          */
9536          isScrollable : function(){
9537             var dom = this.dom;
9538             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9539         },
9540
9541         /**
9542          * 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().
9543          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9544          * @param {Number} value The new scroll value
9545          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9546          * @return {Element} this
9547          */
9548
9549         scrollTo : function(side, value, animate){
9550             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9551             if(!animate || !A){
9552                 this.dom[prop] = value;
9553             }else{
9554                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9555                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9556             }
9557             return this;
9558         },
9559
9560         /**
9561          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9562          * within this element's scrollable range.
9563          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9564          * @param {Number} distance How far to scroll the element in pixels
9565          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9566          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9567          * was scrolled as far as it could go.
9568          */
9569          scroll : function(direction, distance, animate){
9570              if(!this.isScrollable()){
9571                  return;
9572              }
9573              var el = this.dom;
9574              var l = el.scrollLeft, t = el.scrollTop;
9575              var w = el.scrollWidth, h = el.scrollHeight;
9576              var cw = el.clientWidth, ch = el.clientHeight;
9577              direction = direction.toLowerCase();
9578              var scrolled = false;
9579              var a = this.preanim(arguments, 2);
9580              switch(direction){
9581                  case "l":
9582                  case "left":
9583                      if(w - l > cw){
9584                          var v = Math.min(l + distance, w-cw);
9585                          this.scrollTo("left", v, a);
9586                          scrolled = true;
9587                      }
9588                      break;
9589                 case "r":
9590                 case "right":
9591                      if(l > 0){
9592                          var v = Math.max(l - distance, 0);
9593                          this.scrollTo("left", v, a);
9594                          scrolled = true;
9595                      }
9596                      break;
9597                 case "t":
9598                 case "top":
9599                 case "up":
9600                      if(t > 0){
9601                          var v = Math.max(t - distance, 0);
9602                          this.scrollTo("top", v, a);
9603                          scrolled = true;
9604                      }
9605                      break;
9606                 case "b":
9607                 case "bottom":
9608                 case "down":
9609                      if(h - t > ch){
9610                          var v = Math.min(t + distance, h-ch);
9611                          this.scrollTo("top", v, a);
9612                          scrolled = true;
9613                      }
9614                      break;
9615              }
9616              return scrolled;
9617         },
9618
9619         /**
9620          * Translates the passed page coordinates into left/top css values for this element
9621          * @param {Number/Array} x The page x or an array containing [x, y]
9622          * @param {Number} y The page y
9623          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9624          */
9625         translatePoints : function(x, y){
9626             if(typeof x == 'object' || x instanceof Array){
9627                 y = x[1]; x = x[0];
9628             }
9629             var p = this.getStyle('position');
9630             var o = this.getXY();
9631
9632             var l = parseInt(this.getStyle('left'), 10);
9633             var t = parseInt(this.getStyle('top'), 10);
9634
9635             if(isNaN(l)){
9636                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9637             }
9638             if(isNaN(t)){
9639                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9640             }
9641
9642             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9643         },
9644
9645         /**
9646          * Returns the current scroll position of the element.
9647          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9648          */
9649         getScroll : function(){
9650             var d = this.dom, doc = document;
9651             if(d == doc || d == doc.body){
9652                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9653                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9654                 return {left: l, top: t};
9655             }else{
9656                 return {left: d.scrollLeft, top: d.scrollTop};
9657             }
9658         },
9659
9660         /**
9661          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9662          * are convert to standard 6 digit hex color.
9663          * @param {String} attr The css attribute
9664          * @param {String} defaultValue The default value to use when a valid color isn't found
9665          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9666          * YUI color anims.
9667          */
9668         getColor : function(attr, defaultValue, prefix){
9669             var v = this.getStyle(attr);
9670             if(!v || v == "transparent" || v == "inherit") {
9671                 return defaultValue;
9672             }
9673             var color = typeof prefix == "undefined" ? "#" : prefix;
9674             if(v.substr(0, 4) == "rgb("){
9675                 var rvs = v.slice(4, v.length -1).split(",");
9676                 for(var i = 0; i < 3; i++){
9677                     var h = parseInt(rvs[i]).toString(16);
9678                     if(h < 16){
9679                         h = "0" + h;
9680                     }
9681                     color += h;
9682                 }
9683             } else {
9684                 if(v.substr(0, 1) == "#"){
9685                     if(v.length == 4) {
9686                         for(var i = 1; i < 4; i++){
9687                             var c = v.charAt(i);
9688                             color +=  c + c;
9689                         }
9690                     }else if(v.length == 7){
9691                         color += v.substr(1);
9692                     }
9693                 }
9694             }
9695             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9696         },
9697
9698         /**
9699          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9700          * gradient background, rounded corners and a 4-way shadow.
9701          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9702          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9703          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9704          * @return {Roo.Element} this
9705          */
9706         boxWrap : function(cls){
9707             cls = cls || 'x-box';
9708             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9709             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9710             return el;
9711         },
9712
9713         /**
9714          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9715          * @param {String} namespace The namespace in which to look for the attribute
9716          * @param {String} name The attribute name
9717          * @return {String} The attribute value
9718          */
9719         getAttributeNS : Roo.isIE ? function(ns, name){
9720             var d = this.dom;
9721             var type = typeof d[ns+":"+name];
9722             if(type != 'undefined' && type != 'unknown'){
9723                 return d[ns+":"+name];
9724             }
9725             return d[name];
9726         } : function(ns, name){
9727             var d = this.dom;
9728             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9729         },
9730         
9731         
9732         /**
9733          * Sets or Returns the value the dom attribute value
9734          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9735          * @param {String} value (optional) The value to set the attribute to
9736          * @return {String} The attribute value
9737          */
9738         attr : function(name){
9739             if (arguments.length > 1) {
9740                 this.dom.setAttribute(name, arguments[1]);
9741                 return arguments[1];
9742             }
9743             if (typeof(name) == 'object') {
9744                 for(var i in name) {
9745                     this.attr(i, name[i]);
9746                 }
9747                 return name;
9748             }
9749             
9750             
9751             if (!this.dom.hasAttribute(name)) {
9752                 return undefined;
9753             }
9754             return this.dom.getAttribute(name);
9755         }
9756         
9757         
9758         
9759     };
9760
9761     var ep = El.prototype;
9762
9763     /**
9764      * Appends an event handler (Shorthand for addListener)
9765      * @param {String}   eventName     The type of event to append
9766      * @param {Function} fn        The method the event invokes
9767      * @param {Object} scope       (optional) The scope (this object) of the fn
9768      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9769      * @method
9770      */
9771     ep.on = ep.addListener;
9772         // backwards compat
9773     ep.mon = ep.addListener;
9774
9775     /**
9776      * Removes an event handler from this element (shorthand for removeListener)
9777      * @param {String} eventName the type of event to remove
9778      * @param {Function} fn the method the event invokes
9779      * @return {Roo.Element} this
9780      * @method
9781      */
9782     ep.un = ep.removeListener;
9783
9784     /**
9785      * true to automatically adjust width and height settings for box-model issues (default to true)
9786      */
9787     ep.autoBoxAdjust = true;
9788
9789     // private
9790     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9791
9792     // private
9793     El.addUnits = function(v, defaultUnit){
9794         if(v === "" || v == "auto"){
9795             return v;
9796         }
9797         if(v === undefined){
9798             return '';
9799         }
9800         if(typeof v == "number" || !El.unitPattern.test(v)){
9801             return v + (defaultUnit || 'px');
9802         }
9803         return v;
9804     };
9805
9806     // special markup used throughout Roo when box wrapping elements
9807     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>';
9808     /**
9809      * Visibility mode constant - Use visibility to hide element
9810      * @static
9811      * @type Number
9812      */
9813     El.VISIBILITY = 1;
9814     /**
9815      * Visibility mode constant - Use display to hide element
9816      * @static
9817      * @type Number
9818      */
9819     El.DISPLAY = 2;
9820
9821     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9822     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9823     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9824
9825
9826
9827     /**
9828      * @private
9829      */
9830     El.cache = {};
9831
9832     var docEl;
9833
9834     /**
9835      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9836      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9837      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9838      * @return {Element} The Element object
9839      * @static
9840      */
9841     El.get = function(el){
9842         var ex, elm, id;
9843         if(!el){ return null; }
9844         if(typeof el == "string"){ // element id
9845             if(!(elm = document.getElementById(el))){
9846                 return null;
9847             }
9848             if(ex = El.cache[el]){
9849                 ex.dom = elm;
9850             }else{
9851                 ex = El.cache[el] = new El(elm);
9852             }
9853             return ex;
9854         }else if(el.tagName){ // dom element
9855             if(!(id = el.id)){
9856                 id = Roo.id(el);
9857             }
9858             if(ex = El.cache[id]){
9859                 ex.dom = el;
9860             }else{
9861                 ex = El.cache[id] = new El(el);
9862             }
9863             return ex;
9864         }else if(el instanceof El){
9865             if(el != docEl){
9866                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9867                                                               // catch case where it hasn't been appended
9868                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9869             }
9870             return el;
9871         }else if(el.isComposite){
9872             return el;
9873         }else if(el instanceof Array){
9874             return El.select(el);
9875         }else if(el == document){
9876             // create a bogus element object representing the document object
9877             if(!docEl){
9878                 var f = function(){};
9879                 f.prototype = El.prototype;
9880                 docEl = new f();
9881                 docEl.dom = document;
9882             }
9883             return docEl;
9884         }
9885         return null;
9886     };
9887
9888     // private
9889     El.uncache = function(el){
9890         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9891             if(a[i]){
9892                 delete El.cache[a[i].id || a[i]];
9893             }
9894         }
9895     };
9896
9897     // private
9898     // Garbage collection - uncache elements/purge listeners on orphaned elements
9899     // so we don't hold a reference and cause the browser to retain them
9900     El.garbageCollect = function(){
9901         if(!Roo.enableGarbageCollector){
9902             clearInterval(El.collectorThread);
9903             return;
9904         }
9905         for(var eid in El.cache){
9906             var el = El.cache[eid], d = el.dom;
9907             // -------------------------------------------------------
9908             // Determining what is garbage:
9909             // -------------------------------------------------------
9910             // !d
9911             // dom node is null, definitely garbage
9912             // -------------------------------------------------------
9913             // !d.parentNode
9914             // no parentNode == direct orphan, definitely garbage
9915             // -------------------------------------------------------
9916             // !d.offsetParent && !document.getElementById(eid)
9917             // display none elements have no offsetParent so we will
9918             // also try to look it up by it's id. However, check
9919             // offsetParent first so we don't do unneeded lookups.
9920             // This enables collection of elements that are not orphans
9921             // directly, but somewhere up the line they have an orphan
9922             // parent.
9923             // -------------------------------------------------------
9924             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9925                 delete El.cache[eid];
9926                 if(d && Roo.enableListenerCollection){
9927                     E.purgeElement(d);
9928                 }
9929             }
9930         }
9931     }
9932     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9933
9934
9935     // dom is optional
9936     El.Flyweight = function(dom){
9937         this.dom = dom;
9938     };
9939     El.Flyweight.prototype = El.prototype;
9940
9941     El._flyweights = {};
9942     /**
9943      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9944      * the dom node can be overwritten by other code.
9945      * @param {String/HTMLElement} el The dom node or id
9946      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9947      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9948      * @static
9949      * @return {Element} The shared Element object
9950      */
9951     El.fly = function(el, named){
9952         named = named || '_global';
9953         el = Roo.getDom(el);
9954         if(!el){
9955             return null;
9956         }
9957         if(!El._flyweights[named]){
9958             El._flyweights[named] = new El.Flyweight();
9959         }
9960         El._flyweights[named].dom = el;
9961         return El._flyweights[named];
9962     };
9963
9964     /**
9965      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9966      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9967      * Shorthand of {@link Roo.Element#get}
9968      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9969      * @return {Element} The Element object
9970      * @member Roo
9971      * @method get
9972      */
9973     Roo.get = El.get;
9974     /**
9975      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9976      * the dom node can be overwritten by other code.
9977      * Shorthand of {@link Roo.Element#fly}
9978      * @param {String/HTMLElement} el The dom node or id
9979      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9980      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9981      * @static
9982      * @return {Element} The shared Element object
9983      * @member Roo
9984      * @method fly
9985      */
9986     Roo.fly = El.fly;
9987
9988     // speedy lookup for elements never to box adjust
9989     var noBoxAdjust = Roo.isStrict ? {
9990         select:1
9991     } : {
9992         input:1, select:1, textarea:1
9993     };
9994     if(Roo.isIE || Roo.isGecko){
9995         noBoxAdjust['button'] = 1;
9996     }
9997
9998
9999     Roo.EventManager.on(window, 'unload', function(){
10000         delete El.cache;
10001         delete El._flyweights;
10002     });
10003 })();
10004
10005
10006
10007
10008 if(Roo.DomQuery){
10009     Roo.Element.selectorFunction = Roo.DomQuery.select;
10010 }
10011
10012 Roo.Element.select = function(selector, unique, root){
10013     var els;
10014     if(typeof selector == "string"){
10015         els = Roo.Element.selectorFunction(selector, root);
10016     }else if(selector.length !== undefined){
10017         els = selector;
10018     }else{
10019         throw "Invalid selector";
10020     }
10021     if(unique === true){
10022         return new Roo.CompositeElement(els);
10023     }else{
10024         return new Roo.CompositeElementLite(els);
10025     }
10026 };
10027 /**
10028  * Selects elements based on the passed CSS selector to enable working on them as 1.
10029  * @param {String/Array} selector The CSS selector or an array of elements
10030  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10031  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10032  * @return {CompositeElementLite/CompositeElement}
10033  * @member Roo
10034  * @method select
10035  */
10036 Roo.select = Roo.Element.select;
10037
10038
10039
10040
10041
10042
10043
10044
10045
10046
10047
10048
10049
10050
10051 /*
10052  * Based on:
10053  * Ext JS Library 1.1.1
10054  * Copyright(c) 2006-2007, Ext JS, LLC.
10055  *
10056  * Originally Released Under LGPL - original licence link has changed is not relivant.
10057  *
10058  * Fork - LGPL
10059  * <script type="text/javascript">
10060  */
10061
10062
10063
10064 //Notifies Element that fx methods are available
10065 Roo.enableFx = true;
10066
10067 /**
10068  * @class Roo.Fx
10069  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10070  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10071  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10072  * Element effects to work.</p><br/>
10073  *
10074  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10075  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10076  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10077  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10078  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10079  * expected results and should be done with care.</p><br/>
10080  *
10081  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10082  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10083 <pre>
10084 Value  Description
10085 -----  -----------------------------
10086 tl     The top left corner
10087 t      The center of the top edge
10088 tr     The top right corner
10089 l      The center of the left edge
10090 r      The center of the right edge
10091 bl     The bottom left corner
10092 b      The center of the bottom edge
10093 br     The bottom right corner
10094 </pre>
10095  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10096  * below are common options that can be passed to any Fx method.</b>
10097  * @cfg {Function} callback A function called when the effect is finished
10098  * @cfg {Object} scope The scope of the effect function
10099  * @cfg {String} easing A valid Easing value for the effect
10100  * @cfg {String} afterCls A css class to apply after the effect
10101  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10102  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10103  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10104  * effects that end with the element being visually hidden, ignored otherwise)
10105  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10106  * a function which returns such a specification that will be applied to the Element after the effect finishes
10107  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10108  * @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
10109  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10110  */
10111 Roo.Fx = {
10112         /**
10113          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10114          * origin for the slide effect.  This function automatically handles wrapping the element with
10115          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10116          * Usage:
10117          *<pre><code>
10118 // default: slide the element in from the top
10119 el.slideIn();
10120
10121 // custom: slide the element in from the right with a 2-second duration
10122 el.slideIn('r', { duration: 2 });
10123
10124 // common config options shown with default values
10125 el.slideIn('t', {
10126     easing: 'easeOut',
10127     duration: .5
10128 });
10129 </code></pre>
10130          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10131          * @param {Object} options (optional) Object literal with any of the Fx config options
10132          * @return {Roo.Element} The Element
10133          */
10134     slideIn : function(anchor, o){
10135         var el = this.getFxEl();
10136         o = o || {};
10137
10138         el.queueFx(o, function(){
10139
10140             anchor = anchor || "t";
10141
10142             // fix display to visibility
10143             this.fixDisplay();
10144
10145             // restore values after effect
10146             var r = this.getFxRestore();
10147             var b = this.getBox();
10148             // fixed size for slide
10149             this.setSize(b);
10150
10151             // wrap if needed
10152             var wrap = this.fxWrap(r.pos, o, "hidden");
10153
10154             var st = this.dom.style;
10155             st.visibility = "visible";
10156             st.position = "absolute";
10157
10158             // clear out temp styles after slide and unwrap
10159             var after = function(){
10160                 el.fxUnwrap(wrap, r.pos, o);
10161                 st.width = r.width;
10162                 st.height = r.height;
10163                 el.afterFx(o);
10164             };
10165             // time to calc the positions
10166             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10167
10168             switch(anchor.toLowerCase()){
10169                 case "t":
10170                     wrap.setSize(b.width, 0);
10171                     st.left = st.bottom = "0";
10172                     a = {height: bh};
10173                 break;
10174                 case "l":
10175                     wrap.setSize(0, b.height);
10176                     st.right = st.top = "0";
10177                     a = {width: bw};
10178                 break;
10179                 case "r":
10180                     wrap.setSize(0, b.height);
10181                     wrap.setX(b.right);
10182                     st.left = st.top = "0";
10183                     a = {width: bw, points: pt};
10184                 break;
10185                 case "b":
10186                     wrap.setSize(b.width, 0);
10187                     wrap.setY(b.bottom);
10188                     st.left = st.top = "0";
10189                     a = {height: bh, points: pt};
10190                 break;
10191                 case "tl":
10192                     wrap.setSize(0, 0);
10193                     st.right = st.bottom = "0";
10194                     a = {width: bw, height: bh};
10195                 break;
10196                 case "bl":
10197                     wrap.setSize(0, 0);
10198                     wrap.setY(b.y+b.height);
10199                     st.right = st.top = "0";
10200                     a = {width: bw, height: bh, points: pt};
10201                 break;
10202                 case "br":
10203                     wrap.setSize(0, 0);
10204                     wrap.setXY([b.right, b.bottom]);
10205                     st.left = st.top = "0";
10206                     a = {width: bw, height: bh, points: pt};
10207                 break;
10208                 case "tr":
10209                     wrap.setSize(0, 0);
10210                     wrap.setX(b.x+b.width);
10211                     st.left = st.bottom = "0";
10212                     a = {width: bw, height: bh, points: pt};
10213                 break;
10214             }
10215             this.dom.style.visibility = "visible";
10216             wrap.show();
10217
10218             arguments.callee.anim = wrap.fxanim(a,
10219                 o,
10220                 'motion',
10221                 .5,
10222                 'easeOut', after);
10223         });
10224         return this;
10225     },
10226     
10227         /**
10228          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10229          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10230          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10231          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10232          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10233          * Usage:
10234          *<pre><code>
10235 // default: slide the element out to the top
10236 el.slideOut();
10237
10238 // custom: slide the element out to the right with a 2-second duration
10239 el.slideOut('r', { duration: 2 });
10240
10241 // common config options shown with default values
10242 el.slideOut('t', {
10243     easing: 'easeOut',
10244     duration: .5,
10245     remove: false,
10246     useDisplay: false
10247 });
10248 </code></pre>
10249          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10250          * @param {Object} options (optional) Object literal with any of the Fx config options
10251          * @return {Roo.Element} The Element
10252          */
10253     slideOut : function(anchor, o){
10254         var el = this.getFxEl();
10255         o = o || {};
10256
10257         el.queueFx(o, function(){
10258
10259             anchor = anchor || "t";
10260
10261             // restore values after effect
10262             var r = this.getFxRestore();
10263             
10264             var b = this.getBox();
10265             // fixed size for slide
10266             this.setSize(b);
10267
10268             // wrap if needed
10269             var wrap = this.fxWrap(r.pos, o, "visible");
10270
10271             var st = this.dom.style;
10272             st.visibility = "visible";
10273             st.position = "absolute";
10274
10275             wrap.setSize(b);
10276
10277             var after = function(){
10278                 if(o.useDisplay){
10279                     el.setDisplayed(false);
10280                 }else{
10281                     el.hide();
10282                 }
10283
10284                 el.fxUnwrap(wrap, r.pos, o);
10285
10286                 st.width = r.width;
10287                 st.height = r.height;
10288
10289                 el.afterFx(o);
10290             };
10291
10292             var a, zero = {to: 0};
10293             switch(anchor.toLowerCase()){
10294                 case "t":
10295                     st.left = st.bottom = "0";
10296                     a = {height: zero};
10297                 break;
10298                 case "l":
10299                     st.right = st.top = "0";
10300                     a = {width: zero};
10301                 break;
10302                 case "r":
10303                     st.left = st.top = "0";
10304                     a = {width: zero, points: {to:[b.right, b.y]}};
10305                 break;
10306                 case "b":
10307                     st.left = st.top = "0";
10308                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10309                 break;
10310                 case "tl":
10311                     st.right = st.bottom = "0";
10312                     a = {width: zero, height: zero};
10313                 break;
10314                 case "bl":
10315                     st.right = st.top = "0";
10316                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10317                 break;
10318                 case "br":
10319                     st.left = st.top = "0";
10320                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10321                 break;
10322                 case "tr":
10323                     st.left = st.bottom = "0";
10324                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10325                 break;
10326             }
10327
10328             arguments.callee.anim = wrap.fxanim(a,
10329                 o,
10330                 'motion',
10331                 .5,
10332                 "easeOut", after);
10333         });
10334         return this;
10335     },
10336
10337         /**
10338          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10339          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10340          * The element must be removed from the DOM using the 'remove' config option if desired.
10341          * Usage:
10342          *<pre><code>
10343 // default
10344 el.puff();
10345
10346 // common config options shown with default values
10347 el.puff({
10348     easing: 'easeOut',
10349     duration: .5,
10350     remove: false,
10351     useDisplay: false
10352 });
10353 </code></pre>
10354          * @param {Object} options (optional) Object literal with any of the Fx config options
10355          * @return {Roo.Element} The Element
10356          */
10357     puff : function(o){
10358         var el = this.getFxEl();
10359         o = o || {};
10360
10361         el.queueFx(o, function(){
10362             this.clearOpacity();
10363             this.show();
10364
10365             // restore values after effect
10366             var r = this.getFxRestore();
10367             var st = this.dom.style;
10368
10369             var after = function(){
10370                 if(o.useDisplay){
10371                     el.setDisplayed(false);
10372                 }else{
10373                     el.hide();
10374                 }
10375
10376                 el.clearOpacity();
10377
10378                 el.setPositioning(r.pos);
10379                 st.width = r.width;
10380                 st.height = r.height;
10381                 st.fontSize = '';
10382                 el.afterFx(o);
10383             };
10384
10385             var width = this.getWidth();
10386             var height = this.getHeight();
10387
10388             arguments.callee.anim = this.fxanim({
10389                     width : {to: this.adjustWidth(width * 2)},
10390                     height : {to: this.adjustHeight(height * 2)},
10391                     points : {by: [-(width * .5), -(height * .5)]},
10392                     opacity : {to: 0},
10393                     fontSize: {to:200, unit: "%"}
10394                 },
10395                 o,
10396                 'motion',
10397                 .5,
10398                 "easeOut", after);
10399         });
10400         return this;
10401     },
10402
10403         /**
10404          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10405          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10406          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10407          * Usage:
10408          *<pre><code>
10409 // default
10410 el.switchOff();
10411
10412 // all config options shown with default values
10413 el.switchOff({
10414     easing: 'easeIn',
10415     duration: .3,
10416     remove: false,
10417     useDisplay: false
10418 });
10419 </code></pre>
10420          * @param {Object} options (optional) Object literal with any of the Fx config options
10421          * @return {Roo.Element} The Element
10422          */
10423     switchOff : function(o){
10424         var el = this.getFxEl();
10425         o = o || {};
10426
10427         el.queueFx(o, function(){
10428             this.clearOpacity();
10429             this.clip();
10430
10431             // restore values after effect
10432             var r = this.getFxRestore();
10433             var st = this.dom.style;
10434
10435             var after = function(){
10436                 if(o.useDisplay){
10437                     el.setDisplayed(false);
10438                 }else{
10439                     el.hide();
10440                 }
10441
10442                 el.clearOpacity();
10443                 el.setPositioning(r.pos);
10444                 st.width = r.width;
10445                 st.height = r.height;
10446
10447                 el.afterFx(o);
10448             };
10449
10450             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10451                 this.clearOpacity();
10452                 (function(){
10453                     this.fxanim({
10454                         height:{to:1},
10455                         points:{by:[0, this.getHeight() * .5]}
10456                     }, o, 'motion', 0.3, 'easeIn', after);
10457                 }).defer(100, this);
10458             });
10459         });
10460         return this;
10461     },
10462
10463     /**
10464      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10465      * changed using the "attr" config option) and then fading back to the original color. If no original
10466      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10467      * Usage:
10468 <pre><code>
10469 // default: highlight background to yellow
10470 el.highlight();
10471
10472 // custom: highlight foreground text to blue for 2 seconds
10473 el.highlight("0000ff", { attr: 'color', duration: 2 });
10474
10475 // common config options shown with default values
10476 el.highlight("ffff9c", {
10477     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10478     endColor: (current color) or "ffffff",
10479     easing: 'easeIn',
10480     duration: 1
10481 });
10482 </code></pre>
10483      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10484      * @param {Object} options (optional) Object literal with any of the Fx config options
10485      * @return {Roo.Element} The Element
10486      */ 
10487     highlight : function(color, o){
10488         var el = this.getFxEl();
10489         o = o || {};
10490
10491         el.queueFx(o, function(){
10492             color = color || "ffff9c";
10493             attr = o.attr || "backgroundColor";
10494
10495             this.clearOpacity();
10496             this.show();
10497
10498             var origColor = this.getColor(attr);
10499             var restoreColor = this.dom.style[attr];
10500             endColor = (o.endColor || origColor) || "ffffff";
10501
10502             var after = function(){
10503                 el.dom.style[attr] = restoreColor;
10504                 el.afterFx(o);
10505             };
10506
10507             var a = {};
10508             a[attr] = {from: color, to: endColor};
10509             arguments.callee.anim = this.fxanim(a,
10510                 o,
10511                 'color',
10512                 1,
10513                 'easeIn', after);
10514         });
10515         return this;
10516     },
10517
10518    /**
10519     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10520     * Usage:
10521 <pre><code>
10522 // default: a single light blue ripple
10523 el.frame();
10524
10525 // custom: 3 red ripples lasting 3 seconds total
10526 el.frame("ff0000", 3, { duration: 3 });
10527
10528 // common config options shown with default values
10529 el.frame("C3DAF9", 1, {
10530     duration: 1 //duration of entire animation (not each individual ripple)
10531     // Note: Easing is not configurable and will be ignored if included
10532 });
10533 </code></pre>
10534     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10535     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10536     * @param {Object} options (optional) Object literal with any of the Fx config options
10537     * @return {Roo.Element} The Element
10538     */
10539     frame : function(color, count, o){
10540         var el = this.getFxEl();
10541         o = o || {};
10542
10543         el.queueFx(o, function(){
10544             color = color || "#C3DAF9";
10545             if(color.length == 6){
10546                 color = "#" + color;
10547             }
10548             count = count || 1;
10549             duration = o.duration || 1;
10550             this.show();
10551
10552             var b = this.getBox();
10553             var animFn = function(){
10554                 var proxy = this.createProxy({
10555
10556                      style:{
10557                         visbility:"hidden",
10558                         position:"absolute",
10559                         "z-index":"35000", // yee haw
10560                         border:"0px solid " + color
10561                      }
10562                   });
10563                 var scale = Roo.isBorderBox ? 2 : 1;
10564                 proxy.animate({
10565                     top:{from:b.y, to:b.y - 20},
10566                     left:{from:b.x, to:b.x - 20},
10567                     borderWidth:{from:0, to:10},
10568                     opacity:{from:1, to:0},
10569                     height:{from:b.height, to:(b.height + (20*scale))},
10570                     width:{from:b.width, to:(b.width + (20*scale))}
10571                 }, duration, function(){
10572                     proxy.remove();
10573                 });
10574                 if(--count > 0){
10575                      animFn.defer((duration/2)*1000, this);
10576                 }else{
10577                     el.afterFx(o);
10578                 }
10579             };
10580             animFn.call(this);
10581         });
10582         return this;
10583     },
10584
10585    /**
10586     * Creates a pause before any subsequent queued effects begin.  If there are
10587     * no effects queued after the pause it will have no effect.
10588     * Usage:
10589 <pre><code>
10590 el.pause(1);
10591 </code></pre>
10592     * @param {Number} seconds The length of time to pause (in seconds)
10593     * @return {Roo.Element} The Element
10594     */
10595     pause : function(seconds){
10596         var el = this.getFxEl();
10597         var o = {};
10598
10599         el.queueFx(o, function(){
10600             setTimeout(function(){
10601                 el.afterFx(o);
10602             }, seconds * 1000);
10603         });
10604         return this;
10605     },
10606
10607    /**
10608     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10609     * using the "endOpacity" config option.
10610     * Usage:
10611 <pre><code>
10612 // default: fade in from opacity 0 to 100%
10613 el.fadeIn();
10614
10615 // custom: fade in from opacity 0 to 75% over 2 seconds
10616 el.fadeIn({ endOpacity: .75, duration: 2});
10617
10618 // common config options shown with default values
10619 el.fadeIn({
10620     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10621     easing: 'easeOut',
10622     duration: .5
10623 });
10624 </code></pre>
10625     * @param {Object} options (optional) Object literal with any of the Fx config options
10626     * @return {Roo.Element} The Element
10627     */
10628     fadeIn : function(o){
10629         var el = this.getFxEl();
10630         o = o || {};
10631         el.queueFx(o, function(){
10632             this.setOpacity(0);
10633             this.fixDisplay();
10634             this.dom.style.visibility = 'visible';
10635             var to = o.endOpacity || 1;
10636             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10637                 o, null, .5, "easeOut", function(){
10638                 if(to == 1){
10639                     this.clearOpacity();
10640                 }
10641                 el.afterFx(o);
10642             });
10643         });
10644         return this;
10645     },
10646
10647    /**
10648     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10649     * using the "endOpacity" config option.
10650     * Usage:
10651 <pre><code>
10652 // default: fade out from the element's current opacity to 0
10653 el.fadeOut();
10654
10655 // custom: fade out from the element's current opacity to 25% over 2 seconds
10656 el.fadeOut({ endOpacity: .25, duration: 2});
10657
10658 // common config options shown with default values
10659 el.fadeOut({
10660     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10661     easing: 'easeOut',
10662     duration: .5
10663     remove: false,
10664     useDisplay: false
10665 });
10666 </code></pre>
10667     * @param {Object} options (optional) Object literal with any of the Fx config options
10668     * @return {Roo.Element} The Element
10669     */
10670     fadeOut : function(o){
10671         var el = this.getFxEl();
10672         o = o || {};
10673         el.queueFx(o, function(){
10674             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10675                 o, null, .5, "easeOut", function(){
10676                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10677                      this.dom.style.display = "none";
10678                 }else{
10679                      this.dom.style.visibility = "hidden";
10680                 }
10681                 this.clearOpacity();
10682                 el.afterFx(o);
10683             });
10684         });
10685         return this;
10686     },
10687
10688    /**
10689     * Animates the transition of an element's dimensions from a starting height/width
10690     * to an ending height/width.
10691     * Usage:
10692 <pre><code>
10693 // change height and width to 100x100 pixels
10694 el.scale(100, 100);
10695
10696 // common config options shown with default values.  The height and width will default to
10697 // the element's existing values if passed as null.
10698 el.scale(
10699     [element's width],
10700     [element's height], {
10701     easing: 'easeOut',
10702     duration: .35
10703 });
10704 </code></pre>
10705     * @param {Number} width  The new width (pass undefined to keep the original width)
10706     * @param {Number} height  The new height (pass undefined to keep the original height)
10707     * @param {Object} options (optional) Object literal with any of the Fx config options
10708     * @return {Roo.Element} The Element
10709     */
10710     scale : function(w, h, o){
10711         this.shift(Roo.apply({}, o, {
10712             width: w,
10713             height: h
10714         }));
10715         return this;
10716     },
10717
10718    /**
10719     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10720     * Any of these properties not specified in the config object will not be changed.  This effect 
10721     * requires that at least one new dimension, position or opacity setting must be passed in on
10722     * the config object in order for the function to have any effect.
10723     * Usage:
10724 <pre><code>
10725 // slide the element horizontally to x position 200 while changing the height and opacity
10726 el.shift({ x: 200, height: 50, opacity: .8 });
10727
10728 // common config options shown with default values.
10729 el.shift({
10730     width: [element's width],
10731     height: [element's height],
10732     x: [element's x position],
10733     y: [element's y position],
10734     opacity: [element's opacity],
10735     easing: 'easeOut',
10736     duration: .35
10737 });
10738 </code></pre>
10739     * @param {Object} options  Object literal with any of the Fx config options
10740     * @return {Roo.Element} The Element
10741     */
10742     shift : function(o){
10743         var el = this.getFxEl();
10744         o = o || {};
10745         el.queueFx(o, function(){
10746             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10747             if(w !== undefined){
10748                 a.width = {to: this.adjustWidth(w)};
10749             }
10750             if(h !== undefined){
10751                 a.height = {to: this.adjustHeight(h)};
10752             }
10753             if(x !== undefined || y !== undefined){
10754                 a.points = {to: [
10755                     x !== undefined ? x : this.getX(),
10756                     y !== undefined ? y : this.getY()
10757                 ]};
10758             }
10759             if(op !== undefined){
10760                 a.opacity = {to: op};
10761             }
10762             if(o.xy !== undefined){
10763                 a.points = {to: o.xy};
10764             }
10765             arguments.callee.anim = this.fxanim(a,
10766                 o, 'motion', .35, "easeOut", function(){
10767                 el.afterFx(o);
10768             });
10769         });
10770         return this;
10771     },
10772
10773         /**
10774          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10775          * ending point of the effect.
10776          * Usage:
10777          *<pre><code>
10778 // default: slide the element downward while fading out
10779 el.ghost();
10780
10781 // custom: slide the element out to the right with a 2-second duration
10782 el.ghost('r', { duration: 2 });
10783
10784 // common config options shown with default values
10785 el.ghost('b', {
10786     easing: 'easeOut',
10787     duration: .5
10788     remove: false,
10789     useDisplay: false
10790 });
10791 </code></pre>
10792          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10793          * @param {Object} options (optional) Object literal with any of the Fx config options
10794          * @return {Roo.Element} The Element
10795          */
10796     ghost : function(anchor, o){
10797         var el = this.getFxEl();
10798         o = o || {};
10799
10800         el.queueFx(o, function(){
10801             anchor = anchor || "b";
10802
10803             // restore values after effect
10804             var r = this.getFxRestore();
10805             var w = this.getWidth(),
10806                 h = this.getHeight();
10807
10808             var st = this.dom.style;
10809
10810             var after = function(){
10811                 if(o.useDisplay){
10812                     el.setDisplayed(false);
10813                 }else{
10814                     el.hide();
10815                 }
10816
10817                 el.clearOpacity();
10818                 el.setPositioning(r.pos);
10819                 st.width = r.width;
10820                 st.height = r.height;
10821
10822                 el.afterFx(o);
10823             };
10824
10825             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10826             switch(anchor.toLowerCase()){
10827                 case "t":
10828                     pt.by = [0, -h];
10829                 break;
10830                 case "l":
10831                     pt.by = [-w, 0];
10832                 break;
10833                 case "r":
10834                     pt.by = [w, 0];
10835                 break;
10836                 case "b":
10837                     pt.by = [0, h];
10838                 break;
10839                 case "tl":
10840                     pt.by = [-w, -h];
10841                 break;
10842                 case "bl":
10843                     pt.by = [-w, h];
10844                 break;
10845                 case "br":
10846                     pt.by = [w, h];
10847                 break;
10848                 case "tr":
10849                     pt.by = [w, -h];
10850                 break;
10851             }
10852
10853             arguments.callee.anim = this.fxanim(a,
10854                 o,
10855                 'motion',
10856                 .5,
10857                 "easeOut", after);
10858         });
10859         return this;
10860     },
10861
10862         /**
10863          * Ensures that all effects queued after syncFx is called on the element are
10864          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10865          * @return {Roo.Element} The Element
10866          */
10867     syncFx : function(){
10868         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10869             block : false,
10870             concurrent : true,
10871             stopFx : false
10872         });
10873         return this;
10874     },
10875
10876         /**
10877          * Ensures that all effects queued after sequenceFx is called on the element are
10878          * run in sequence.  This is the opposite of {@link #syncFx}.
10879          * @return {Roo.Element} The Element
10880          */
10881     sequenceFx : function(){
10882         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10883             block : false,
10884             concurrent : false,
10885             stopFx : false
10886         });
10887         return this;
10888     },
10889
10890         /* @private */
10891     nextFx : function(){
10892         var ef = this.fxQueue[0];
10893         if(ef){
10894             ef.call(this);
10895         }
10896     },
10897
10898         /**
10899          * Returns true if the element has any effects actively running or queued, else returns false.
10900          * @return {Boolean} True if element has active effects, else false
10901          */
10902     hasActiveFx : function(){
10903         return this.fxQueue && this.fxQueue[0];
10904     },
10905
10906         /**
10907          * Stops any running effects and clears the element's internal effects queue if it contains
10908          * any additional effects that haven't started yet.
10909          * @return {Roo.Element} The Element
10910          */
10911     stopFx : function(){
10912         if(this.hasActiveFx()){
10913             var cur = this.fxQueue[0];
10914             if(cur && cur.anim && cur.anim.isAnimated()){
10915                 this.fxQueue = [cur]; // clear out others
10916                 cur.anim.stop(true);
10917             }
10918         }
10919         return this;
10920     },
10921
10922         /* @private */
10923     beforeFx : function(o){
10924         if(this.hasActiveFx() && !o.concurrent){
10925            if(o.stopFx){
10926                this.stopFx();
10927                return true;
10928            }
10929            return false;
10930         }
10931         return true;
10932     },
10933
10934         /**
10935          * Returns true if the element is currently blocking so that no other effect can be queued
10936          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10937          * used to ensure that an effect initiated by a user action runs to completion prior to the
10938          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10939          * @return {Boolean} True if blocking, else false
10940          */
10941     hasFxBlock : function(){
10942         var q = this.fxQueue;
10943         return q && q[0] && q[0].block;
10944     },
10945
10946         /* @private */
10947     queueFx : function(o, fn){
10948         if(!this.fxQueue){
10949             this.fxQueue = [];
10950         }
10951         if(!this.hasFxBlock()){
10952             Roo.applyIf(o, this.fxDefaults);
10953             if(!o.concurrent){
10954                 var run = this.beforeFx(o);
10955                 fn.block = o.block;
10956                 this.fxQueue.push(fn);
10957                 if(run){
10958                     this.nextFx();
10959                 }
10960             }else{
10961                 fn.call(this);
10962             }
10963         }
10964         return this;
10965     },
10966
10967         /* @private */
10968     fxWrap : function(pos, o, vis){
10969         var wrap;
10970         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10971             var wrapXY;
10972             if(o.fixPosition){
10973                 wrapXY = this.getXY();
10974             }
10975             var div = document.createElement("div");
10976             div.style.visibility = vis;
10977             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10978             wrap.setPositioning(pos);
10979             if(wrap.getStyle("position") == "static"){
10980                 wrap.position("relative");
10981             }
10982             this.clearPositioning('auto');
10983             wrap.clip();
10984             wrap.dom.appendChild(this.dom);
10985             if(wrapXY){
10986                 wrap.setXY(wrapXY);
10987             }
10988         }
10989         return wrap;
10990     },
10991
10992         /* @private */
10993     fxUnwrap : function(wrap, pos, o){
10994         this.clearPositioning();
10995         this.setPositioning(pos);
10996         if(!o.wrap){
10997             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10998             wrap.remove();
10999         }
11000     },
11001
11002         /* @private */
11003     getFxRestore : function(){
11004         var st = this.dom.style;
11005         return {pos: this.getPositioning(), width: st.width, height : st.height};
11006     },
11007
11008         /* @private */
11009     afterFx : function(o){
11010         if(o.afterStyle){
11011             this.applyStyles(o.afterStyle);
11012         }
11013         if(o.afterCls){
11014             this.addClass(o.afterCls);
11015         }
11016         if(o.remove === true){
11017             this.remove();
11018         }
11019         Roo.callback(o.callback, o.scope, [this]);
11020         if(!o.concurrent){
11021             this.fxQueue.shift();
11022             this.nextFx();
11023         }
11024     },
11025
11026         /* @private */
11027     getFxEl : function(){ // support for composite element fx
11028         return Roo.get(this.dom);
11029     },
11030
11031         /* @private */
11032     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11033         animType = animType || 'run';
11034         opt = opt || {};
11035         var anim = Roo.lib.Anim[animType](
11036             this.dom, args,
11037             (opt.duration || defaultDur) || .35,
11038             (opt.easing || defaultEase) || 'easeOut',
11039             function(){
11040                 Roo.callback(cb, this);
11041             },
11042             this
11043         );
11044         opt.anim = anim;
11045         return anim;
11046     }
11047 };
11048
11049 // backwords compat
11050 Roo.Fx.resize = Roo.Fx.scale;
11051
11052 //When included, Roo.Fx is automatically applied to Element so that all basic
11053 //effects are available directly via the Element API
11054 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11055  * Based on:
11056  * Ext JS Library 1.1.1
11057  * Copyright(c) 2006-2007, Ext JS, LLC.
11058  *
11059  * Originally Released Under LGPL - original licence link has changed is not relivant.
11060  *
11061  * Fork - LGPL
11062  * <script type="text/javascript">
11063  */
11064
11065
11066 /**
11067  * @class Roo.CompositeElement
11068  * Standard composite class. Creates a Roo.Element for every element in the collection.
11069  * <br><br>
11070  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11071  * actions will be performed on all the elements in this collection.</b>
11072  * <br><br>
11073  * All methods return <i>this</i> and can be chained.
11074  <pre><code>
11075  var els = Roo.select("#some-el div.some-class", true);
11076  // or select directly from an existing element
11077  var el = Roo.get('some-el');
11078  el.select('div.some-class', true);
11079
11080  els.setWidth(100); // all elements become 100 width
11081  els.hide(true); // all elements fade out and hide
11082  // or
11083  els.setWidth(100).hide(true);
11084  </code></pre>
11085  */
11086 Roo.CompositeElement = function(els){
11087     this.elements = [];
11088     this.addElements(els);
11089 };
11090 Roo.CompositeElement.prototype = {
11091     isComposite: true,
11092     addElements : function(els){
11093         if(!els) {
11094             return this;
11095         }
11096         if(typeof els == "string"){
11097             els = Roo.Element.selectorFunction(els);
11098         }
11099         var yels = this.elements;
11100         var index = yels.length-1;
11101         for(var i = 0, len = els.length; i < len; i++) {
11102                 yels[++index] = Roo.get(els[i]);
11103         }
11104         return this;
11105     },
11106
11107     /**
11108     * Clears this composite and adds the elements returned by the passed selector.
11109     * @param {String/Array} els A string CSS selector, an array of elements or an element
11110     * @return {CompositeElement} this
11111     */
11112     fill : function(els){
11113         this.elements = [];
11114         this.add(els);
11115         return this;
11116     },
11117
11118     /**
11119     * Filters this composite to only elements that match the passed selector.
11120     * @param {String} selector A string CSS selector
11121     * @param {Boolean} inverse return inverse filter (not matches)
11122     * @return {CompositeElement} this
11123     */
11124     filter : function(selector, inverse){
11125         var els = [];
11126         inverse = inverse || false;
11127         this.each(function(el){
11128             var match = inverse ? !el.is(selector) : el.is(selector);
11129             if(match){
11130                 els[els.length] = el.dom;
11131             }
11132         });
11133         this.fill(els);
11134         return this;
11135     },
11136
11137     invoke : function(fn, args){
11138         var els = this.elements;
11139         for(var i = 0, len = els.length; i < len; i++) {
11140                 Roo.Element.prototype[fn].apply(els[i], args);
11141         }
11142         return this;
11143     },
11144     /**
11145     * Adds elements to this composite.
11146     * @param {String/Array} els A string CSS selector, an array of elements or an element
11147     * @return {CompositeElement} this
11148     */
11149     add : function(els){
11150         if(typeof els == "string"){
11151             this.addElements(Roo.Element.selectorFunction(els));
11152         }else if(els.length !== undefined){
11153             this.addElements(els);
11154         }else{
11155             this.addElements([els]);
11156         }
11157         return this;
11158     },
11159     /**
11160     * Calls the passed function passing (el, this, index) for each element in this composite.
11161     * @param {Function} fn The function to call
11162     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11163     * @return {CompositeElement} this
11164     */
11165     each : function(fn, scope){
11166         var els = this.elements;
11167         for(var i = 0, len = els.length; i < len; i++){
11168             if(fn.call(scope || els[i], els[i], this, i) === false) {
11169                 break;
11170             }
11171         }
11172         return this;
11173     },
11174
11175     /**
11176      * Returns the Element object at the specified index
11177      * @param {Number} index
11178      * @return {Roo.Element}
11179      */
11180     item : function(index){
11181         return this.elements[index] || null;
11182     },
11183
11184     /**
11185      * Returns the first Element
11186      * @return {Roo.Element}
11187      */
11188     first : function(){
11189         return this.item(0);
11190     },
11191
11192     /**
11193      * Returns the last Element
11194      * @return {Roo.Element}
11195      */
11196     last : function(){
11197         return this.item(this.elements.length-1);
11198     },
11199
11200     /**
11201      * Returns the number of elements in this composite
11202      * @return Number
11203      */
11204     getCount : function(){
11205         return this.elements.length;
11206     },
11207
11208     /**
11209      * Returns true if this composite contains the passed element
11210      * @return Boolean
11211      */
11212     contains : function(el){
11213         return this.indexOf(el) !== -1;
11214     },
11215
11216     /**
11217      * Returns true if this composite contains the passed element
11218      * @return Boolean
11219      */
11220     indexOf : function(el){
11221         return this.elements.indexOf(Roo.get(el));
11222     },
11223
11224
11225     /**
11226     * Removes the specified element(s).
11227     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11228     * or an array of any of those.
11229     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11230     * @return {CompositeElement} this
11231     */
11232     removeElement : function(el, removeDom){
11233         if(el instanceof Array){
11234             for(var i = 0, len = el.length; i < len; i++){
11235                 this.removeElement(el[i]);
11236             }
11237             return this;
11238         }
11239         var index = typeof el == 'number' ? el : this.indexOf(el);
11240         if(index !== -1){
11241             if(removeDom){
11242                 var d = this.elements[index];
11243                 if(d.dom){
11244                     d.remove();
11245                 }else{
11246                     d.parentNode.removeChild(d);
11247                 }
11248             }
11249             this.elements.splice(index, 1);
11250         }
11251         return this;
11252     },
11253
11254     /**
11255     * Replaces the specified element with the passed element.
11256     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11257     * to replace.
11258     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11259     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11260     * @return {CompositeElement} this
11261     */
11262     replaceElement : function(el, replacement, domReplace){
11263         var index = typeof el == 'number' ? el : this.indexOf(el);
11264         if(index !== -1){
11265             if(domReplace){
11266                 this.elements[index].replaceWith(replacement);
11267             }else{
11268                 this.elements.splice(index, 1, Roo.get(replacement))
11269             }
11270         }
11271         return this;
11272     },
11273
11274     /**
11275      * Removes all elements.
11276      */
11277     clear : function(){
11278         this.elements = [];
11279     }
11280 };
11281 (function(){
11282     Roo.CompositeElement.createCall = function(proto, fnName){
11283         if(!proto[fnName]){
11284             proto[fnName] = function(){
11285                 return this.invoke(fnName, arguments);
11286             };
11287         }
11288     };
11289     for(var fnName in Roo.Element.prototype){
11290         if(typeof Roo.Element.prototype[fnName] == "function"){
11291             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11292         }
11293     };
11294 })();
11295 /*
11296  * Based on:
11297  * Ext JS Library 1.1.1
11298  * Copyright(c) 2006-2007, Ext JS, LLC.
11299  *
11300  * Originally Released Under LGPL - original licence link has changed is not relivant.
11301  *
11302  * Fork - LGPL
11303  * <script type="text/javascript">
11304  */
11305
11306 /**
11307  * @class Roo.CompositeElementLite
11308  * @extends Roo.CompositeElement
11309  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11310  <pre><code>
11311  var els = Roo.select("#some-el div.some-class");
11312  // or select directly from an existing element
11313  var el = Roo.get('some-el');
11314  el.select('div.some-class');
11315
11316  els.setWidth(100); // all elements become 100 width
11317  els.hide(true); // all elements fade out and hide
11318  // or
11319  els.setWidth(100).hide(true);
11320  </code></pre><br><br>
11321  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11322  * actions will be performed on all the elements in this collection.</b>
11323  */
11324 Roo.CompositeElementLite = function(els){
11325     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11326     this.el = new Roo.Element.Flyweight();
11327 };
11328 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11329     addElements : function(els){
11330         if(els){
11331             if(els instanceof Array){
11332                 this.elements = this.elements.concat(els);
11333             }else{
11334                 var yels = this.elements;
11335                 var index = yels.length-1;
11336                 for(var i = 0, len = els.length; i < len; i++) {
11337                     yels[++index] = els[i];
11338                 }
11339             }
11340         }
11341         return this;
11342     },
11343     invoke : function(fn, args){
11344         var els = this.elements;
11345         var el = this.el;
11346         for(var i = 0, len = els.length; i < len; i++) {
11347             el.dom = els[i];
11348                 Roo.Element.prototype[fn].apply(el, args);
11349         }
11350         return this;
11351     },
11352     /**
11353      * Returns a flyweight Element of the dom element object at the specified index
11354      * @param {Number} index
11355      * @return {Roo.Element}
11356      */
11357     item : function(index){
11358         if(!this.elements[index]){
11359             return null;
11360         }
11361         this.el.dom = this.elements[index];
11362         return this.el;
11363     },
11364
11365     // fixes scope with flyweight
11366     addListener : function(eventName, handler, scope, opt){
11367         var els = this.elements;
11368         for(var i = 0, len = els.length; i < len; i++) {
11369             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11370         }
11371         return this;
11372     },
11373
11374     /**
11375     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11376     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11377     * a reference to the dom node, use el.dom.</b>
11378     * @param {Function} fn The function to call
11379     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11380     * @return {CompositeElement} this
11381     */
11382     each : function(fn, scope){
11383         var els = this.elements;
11384         var el = this.el;
11385         for(var i = 0, len = els.length; i < len; i++){
11386             el.dom = els[i];
11387                 if(fn.call(scope || el, el, this, i) === false){
11388                 break;
11389             }
11390         }
11391         return this;
11392     },
11393
11394     indexOf : function(el){
11395         return this.elements.indexOf(Roo.getDom(el));
11396     },
11397
11398     replaceElement : function(el, replacement, domReplace){
11399         var index = typeof el == 'number' ? el : this.indexOf(el);
11400         if(index !== -1){
11401             replacement = Roo.getDom(replacement);
11402             if(domReplace){
11403                 var d = this.elements[index];
11404                 d.parentNode.insertBefore(replacement, d);
11405                 d.parentNode.removeChild(d);
11406             }
11407             this.elements.splice(index, 1, replacement);
11408         }
11409         return this;
11410     }
11411 });
11412 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11413
11414 /*
11415  * Based on:
11416  * Ext JS Library 1.1.1
11417  * Copyright(c) 2006-2007, Ext JS, LLC.
11418  *
11419  * Originally Released Under LGPL - original licence link has changed is not relivant.
11420  *
11421  * Fork - LGPL
11422  * <script type="text/javascript">
11423  */
11424
11425  
11426
11427 /**
11428  * @class Roo.data.Connection
11429  * @extends Roo.util.Observable
11430  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11431  * either to a configured URL, or to a URL specified at request time.<br><br>
11432  * <p>
11433  * Requests made by this class are asynchronous, and will return immediately. No data from
11434  * the server will be available to the statement immediately following the {@link #request} call.
11435  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11436  * <p>
11437  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11438  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11439  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11440  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11441  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11442  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11443  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11444  * standard DOM methods.
11445  * @constructor
11446  * @param {Object} config a configuration object.
11447  */
11448 Roo.data.Connection = function(config){
11449     Roo.apply(this, config);
11450     this.addEvents({
11451         /**
11452          * @event beforerequest
11453          * Fires before a network request is made to retrieve a data object.
11454          * @param {Connection} conn This Connection object.
11455          * @param {Object} options The options config object passed to the {@link #request} method.
11456          */
11457         "beforerequest" : true,
11458         /**
11459          * @event requestcomplete
11460          * Fires if the request was successfully completed.
11461          * @param {Connection} conn This Connection object.
11462          * @param {Object} response The XHR object containing the response data.
11463          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11464          * @param {Object} options The options config object passed to the {@link #request} method.
11465          */
11466         "requestcomplete" : true,
11467         /**
11468          * @event requestexception
11469          * Fires if an error HTTP status was returned from the server.
11470          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11471          * @param {Connection} conn This Connection object.
11472          * @param {Object} response The XHR object containing the response data.
11473          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11474          * @param {Object} options The options config object passed to the {@link #request} method.
11475          */
11476         "requestexception" : true
11477     });
11478     Roo.data.Connection.superclass.constructor.call(this);
11479 };
11480
11481 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11482     /**
11483      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11484      */
11485     /**
11486      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11487      * extra parameters to each request made by this object. (defaults to undefined)
11488      */
11489     /**
11490      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11491      *  to each request made by this object. (defaults to undefined)
11492      */
11493     /**
11494      * @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)
11495      */
11496     /**
11497      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11498      */
11499     timeout : 30000,
11500     /**
11501      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11502      * @type Boolean
11503      */
11504     autoAbort:false,
11505
11506     /**
11507      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11508      * @type Boolean
11509      */
11510     disableCaching: true,
11511
11512     /**
11513      * Sends an HTTP request to a remote server.
11514      * @param {Object} options An object which may contain the following properties:<ul>
11515      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11516      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11517      * request, a url encoded string or a function to call to get either.</li>
11518      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11519      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11520      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11521      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11522      * <li>options {Object} The parameter to the request call.</li>
11523      * <li>success {Boolean} True if the request succeeded.</li>
11524      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11525      * </ul></li>
11526      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11527      * The callback is passed the following parameters:<ul>
11528      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11529      * <li>options {Object} The parameter to the request call.</li>
11530      * </ul></li>
11531      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11532      * The callback is passed the following parameters:<ul>
11533      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11534      * <li>options {Object} The parameter to the request call.</li>
11535      * </ul></li>
11536      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11537      * for the callback function. Defaults to the browser window.</li>
11538      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11539      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11540      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11541      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11542      * params for the post data. Any params will be appended to the URL.</li>
11543      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11544      * </ul>
11545      * @return {Number} transactionId
11546      */
11547     request : function(o){
11548         if(this.fireEvent("beforerequest", this, o) !== false){
11549             var p = o.params;
11550
11551             if(typeof p == "function"){
11552                 p = p.call(o.scope||window, o);
11553             }
11554             if(typeof p == "object"){
11555                 p = Roo.urlEncode(o.params);
11556             }
11557             if(this.extraParams){
11558                 var extras = Roo.urlEncode(this.extraParams);
11559                 p = p ? (p + '&' + extras) : extras;
11560             }
11561
11562             var url = o.url || this.url;
11563             if(typeof url == 'function'){
11564                 url = url.call(o.scope||window, o);
11565             }
11566
11567             if(o.form){
11568                 var form = Roo.getDom(o.form);
11569                 url = url || form.action;
11570
11571                 var enctype = form.getAttribute("enctype");
11572                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11573                     return this.doFormUpload(o, p, url);
11574                 }
11575                 var f = Roo.lib.Ajax.serializeForm(form);
11576                 p = p ? (p + '&' + f) : f;
11577             }
11578
11579             var hs = o.headers;
11580             if(this.defaultHeaders){
11581                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11582                 if(!o.headers){
11583                     o.headers = hs;
11584                 }
11585             }
11586
11587             var cb = {
11588                 success: this.handleResponse,
11589                 failure: this.handleFailure,
11590                 scope: this,
11591                 argument: {options: o},
11592                 timeout : o.timeout || this.timeout
11593             };
11594
11595             var method = o.method||this.method||(p ? "POST" : "GET");
11596
11597             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11598                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11599             }
11600
11601             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11602                 if(o.autoAbort){
11603                     this.abort();
11604                 }
11605             }else if(this.autoAbort !== false){
11606                 this.abort();
11607             }
11608
11609             if((method == 'GET' && p) || o.xmlData){
11610                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11611                 p = '';
11612             }
11613             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11614             return this.transId;
11615         }else{
11616             Roo.callback(o.callback, o.scope, [o, null, null]);
11617             return null;
11618         }
11619     },
11620
11621     /**
11622      * Determine whether this object has a request outstanding.
11623      * @param {Number} transactionId (Optional) defaults to the last transaction
11624      * @return {Boolean} True if there is an outstanding request.
11625      */
11626     isLoading : function(transId){
11627         if(transId){
11628             return Roo.lib.Ajax.isCallInProgress(transId);
11629         }else{
11630             return this.transId ? true : false;
11631         }
11632     },
11633
11634     /**
11635      * Aborts any outstanding request.
11636      * @param {Number} transactionId (Optional) defaults to the last transaction
11637      */
11638     abort : function(transId){
11639         if(transId || this.isLoading()){
11640             Roo.lib.Ajax.abort(transId || this.transId);
11641         }
11642     },
11643
11644     // private
11645     handleResponse : function(response){
11646         this.transId = false;
11647         var options = response.argument.options;
11648         response.argument = options ? options.argument : null;
11649         this.fireEvent("requestcomplete", this, response, options);
11650         Roo.callback(options.success, options.scope, [response, options]);
11651         Roo.callback(options.callback, options.scope, [options, true, response]);
11652     },
11653
11654     // private
11655     handleFailure : function(response, e){
11656         this.transId = false;
11657         var options = response.argument.options;
11658         response.argument = options ? options.argument : null;
11659         this.fireEvent("requestexception", this, response, options, e);
11660         Roo.callback(options.failure, options.scope, [response, options]);
11661         Roo.callback(options.callback, options.scope, [options, false, response]);
11662     },
11663
11664     // private
11665     doFormUpload : function(o, ps, url){
11666         var id = Roo.id();
11667         var frame = document.createElement('iframe');
11668         frame.id = id;
11669         frame.name = id;
11670         frame.className = 'x-hidden';
11671         if(Roo.isIE){
11672             frame.src = Roo.SSL_SECURE_URL;
11673         }
11674         document.body.appendChild(frame);
11675
11676         if(Roo.isIE){
11677            document.frames[id].name = id;
11678         }
11679
11680         var form = Roo.getDom(o.form);
11681         form.target = id;
11682         form.method = 'POST';
11683         form.enctype = form.encoding = 'multipart/form-data';
11684         if(url){
11685             form.action = url;
11686         }
11687
11688         var hiddens, hd;
11689         if(ps){ // add dynamic params
11690             hiddens = [];
11691             ps = Roo.urlDecode(ps, false);
11692             for(var k in ps){
11693                 if(ps.hasOwnProperty(k)){
11694                     hd = document.createElement('input');
11695                     hd.type = 'hidden';
11696                     hd.name = k;
11697                     hd.value = ps[k];
11698                     form.appendChild(hd);
11699                     hiddens.push(hd);
11700                 }
11701             }
11702         }
11703
11704         function cb(){
11705             var r = {  // bogus response object
11706                 responseText : '',
11707                 responseXML : null
11708             };
11709
11710             r.argument = o ? o.argument : null;
11711
11712             try { //
11713                 var doc;
11714                 if(Roo.isIE){
11715                     doc = frame.contentWindow.document;
11716                 }else {
11717                     doc = (frame.contentDocument || window.frames[id].document);
11718                 }
11719                 if(doc && doc.body){
11720                     r.responseText = doc.body.innerHTML;
11721                 }
11722                 if(doc && doc.XMLDocument){
11723                     r.responseXML = doc.XMLDocument;
11724                 }else {
11725                     r.responseXML = doc;
11726                 }
11727             }
11728             catch(e) {
11729                 // ignore
11730             }
11731
11732             Roo.EventManager.removeListener(frame, 'load', cb, this);
11733
11734             this.fireEvent("requestcomplete", this, r, o);
11735             Roo.callback(o.success, o.scope, [r, o]);
11736             Roo.callback(o.callback, o.scope, [o, true, r]);
11737
11738             setTimeout(function(){document.body.removeChild(frame);}, 100);
11739         }
11740
11741         Roo.EventManager.on(frame, 'load', cb, this);
11742         form.submit();
11743
11744         if(hiddens){ // remove dynamic params
11745             for(var i = 0, len = hiddens.length; i < len; i++){
11746                 form.removeChild(hiddens[i]);
11747             }
11748         }
11749     }
11750 });
11751 /*
11752  * Based on:
11753  * Ext JS Library 1.1.1
11754  * Copyright(c) 2006-2007, Ext JS, LLC.
11755  *
11756  * Originally Released Under LGPL - original licence link has changed is not relivant.
11757  *
11758  * Fork - LGPL
11759  * <script type="text/javascript">
11760  */
11761  
11762 /**
11763  * Global Ajax request class.
11764  * 
11765  * @class Roo.Ajax
11766  * @extends Roo.data.Connection
11767  * @static
11768  * 
11769  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11770  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11771  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11772  * @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)
11773  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11774  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11775  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11776  */
11777 Roo.Ajax = new Roo.data.Connection({
11778     // fix up the docs
11779     /**
11780      * @scope Roo.Ajax
11781      * @type {Boolear} 
11782      */
11783     autoAbort : false,
11784
11785     /**
11786      * Serialize the passed form into a url encoded string
11787      * @scope Roo.Ajax
11788      * @param {String/HTMLElement} form
11789      * @return {String}
11790      */
11791     serializeForm : function(form){
11792         return Roo.lib.Ajax.serializeForm(form);
11793     }
11794 });/*
11795  * Based on:
11796  * Ext JS Library 1.1.1
11797  * Copyright(c) 2006-2007, Ext JS, LLC.
11798  *
11799  * Originally Released Under LGPL - original licence link has changed is not relivant.
11800  *
11801  * Fork - LGPL
11802  * <script type="text/javascript">
11803  */
11804
11805  
11806 /**
11807  * @class Roo.UpdateManager
11808  * @extends Roo.util.Observable
11809  * Provides AJAX-style update for Element object.<br><br>
11810  * Usage:<br>
11811  * <pre><code>
11812  * // Get it from a Roo.Element object
11813  * var el = Roo.get("foo");
11814  * var mgr = el.getUpdateManager();
11815  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11816  * ...
11817  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11818  * <br>
11819  * // or directly (returns the same UpdateManager instance)
11820  * var mgr = new Roo.UpdateManager("myElementId");
11821  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11822  * mgr.on("update", myFcnNeedsToKnow);
11823  * <br>
11824    // short handed call directly from the element object
11825    Roo.get("foo").load({
11826         url: "bar.php",
11827         scripts:true,
11828         params: "for=bar",
11829         text: "Loading Foo..."
11830    });
11831  * </code></pre>
11832  * @constructor
11833  * Create new UpdateManager directly.
11834  * @param {String/HTMLElement/Roo.Element} el The element to update
11835  * @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).
11836  */
11837 Roo.UpdateManager = function(el, forceNew){
11838     el = Roo.get(el);
11839     if(!forceNew && el.updateManager){
11840         return el.updateManager;
11841     }
11842     /**
11843      * The Element object
11844      * @type Roo.Element
11845      */
11846     this.el = el;
11847     /**
11848      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11849      * @type String
11850      */
11851     this.defaultUrl = null;
11852
11853     this.addEvents({
11854         /**
11855          * @event beforeupdate
11856          * Fired before an update is made, return false from your handler and the update is cancelled.
11857          * @param {Roo.Element} el
11858          * @param {String/Object/Function} url
11859          * @param {String/Object} params
11860          */
11861         "beforeupdate": true,
11862         /**
11863          * @event update
11864          * Fired after successful update is made.
11865          * @param {Roo.Element} el
11866          * @param {Object} oResponseObject The response Object
11867          */
11868         "update": true,
11869         /**
11870          * @event failure
11871          * Fired on update failure.
11872          * @param {Roo.Element} el
11873          * @param {Object} oResponseObject The response Object
11874          */
11875         "failure": true
11876     });
11877     var d = Roo.UpdateManager.defaults;
11878     /**
11879      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11880      * @type String
11881      */
11882     this.sslBlankUrl = d.sslBlankUrl;
11883     /**
11884      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11885      * @type Boolean
11886      */
11887     this.disableCaching = d.disableCaching;
11888     /**
11889      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11890      * @type String
11891      */
11892     this.indicatorText = d.indicatorText;
11893     /**
11894      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11895      * @type String
11896      */
11897     this.showLoadIndicator = d.showLoadIndicator;
11898     /**
11899      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11900      * @type Number
11901      */
11902     this.timeout = d.timeout;
11903
11904     /**
11905      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11906      * @type Boolean
11907      */
11908     this.loadScripts = d.loadScripts;
11909
11910     /**
11911      * Transaction object of current executing transaction
11912      */
11913     this.transaction = null;
11914
11915     /**
11916      * @private
11917      */
11918     this.autoRefreshProcId = null;
11919     /**
11920      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11921      * @type Function
11922      */
11923     this.refreshDelegate = this.refresh.createDelegate(this);
11924     /**
11925      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11926      * @type Function
11927      */
11928     this.updateDelegate = this.update.createDelegate(this);
11929     /**
11930      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11931      * @type Function
11932      */
11933     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11934     /**
11935      * @private
11936      */
11937     this.successDelegate = this.processSuccess.createDelegate(this);
11938     /**
11939      * @private
11940      */
11941     this.failureDelegate = this.processFailure.createDelegate(this);
11942
11943     if(!this.renderer){
11944      /**
11945       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11946       */
11947     this.renderer = new Roo.UpdateManager.BasicRenderer();
11948     }
11949     
11950     Roo.UpdateManager.superclass.constructor.call(this);
11951 };
11952
11953 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11954     /**
11955      * Get the Element this UpdateManager is bound to
11956      * @return {Roo.Element} The element
11957      */
11958     getEl : function(){
11959         return this.el;
11960     },
11961     /**
11962      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11963      * @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:
11964 <pre><code>
11965 um.update({<br/>
11966     url: "your-url.php",<br/>
11967     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11968     callback: yourFunction,<br/>
11969     scope: yourObject, //(optional scope)  <br/>
11970     discardUrl: false, <br/>
11971     nocache: false,<br/>
11972     text: "Loading...",<br/>
11973     timeout: 30,<br/>
11974     scripts: false<br/>
11975 });
11976 </code></pre>
11977      * The only required property is url. The optional properties nocache, text and scripts
11978      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11979      * @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}
11980      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11981      * @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.
11982      */
11983     update : function(url, params, callback, discardUrl){
11984         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11985             var method = this.method,
11986                 cfg;
11987             if(typeof url == "object"){ // must be config object
11988                 cfg = url;
11989                 url = cfg.url;
11990                 params = params || cfg.params;
11991                 callback = callback || cfg.callback;
11992                 discardUrl = discardUrl || cfg.discardUrl;
11993                 if(callback && cfg.scope){
11994                     callback = callback.createDelegate(cfg.scope);
11995                 }
11996                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11997                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11998                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11999                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12000                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12001             }
12002             this.showLoading();
12003             if(!discardUrl){
12004                 this.defaultUrl = url;
12005             }
12006             if(typeof url == "function"){
12007                 url = url.call(this);
12008             }
12009
12010             method = method || (params ? "POST" : "GET");
12011             if(method == "GET"){
12012                 url = this.prepareUrl(url);
12013             }
12014
12015             var o = Roo.apply(cfg ||{}, {
12016                 url : url,
12017                 params: params,
12018                 success: this.successDelegate,
12019                 failure: this.failureDelegate,
12020                 callback: undefined,
12021                 timeout: (this.timeout*1000),
12022                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12023             });
12024             Roo.log("updated manager called with timeout of " + o.timeout);
12025             this.transaction = Roo.Ajax.request(o);
12026         }
12027     },
12028
12029     /**
12030      * 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.
12031      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12032      * @param {String/HTMLElement} form The form Id or form element
12033      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12034      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12035      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12036      */
12037     formUpdate : function(form, url, reset, callback){
12038         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12039             if(typeof url == "function"){
12040                 url = url.call(this);
12041             }
12042             form = Roo.getDom(form);
12043             this.transaction = Roo.Ajax.request({
12044                 form: form,
12045                 url:url,
12046                 success: this.successDelegate,
12047                 failure: this.failureDelegate,
12048                 timeout: (this.timeout*1000),
12049                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12050             });
12051             this.showLoading.defer(1, this);
12052         }
12053     },
12054
12055     /**
12056      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12057      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12058      */
12059     refresh : function(callback){
12060         if(this.defaultUrl == null){
12061             return;
12062         }
12063         this.update(this.defaultUrl, null, callback, true);
12064     },
12065
12066     /**
12067      * Set this element to auto refresh.
12068      * @param {Number} interval How often to update (in seconds).
12069      * @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)
12070      * @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}
12071      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12072      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12073      */
12074     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12075         if(refreshNow){
12076             this.update(url || this.defaultUrl, params, callback, true);
12077         }
12078         if(this.autoRefreshProcId){
12079             clearInterval(this.autoRefreshProcId);
12080         }
12081         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12082     },
12083
12084     /**
12085      * Stop auto refresh on this element.
12086      */
12087      stopAutoRefresh : function(){
12088         if(this.autoRefreshProcId){
12089             clearInterval(this.autoRefreshProcId);
12090             delete this.autoRefreshProcId;
12091         }
12092     },
12093
12094     isAutoRefreshing : function(){
12095        return this.autoRefreshProcId ? true : false;
12096     },
12097     /**
12098      * Called to update the element to "Loading" state. Override to perform custom action.
12099      */
12100     showLoading : function(){
12101         if(this.showLoadIndicator){
12102             this.el.update(this.indicatorText);
12103         }
12104     },
12105
12106     /**
12107      * Adds unique parameter to query string if disableCaching = true
12108      * @private
12109      */
12110     prepareUrl : function(url){
12111         if(this.disableCaching){
12112             var append = "_dc=" + (new Date().getTime());
12113             if(url.indexOf("?") !== -1){
12114                 url += "&" + append;
12115             }else{
12116                 url += "?" + append;
12117             }
12118         }
12119         return url;
12120     },
12121
12122     /**
12123      * @private
12124      */
12125     processSuccess : function(response){
12126         this.transaction = null;
12127         if(response.argument.form && response.argument.reset){
12128             try{ // put in try/catch since some older FF releases had problems with this
12129                 response.argument.form.reset();
12130             }catch(e){}
12131         }
12132         if(this.loadScripts){
12133             this.renderer.render(this.el, response, this,
12134                 this.updateComplete.createDelegate(this, [response]));
12135         }else{
12136             this.renderer.render(this.el, response, this);
12137             this.updateComplete(response);
12138         }
12139     },
12140
12141     updateComplete : function(response){
12142         this.fireEvent("update", this.el, response);
12143         if(typeof response.argument.callback == "function"){
12144             response.argument.callback(this.el, true, response);
12145         }
12146     },
12147
12148     /**
12149      * @private
12150      */
12151     processFailure : function(response){
12152         this.transaction = null;
12153         this.fireEvent("failure", this.el, response);
12154         if(typeof response.argument.callback == "function"){
12155             response.argument.callback(this.el, false, response);
12156         }
12157     },
12158
12159     /**
12160      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12161      * @param {Object} renderer The object implementing the render() method
12162      */
12163     setRenderer : function(renderer){
12164         this.renderer = renderer;
12165     },
12166
12167     getRenderer : function(){
12168        return this.renderer;
12169     },
12170
12171     /**
12172      * Set the defaultUrl used for updates
12173      * @param {String/Function} defaultUrl The url or a function to call to get the url
12174      */
12175     setDefaultUrl : function(defaultUrl){
12176         this.defaultUrl = defaultUrl;
12177     },
12178
12179     /**
12180      * Aborts the executing transaction
12181      */
12182     abort : function(){
12183         if(this.transaction){
12184             Roo.Ajax.abort(this.transaction);
12185         }
12186     },
12187
12188     /**
12189      * Returns true if an update is in progress
12190      * @return {Boolean}
12191      */
12192     isUpdating : function(){
12193         if(this.transaction){
12194             return Roo.Ajax.isLoading(this.transaction);
12195         }
12196         return false;
12197     }
12198 });
12199
12200 /**
12201  * @class Roo.UpdateManager.defaults
12202  * @static (not really - but it helps the doc tool)
12203  * The defaults collection enables customizing the default properties of UpdateManager
12204  */
12205    Roo.UpdateManager.defaults = {
12206        /**
12207          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12208          * @type Number
12209          */
12210          timeout : 30,
12211
12212          /**
12213          * True to process scripts by default (Defaults to false).
12214          * @type Boolean
12215          */
12216         loadScripts : false,
12217
12218         /**
12219         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12220         * @type String
12221         */
12222         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12223         /**
12224          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12225          * @type Boolean
12226          */
12227         disableCaching : false,
12228         /**
12229          * Whether to show indicatorText when loading (Defaults to true).
12230          * @type Boolean
12231          */
12232         showLoadIndicator : true,
12233         /**
12234          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12235          * @type String
12236          */
12237         indicatorText : '<div class="loading-indicator">Loading...</div>'
12238    };
12239
12240 /**
12241  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12242  *Usage:
12243  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12244  * @param {String/HTMLElement/Roo.Element} el The element to update
12245  * @param {String} url The url
12246  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12247  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12248  * @static
12249  * @deprecated
12250  * @member Roo.UpdateManager
12251  */
12252 Roo.UpdateManager.updateElement = function(el, url, params, options){
12253     var um = Roo.get(el, true).getUpdateManager();
12254     Roo.apply(um, options);
12255     um.update(url, params, options ? options.callback : null);
12256 };
12257 // alias for backwards compat
12258 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12259 /**
12260  * @class Roo.UpdateManager.BasicRenderer
12261  * Default Content renderer. Updates the elements innerHTML with the responseText.
12262  */
12263 Roo.UpdateManager.BasicRenderer = function(){};
12264
12265 Roo.UpdateManager.BasicRenderer.prototype = {
12266     /**
12267      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12268      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12269      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12270      * @param {Roo.Element} el The element being rendered
12271      * @param {Object} response The YUI Connect response object
12272      * @param {UpdateManager} updateManager The calling update manager
12273      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12274      */
12275      render : function(el, response, updateManager, callback){
12276         el.update(response.responseText, updateManager.loadScripts, callback);
12277     }
12278 };
12279 /*
12280  * Based on:
12281  * Roo JS
12282  * (c)) Alan Knowles
12283  * Licence : LGPL
12284  */
12285
12286
12287 /**
12288  * @class Roo.DomTemplate
12289  * @extends Roo.Template
12290  * An effort at a dom based template engine..
12291  *
12292  * Similar to XTemplate, except it uses dom parsing to create the template..
12293  *
12294  * Supported features:
12295  *
12296  *  Tags:
12297
12298 <pre><code>
12299       {a_variable} - output encoded.
12300       {a_variable.format:("Y-m-d")} - call a method on the variable
12301       {a_variable:raw} - unencoded output
12302       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12303       {a_variable:this.method_on_template(...)} - call a method on the template object.
12304  
12305 </code></pre>
12306  *  The tpl tag:
12307 <pre><code>
12308         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12309         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12310         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12311         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12312   
12313 </code></pre>
12314  *      
12315  */
12316 Roo.DomTemplate = function()
12317 {
12318      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12319      if (this.html) {
12320         this.compile();
12321      }
12322 };
12323
12324
12325 Roo.extend(Roo.DomTemplate, Roo.Template, {
12326     /**
12327      * id counter for sub templates.
12328      */
12329     id : 0,
12330     /**
12331      * flag to indicate if dom parser is inside a pre,
12332      * it will strip whitespace if not.
12333      */
12334     inPre : false,
12335     
12336     /**
12337      * The various sub templates
12338      */
12339     tpls : false,
12340     
12341     
12342     
12343     /**
12344      *
12345      * basic tag replacing syntax
12346      * WORD:WORD()
12347      *
12348      * // you can fake an object call by doing this
12349      *  x.t:(test,tesT) 
12350      * 
12351      */
12352     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12353     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12354     
12355     iterChild : function (node, method) {
12356         
12357         var oldPre = this.inPre;
12358         if (node.tagName == 'PRE') {
12359             this.inPre = true;
12360         }
12361         for( var i = 0; i < node.childNodes.length; i++) {
12362             method.call(this, node.childNodes[i]);
12363         }
12364         this.inPre = oldPre;
12365     },
12366     
12367     
12368     
12369     /**
12370      * compile the template
12371      *
12372      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12373      *
12374      */
12375     compile: function()
12376     {
12377         var s = this.html;
12378         
12379         // covert the html into DOM...
12380         var doc = false;
12381         var div =false;
12382         try {
12383             doc = document.implementation.createHTMLDocument("");
12384             doc.documentElement.innerHTML =   this.html  ;
12385             div = doc.documentElement;
12386         } catch (e) {
12387             // old IE... - nasty -- it causes all sorts of issues.. with
12388             // images getting pulled from server..
12389             div = document.createElement('div');
12390             div.innerHTML = this.html;
12391         }
12392         //doc.documentElement.innerHTML = htmlBody
12393          
12394         
12395         
12396         this.tpls = [];
12397         var _t = this;
12398         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12399         
12400         var tpls = this.tpls;
12401         
12402         // create a top level template from the snippet..
12403         
12404         //Roo.log(div.innerHTML);
12405         
12406         var tpl = {
12407             uid : 'master',
12408             id : this.id++,
12409             attr : false,
12410             value : false,
12411             body : div.innerHTML,
12412             
12413             forCall : false,
12414             execCall : false,
12415             dom : div,
12416             isTop : true
12417             
12418         };
12419         tpls.unshift(tpl);
12420         
12421         
12422         // compile them...
12423         this.tpls = [];
12424         Roo.each(tpls, function(tp){
12425             this.compileTpl(tp);
12426             this.tpls[tp.id] = tp;
12427         }, this);
12428         
12429         this.master = tpls[0];
12430         return this;
12431         
12432         
12433     },
12434     
12435     compileNode : function(node, istop) {
12436         // test for
12437         //Roo.log(node);
12438         
12439         
12440         // skip anything not a tag..
12441         if (node.nodeType != 1) {
12442             if (node.nodeType == 3 && !this.inPre) {
12443                 // reduce white space..
12444                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12445                 
12446             }
12447             return;
12448         }
12449         
12450         var tpl = {
12451             uid : false,
12452             id : false,
12453             attr : false,
12454             value : false,
12455             body : '',
12456             
12457             forCall : false,
12458             execCall : false,
12459             dom : false,
12460             isTop : istop
12461             
12462             
12463         };
12464         
12465         
12466         switch(true) {
12467             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12468             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12469             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12470             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12471             // no default..
12472         }
12473         
12474         
12475         if (!tpl.attr) {
12476             // just itterate children..
12477             this.iterChild(node,this.compileNode);
12478             return;
12479         }
12480         tpl.uid = this.id++;
12481         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12482         node.removeAttribute('roo-'+ tpl.attr);
12483         if (tpl.attr != 'name') {
12484             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12485             node.parentNode.replaceChild(placeholder,  node);
12486         } else {
12487             
12488             var placeholder =  document.createElement('span');
12489             placeholder.className = 'roo-tpl-' + tpl.value;
12490             node.parentNode.replaceChild(placeholder,  node);
12491         }
12492         
12493         // parent now sees '{domtplXXXX}
12494         this.iterChild(node,this.compileNode);
12495         
12496         // we should now have node body...
12497         var div = document.createElement('div');
12498         div.appendChild(node);
12499         tpl.dom = node;
12500         // this has the unfortunate side effect of converting tagged attributes
12501         // eg. href="{...}" into %7C...%7D
12502         // this has been fixed by searching for those combo's although it's a bit hacky..
12503         
12504         
12505         tpl.body = div.innerHTML;
12506         
12507         
12508          
12509         tpl.id = tpl.uid;
12510         switch(tpl.attr) {
12511             case 'for' :
12512                 switch (tpl.value) {
12513                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12514                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12515                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12516                 }
12517                 break;
12518             
12519             case 'exec':
12520                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12521                 break;
12522             
12523             case 'if':     
12524                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12525                 break;
12526             
12527             case 'name':
12528                 tpl.id  = tpl.value; // replace non characters???
12529                 break;
12530             
12531         }
12532         
12533         
12534         this.tpls.push(tpl);
12535         
12536         
12537         
12538     },
12539     
12540     
12541     
12542     
12543     /**
12544      * Compile a segment of the template into a 'sub-template'
12545      *
12546      * 
12547      * 
12548      *
12549      */
12550     compileTpl : function(tpl)
12551     {
12552         var fm = Roo.util.Format;
12553         var useF = this.disableFormats !== true;
12554         
12555         var sep = Roo.isGecko ? "+\n" : ",\n";
12556         
12557         var undef = function(str) {
12558             Roo.debug && Roo.log("Property not found :"  + str);
12559             return '';
12560         };
12561           
12562         //Roo.log(tpl.body);
12563         
12564         
12565         
12566         var fn = function(m, lbrace, name, format, args)
12567         {
12568             //Roo.log("ARGS");
12569             //Roo.log(arguments);
12570             args = args ? args.replace(/\\'/g,"'") : args;
12571             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12572             if (typeof(format) == 'undefined') {
12573                 format =  'htmlEncode'; 
12574             }
12575             if (format == 'raw' ) {
12576                 format = false;
12577             }
12578             
12579             if(name.substr(0, 6) == 'domtpl'){
12580                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12581             }
12582             
12583             // build an array of options to determine if value is undefined..
12584             
12585             // basically get 'xxxx.yyyy' then do
12586             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12587             //    (function () { Roo.log("Property not found"); return ''; })() :
12588             //    ......
12589             
12590             var udef_ar = [];
12591             var lookfor = '';
12592             Roo.each(name.split('.'), function(st) {
12593                 lookfor += (lookfor.length ? '.': '') + st;
12594                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12595             });
12596             
12597             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12598             
12599             
12600             if(format && useF){
12601                 
12602                 args = args ? ',' + args : "";
12603                  
12604                 if(format.substr(0, 5) != "this."){
12605                     format = "fm." + format + '(';
12606                 }else{
12607                     format = 'this.call("'+ format.substr(5) + '", ';
12608                     args = ", values";
12609                 }
12610                 
12611                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12612             }
12613              
12614             if (args && args.length) {
12615                 // called with xxyx.yuu:(test,test)
12616                 // change to ()
12617                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12618             }
12619             // raw.. - :raw modifier..
12620             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12621             
12622         };
12623         var body;
12624         // branched to use + in gecko and [].join() in others
12625         if(Roo.isGecko){
12626             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12627                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12628                     "';};};";
12629         }else{
12630             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12631             body.push(tpl.body.replace(/(\r\n|\n)/g,
12632                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12633             body.push("'].join('');};};");
12634             body = body.join('');
12635         }
12636         
12637         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12638        
12639         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12640         eval(body);
12641         
12642         return this;
12643     },
12644      
12645     /**
12646      * same as applyTemplate, except it's done to one of the subTemplates
12647      * when using named templates, you can do:
12648      *
12649      * var str = pl.applySubTemplate('your-name', values);
12650      *
12651      * 
12652      * @param {Number} id of the template
12653      * @param {Object} values to apply to template
12654      * @param {Object} parent (normaly the instance of this object)
12655      */
12656     applySubTemplate : function(id, values, parent)
12657     {
12658         
12659         
12660         var t = this.tpls[id];
12661         
12662         
12663         try { 
12664             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12665                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12666                 return '';
12667             }
12668         } catch(e) {
12669             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12670             Roo.log(values);
12671           
12672             return '';
12673         }
12674         try { 
12675             
12676             if(t.execCall && t.execCall.call(this, values, parent)){
12677                 return '';
12678             }
12679         } catch(e) {
12680             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12681             Roo.log(values);
12682             return '';
12683         }
12684         
12685         try {
12686             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12687             parent = t.target ? values : parent;
12688             if(t.forCall && vs instanceof Array){
12689                 var buf = [];
12690                 for(var i = 0, len = vs.length; i < len; i++){
12691                     try {
12692                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12693                     } catch (e) {
12694                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12695                         Roo.log(e.body);
12696                         //Roo.log(t.compiled);
12697                         Roo.log(vs[i]);
12698                     }   
12699                 }
12700                 return buf.join('');
12701             }
12702         } catch (e) {
12703             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12704             Roo.log(values);
12705             return '';
12706         }
12707         try {
12708             return t.compiled.call(this, vs, parent);
12709         } catch (e) {
12710             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12711             Roo.log(e.body);
12712             //Roo.log(t.compiled);
12713             Roo.log(values);
12714             return '';
12715         }
12716     },
12717
12718    
12719
12720     applyTemplate : function(values){
12721         return this.master.compiled.call(this, values, {});
12722         //var s = this.subs;
12723     },
12724
12725     apply : function(){
12726         return this.applyTemplate.apply(this, arguments);
12727     }
12728
12729  });
12730
12731 Roo.DomTemplate.from = function(el){
12732     el = Roo.getDom(el);
12733     return new Roo.Domtemplate(el.value || el.innerHTML);
12734 };/*
12735  * Based on:
12736  * Ext JS Library 1.1.1
12737  * Copyright(c) 2006-2007, Ext JS, LLC.
12738  *
12739  * Originally Released Under LGPL - original licence link has changed is not relivant.
12740  *
12741  * Fork - LGPL
12742  * <script type="text/javascript">
12743  */
12744
12745 /**
12746  * @class Roo.util.DelayedTask
12747  * Provides a convenient method of performing setTimeout where a new
12748  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12749  * You can use this class to buffer
12750  * the keypress events for a certain number of milliseconds, and perform only if they stop
12751  * for that amount of time.
12752  * @constructor The parameters to this constructor serve as defaults and are not required.
12753  * @param {Function} fn (optional) The default function to timeout
12754  * @param {Object} scope (optional) The default scope of that timeout
12755  * @param {Array} args (optional) The default Array of arguments
12756  */
12757 Roo.util.DelayedTask = function(fn, scope, args){
12758     var id = null, d, t;
12759
12760     var call = function(){
12761         var now = new Date().getTime();
12762         if(now - t >= d){
12763             clearInterval(id);
12764             id = null;
12765             fn.apply(scope, args || []);
12766         }
12767     };
12768     /**
12769      * Cancels any pending timeout and queues a new one
12770      * @param {Number} delay The milliseconds to delay
12771      * @param {Function} newFn (optional) Overrides function passed to constructor
12772      * @param {Object} newScope (optional) Overrides scope passed to constructor
12773      * @param {Array} newArgs (optional) Overrides args passed to constructor
12774      */
12775     this.delay = function(delay, newFn, newScope, newArgs){
12776         if(id && delay != d){
12777             this.cancel();
12778         }
12779         d = delay;
12780         t = new Date().getTime();
12781         fn = newFn || fn;
12782         scope = newScope || scope;
12783         args = newArgs || args;
12784         if(!id){
12785             id = setInterval(call, d);
12786         }
12787     };
12788
12789     /**
12790      * Cancel the last queued timeout
12791      */
12792     this.cancel = function(){
12793         if(id){
12794             clearInterval(id);
12795             id = null;
12796         }
12797     };
12798 };/*
12799  * Based on:
12800  * Ext JS Library 1.1.1
12801  * Copyright(c) 2006-2007, Ext JS, LLC.
12802  *
12803  * Originally Released Under LGPL - original licence link has changed is not relivant.
12804  *
12805  * Fork - LGPL
12806  * <script type="text/javascript">
12807  */
12808  
12809  
12810 Roo.util.TaskRunner = function(interval){
12811     interval = interval || 10;
12812     var tasks = [], removeQueue = [];
12813     var id = 0;
12814     var running = false;
12815
12816     var stopThread = function(){
12817         running = false;
12818         clearInterval(id);
12819         id = 0;
12820     };
12821
12822     var startThread = function(){
12823         if(!running){
12824             running = true;
12825             id = setInterval(runTasks, interval);
12826         }
12827     };
12828
12829     var removeTask = function(task){
12830         removeQueue.push(task);
12831         if(task.onStop){
12832             task.onStop();
12833         }
12834     };
12835
12836     var runTasks = function(){
12837         if(removeQueue.length > 0){
12838             for(var i = 0, len = removeQueue.length; i < len; i++){
12839                 tasks.remove(removeQueue[i]);
12840             }
12841             removeQueue = [];
12842             if(tasks.length < 1){
12843                 stopThread();
12844                 return;
12845             }
12846         }
12847         var now = new Date().getTime();
12848         for(var i = 0, len = tasks.length; i < len; ++i){
12849             var t = tasks[i];
12850             var itime = now - t.taskRunTime;
12851             if(t.interval <= itime){
12852                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12853                 t.taskRunTime = now;
12854                 if(rt === false || t.taskRunCount === t.repeat){
12855                     removeTask(t);
12856                     return;
12857                 }
12858             }
12859             if(t.duration && t.duration <= (now - t.taskStartTime)){
12860                 removeTask(t);
12861             }
12862         }
12863     };
12864
12865     /**
12866      * Queues a new task.
12867      * @param {Object} task
12868      */
12869     this.start = function(task){
12870         tasks.push(task);
12871         task.taskStartTime = new Date().getTime();
12872         task.taskRunTime = 0;
12873         task.taskRunCount = 0;
12874         startThread();
12875         return task;
12876     };
12877
12878     this.stop = function(task){
12879         removeTask(task);
12880         return task;
12881     };
12882
12883     this.stopAll = function(){
12884         stopThread();
12885         for(var i = 0, len = tasks.length; i < len; i++){
12886             if(tasks[i].onStop){
12887                 tasks[i].onStop();
12888             }
12889         }
12890         tasks = [];
12891         removeQueue = [];
12892     };
12893 };
12894
12895 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12896  * Based on:
12897  * Ext JS Library 1.1.1
12898  * Copyright(c) 2006-2007, Ext JS, LLC.
12899  *
12900  * Originally Released Under LGPL - original licence link has changed is not relivant.
12901  *
12902  * Fork - LGPL
12903  * <script type="text/javascript">
12904  */
12905
12906  
12907 /**
12908  * @class Roo.util.MixedCollection
12909  * @extends Roo.util.Observable
12910  * A Collection class that maintains both numeric indexes and keys and exposes events.
12911  * @constructor
12912  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12913  * collection (defaults to false)
12914  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12915  * and return the key value for that item.  This is used when available to look up the key on items that
12916  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12917  * equivalent to providing an implementation for the {@link #getKey} method.
12918  */
12919 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12920     this.items = [];
12921     this.map = {};
12922     this.keys = [];
12923     this.length = 0;
12924     this.addEvents({
12925         /**
12926          * @event clear
12927          * Fires when the collection is cleared.
12928          */
12929         "clear" : true,
12930         /**
12931          * @event add
12932          * Fires when an item is added to the collection.
12933          * @param {Number} index The index at which the item was added.
12934          * @param {Object} o The item added.
12935          * @param {String} key The key associated with the added item.
12936          */
12937         "add" : true,
12938         /**
12939          * @event replace
12940          * Fires when an item is replaced in the collection.
12941          * @param {String} key he key associated with the new added.
12942          * @param {Object} old The item being replaced.
12943          * @param {Object} new The new item.
12944          */
12945         "replace" : true,
12946         /**
12947          * @event remove
12948          * Fires when an item is removed from the collection.
12949          * @param {Object} o The item being removed.
12950          * @param {String} key (optional) The key associated with the removed item.
12951          */
12952         "remove" : true,
12953         "sort" : true
12954     });
12955     this.allowFunctions = allowFunctions === true;
12956     if(keyFn){
12957         this.getKey = keyFn;
12958     }
12959     Roo.util.MixedCollection.superclass.constructor.call(this);
12960 };
12961
12962 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12963     allowFunctions : false,
12964     
12965 /**
12966  * Adds an item to the collection.
12967  * @param {String} key The key to associate with the item
12968  * @param {Object} o The item to add.
12969  * @return {Object} The item added.
12970  */
12971     add : function(key, o){
12972         if(arguments.length == 1){
12973             o = arguments[0];
12974             key = this.getKey(o);
12975         }
12976         if(typeof key == "undefined" || key === null){
12977             this.length++;
12978             this.items.push(o);
12979             this.keys.push(null);
12980         }else{
12981             var old = this.map[key];
12982             if(old){
12983                 return this.replace(key, o);
12984             }
12985             this.length++;
12986             this.items.push(o);
12987             this.map[key] = o;
12988             this.keys.push(key);
12989         }
12990         this.fireEvent("add", this.length-1, o, key);
12991         return o;
12992     },
12993        
12994 /**
12995   * MixedCollection has a generic way to fetch keys if you implement getKey.
12996 <pre><code>
12997 // normal way
12998 var mc = new Roo.util.MixedCollection();
12999 mc.add(someEl.dom.id, someEl);
13000 mc.add(otherEl.dom.id, otherEl);
13001 //and so on
13002
13003 // using getKey
13004 var mc = new Roo.util.MixedCollection();
13005 mc.getKey = function(el){
13006    return el.dom.id;
13007 };
13008 mc.add(someEl);
13009 mc.add(otherEl);
13010
13011 // or via the constructor
13012 var mc = new Roo.util.MixedCollection(false, function(el){
13013    return el.dom.id;
13014 });
13015 mc.add(someEl);
13016 mc.add(otherEl);
13017 </code></pre>
13018  * @param o {Object} The item for which to find the key.
13019  * @return {Object} The key for the passed item.
13020  */
13021     getKey : function(o){
13022          return o.id; 
13023     },
13024    
13025 /**
13026  * Replaces an item in the collection.
13027  * @param {String} key The key associated with the item to replace, or the item to replace.
13028  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13029  * @return {Object}  The new item.
13030  */
13031     replace : function(key, o){
13032         if(arguments.length == 1){
13033             o = arguments[0];
13034             key = this.getKey(o);
13035         }
13036         var old = this.item(key);
13037         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13038              return this.add(key, o);
13039         }
13040         var index = this.indexOfKey(key);
13041         this.items[index] = o;
13042         this.map[key] = o;
13043         this.fireEvent("replace", key, old, o);
13044         return o;
13045     },
13046    
13047 /**
13048  * Adds all elements of an Array or an Object to the collection.
13049  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13050  * an Array of values, each of which are added to the collection.
13051  */
13052     addAll : function(objs){
13053         if(arguments.length > 1 || objs instanceof Array){
13054             var args = arguments.length > 1 ? arguments : objs;
13055             for(var i = 0, len = args.length; i < len; i++){
13056                 this.add(args[i]);
13057             }
13058         }else{
13059             for(var key in objs){
13060                 if(this.allowFunctions || typeof objs[key] != "function"){
13061                     this.add(key, objs[key]);
13062                 }
13063             }
13064         }
13065     },
13066    
13067 /**
13068  * Executes the specified function once for every item in the collection, passing each
13069  * item as the first and only parameter. returning false from the function will stop the iteration.
13070  * @param {Function} fn The function to execute for each item.
13071  * @param {Object} scope (optional) The scope in which to execute the function.
13072  */
13073     each : function(fn, scope){
13074         var items = [].concat(this.items); // each safe for removal
13075         for(var i = 0, len = items.length; i < len; i++){
13076             if(fn.call(scope || items[i], items[i], i, len) === false){
13077                 break;
13078             }
13079         }
13080     },
13081    
13082 /**
13083  * Executes the specified function once for every key in the collection, passing each
13084  * key, and its associated item as the first two parameters.
13085  * @param {Function} fn The function to execute for each item.
13086  * @param {Object} scope (optional) The scope in which to execute the function.
13087  */
13088     eachKey : function(fn, scope){
13089         for(var i = 0, len = this.keys.length; i < len; i++){
13090             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13091         }
13092     },
13093    
13094 /**
13095  * Returns the first item in the collection which elicits a true return value from the
13096  * passed selection function.
13097  * @param {Function} fn The selection function to execute for each item.
13098  * @param {Object} scope (optional) The scope in which to execute the function.
13099  * @return {Object} The first item in the collection which returned true from the selection function.
13100  */
13101     find : function(fn, scope){
13102         for(var i = 0, len = this.items.length; i < len; i++){
13103             if(fn.call(scope || window, this.items[i], this.keys[i])){
13104                 return this.items[i];
13105             }
13106         }
13107         return null;
13108     },
13109    
13110 /**
13111  * Inserts an item at the specified index in the collection.
13112  * @param {Number} index The index to insert the item at.
13113  * @param {String} key The key to associate with the new item, or the item itself.
13114  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13115  * @return {Object} The item inserted.
13116  */
13117     insert : function(index, key, o){
13118         if(arguments.length == 2){
13119             o = arguments[1];
13120             key = this.getKey(o);
13121         }
13122         if(index >= this.length){
13123             return this.add(key, o);
13124         }
13125         this.length++;
13126         this.items.splice(index, 0, o);
13127         if(typeof key != "undefined" && key != null){
13128             this.map[key] = o;
13129         }
13130         this.keys.splice(index, 0, key);
13131         this.fireEvent("add", index, o, key);
13132         return o;
13133     },
13134    
13135 /**
13136  * Removed an item from the collection.
13137  * @param {Object} o The item to remove.
13138  * @return {Object} The item removed.
13139  */
13140     remove : function(o){
13141         return this.removeAt(this.indexOf(o));
13142     },
13143    
13144 /**
13145  * Remove an item from a specified index in the collection.
13146  * @param {Number} index The index within the collection of the item to remove.
13147  */
13148     removeAt : function(index){
13149         if(index < this.length && index >= 0){
13150             this.length--;
13151             var o = this.items[index];
13152             this.items.splice(index, 1);
13153             var key = this.keys[index];
13154             if(typeof key != "undefined"){
13155                 delete this.map[key];
13156             }
13157             this.keys.splice(index, 1);
13158             this.fireEvent("remove", o, key);
13159         }
13160     },
13161    
13162 /**
13163  * Removed an item associated with the passed key fom the collection.
13164  * @param {String} key The key of the item to remove.
13165  */
13166     removeKey : function(key){
13167         return this.removeAt(this.indexOfKey(key));
13168     },
13169    
13170 /**
13171  * Returns the number of items in the collection.
13172  * @return {Number} the number of items in the collection.
13173  */
13174     getCount : function(){
13175         return this.length; 
13176     },
13177    
13178 /**
13179  * Returns index within the collection of the passed Object.
13180  * @param {Object} o The item to find the index of.
13181  * @return {Number} index of the item.
13182  */
13183     indexOf : function(o){
13184         if(!this.items.indexOf){
13185             for(var i = 0, len = this.items.length; i < len; i++){
13186                 if(this.items[i] == o) {
13187                     return i;
13188                 }
13189             }
13190             return -1;
13191         }else{
13192             return this.items.indexOf(o);
13193         }
13194     },
13195    
13196 /**
13197  * Returns index within the collection of the passed key.
13198  * @param {String} key The key to find the index of.
13199  * @return {Number} index of the key.
13200  */
13201     indexOfKey : function(key){
13202         if(!this.keys.indexOf){
13203             for(var i = 0, len = this.keys.length; i < len; i++){
13204                 if(this.keys[i] == key) {
13205                     return i;
13206                 }
13207             }
13208             return -1;
13209         }else{
13210             return this.keys.indexOf(key);
13211         }
13212     },
13213    
13214 /**
13215  * Returns the item associated with the passed key OR index. Key has priority over index.
13216  * @param {String/Number} key The key or index of the item.
13217  * @return {Object} The item associated with the passed key.
13218  */
13219     item : function(key){
13220         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13221         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13222     },
13223     
13224 /**
13225  * Returns the item at the specified index.
13226  * @param {Number} index The index of the item.
13227  * @return {Object}
13228  */
13229     itemAt : function(index){
13230         return this.items[index];
13231     },
13232     
13233 /**
13234  * Returns the item associated with the passed key.
13235  * @param {String/Number} key The key of the item.
13236  * @return {Object} The item associated with the passed key.
13237  */
13238     key : function(key){
13239         return this.map[key];
13240     },
13241    
13242 /**
13243  * Returns true if the collection contains the passed Object as an item.
13244  * @param {Object} o  The Object to look for in the collection.
13245  * @return {Boolean} True if the collection contains the Object as an item.
13246  */
13247     contains : function(o){
13248         return this.indexOf(o) != -1;
13249     },
13250    
13251 /**
13252  * Returns true if the collection contains the passed Object as a key.
13253  * @param {String} key The key to look for in the collection.
13254  * @return {Boolean} True if the collection contains the Object as a key.
13255  */
13256     containsKey : function(key){
13257         return typeof this.map[key] != "undefined";
13258     },
13259    
13260 /**
13261  * Removes all items from the collection.
13262  */
13263     clear : function(){
13264         this.length = 0;
13265         this.items = [];
13266         this.keys = [];
13267         this.map = {};
13268         this.fireEvent("clear");
13269     },
13270    
13271 /**
13272  * Returns the first item in the collection.
13273  * @return {Object} the first item in the collection..
13274  */
13275     first : function(){
13276         return this.items[0]; 
13277     },
13278    
13279 /**
13280  * Returns the last item in the collection.
13281  * @return {Object} the last item in the collection..
13282  */
13283     last : function(){
13284         return this.items[this.length-1];   
13285     },
13286     
13287     _sort : function(property, dir, fn){
13288         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13289         fn = fn || function(a, b){
13290             return a-b;
13291         };
13292         var c = [], k = this.keys, items = this.items;
13293         for(var i = 0, len = items.length; i < len; i++){
13294             c[c.length] = {key: k[i], value: items[i], index: i};
13295         }
13296         c.sort(function(a, b){
13297             var v = fn(a[property], b[property]) * dsc;
13298             if(v == 0){
13299                 v = (a.index < b.index ? -1 : 1);
13300             }
13301             return v;
13302         });
13303         for(var i = 0, len = c.length; i < len; i++){
13304             items[i] = c[i].value;
13305             k[i] = c[i].key;
13306         }
13307         this.fireEvent("sort", this);
13308     },
13309     
13310     /**
13311      * Sorts this collection with the passed comparison function
13312      * @param {String} direction (optional) "ASC" or "DESC"
13313      * @param {Function} fn (optional) comparison function
13314      */
13315     sort : function(dir, fn){
13316         this._sort("value", dir, fn);
13317     },
13318     
13319     /**
13320      * Sorts this collection by keys
13321      * @param {String} direction (optional) "ASC" or "DESC"
13322      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13323      */
13324     keySort : function(dir, fn){
13325         this._sort("key", dir, fn || function(a, b){
13326             return String(a).toUpperCase()-String(b).toUpperCase();
13327         });
13328     },
13329     
13330     /**
13331      * Returns a range of items in this collection
13332      * @param {Number} startIndex (optional) defaults to 0
13333      * @param {Number} endIndex (optional) default to the last item
13334      * @return {Array} An array of items
13335      */
13336     getRange : function(start, end){
13337         var items = this.items;
13338         if(items.length < 1){
13339             return [];
13340         }
13341         start = start || 0;
13342         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13343         var r = [];
13344         if(start <= end){
13345             for(var i = start; i <= end; i++) {
13346                     r[r.length] = items[i];
13347             }
13348         }else{
13349             for(var i = start; i >= end; i--) {
13350                     r[r.length] = items[i];
13351             }
13352         }
13353         return r;
13354     },
13355         
13356     /**
13357      * Filter the <i>objects</i> in this collection by a specific property. 
13358      * Returns a new collection that has been filtered.
13359      * @param {String} property A property on your objects
13360      * @param {String/RegExp} value Either string that the property values 
13361      * should start with or a RegExp to test against the property
13362      * @return {MixedCollection} The new filtered collection
13363      */
13364     filter : function(property, value){
13365         if(!value.exec){ // not a regex
13366             value = String(value);
13367             if(value.length == 0){
13368                 return this.clone();
13369             }
13370             value = new RegExp("^" + Roo.escapeRe(value), "i");
13371         }
13372         return this.filterBy(function(o){
13373             return o && value.test(o[property]);
13374         });
13375         },
13376     
13377     /**
13378      * Filter by a function. * Returns a new collection that has been filtered.
13379      * The passed function will be called with each 
13380      * object in the collection. If the function returns true, the value is included 
13381      * otherwise it is filtered.
13382      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13383      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13384      * @return {MixedCollection} The new filtered collection
13385      */
13386     filterBy : function(fn, scope){
13387         var r = new Roo.util.MixedCollection();
13388         r.getKey = this.getKey;
13389         var k = this.keys, it = this.items;
13390         for(var i = 0, len = it.length; i < len; i++){
13391             if(fn.call(scope||this, it[i], k[i])){
13392                                 r.add(k[i], it[i]);
13393                         }
13394         }
13395         return r;
13396     },
13397     
13398     /**
13399      * Creates a duplicate of this collection
13400      * @return {MixedCollection}
13401      */
13402     clone : function(){
13403         var r = new Roo.util.MixedCollection();
13404         var k = this.keys, it = this.items;
13405         for(var i = 0, len = it.length; i < len; i++){
13406             r.add(k[i], it[i]);
13407         }
13408         r.getKey = this.getKey;
13409         return r;
13410     }
13411 });
13412 /**
13413  * Returns the item associated with the passed key or index.
13414  * @method
13415  * @param {String/Number} key The key or index of the item.
13416  * @return {Object} The item associated with the passed key.
13417  */
13418 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13419  * Based on:
13420  * Ext JS Library 1.1.1
13421  * Copyright(c) 2006-2007, Ext JS, LLC.
13422  *
13423  * Originally Released Under LGPL - original licence link has changed is not relivant.
13424  *
13425  * Fork - LGPL
13426  * <script type="text/javascript">
13427  */
13428 /**
13429  * @class Roo.util.JSON
13430  * Modified version of Douglas Crockford"s json.js that doesn"t
13431  * mess with the Object prototype 
13432  * http://www.json.org/js.html
13433  * @singleton
13434  */
13435 Roo.util.JSON = new (function(){
13436     var useHasOwn = {}.hasOwnProperty ? true : false;
13437     
13438     // crashes Safari in some instances
13439     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13440     
13441     var pad = function(n) {
13442         return n < 10 ? "0" + n : n;
13443     };
13444     
13445     var m = {
13446         "\b": '\\b',
13447         "\t": '\\t',
13448         "\n": '\\n',
13449         "\f": '\\f',
13450         "\r": '\\r',
13451         '"' : '\\"',
13452         "\\": '\\\\'
13453     };
13454
13455     var encodeString = function(s){
13456         if (/["\\\x00-\x1f]/.test(s)) {
13457             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13458                 var c = m[b];
13459                 if(c){
13460                     return c;
13461                 }
13462                 c = b.charCodeAt();
13463                 return "\\u00" +
13464                     Math.floor(c / 16).toString(16) +
13465                     (c % 16).toString(16);
13466             }) + '"';
13467         }
13468         return '"' + s + '"';
13469     };
13470     
13471     var encodeArray = function(o){
13472         var a = ["["], b, i, l = o.length, v;
13473             for (i = 0; i < l; i += 1) {
13474                 v = o[i];
13475                 switch (typeof v) {
13476                     case "undefined":
13477                     case "function":
13478                     case "unknown":
13479                         break;
13480                     default:
13481                         if (b) {
13482                             a.push(',');
13483                         }
13484                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13485                         b = true;
13486                 }
13487             }
13488             a.push("]");
13489             return a.join("");
13490     };
13491     
13492     var encodeDate = function(o){
13493         return '"' + o.getFullYear() + "-" +
13494                 pad(o.getMonth() + 1) + "-" +
13495                 pad(o.getDate()) + "T" +
13496                 pad(o.getHours()) + ":" +
13497                 pad(o.getMinutes()) + ":" +
13498                 pad(o.getSeconds()) + '"';
13499     };
13500     
13501     /**
13502      * Encodes an Object, Array or other value
13503      * @param {Mixed} o The variable to encode
13504      * @return {String} The JSON string
13505      */
13506     this.encode = function(o)
13507     {
13508         // should this be extended to fully wrap stringify..
13509         
13510         if(typeof o == "undefined" || o === null){
13511             return "null";
13512         }else if(o instanceof Array){
13513             return encodeArray(o);
13514         }else if(o instanceof Date){
13515             return encodeDate(o);
13516         }else if(typeof o == "string"){
13517             return encodeString(o);
13518         }else if(typeof o == "number"){
13519             return isFinite(o) ? String(o) : "null";
13520         }else if(typeof o == "boolean"){
13521             return String(o);
13522         }else {
13523             var a = ["{"], b, i, v;
13524             for (i in o) {
13525                 if(!useHasOwn || o.hasOwnProperty(i)) {
13526                     v = o[i];
13527                     switch (typeof v) {
13528                     case "undefined":
13529                     case "function":
13530                     case "unknown":
13531                         break;
13532                     default:
13533                         if(b){
13534                             a.push(',');
13535                         }
13536                         a.push(this.encode(i), ":",
13537                                 v === null ? "null" : this.encode(v));
13538                         b = true;
13539                     }
13540                 }
13541             }
13542             a.push("}");
13543             return a.join("");
13544         }
13545     };
13546     
13547     /**
13548      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13549      * @param {String} json The JSON string
13550      * @return {Object} The resulting object
13551      */
13552     this.decode = function(json){
13553         
13554         return  /** eval:var:json */ eval("(" + json + ')');
13555     };
13556 })();
13557 /** 
13558  * Shorthand for {@link Roo.util.JSON#encode}
13559  * @member Roo encode 
13560  * @method */
13561 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13562 /** 
13563  * Shorthand for {@link Roo.util.JSON#decode}
13564  * @member Roo decode 
13565  * @method */
13566 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13567 /*
13568  * Based on:
13569  * Ext JS Library 1.1.1
13570  * Copyright(c) 2006-2007, Ext JS, LLC.
13571  *
13572  * Originally Released Under LGPL - original licence link has changed is not relivant.
13573  *
13574  * Fork - LGPL
13575  * <script type="text/javascript">
13576  */
13577  
13578 /**
13579  * @class Roo.util.Format
13580  * Reusable data formatting functions
13581  * @singleton
13582  */
13583 Roo.util.Format = function(){
13584     var trimRe = /^\s+|\s+$/g;
13585     return {
13586         /**
13587          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13588          * @param {String} value The string to truncate
13589          * @param {Number} length The maximum length to allow before truncating
13590          * @return {String} The converted text
13591          */
13592         ellipsis : function(value, len){
13593             if(value && value.length > len){
13594                 return value.substr(0, len-3)+"...";
13595             }
13596             return value;
13597         },
13598
13599         /**
13600          * Checks a reference and converts it to empty string if it is undefined
13601          * @param {Mixed} value Reference to check
13602          * @return {Mixed} Empty string if converted, otherwise the original value
13603          */
13604         undef : function(value){
13605             return typeof value != "undefined" ? value : "";
13606         },
13607
13608         /**
13609          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13610          * @param {String} value The string to encode
13611          * @return {String} The encoded text
13612          */
13613         htmlEncode : function(value){
13614             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13615         },
13616
13617         /**
13618          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13619          * @param {String} value The string to decode
13620          * @return {String} The decoded text
13621          */
13622         htmlDecode : function(value){
13623             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13624         },
13625
13626         /**
13627          * Trims any whitespace from either side of a string
13628          * @param {String} value The text to trim
13629          * @return {String} The trimmed text
13630          */
13631         trim : function(value){
13632             return String(value).replace(trimRe, "");
13633         },
13634
13635         /**
13636          * Returns a substring from within an original string
13637          * @param {String} value The original text
13638          * @param {Number} start The start index of the substring
13639          * @param {Number} length The length of the substring
13640          * @return {String} The substring
13641          */
13642         substr : function(value, start, length){
13643             return String(value).substr(start, length);
13644         },
13645
13646         /**
13647          * Converts a string to all lower case letters
13648          * @param {String} value The text to convert
13649          * @return {String} The converted text
13650          */
13651         lowercase : function(value){
13652             return String(value).toLowerCase();
13653         },
13654
13655         /**
13656          * Converts a string to all upper case letters
13657          * @param {String} value The text to convert
13658          * @return {String} The converted text
13659          */
13660         uppercase : function(value){
13661             return String(value).toUpperCase();
13662         },
13663
13664         /**
13665          * Converts the first character only of a string to upper case
13666          * @param {String} value The text to convert
13667          * @return {String} The converted text
13668          */
13669         capitalize : function(value){
13670             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13671         },
13672
13673         // private
13674         call : function(value, fn){
13675             if(arguments.length > 2){
13676                 var args = Array.prototype.slice.call(arguments, 2);
13677                 args.unshift(value);
13678                  
13679                 return /** eval:var:value */  eval(fn).apply(window, args);
13680             }else{
13681                 /** eval:var:value */
13682                 return /** eval:var:value */ eval(fn).call(window, value);
13683             }
13684         },
13685
13686        
13687         /**
13688          * safer version of Math.toFixed..??/
13689          * @param {Number/String} value The numeric value to format
13690          * @param {Number/String} value Decimal places 
13691          * @return {String} The formatted currency string
13692          */
13693         toFixed : function(v, n)
13694         {
13695             // why not use to fixed - precision is buggered???
13696             if (!n) {
13697                 return Math.round(v-0);
13698             }
13699             var fact = Math.pow(10,n+1);
13700             v = (Math.round((v-0)*fact))/fact;
13701             var z = (''+fact).substring(2);
13702             if (v == Math.floor(v)) {
13703                 return Math.floor(v) + '.' + z;
13704             }
13705             
13706             // now just padd decimals..
13707             var ps = String(v).split('.');
13708             var fd = (ps[1] + z);
13709             var r = fd.substring(0,n); 
13710             var rm = fd.substring(n); 
13711             if (rm < 5) {
13712                 return ps[0] + '.' + r;
13713             }
13714             r*=1; // turn it into a number;
13715             r++;
13716             if (String(r).length != n) {
13717                 ps[0]*=1;
13718                 ps[0]++;
13719                 r = String(r).substring(1); // chop the end off.
13720             }
13721             
13722             return ps[0] + '.' + r;
13723              
13724         },
13725         
13726         /**
13727          * Format a number as US currency
13728          * @param {Number/String} value The numeric value to format
13729          * @return {String} The formatted currency string
13730          */
13731         usMoney : function(v){
13732             return '$' + Roo.util.Format.number(v);
13733         },
13734         
13735         /**
13736          * Format a number
13737          * eventually this should probably emulate php's number_format
13738          * @param {Number/String} value The numeric value to format
13739          * @param {Number} decimals number of decimal places
13740          * @return {String} The formatted currency string
13741          */
13742         number : function(v,decimals)
13743         {
13744             // multiply and round.
13745             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13746             var mul = Math.pow(10, decimals);
13747             var zero = String(mul).substring(1);
13748             v = (Math.round((v-0)*mul))/mul;
13749             
13750             // if it's '0' number.. then
13751             
13752             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13753             v = String(v);
13754             var ps = v.split('.');
13755             var whole = ps[0];
13756             
13757             
13758             var r = /(\d+)(\d{3})/;
13759             // add comma's
13760             while (r.test(whole)) {
13761                 whole = whole.replace(r, '$1' + ',' + '$2');
13762             }
13763             
13764             
13765             var sub = ps[1] ?
13766                     // has decimals..
13767                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13768                     // does not have decimals
13769                     (decimals ? ('.' + zero) : '');
13770             
13771             
13772             return whole + sub ;
13773         },
13774         
13775         /**
13776          * Parse a value into a formatted date using the specified format pattern.
13777          * @param {Mixed} value The value to format
13778          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13779          * @return {String} The formatted date string
13780          */
13781         date : function(v, format){
13782             if(!v){
13783                 return "";
13784             }
13785             if(!(v instanceof Date)){
13786                 v = new Date(Date.parse(v));
13787             }
13788             return v.dateFormat(format || Roo.util.Format.defaults.date);
13789         },
13790
13791         /**
13792          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13793          * @param {String} format Any valid date format string
13794          * @return {Function} The date formatting function
13795          */
13796         dateRenderer : function(format){
13797             return function(v){
13798                 return Roo.util.Format.date(v, format);  
13799             };
13800         },
13801
13802         // private
13803         stripTagsRE : /<\/?[^>]+>/gi,
13804         
13805         /**
13806          * Strips all HTML tags
13807          * @param {Mixed} value The text from which to strip tags
13808          * @return {String} The stripped text
13809          */
13810         stripTags : function(v){
13811             return !v ? v : String(v).replace(this.stripTagsRE, "");
13812         }
13813     };
13814 }();
13815 Roo.util.Format.defaults = {
13816     date : 'd/M/Y'
13817 };/*
13818  * Based on:
13819  * Ext JS Library 1.1.1
13820  * Copyright(c) 2006-2007, Ext JS, LLC.
13821  *
13822  * Originally Released Under LGPL - original licence link has changed is not relivant.
13823  *
13824  * Fork - LGPL
13825  * <script type="text/javascript">
13826  */
13827
13828
13829  
13830
13831 /**
13832  * @class Roo.MasterTemplate
13833  * @extends Roo.Template
13834  * Provides a template that can have child templates. The syntax is:
13835 <pre><code>
13836 var t = new Roo.MasterTemplate(
13837         '&lt;select name="{name}"&gt;',
13838                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13839         '&lt;/select&gt;'
13840 );
13841 t.add('options', {value: 'foo', text: 'bar'});
13842 // or you can add multiple child elements in one shot
13843 t.addAll('options', [
13844     {value: 'foo', text: 'bar'},
13845     {value: 'foo2', text: 'bar2'},
13846     {value: 'foo3', text: 'bar3'}
13847 ]);
13848 // then append, applying the master template values
13849 t.append('my-form', {name: 'my-select'});
13850 </code></pre>
13851 * A name attribute for the child template is not required if you have only one child
13852 * template or you want to refer to them by index.
13853  */
13854 Roo.MasterTemplate = function(){
13855     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13856     this.originalHtml = this.html;
13857     var st = {};
13858     var m, re = this.subTemplateRe;
13859     re.lastIndex = 0;
13860     var subIndex = 0;
13861     while(m = re.exec(this.html)){
13862         var name = m[1], content = m[2];
13863         st[subIndex] = {
13864             name: name,
13865             index: subIndex,
13866             buffer: [],
13867             tpl : new Roo.Template(content)
13868         };
13869         if(name){
13870             st[name] = st[subIndex];
13871         }
13872         st[subIndex].tpl.compile();
13873         st[subIndex].tpl.call = this.call.createDelegate(this);
13874         subIndex++;
13875     }
13876     this.subCount = subIndex;
13877     this.subs = st;
13878 };
13879 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13880     /**
13881     * The regular expression used to match sub templates
13882     * @type RegExp
13883     * @property
13884     */
13885     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13886
13887     /**
13888      * Applies the passed values to a child template.
13889      * @param {String/Number} name (optional) The name or index of the child template
13890      * @param {Array/Object} values The values to be applied to the template
13891      * @return {MasterTemplate} this
13892      */
13893      add : function(name, values){
13894         if(arguments.length == 1){
13895             values = arguments[0];
13896             name = 0;
13897         }
13898         var s = this.subs[name];
13899         s.buffer[s.buffer.length] = s.tpl.apply(values);
13900         return this;
13901     },
13902
13903     /**
13904      * Applies all the passed values to a child template.
13905      * @param {String/Number} name (optional) The name or index of the child template
13906      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13907      * @param {Boolean} reset (optional) True to reset the template first
13908      * @return {MasterTemplate} this
13909      */
13910     fill : function(name, values, reset){
13911         var a = arguments;
13912         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13913             values = a[0];
13914             name = 0;
13915             reset = a[1];
13916         }
13917         if(reset){
13918             this.reset();
13919         }
13920         for(var i = 0, len = values.length; i < len; i++){
13921             this.add(name, values[i]);
13922         }
13923         return this;
13924     },
13925
13926     /**
13927      * Resets the template for reuse
13928      * @return {MasterTemplate} this
13929      */
13930      reset : function(){
13931         var s = this.subs;
13932         for(var i = 0; i < this.subCount; i++){
13933             s[i].buffer = [];
13934         }
13935         return this;
13936     },
13937
13938     applyTemplate : function(values){
13939         var s = this.subs;
13940         var replaceIndex = -1;
13941         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13942             return s[++replaceIndex].buffer.join("");
13943         });
13944         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13945     },
13946
13947     apply : function(){
13948         return this.applyTemplate.apply(this, arguments);
13949     },
13950
13951     compile : function(){return this;}
13952 });
13953
13954 /**
13955  * Alias for fill().
13956  * @method
13957  */
13958 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13959  /**
13960  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13961  * var tpl = Roo.MasterTemplate.from('element-id');
13962  * @param {String/HTMLElement} el
13963  * @param {Object} config
13964  * @static
13965  */
13966 Roo.MasterTemplate.from = function(el, config){
13967     el = Roo.getDom(el);
13968     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13969 };/*
13970  * Based on:
13971  * Ext JS Library 1.1.1
13972  * Copyright(c) 2006-2007, Ext JS, LLC.
13973  *
13974  * Originally Released Under LGPL - original licence link has changed is not relivant.
13975  *
13976  * Fork - LGPL
13977  * <script type="text/javascript">
13978  */
13979
13980  
13981 /**
13982  * @class Roo.util.CSS
13983  * Utility class for manipulating CSS rules
13984  * @singleton
13985  */
13986 Roo.util.CSS = function(){
13987         var rules = null;
13988         var doc = document;
13989
13990     var camelRe = /(-[a-z])/gi;
13991     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13992
13993    return {
13994    /**
13995     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13996     * tag and appended to the HEAD of the document.
13997     * @param {String|Object} cssText The text containing the css rules
13998     * @param {String} id An id to add to the stylesheet for later removal
13999     * @return {StyleSheet}
14000     */
14001     createStyleSheet : function(cssText, id){
14002         var ss;
14003         var head = doc.getElementsByTagName("head")[0];
14004         var nrules = doc.createElement("style");
14005         nrules.setAttribute("type", "text/css");
14006         if(id){
14007             nrules.setAttribute("id", id);
14008         }
14009         if (typeof(cssText) != 'string') {
14010             // support object maps..
14011             // not sure if this a good idea.. 
14012             // perhaps it should be merged with the general css handling
14013             // and handle js style props.
14014             var cssTextNew = [];
14015             for(var n in cssText) {
14016                 var citems = [];
14017                 for(var k in cssText[n]) {
14018                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14019                 }
14020                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14021                 
14022             }
14023             cssText = cssTextNew.join("\n");
14024             
14025         }
14026        
14027        
14028        if(Roo.isIE){
14029            head.appendChild(nrules);
14030            ss = nrules.styleSheet;
14031            ss.cssText = cssText;
14032        }else{
14033            try{
14034                 nrules.appendChild(doc.createTextNode(cssText));
14035            }catch(e){
14036                nrules.cssText = cssText; 
14037            }
14038            head.appendChild(nrules);
14039            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14040        }
14041        this.cacheStyleSheet(ss);
14042        return ss;
14043    },
14044
14045    /**
14046     * Removes a style or link tag by id
14047     * @param {String} id The id of the tag
14048     */
14049    removeStyleSheet : function(id){
14050        var existing = doc.getElementById(id);
14051        if(existing){
14052            existing.parentNode.removeChild(existing);
14053        }
14054    },
14055
14056    /**
14057     * Dynamically swaps an existing stylesheet reference for a new one
14058     * @param {String} id The id of an existing link tag to remove
14059     * @param {String} url The href of the new stylesheet to include
14060     */
14061    swapStyleSheet : function(id, url){
14062        this.removeStyleSheet(id);
14063        var ss = doc.createElement("link");
14064        ss.setAttribute("rel", "stylesheet");
14065        ss.setAttribute("type", "text/css");
14066        ss.setAttribute("id", id);
14067        ss.setAttribute("href", url);
14068        doc.getElementsByTagName("head")[0].appendChild(ss);
14069    },
14070    
14071    /**
14072     * Refresh the rule cache if you have dynamically added stylesheets
14073     * @return {Object} An object (hash) of rules indexed by selector
14074     */
14075    refreshCache : function(){
14076        return this.getRules(true);
14077    },
14078
14079    // private
14080    cacheStyleSheet : function(stylesheet){
14081        if(!rules){
14082            rules = {};
14083        }
14084        try{// try catch for cross domain access issue
14085            var ssRules = stylesheet.cssRules || stylesheet.rules;
14086            for(var j = ssRules.length-1; j >= 0; --j){
14087                rules[ssRules[j].selectorText] = ssRules[j];
14088            }
14089        }catch(e){}
14090    },
14091    
14092    /**
14093     * Gets all css rules for the document
14094     * @param {Boolean} refreshCache true to refresh the internal cache
14095     * @return {Object} An object (hash) of rules indexed by selector
14096     */
14097    getRules : function(refreshCache){
14098                 if(rules == null || refreshCache){
14099                         rules = {};
14100                         var ds = doc.styleSheets;
14101                         for(var i =0, len = ds.length; i < len; i++){
14102                             try{
14103                         this.cacheStyleSheet(ds[i]);
14104                     }catch(e){} 
14105                 }
14106                 }
14107                 return rules;
14108         },
14109         
14110         /**
14111     * Gets an an individual CSS rule by selector(s)
14112     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14113     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14114     * @return {CSSRule} The CSS rule or null if one is not found
14115     */
14116    getRule : function(selector, refreshCache){
14117                 var rs = this.getRules(refreshCache);
14118                 if(!(selector instanceof Array)){
14119                     return rs[selector];
14120                 }
14121                 for(var i = 0; i < selector.length; i++){
14122                         if(rs[selector[i]]){
14123                                 return rs[selector[i]];
14124                         }
14125                 }
14126                 return null;
14127         },
14128         
14129         
14130         /**
14131     * Updates a rule property
14132     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14133     * @param {String} property The css property
14134     * @param {String} value The new value for the property
14135     * @return {Boolean} true If a rule was found and updated
14136     */
14137    updateRule : function(selector, property, value){
14138                 if(!(selector instanceof Array)){
14139                         var rule = this.getRule(selector);
14140                         if(rule){
14141                                 rule.style[property.replace(camelRe, camelFn)] = value;
14142                                 return true;
14143                         }
14144                 }else{
14145                         for(var i = 0; i < selector.length; i++){
14146                                 if(this.updateRule(selector[i], property, value)){
14147                                         return true;
14148                                 }
14149                         }
14150                 }
14151                 return false;
14152         }
14153    };   
14154 }();/*
14155  * Based on:
14156  * Ext JS Library 1.1.1
14157  * Copyright(c) 2006-2007, Ext JS, LLC.
14158  *
14159  * Originally Released Under LGPL - original licence link has changed is not relivant.
14160  *
14161  * Fork - LGPL
14162  * <script type="text/javascript">
14163  */
14164
14165  
14166
14167 /**
14168  * @class Roo.util.ClickRepeater
14169  * @extends Roo.util.Observable
14170  * 
14171  * A wrapper class which can be applied to any element. Fires a "click" event while the
14172  * mouse is pressed. The interval between firings may be specified in the config but
14173  * defaults to 10 milliseconds.
14174  * 
14175  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14176  * 
14177  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14178  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14179  * Similar to an autorepeat key delay.
14180  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14181  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14182  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14183  *           "interval" and "delay" are ignored. "immediate" is honored.
14184  * @cfg {Boolean} preventDefault True to prevent the default click event
14185  * @cfg {Boolean} stopDefault True to stop the default click event
14186  * 
14187  * @history
14188  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14189  *     2007-02-02 jvs Renamed to ClickRepeater
14190  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14191  *
14192  *  @constructor
14193  * @param {String/HTMLElement/Element} el The element to listen on
14194  * @param {Object} config
14195  **/
14196 Roo.util.ClickRepeater = function(el, config)
14197 {
14198     this.el = Roo.get(el);
14199     this.el.unselectable();
14200
14201     Roo.apply(this, config);
14202
14203     this.addEvents({
14204     /**
14205      * @event mousedown
14206      * Fires when the mouse button is depressed.
14207      * @param {Roo.util.ClickRepeater} this
14208      */
14209         "mousedown" : true,
14210     /**
14211      * @event click
14212      * Fires on a specified interval during the time the element is pressed.
14213      * @param {Roo.util.ClickRepeater} this
14214      */
14215         "click" : true,
14216     /**
14217      * @event mouseup
14218      * Fires when the mouse key is released.
14219      * @param {Roo.util.ClickRepeater} this
14220      */
14221         "mouseup" : true
14222     });
14223
14224     this.el.on("mousedown", this.handleMouseDown, this);
14225     if(this.preventDefault || this.stopDefault){
14226         this.el.on("click", function(e){
14227             if(this.preventDefault){
14228                 e.preventDefault();
14229             }
14230             if(this.stopDefault){
14231                 e.stopEvent();
14232             }
14233         }, this);
14234     }
14235
14236     // allow inline handler
14237     if(this.handler){
14238         this.on("click", this.handler,  this.scope || this);
14239     }
14240
14241     Roo.util.ClickRepeater.superclass.constructor.call(this);
14242 };
14243
14244 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14245     interval : 20,
14246     delay: 250,
14247     preventDefault : true,
14248     stopDefault : false,
14249     timer : 0,
14250
14251     // private
14252     handleMouseDown : function(){
14253         clearTimeout(this.timer);
14254         this.el.blur();
14255         if(this.pressClass){
14256             this.el.addClass(this.pressClass);
14257         }
14258         this.mousedownTime = new Date();
14259
14260         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14261         this.el.on("mouseout", this.handleMouseOut, this);
14262
14263         this.fireEvent("mousedown", this);
14264         this.fireEvent("click", this);
14265         
14266         this.timer = this.click.defer(this.delay || this.interval, this);
14267     },
14268
14269     // private
14270     click : function(){
14271         this.fireEvent("click", this);
14272         this.timer = this.click.defer(this.getInterval(), this);
14273     },
14274
14275     // private
14276     getInterval: function(){
14277         if(!this.accelerate){
14278             return this.interval;
14279         }
14280         var pressTime = this.mousedownTime.getElapsed();
14281         if(pressTime < 500){
14282             return 400;
14283         }else if(pressTime < 1700){
14284             return 320;
14285         }else if(pressTime < 2600){
14286             return 250;
14287         }else if(pressTime < 3500){
14288             return 180;
14289         }else if(pressTime < 4400){
14290             return 140;
14291         }else if(pressTime < 5300){
14292             return 80;
14293         }else if(pressTime < 6200){
14294             return 50;
14295         }else{
14296             return 10;
14297         }
14298     },
14299
14300     // private
14301     handleMouseOut : function(){
14302         clearTimeout(this.timer);
14303         if(this.pressClass){
14304             this.el.removeClass(this.pressClass);
14305         }
14306         this.el.on("mouseover", this.handleMouseReturn, this);
14307     },
14308
14309     // private
14310     handleMouseReturn : function(){
14311         this.el.un("mouseover", this.handleMouseReturn);
14312         if(this.pressClass){
14313             this.el.addClass(this.pressClass);
14314         }
14315         this.click();
14316     },
14317
14318     // private
14319     handleMouseUp : function(){
14320         clearTimeout(this.timer);
14321         this.el.un("mouseover", this.handleMouseReturn);
14322         this.el.un("mouseout", this.handleMouseOut);
14323         Roo.get(document).un("mouseup", this.handleMouseUp);
14324         this.el.removeClass(this.pressClass);
14325         this.fireEvent("mouseup", this);
14326     }
14327 });/*
14328  * Based on:
14329  * Ext JS Library 1.1.1
14330  * Copyright(c) 2006-2007, Ext JS, LLC.
14331  *
14332  * Originally Released Under LGPL - original licence link has changed is not relivant.
14333  *
14334  * Fork - LGPL
14335  * <script type="text/javascript">
14336  */
14337
14338  
14339 /**
14340  * @class Roo.KeyNav
14341  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14342  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14343  * way to implement custom navigation schemes for any UI component.</p>
14344  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14345  * pageUp, pageDown, del, home, end.  Usage:</p>
14346  <pre><code>
14347 var nav = new Roo.KeyNav("my-element", {
14348     "left" : function(e){
14349         this.moveLeft(e.ctrlKey);
14350     },
14351     "right" : function(e){
14352         this.moveRight(e.ctrlKey);
14353     },
14354     "enter" : function(e){
14355         this.save();
14356     },
14357     scope : this
14358 });
14359 </code></pre>
14360  * @constructor
14361  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14362  * @param {Object} config The config
14363  */
14364 Roo.KeyNav = function(el, config){
14365     this.el = Roo.get(el);
14366     Roo.apply(this, config);
14367     if(!this.disabled){
14368         this.disabled = true;
14369         this.enable();
14370     }
14371 };
14372
14373 Roo.KeyNav.prototype = {
14374     /**
14375      * @cfg {Boolean} disabled
14376      * True to disable this KeyNav instance (defaults to false)
14377      */
14378     disabled : false,
14379     /**
14380      * @cfg {String} defaultEventAction
14381      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14382      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14383      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14384      */
14385     defaultEventAction: "stopEvent",
14386     /**
14387      * @cfg {Boolean} forceKeyDown
14388      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14389      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14390      * handle keydown instead of keypress.
14391      */
14392     forceKeyDown : false,
14393
14394     // private
14395     prepareEvent : function(e){
14396         var k = e.getKey();
14397         var h = this.keyToHandler[k];
14398         //if(h && this[h]){
14399         //    e.stopPropagation();
14400         //}
14401         if(Roo.isSafari && h && k >= 37 && k <= 40){
14402             e.stopEvent();
14403         }
14404     },
14405
14406     // private
14407     relay : function(e){
14408         var k = e.getKey();
14409         var h = this.keyToHandler[k];
14410         if(h && this[h]){
14411             if(this.doRelay(e, this[h], h) !== true){
14412                 e[this.defaultEventAction]();
14413             }
14414         }
14415     },
14416
14417     // private
14418     doRelay : function(e, h, hname){
14419         return h.call(this.scope || this, e);
14420     },
14421
14422     // possible handlers
14423     enter : false,
14424     left : false,
14425     right : false,
14426     up : false,
14427     down : false,
14428     tab : false,
14429     esc : false,
14430     pageUp : false,
14431     pageDown : false,
14432     del : false,
14433     home : false,
14434     end : false,
14435
14436     // quick lookup hash
14437     keyToHandler : {
14438         37 : "left",
14439         39 : "right",
14440         38 : "up",
14441         40 : "down",
14442         33 : "pageUp",
14443         34 : "pageDown",
14444         46 : "del",
14445         36 : "home",
14446         35 : "end",
14447         13 : "enter",
14448         27 : "esc",
14449         9  : "tab"
14450     },
14451
14452         /**
14453          * Enable this KeyNav
14454          */
14455         enable: function(){
14456                 if(this.disabled){
14457             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14458             // the EventObject will normalize Safari automatically
14459             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14460                 this.el.on("keydown", this.relay,  this);
14461             }else{
14462                 this.el.on("keydown", this.prepareEvent,  this);
14463                 this.el.on("keypress", this.relay,  this);
14464             }
14465                     this.disabled = false;
14466                 }
14467         },
14468
14469         /**
14470          * Disable this KeyNav
14471          */
14472         disable: function(){
14473                 if(!this.disabled){
14474                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14475                 this.el.un("keydown", this.relay);
14476             }else{
14477                 this.el.un("keydown", this.prepareEvent);
14478                 this.el.un("keypress", this.relay);
14479             }
14480                     this.disabled = true;
14481                 }
14482         }
14483 };/*
14484  * Based on:
14485  * Ext JS Library 1.1.1
14486  * Copyright(c) 2006-2007, Ext JS, LLC.
14487  *
14488  * Originally Released Under LGPL - original licence link has changed is not relivant.
14489  *
14490  * Fork - LGPL
14491  * <script type="text/javascript">
14492  */
14493
14494  
14495 /**
14496  * @class Roo.KeyMap
14497  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14498  * The constructor accepts the same config object as defined by {@link #addBinding}.
14499  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14500  * combination it will call the function with this signature (if the match is a multi-key
14501  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14502  * A KeyMap can also handle a string representation of keys.<br />
14503  * Usage:
14504  <pre><code>
14505 // map one key by key code
14506 var map = new Roo.KeyMap("my-element", {
14507     key: 13, // or Roo.EventObject.ENTER
14508     fn: myHandler,
14509     scope: myObject
14510 });
14511
14512 // map multiple keys to one action by string
14513 var map = new Roo.KeyMap("my-element", {
14514     key: "a\r\n\t",
14515     fn: myHandler,
14516     scope: myObject
14517 });
14518
14519 // map multiple keys to multiple actions by strings and array of codes
14520 var map = new Roo.KeyMap("my-element", [
14521     {
14522         key: [10,13],
14523         fn: function(){ alert("Return was pressed"); }
14524     }, {
14525         key: "abc",
14526         fn: function(){ alert('a, b or c was pressed'); }
14527     }, {
14528         key: "\t",
14529         ctrl:true,
14530         shift:true,
14531         fn: function(){ alert('Control + shift + tab was pressed.'); }
14532     }
14533 ]);
14534 </code></pre>
14535  * <b>Note: A KeyMap starts enabled</b>
14536  * @constructor
14537  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14538  * @param {Object} config The config (see {@link #addBinding})
14539  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14540  */
14541 Roo.KeyMap = function(el, config, eventName){
14542     this.el  = Roo.get(el);
14543     this.eventName = eventName || "keydown";
14544     this.bindings = [];
14545     if(config){
14546         this.addBinding(config);
14547     }
14548     this.enable();
14549 };
14550
14551 Roo.KeyMap.prototype = {
14552     /**
14553      * True to stop the event from bubbling and prevent the default browser action if the
14554      * key was handled by the KeyMap (defaults to false)
14555      * @type Boolean
14556      */
14557     stopEvent : false,
14558
14559     /**
14560      * Add a new binding to this KeyMap. The following config object properties are supported:
14561      * <pre>
14562 Property    Type             Description
14563 ----------  ---------------  ----------------------------------------------------------------------
14564 key         String/Array     A single keycode or an array of keycodes to handle
14565 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14566 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14567 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14568 fn          Function         The function to call when KeyMap finds the expected key combination
14569 scope       Object           The scope of the callback function
14570 </pre>
14571      *
14572      * Usage:
14573      * <pre><code>
14574 // Create a KeyMap
14575 var map = new Roo.KeyMap(document, {
14576     key: Roo.EventObject.ENTER,
14577     fn: handleKey,
14578     scope: this
14579 });
14580
14581 //Add a new binding to the existing KeyMap later
14582 map.addBinding({
14583     key: 'abc',
14584     shift: true,
14585     fn: handleKey,
14586     scope: this
14587 });
14588 </code></pre>
14589      * @param {Object/Array} config A single KeyMap config or an array of configs
14590      */
14591         addBinding : function(config){
14592         if(config instanceof Array){
14593             for(var i = 0, len = config.length; i < len; i++){
14594                 this.addBinding(config[i]);
14595             }
14596             return;
14597         }
14598         var keyCode = config.key,
14599             shift = config.shift, 
14600             ctrl = config.ctrl, 
14601             alt = config.alt,
14602             fn = config.fn,
14603             scope = config.scope;
14604         if(typeof keyCode == "string"){
14605             var ks = [];
14606             var keyString = keyCode.toUpperCase();
14607             for(var j = 0, len = keyString.length; j < len; j++){
14608                 ks.push(keyString.charCodeAt(j));
14609             }
14610             keyCode = ks;
14611         }
14612         var keyArray = keyCode instanceof Array;
14613         var handler = function(e){
14614             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14615                 var k = e.getKey();
14616                 if(keyArray){
14617                     for(var i = 0, len = keyCode.length; i < len; i++){
14618                         if(keyCode[i] == k){
14619                           if(this.stopEvent){
14620                               e.stopEvent();
14621                           }
14622                           fn.call(scope || window, k, e);
14623                           return;
14624                         }
14625                     }
14626                 }else{
14627                     if(k == keyCode){
14628                         if(this.stopEvent){
14629                            e.stopEvent();
14630                         }
14631                         fn.call(scope || window, k, e);
14632                     }
14633                 }
14634             }
14635         };
14636         this.bindings.push(handler);  
14637         },
14638
14639     /**
14640      * Shorthand for adding a single key listener
14641      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14642      * following options:
14643      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14644      * @param {Function} fn The function to call
14645      * @param {Object} scope (optional) The scope of the function
14646      */
14647     on : function(key, fn, scope){
14648         var keyCode, shift, ctrl, alt;
14649         if(typeof key == "object" && !(key instanceof Array)){
14650             keyCode = key.key;
14651             shift = key.shift;
14652             ctrl = key.ctrl;
14653             alt = key.alt;
14654         }else{
14655             keyCode = key;
14656         }
14657         this.addBinding({
14658             key: keyCode,
14659             shift: shift,
14660             ctrl: ctrl,
14661             alt: alt,
14662             fn: fn,
14663             scope: scope
14664         })
14665     },
14666
14667     // private
14668     handleKeyDown : function(e){
14669             if(this.enabled){ //just in case
14670             var b = this.bindings;
14671             for(var i = 0, len = b.length; i < len; i++){
14672                 b[i].call(this, e);
14673             }
14674             }
14675         },
14676         
14677         /**
14678          * Returns true if this KeyMap is enabled
14679          * @return {Boolean} 
14680          */
14681         isEnabled : function(){
14682             return this.enabled;  
14683         },
14684         
14685         /**
14686          * Enables this KeyMap
14687          */
14688         enable: function(){
14689                 if(!this.enabled){
14690                     this.el.on(this.eventName, this.handleKeyDown, this);
14691                     this.enabled = true;
14692                 }
14693         },
14694
14695         /**
14696          * Disable this KeyMap
14697          */
14698         disable: function(){
14699                 if(this.enabled){
14700                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14701                     this.enabled = false;
14702                 }
14703         }
14704 };/*
14705  * Based on:
14706  * Ext JS Library 1.1.1
14707  * Copyright(c) 2006-2007, Ext JS, LLC.
14708  *
14709  * Originally Released Under LGPL - original licence link has changed is not relivant.
14710  *
14711  * Fork - LGPL
14712  * <script type="text/javascript">
14713  */
14714
14715  
14716 /**
14717  * @class Roo.util.TextMetrics
14718  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14719  * wide, in pixels, a given block of text will be.
14720  * @singleton
14721  */
14722 Roo.util.TextMetrics = function(){
14723     var shared;
14724     return {
14725         /**
14726          * Measures the size of the specified text
14727          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14728          * that can affect the size of the rendered text
14729          * @param {String} text The text to measure
14730          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14731          * in order to accurately measure the text height
14732          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14733          */
14734         measure : function(el, text, fixedWidth){
14735             if(!shared){
14736                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14737             }
14738             shared.bind(el);
14739             shared.setFixedWidth(fixedWidth || 'auto');
14740             return shared.getSize(text);
14741         },
14742
14743         /**
14744          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14745          * the overhead of multiple calls to initialize the style properties on each measurement.
14746          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14747          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14748          * in order to accurately measure the text height
14749          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14750          */
14751         createInstance : function(el, fixedWidth){
14752             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14753         }
14754     };
14755 }();
14756
14757  
14758
14759 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14760     var ml = new Roo.Element(document.createElement('div'));
14761     document.body.appendChild(ml.dom);
14762     ml.position('absolute');
14763     ml.setLeftTop(-1000, -1000);
14764     ml.hide();
14765
14766     if(fixedWidth){
14767         ml.setWidth(fixedWidth);
14768     }
14769      
14770     var instance = {
14771         /**
14772          * Returns the size of the specified text based on the internal element's style and width properties
14773          * @memberOf Roo.util.TextMetrics.Instance#
14774          * @param {String} text The text to measure
14775          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14776          */
14777         getSize : function(text){
14778             ml.update(text);
14779             var s = ml.getSize();
14780             ml.update('');
14781             return s;
14782         },
14783
14784         /**
14785          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14786          * that can affect the size of the rendered text
14787          * @memberOf Roo.util.TextMetrics.Instance#
14788          * @param {String/HTMLElement} el The element, dom node or id
14789          */
14790         bind : function(el){
14791             ml.setStyle(
14792                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14793             );
14794         },
14795
14796         /**
14797          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14798          * to set a fixed width in order to accurately measure the text height.
14799          * @memberOf Roo.util.TextMetrics.Instance#
14800          * @param {Number} width The width to set on the element
14801          */
14802         setFixedWidth : function(width){
14803             ml.setWidth(width);
14804         },
14805
14806         /**
14807          * Returns the measured width of the specified text
14808          * @memberOf Roo.util.TextMetrics.Instance#
14809          * @param {String} text The text to measure
14810          * @return {Number} width The width in pixels
14811          */
14812         getWidth : function(text){
14813             ml.dom.style.width = 'auto';
14814             return this.getSize(text).width;
14815         },
14816
14817         /**
14818          * Returns the measured height of the specified text.  For multiline text, be sure to call
14819          * {@link #setFixedWidth} if necessary.
14820          * @memberOf Roo.util.TextMetrics.Instance#
14821          * @param {String} text The text to measure
14822          * @return {Number} height The height in pixels
14823          */
14824         getHeight : function(text){
14825             return this.getSize(text).height;
14826         }
14827     };
14828
14829     instance.bind(bindTo);
14830
14831     return instance;
14832 };
14833
14834 // backwards compat
14835 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14836  * Based on:
14837  * Ext JS Library 1.1.1
14838  * Copyright(c) 2006-2007, Ext JS, LLC.
14839  *
14840  * Originally Released Under LGPL - original licence link has changed is not relivant.
14841  *
14842  * Fork - LGPL
14843  * <script type="text/javascript">
14844  */
14845
14846 /**
14847  * @class Roo.state.Provider
14848  * Abstract base class for state provider implementations. This class provides methods
14849  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14850  * Provider interface.
14851  */
14852 Roo.state.Provider = function(){
14853     /**
14854      * @event statechange
14855      * Fires when a state change occurs.
14856      * @param {Provider} this This state provider
14857      * @param {String} key The state key which was changed
14858      * @param {String} value The encoded value for the state
14859      */
14860     this.addEvents({
14861         "statechange": true
14862     });
14863     this.state = {};
14864     Roo.state.Provider.superclass.constructor.call(this);
14865 };
14866 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14867     /**
14868      * Returns the current value for a key
14869      * @param {String} name The key name
14870      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14871      * @return {Mixed} The state data
14872      */
14873     get : function(name, defaultValue){
14874         return typeof this.state[name] == "undefined" ?
14875             defaultValue : this.state[name];
14876     },
14877     
14878     /**
14879      * Clears a value from the state
14880      * @param {String} name The key name
14881      */
14882     clear : function(name){
14883         delete this.state[name];
14884         this.fireEvent("statechange", this, name, null);
14885     },
14886     
14887     /**
14888      * Sets the value for a key
14889      * @param {String} name The key name
14890      * @param {Mixed} value The value to set
14891      */
14892     set : function(name, value){
14893         this.state[name] = value;
14894         this.fireEvent("statechange", this, name, value);
14895     },
14896     
14897     /**
14898      * Decodes a string previously encoded with {@link #encodeValue}.
14899      * @param {String} value The value to decode
14900      * @return {Mixed} The decoded value
14901      */
14902     decodeValue : function(cookie){
14903         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14904         var matches = re.exec(unescape(cookie));
14905         if(!matches || !matches[1]) {
14906             return; // non state cookie
14907         }
14908         var type = matches[1];
14909         var v = matches[2];
14910         switch(type){
14911             case "n":
14912                 return parseFloat(v);
14913             case "d":
14914                 return new Date(Date.parse(v));
14915             case "b":
14916                 return (v == "1");
14917             case "a":
14918                 var all = [];
14919                 var values = v.split("^");
14920                 for(var i = 0, len = values.length; i < len; i++){
14921                     all.push(this.decodeValue(values[i]));
14922                 }
14923                 return all;
14924            case "o":
14925                 var all = {};
14926                 var values = v.split("^");
14927                 for(var i = 0, len = values.length; i < len; i++){
14928                     var kv = values[i].split("=");
14929                     all[kv[0]] = this.decodeValue(kv[1]);
14930                 }
14931                 return all;
14932            default:
14933                 return v;
14934         }
14935     },
14936     
14937     /**
14938      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14939      * @param {Mixed} value The value to encode
14940      * @return {String} The encoded value
14941      */
14942     encodeValue : function(v){
14943         var enc;
14944         if(typeof v == "number"){
14945             enc = "n:" + v;
14946         }else if(typeof v == "boolean"){
14947             enc = "b:" + (v ? "1" : "0");
14948         }else if(v instanceof Date){
14949             enc = "d:" + v.toGMTString();
14950         }else if(v instanceof Array){
14951             var flat = "";
14952             for(var i = 0, len = v.length; i < len; i++){
14953                 flat += this.encodeValue(v[i]);
14954                 if(i != len-1) {
14955                     flat += "^";
14956                 }
14957             }
14958             enc = "a:" + flat;
14959         }else if(typeof v == "object"){
14960             var flat = "";
14961             for(var key in v){
14962                 if(typeof v[key] != "function"){
14963                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14964                 }
14965             }
14966             enc = "o:" + flat.substring(0, flat.length-1);
14967         }else{
14968             enc = "s:" + v;
14969         }
14970         return escape(enc);        
14971     }
14972 });
14973
14974 /*
14975  * Based on:
14976  * Ext JS Library 1.1.1
14977  * Copyright(c) 2006-2007, Ext JS, LLC.
14978  *
14979  * Originally Released Under LGPL - original licence link has changed is not relivant.
14980  *
14981  * Fork - LGPL
14982  * <script type="text/javascript">
14983  */
14984 /**
14985  * @class Roo.state.Manager
14986  * This is the global state manager. By default all components that are "state aware" check this class
14987  * for state information if you don't pass them a custom state provider. In order for this class
14988  * to be useful, it must be initialized with a provider when your application initializes.
14989  <pre><code>
14990 // in your initialization function
14991 init : function(){
14992    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14993    ...
14994    // supposed you have a {@link Roo.BorderLayout}
14995    var layout = new Roo.BorderLayout(...);
14996    layout.restoreState();
14997    // or a {Roo.BasicDialog}
14998    var dialog = new Roo.BasicDialog(...);
14999    dialog.restoreState();
15000  </code></pre>
15001  * @singleton
15002  */
15003 Roo.state.Manager = function(){
15004     var provider = new Roo.state.Provider();
15005     
15006     return {
15007         /**
15008          * Configures the default state provider for your application
15009          * @param {Provider} stateProvider The state provider to set
15010          */
15011         setProvider : function(stateProvider){
15012             provider = stateProvider;
15013         },
15014         
15015         /**
15016          * Returns the current value for a key
15017          * @param {String} name The key name
15018          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15019          * @return {Mixed} The state data
15020          */
15021         get : function(key, defaultValue){
15022             return provider.get(key, defaultValue);
15023         },
15024         
15025         /**
15026          * Sets the value for a key
15027          * @param {String} name The key name
15028          * @param {Mixed} value The state data
15029          */
15030          set : function(key, value){
15031             provider.set(key, value);
15032         },
15033         
15034         /**
15035          * Clears a value from the state
15036          * @param {String} name The key name
15037          */
15038         clear : function(key){
15039             provider.clear(key);
15040         },
15041         
15042         /**
15043          * Gets the currently configured state provider
15044          * @return {Provider} The state provider
15045          */
15046         getProvider : function(){
15047             return provider;
15048         }
15049     };
15050 }();
15051 /*
15052  * Based on:
15053  * Ext JS Library 1.1.1
15054  * Copyright(c) 2006-2007, Ext JS, LLC.
15055  *
15056  * Originally Released Under LGPL - original licence link has changed is not relivant.
15057  *
15058  * Fork - LGPL
15059  * <script type="text/javascript">
15060  */
15061 /**
15062  * @class Roo.state.CookieProvider
15063  * @extends Roo.state.Provider
15064  * The default Provider implementation which saves state via cookies.
15065  * <br />Usage:
15066  <pre><code>
15067    var cp = new Roo.state.CookieProvider({
15068        path: "/cgi-bin/",
15069        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15070        domain: "roojs.com"
15071    })
15072    Roo.state.Manager.setProvider(cp);
15073  </code></pre>
15074  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15075  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15076  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15077  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15078  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15079  * domain the page is running on including the 'www' like 'www.roojs.com')
15080  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15081  * @constructor
15082  * Create a new CookieProvider
15083  * @param {Object} config The configuration object
15084  */
15085 Roo.state.CookieProvider = function(config){
15086     Roo.state.CookieProvider.superclass.constructor.call(this);
15087     this.path = "/";
15088     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15089     this.domain = null;
15090     this.secure = false;
15091     Roo.apply(this, config);
15092     this.state = this.readCookies();
15093 };
15094
15095 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15096     // private
15097     set : function(name, value){
15098         if(typeof value == "undefined" || value === null){
15099             this.clear(name);
15100             return;
15101         }
15102         this.setCookie(name, value);
15103         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15104     },
15105
15106     // private
15107     clear : function(name){
15108         this.clearCookie(name);
15109         Roo.state.CookieProvider.superclass.clear.call(this, name);
15110     },
15111
15112     // private
15113     readCookies : function(){
15114         var cookies = {};
15115         var c = document.cookie + ";";
15116         var re = /\s?(.*?)=(.*?);/g;
15117         var matches;
15118         while((matches = re.exec(c)) != null){
15119             var name = matches[1];
15120             var value = matches[2];
15121             if(name && name.substring(0,3) == "ys-"){
15122                 cookies[name.substr(3)] = this.decodeValue(value);
15123             }
15124         }
15125         return cookies;
15126     },
15127
15128     // private
15129     setCookie : function(name, value){
15130         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15131            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15132            ((this.path == null) ? "" : ("; path=" + this.path)) +
15133            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15134            ((this.secure == true) ? "; secure" : "");
15135     },
15136
15137     // private
15138     clearCookie : function(name){
15139         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15140            ((this.path == null) ? "" : ("; path=" + this.path)) +
15141            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15142            ((this.secure == true) ? "; secure" : "");
15143     }
15144 });/*
15145  * Based on:
15146  * Ext JS Library 1.1.1
15147  * Copyright(c) 2006-2007, Ext JS, LLC.
15148  *
15149  * Originally Released Under LGPL - original licence link has changed is not relivant.
15150  *
15151  * Fork - LGPL
15152  * <script type="text/javascript">
15153  */
15154  
15155
15156 /**
15157  * @class Roo.ComponentMgr
15158  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15159  * @singleton
15160  */
15161 Roo.ComponentMgr = function(){
15162     var all = new Roo.util.MixedCollection();
15163
15164     return {
15165         /**
15166          * Registers a component.
15167          * @param {Roo.Component} c The component
15168          */
15169         register : function(c){
15170             all.add(c);
15171         },
15172
15173         /**
15174          * Unregisters a component.
15175          * @param {Roo.Component} c The component
15176          */
15177         unregister : function(c){
15178             all.remove(c);
15179         },
15180
15181         /**
15182          * Returns a component by id
15183          * @param {String} id The component id
15184          */
15185         get : function(id){
15186             return all.get(id);
15187         },
15188
15189         /**
15190          * Registers a function that will be called when a specified component is added to ComponentMgr
15191          * @param {String} id The component id
15192          * @param {Funtction} fn The callback function
15193          * @param {Object} scope The scope of the callback
15194          */
15195         onAvailable : function(id, fn, scope){
15196             all.on("add", function(index, o){
15197                 if(o.id == id){
15198                     fn.call(scope || o, o);
15199                     all.un("add", fn, scope);
15200                 }
15201             });
15202         }
15203     };
15204 }();/*
15205  * Based on:
15206  * Ext JS Library 1.1.1
15207  * Copyright(c) 2006-2007, Ext JS, LLC.
15208  *
15209  * Originally Released Under LGPL - original licence link has changed is not relivant.
15210  *
15211  * Fork - LGPL
15212  * <script type="text/javascript">
15213  */
15214  
15215 /**
15216  * @class Roo.Component
15217  * @extends Roo.util.Observable
15218  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15219  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15220  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15221  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15222  * All visual components (widgets) that require rendering into a layout should subclass Component.
15223  * @constructor
15224  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15225  * 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
15226  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15227  */
15228 Roo.Component = function(config){
15229     config = config || {};
15230     if(config.tagName || config.dom || typeof config == "string"){ // element object
15231         config = {el: config, id: config.id || config};
15232     }
15233     this.initialConfig = config;
15234
15235     Roo.apply(this, config);
15236     this.addEvents({
15237         /**
15238          * @event disable
15239          * Fires after the component is disabled.
15240              * @param {Roo.Component} this
15241              */
15242         disable : true,
15243         /**
15244          * @event enable
15245          * Fires after the component is enabled.
15246              * @param {Roo.Component} this
15247              */
15248         enable : true,
15249         /**
15250          * @event beforeshow
15251          * Fires before the component is shown.  Return false to stop the show.
15252              * @param {Roo.Component} this
15253              */
15254         beforeshow : true,
15255         /**
15256          * @event show
15257          * Fires after the component is shown.
15258              * @param {Roo.Component} this
15259              */
15260         show : true,
15261         /**
15262          * @event beforehide
15263          * Fires before the component is hidden. Return false to stop the hide.
15264              * @param {Roo.Component} this
15265              */
15266         beforehide : true,
15267         /**
15268          * @event hide
15269          * Fires after the component is hidden.
15270              * @param {Roo.Component} this
15271              */
15272         hide : true,
15273         /**
15274          * @event beforerender
15275          * Fires before the component is rendered. Return false to stop the render.
15276              * @param {Roo.Component} this
15277              */
15278         beforerender : true,
15279         /**
15280          * @event render
15281          * Fires after the component is rendered.
15282              * @param {Roo.Component} this
15283              */
15284         render : true,
15285         /**
15286          * @event beforedestroy
15287          * Fires before the component is destroyed. Return false to stop the destroy.
15288              * @param {Roo.Component} this
15289              */
15290         beforedestroy : true,
15291         /**
15292          * @event destroy
15293          * Fires after the component is destroyed.
15294              * @param {Roo.Component} this
15295              */
15296         destroy : true
15297     });
15298     if(!this.id){
15299         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15300     }
15301     Roo.ComponentMgr.register(this);
15302     Roo.Component.superclass.constructor.call(this);
15303     this.initComponent();
15304     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15305         this.render(this.renderTo);
15306         delete this.renderTo;
15307     }
15308 };
15309
15310 /** @private */
15311 Roo.Component.AUTO_ID = 1000;
15312
15313 Roo.extend(Roo.Component, Roo.util.Observable, {
15314     /**
15315      * @scope Roo.Component.prototype
15316      * @type {Boolean}
15317      * true if this component is hidden. Read-only.
15318      */
15319     hidden : false,
15320     /**
15321      * @type {Boolean}
15322      * true if this component is disabled. Read-only.
15323      */
15324     disabled : false,
15325     /**
15326      * @type {Boolean}
15327      * true if this component has been rendered. Read-only.
15328      */
15329     rendered : false,
15330     
15331     /** @cfg {String} disableClass
15332      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15333      */
15334     disabledClass : "x-item-disabled",
15335         /** @cfg {Boolean} allowDomMove
15336          * Whether the component can move the Dom node when rendering (defaults to true).
15337          */
15338     allowDomMove : true,
15339     /** @cfg {String} hideMode (display|visibility)
15340      * How this component should hidden. Supported values are
15341      * "visibility" (css visibility), "offsets" (negative offset position) and
15342      * "display" (css display) - defaults to "display".
15343      */
15344     hideMode: 'display',
15345
15346     /** @private */
15347     ctype : "Roo.Component",
15348
15349     /**
15350      * @cfg {String} actionMode 
15351      * which property holds the element that used for  hide() / show() / disable() / enable()
15352      * default is 'el' 
15353      */
15354     actionMode : "el",
15355
15356     /** @private */
15357     getActionEl : function(){
15358         return this[this.actionMode];
15359     },
15360
15361     initComponent : Roo.emptyFn,
15362     /**
15363      * If this is a lazy rendering component, render it to its container element.
15364      * @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.
15365      */
15366     render : function(container, position){
15367         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15368             if(!container && this.el){
15369                 this.el = Roo.get(this.el);
15370                 container = this.el.dom.parentNode;
15371                 this.allowDomMove = false;
15372             }
15373             this.container = Roo.get(container);
15374             this.rendered = true;
15375             if(position !== undefined){
15376                 if(typeof position == 'number'){
15377                     position = this.container.dom.childNodes[position];
15378                 }else{
15379                     position = Roo.getDom(position);
15380                 }
15381             }
15382             this.onRender(this.container, position || null);
15383             if(this.cls){
15384                 this.el.addClass(this.cls);
15385                 delete this.cls;
15386             }
15387             if(this.style){
15388                 this.el.applyStyles(this.style);
15389                 delete this.style;
15390             }
15391             this.fireEvent("render", this);
15392             this.afterRender(this.container);
15393             if(this.hidden){
15394                 this.hide();
15395             }
15396             if(this.disabled){
15397                 this.disable();
15398             }
15399         }
15400         return this;
15401     },
15402
15403     /** @private */
15404     // default function is not really useful
15405     onRender : function(ct, position){
15406         if(this.el){
15407             this.el = Roo.get(this.el);
15408             if(this.allowDomMove !== false){
15409                 ct.dom.insertBefore(this.el.dom, position);
15410             }
15411         }
15412     },
15413
15414     /** @private */
15415     getAutoCreate : function(){
15416         var cfg = typeof this.autoCreate == "object" ?
15417                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15418         if(this.id && !cfg.id){
15419             cfg.id = this.id;
15420         }
15421         return cfg;
15422     },
15423
15424     /** @private */
15425     afterRender : Roo.emptyFn,
15426
15427     /**
15428      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15429      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15430      */
15431     destroy : function(){
15432         if(this.fireEvent("beforedestroy", this) !== false){
15433             this.purgeListeners();
15434             this.beforeDestroy();
15435             if(this.rendered){
15436                 this.el.removeAllListeners();
15437                 this.el.remove();
15438                 if(this.actionMode == "container"){
15439                     this.container.remove();
15440                 }
15441             }
15442             this.onDestroy();
15443             Roo.ComponentMgr.unregister(this);
15444             this.fireEvent("destroy", this);
15445         }
15446     },
15447
15448         /** @private */
15449     beforeDestroy : function(){
15450
15451     },
15452
15453         /** @private */
15454         onDestroy : function(){
15455
15456     },
15457
15458     /**
15459      * Returns the underlying {@link Roo.Element}.
15460      * @return {Roo.Element} The element
15461      */
15462     getEl : function(){
15463         return this.el;
15464     },
15465
15466     /**
15467      * Returns the id of this component.
15468      * @return {String}
15469      */
15470     getId : function(){
15471         return this.id;
15472     },
15473
15474     /**
15475      * Try to focus this component.
15476      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15477      * @return {Roo.Component} this
15478      */
15479     focus : function(selectText){
15480         if(this.rendered){
15481             this.el.focus();
15482             if(selectText === true){
15483                 this.el.dom.select();
15484             }
15485         }
15486         return this;
15487     },
15488
15489     /** @private */
15490     blur : function(){
15491         if(this.rendered){
15492             this.el.blur();
15493         }
15494         return this;
15495     },
15496
15497     /**
15498      * Disable this component.
15499      * @return {Roo.Component} this
15500      */
15501     disable : function(){
15502         if(this.rendered){
15503             this.onDisable();
15504         }
15505         this.disabled = true;
15506         this.fireEvent("disable", this);
15507         return this;
15508     },
15509
15510         // private
15511     onDisable : function(){
15512         this.getActionEl().addClass(this.disabledClass);
15513         this.el.dom.disabled = true;
15514     },
15515
15516     /**
15517      * Enable this component.
15518      * @return {Roo.Component} this
15519      */
15520     enable : function(){
15521         if(this.rendered){
15522             this.onEnable();
15523         }
15524         this.disabled = false;
15525         this.fireEvent("enable", this);
15526         return this;
15527     },
15528
15529         // private
15530     onEnable : function(){
15531         this.getActionEl().removeClass(this.disabledClass);
15532         this.el.dom.disabled = false;
15533     },
15534
15535     /**
15536      * Convenience function for setting disabled/enabled by boolean.
15537      * @param {Boolean} disabled
15538      */
15539     setDisabled : function(disabled){
15540         this[disabled ? "disable" : "enable"]();
15541     },
15542
15543     /**
15544      * Show this component.
15545      * @return {Roo.Component} this
15546      */
15547     show: function(){
15548         if(this.fireEvent("beforeshow", this) !== false){
15549             this.hidden = false;
15550             if(this.rendered){
15551                 this.onShow();
15552             }
15553             this.fireEvent("show", this);
15554         }
15555         return this;
15556     },
15557
15558     // private
15559     onShow : function(){
15560         var ae = this.getActionEl();
15561         if(this.hideMode == 'visibility'){
15562             ae.dom.style.visibility = "visible";
15563         }else if(this.hideMode == 'offsets'){
15564             ae.removeClass('x-hidden');
15565         }else{
15566             ae.dom.style.display = "";
15567         }
15568     },
15569
15570     /**
15571      * Hide this component.
15572      * @return {Roo.Component} this
15573      */
15574     hide: function(){
15575         if(this.fireEvent("beforehide", this) !== false){
15576             this.hidden = true;
15577             if(this.rendered){
15578                 this.onHide();
15579             }
15580             this.fireEvent("hide", this);
15581         }
15582         return this;
15583     },
15584
15585     // private
15586     onHide : function(){
15587         var ae = this.getActionEl();
15588         if(this.hideMode == 'visibility'){
15589             ae.dom.style.visibility = "hidden";
15590         }else if(this.hideMode == 'offsets'){
15591             ae.addClass('x-hidden');
15592         }else{
15593             ae.dom.style.display = "none";
15594         }
15595     },
15596
15597     /**
15598      * Convenience function to hide or show this component by boolean.
15599      * @param {Boolean} visible True to show, false to hide
15600      * @return {Roo.Component} this
15601      */
15602     setVisible: function(visible){
15603         if(visible) {
15604             this.show();
15605         }else{
15606             this.hide();
15607         }
15608         return this;
15609     },
15610
15611     /**
15612      * Returns true if this component is visible.
15613      */
15614     isVisible : function(){
15615         return this.getActionEl().isVisible();
15616     },
15617
15618     cloneConfig : function(overrides){
15619         overrides = overrides || {};
15620         var id = overrides.id || Roo.id();
15621         var cfg = Roo.applyIf(overrides, this.initialConfig);
15622         cfg.id = id; // prevent dup id
15623         return new this.constructor(cfg);
15624     }
15625 });/*
15626  * Based on:
15627  * Ext JS Library 1.1.1
15628  * Copyright(c) 2006-2007, Ext JS, LLC.
15629  *
15630  * Originally Released Under LGPL - original licence link has changed is not relivant.
15631  *
15632  * Fork - LGPL
15633  * <script type="text/javascript">
15634  */
15635
15636 /**
15637  * @class Roo.BoxComponent
15638  * @extends Roo.Component
15639  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15640  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15641  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15642  * layout containers.
15643  * @constructor
15644  * @param {Roo.Element/String/Object} config The configuration options.
15645  */
15646 Roo.BoxComponent = function(config){
15647     Roo.Component.call(this, config);
15648     this.addEvents({
15649         /**
15650          * @event resize
15651          * Fires after the component is resized.
15652              * @param {Roo.Component} this
15653              * @param {Number} adjWidth The box-adjusted width that was set
15654              * @param {Number} adjHeight The box-adjusted height that was set
15655              * @param {Number} rawWidth The width that was originally specified
15656              * @param {Number} rawHeight The height that was originally specified
15657              */
15658         resize : true,
15659         /**
15660          * @event move
15661          * Fires after the component is moved.
15662              * @param {Roo.Component} this
15663              * @param {Number} x The new x position
15664              * @param {Number} y The new y position
15665              */
15666         move : true
15667     });
15668 };
15669
15670 Roo.extend(Roo.BoxComponent, Roo.Component, {
15671     // private, set in afterRender to signify that the component has been rendered
15672     boxReady : false,
15673     // private, used to defer height settings to subclasses
15674     deferHeight: false,
15675     /** @cfg {Number} width
15676      * width (optional) size of component
15677      */
15678      /** @cfg {Number} height
15679      * height (optional) size of component
15680      */
15681      
15682     /**
15683      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15684      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15685      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15686      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15687      * @return {Roo.BoxComponent} this
15688      */
15689     setSize : function(w, h){
15690         // support for standard size objects
15691         if(typeof w == 'object'){
15692             h = w.height;
15693             w = w.width;
15694         }
15695         // not rendered
15696         if(!this.boxReady){
15697             this.width = w;
15698             this.height = h;
15699             return this;
15700         }
15701
15702         // prevent recalcs when not needed
15703         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15704             return this;
15705         }
15706         this.lastSize = {width: w, height: h};
15707
15708         var adj = this.adjustSize(w, h);
15709         var aw = adj.width, ah = adj.height;
15710         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15711             var rz = this.getResizeEl();
15712             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15713                 rz.setSize(aw, ah);
15714             }else if(!this.deferHeight && ah !== undefined){
15715                 rz.setHeight(ah);
15716             }else if(aw !== undefined){
15717                 rz.setWidth(aw);
15718             }
15719             this.onResize(aw, ah, w, h);
15720             this.fireEvent('resize', this, aw, ah, w, h);
15721         }
15722         return this;
15723     },
15724
15725     /**
15726      * Gets the current size of the component's underlying element.
15727      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15728      */
15729     getSize : function(){
15730         return this.el.getSize();
15731     },
15732
15733     /**
15734      * Gets the current XY position of the component's underlying element.
15735      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15736      * @return {Array} The XY position of the element (e.g., [100, 200])
15737      */
15738     getPosition : function(local){
15739         if(local === true){
15740             return [this.el.getLeft(true), this.el.getTop(true)];
15741         }
15742         return this.xy || this.el.getXY();
15743     },
15744
15745     /**
15746      * Gets the current box measurements 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      * @returns {Object} box An object in the format {x, y, width, height}
15749      */
15750     getBox : function(local){
15751         var s = this.el.getSize();
15752         if(local){
15753             s.x = this.el.getLeft(true);
15754             s.y = this.el.getTop(true);
15755         }else{
15756             var xy = this.xy || this.el.getXY();
15757             s.x = xy[0];
15758             s.y = xy[1];
15759         }
15760         return s;
15761     },
15762
15763     /**
15764      * Sets the current box measurements of the component's underlying element.
15765      * @param {Object} box An object in the format {x, y, width, height}
15766      * @returns {Roo.BoxComponent} this
15767      */
15768     updateBox : function(box){
15769         this.setSize(box.width, box.height);
15770         this.setPagePosition(box.x, box.y);
15771         return this;
15772     },
15773
15774     // protected
15775     getResizeEl : function(){
15776         return this.resizeEl || this.el;
15777     },
15778
15779     // protected
15780     getPositionEl : function(){
15781         return this.positionEl || this.el;
15782     },
15783
15784     /**
15785      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15786      * This method fires the move event.
15787      * @param {Number} left The new left
15788      * @param {Number} top The new top
15789      * @returns {Roo.BoxComponent} this
15790      */
15791     setPosition : function(x, y){
15792         this.x = x;
15793         this.y = y;
15794         if(!this.boxReady){
15795             return this;
15796         }
15797         var adj = this.adjustPosition(x, y);
15798         var ax = adj.x, ay = adj.y;
15799
15800         var el = this.getPositionEl();
15801         if(ax !== undefined || ay !== undefined){
15802             if(ax !== undefined && ay !== undefined){
15803                 el.setLeftTop(ax, ay);
15804             }else if(ax !== undefined){
15805                 el.setLeft(ax);
15806             }else if(ay !== undefined){
15807                 el.setTop(ay);
15808             }
15809             this.onPosition(ax, ay);
15810             this.fireEvent('move', this, ax, ay);
15811         }
15812         return this;
15813     },
15814
15815     /**
15816      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15817      * This method fires the move event.
15818      * @param {Number} x The new x position
15819      * @param {Number} y The new y position
15820      * @returns {Roo.BoxComponent} this
15821      */
15822     setPagePosition : function(x, y){
15823         this.pageX = x;
15824         this.pageY = y;
15825         if(!this.boxReady){
15826             return;
15827         }
15828         if(x === undefined || y === undefined){ // cannot translate undefined points
15829             return;
15830         }
15831         var p = this.el.translatePoints(x, y);
15832         this.setPosition(p.left, p.top);
15833         return this;
15834     },
15835
15836     // private
15837     onRender : function(ct, position){
15838         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15839         if(this.resizeEl){
15840             this.resizeEl = Roo.get(this.resizeEl);
15841         }
15842         if(this.positionEl){
15843             this.positionEl = Roo.get(this.positionEl);
15844         }
15845     },
15846
15847     // private
15848     afterRender : function(){
15849         Roo.BoxComponent.superclass.afterRender.call(this);
15850         this.boxReady = true;
15851         this.setSize(this.width, this.height);
15852         if(this.x || this.y){
15853             this.setPosition(this.x, this.y);
15854         }
15855         if(this.pageX || this.pageY){
15856             this.setPagePosition(this.pageX, this.pageY);
15857         }
15858     },
15859
15860     /**
15861      * Force the component's size to recalculate based on the underlying element's current height and width.
15862      * @returns {Roo.BoxComponent} this
15863      */
15864     syncSize : function(){
15865         delete this.lastSize;
15866         this.setSize(this.el.getWidth(), this.el.getHeight());
15867         return this;
15868     },
15869
15870     /**
15871      * Called after the component is resized, this method is empty by default but can be implemented by any
15872      * subclass that needs to perform custom logic after a resize occurs.
15873      * @param {Number} adjWidth The box-adjusted width that was set
15874      * @param {Number} adjHeight The box-adjusted height that was set
15875      * @param {Number} rawWidth The width that was originally specified
15876      * @param {Number} rawHeight The height that was originally specified
15877      */
15878     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15879
15880     },
15881
15882     /**
15883      * Called after the component is moved, this method is empty by default but can be implemented by any
15884      * subclass that needs to perform custom logic after a move occurs.
15885      * @param {Number} x The new x position
15886      * @param {Number} y The new y position
15887      */
15888     onPosition : function(x, y){
15889
15890     },
15891
15892     // private
15893     adjustSize : function(w, h){
15894         if(this.autoWidth){
15895             w = 'auto';
15896         }
15897         if(this.autoHeight){
15898             h = 'auto';
15899         }
15900         return {width : w, height: h};
15901     },
15902
15903     // private
15904     adjustPosition : function(x, y){
15905         return {x : x, y: y};
15906     }
15907 });/*
15908  * Original code for Roojs - LGPL
15909  * <script type="text/javascript">
15910  */
15911  
15912 /**
15913  * @class Roo.XComponent
15914  * A delayed Element creator...
15915  * Or a way to group chunks of interface together.
15916  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15917  *  used in conjunction with XComponent.build() it will create an instance of each element,
15918  *  then call addxtype() to build the User interface.
15919  * 
15920  * Mypart.xyx = new Roo.XComponent({
15921
15922     parent : 'Mypart.xyz', // empty == document.element.!!
15923     order : '001',
15924     name : 'xxxx'
15925     region : 'xxxx'
15926     disabled : function() {} 
15927      
15928     tree : function() { // return an tree of xtype declared components
15929         var MODULE = this;
15930         return 
15931         {
15932             xtype : 'NestedLayoutPanel',
15933             // technicall
15934         }
15935      ]
15936  *})
15937  *
15938  *
15939  * It can be used to build a big heiracy, with parent etc.
15940  * or you can just use this to render a single compoent to a dom element
15941  * MYPART.render(Roo.Element | String(id) | dom_element )
15942  *
15943  *
15944  * Usage patterns.
15945  *
15946  * Classic Roo
15947  *
15948  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15949  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15950  *
15951  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15952  *
15953  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15954  * - if mulitple topModules exist, the last one is defined as the top module.
15955  *
15956  * Embeded Roo
15957  * 
15958  * When the top level or multiple modules are to embedded into a existing HTML page,
15959  * the parent element can container '#id' of the element where the module will be drawn.
15960  *
15961  * Bootstrap Roo
15962  *
15963  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15964  * it relies more on a include mechanism, where sub modules are included into an outer page.
15965  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15966  * 
15967  * Bootstrap Roo Included elements
15968  *
15969  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15970  * hence confusing the component builder as it thinks there are multiple top level elements. 
15971  *
15972  * 
15973  * 
15974  * @extends Roo.util.Observable
15975  * @constructor
15976  * @param cfg {Object} configuration of component
15977  * 
15978  */
15979 Roo.XComponent = function(cfg) {
15980     Roo.apply(this, cfg);
15981     this.addEvents({ 
15982         /**
15983              * @event built
15984              * Fires when this the componnt is built
15985              * @param {Roo.XComponent} c the component
15986              */
15987         'built' : true
15988         
15989     });
15990     this.region = this.region || 'center'; // default..
15991     Roo.XComponent.register(this);
15992     this.modules = false;
15993     this.el = false; // where the layout goes..
15994     
15995     
15996 }
15997 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15998     /**
15999      * @property el
16000      * The created element (with Roo.factory())
16001      * @type {Roo.Layout}
16002      */
16003     el  : false,
16004     
16005     /**
16006      * @property el
16007      * for BC  - use el in new code
16008      * @type {Roo.Layout}
16009      */
16010     panel : false,
16011     
16012     /**
16013      * @property layout
16014      * for BC  - use el in new code
16015      * @type {Roo.Layout}
16016      */
16017     layout : false,
16018     
16019      /**
16020      * @cfg {Function|boolean} disabled
16021      * If this module is disabled by some rule, return true from the funtion
16022      */
16023     disabled : false,
16024     
16025     /**
16026      * @cfg {String} parent 
16027      * Name of parent element which it get xtype added to..
16028      */
16029     parent: false,
16030     
16031     /**
16032      * @cfg {String} order
16033      * Used to set the order in which elements are created (usefull for multiple tabs)
16034      */
16035     
16036     order : false,
16037     /**
16038      * @cfg {String} name
16039      * String to display while loading.
16040      */
16041     name : false,
16042     /**
16043      * @cfg {String} region
16044      * Region to render component to (defaults to center)
16045      */
16046     region : 'center',
16047     
16048     /**
16049      * @cfg {Array} items
16050      * A single item array - the first element is the root of the tree..
16051      * It's done this way to stay compatible with the Xtype system...
16052      */
16053     items : false,
16054     
16055     /**
16056      * @property _tree
16057      * The method that retuns the tree of parts that make up this compoennt 
16058      * @type {function}
16059      */
16060     _tree  : false,
16061     
16062      /**
16063      * render
16064      * render element to dom or tree
16065      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16066      */
16067     
16068     render : function(el)
16069     {
16070         
16071         el = el || false;
16072         var hp = this.parent ? 1 : 0;
16073         Roo.debug &&  Roo.log(this);
16074         
16075         var tree = this._tree ? this._tree() : this.tree();
16076
16077         
16078         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16079             // if parent is a '#.....' string, then let's use that..
16080             var ename = this.parent.substr(1);
16081             this.parent = false;
16082             Roo.debug && Roo.log(ename);
16083             switch (ename) {
16084                 case 'bootstrap-body':
16085                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16086                         // this is the BorderLayout standard?
16087                        this.parent = { el : true };
16088                        break;
16089                     }
16090                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16091                         // need to insert stuff...
16092                         this.parent =  {
16093                              el : new Roo.bootstrap.layout.Border({
16094                                  el : document.body, 
16095                      
16096                                  center: {
16097                                     titlebar: false,
16098                                     autoScroll:false,
16099                                     closeOnTab: true,
16100                                     tabPosition: 'top',
16101                                       //resizeTabs: true,
16102                                     alwaysShowTabs: true,
16103                                     hideTabs: false
16104                                      //minTabWidth: 140
16105                                  }
16106                              })
16107                         
16108                          };
16109                          break;
16110                     }
16111                          
16112                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16113                         this.parent = { el :  new  Roo.bootstrap.Body() };
16114                         Roo.debug && Roo.log("setting el to doc body");
16115                          
16116                     } else {
16117                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16118                     }
16119                     break;
16120                 case 'bootstrap':
16121                     this.parent = { el : true};
16122                     // fall through
16123                 default:
16124                     el = Roo.get(ename);
16125                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16126                         this.parent = { el : true};
16127                     }
16128                     
16129                     break;
16130             }
16131                 
16132             
16133             if (!el && !this.parent) {
16134                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16135                 return;
16136             }
16137         }
16138         
16139         Roo.debug && Roo.log("EL:");
16140         Roo.debug && Roo.log(el);
16141         Roo.debug && Roo.log("this.parent.el:");
16142         Roo.debug && Roo.log(this.parent.el);
16143         
16144
16145         // altertive root elements ??? - we need a better way to indicate these.
16146         var is_alt = Roo.XComponent.is_alt ||
16147                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16148                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16149                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16150         
16151         
16152         
16153         if (!this.parent && is_alt) {
16154             //el = Roo.get(document.body);
16155             this.parent = { el : true };
16156         }
16157             
16158             
16159         
16160         if (!this.parent) {
16161             
16162             Roo.debug && Roo.log("no parent - creating one");
16163             
16164             el = el ? Roo.get(el) : false;      
16165             
16166             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16167                 
16168                 this.parent =  {
16169                     el : new Roo.bootstrap.layout.Border({
16170                         el: el || document.body,
16171                     
16172                         center: {
16173                             titlebar: false,
16174                             autoScroll:false,
16175                             closeOnTab: true,
16176                             tabPosition: 'top',
16177                              //resizeTabs: true,
16178                             alwaysShowTabs: false,
16179                             hideTabs: true,
16180                             minTabWidth: 140,
16181                             overflow: 'visible'
16182                          }
16183                      })
16184                 };
16185             } else {
16186             
16187                 // it's a top level one..
16188                 this.parent =  {
16189                     el : new Roo.BorderLayout(el || document.body, {
16190                         center: {
16191                             titlebar: false,
16192                             autoScroll:false,
16193                             closeOnTab: true,
16194                             tabPosition: 'top',
16195                              //resizeTabs: true,
16196                             alwaysShowTabs: el && hp? false :  true,
16197                             hideTabs: el || !hp ? true :  false,
16198                             minTabWidth: 140
16199                          }
16200                     })
16201                 };
16202             }
16203         }
16204         
16205         if (!this.parent.el) {
16206                 // probably an old style ctor, which has been disabled.
16207                 return;
16208
16209         }
16210                 // The 'tree' method is  '_tree now' 
16211             
16212         tree.region = tree.region || this.region;
16213         var is_body = false;
16214         if (this.parent.el === true) {
16215             // bootstrap... - body..
16216             if (el) {
16217                 tree.el = el;
16218             }
16219             this.parent.el = Roo.factory(tree);
16220             is_body = true;
16221         }
16222         
16223         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16224         this.fireEvent('built', this);
16225         
16226         this.panel = this.el;
16227         this.layout = this.panel.layout;
16228         this.parentLayout = this.parent.layout  || false;  
16229          
16230     }
16231     
16232 });
16233
16234 Roo.apply(Roo.XComponent, {
16235     /**
16236      * @property  hideProgress
16237      * true to disable the building progress bar.. usefull on single page renders.
16238      * @type Boolean
16239      */
16240     hideProgress : false,
16241     /**
16242      * @property  buildCompleted
16243      * True when the builder has completed building the interface.
16244      * @type Boolean
16245      */
16246     buildCompleted : false,
16247      
16248     /**
16249      * @property  topModule
16250      * the upper most module - uses document.element as it's constructor.
16251      * @type Object
16252      */
16253      
16254     topModule  : false,
16255       
16256     /**
16257      * @property  modules
16258      * array of modules to be created by registration system.
16259      * @type {Array} of Roo.XComponent
16260      */
16261     
16262     modules : [],
16263     /**
16264      * @property  elmodules
16265      * array of modules to be created by which use #ID 
16266      * @type {Array} of Roo.XComponent
16267      */
16268      
16269     elmodules : [],
16270
16271      /**
16272      * @property  is_alt
16273      * Is an alternative Root - normally used by bootstrap or other systems,
16274      *    where the top element in the tree can wrap 'body' 
16275      * @type {boolean}  (default false)
16276      */
16277      
16278     is_alt : false,
16279     /**
16280      * @property  build_from_html
16281      * Build elements from html - used by bootstrap HTML stuff 
16282      *    - this is cleared after build is completed
16283      * @type {boolean}    (default false)
16284      */
16285      
16286     build_from_html : false,
16287     /**
16288      * Register components to be built later.
16289      *
16290      * This solves the following issues
16291      * - Building is not done on page load, but after an authentication process has occured.
16292      * - Interface elements are registered on page load
16293      * - Parent Interface elements may not be loaded before child, so this handles that..
16294      * 
16295      *
16296      * example:
16297      * 
16298      * MyApp.register({
16299           order : '000001',
16300           module : 'Pman.Tab.projectMgr',
16301           region : 'center',
16302           parent : 'Pman.layout',
16303           disabled : false,  // or use a function..
16304         })
16305      
16306      * * @param {Object} details about module
16307      */
16308     register : function(obj) {
16309                 
16310         Roo.XComponent.event.fireEvent('register', obj);
16311         switch(typeof(obj.disabled) ) {
16312                 
16313             case 'undefined':
16314                 break;
16315             
16316             case 'function':
16317                 if ( obj.disabled() ) {
16318                         return;
16319                 }
16320                 break;
16321             
16322             default:
16323                 if (obj.disabled) {
16324                         return;
16325                 }
16326                 break;
16327         }
16328                 
16329         this.modules.push(obj);
16330          
16331     },
16332     /**
16333      * convert a string to an object..
16334      * eg. 'AAA.BBB' -> finds AAA.BBB
16335
16336      */
16337     
16338     toObject : function(str)
16339     {
16340         if (!str || typeof(str) == 'object') {
16341             return str;
16342         }
16343         if (str.substring(0,1) == '#') {
16344             return str;
16345         }
16346
16347         var ar = str.split('.');
16348         var rt, o;
16349         rt = ar.shift();
16350             /** eval:var:o */
16351         try {
16352             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16353         } catch (e) {
16354             throw "Module not found : " + str;
16355         }
16356         
16357         if (o === false) {
16358             throw "Module not found : " + str;
16359         }
16360         Roo.each(ar, function(e) {
16361             if (typeof(o[e]) == 'undefined') {
16362                 throw "Module not found : " + str;
16363             }
16364             o = o[e];
16365         });
16366         
16367         return o;
16368         
16369     },
16370     
16371     
16372     /**
16373      * move modules into their correct place in the tree..
16374      * 
16375      */
16376     preBuild : function ()
16377     {
16378         var _t = this;
16379         Roo.each(this.modules , function (obj)
16380         {
16381             Roo.XComponent.event.fireEvent('beforebuild', obj);
16382             
16383             var opar = obj.parent;
16384             try { 
16385                 obj.parent = this.toObject(opar);
16386             } catch(e) {
16387                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16388                 return;
16389             }
16390             
16391             if (!obj.parent) {
16392                 Roo.debug && Roo.log("GOT top level module");
16393                 Roo.debug && Roo.log(obj);
16394                 obj.modules = new Roo.util.MixedCollection(false, 
16395                     function(o) { return o.order + '' }
16396                 );
16397                 this.topModule = obj;
16398                 return;
16399             }
16400                         // parent is a string (usually a dom element name..)
16401             if (typeof(obj.parent) == 'string') {
16402                 this.elmodules.push(obj);
16403                 return;
16404             }
16405             if (obj.parent.constructor != Roo.XComponent) {
16406                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16407             }
16408             if (!obj.parent.modules) {
16409                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16410                     function(o) { return o.order + '' }
16411                 );
16412             }
16413             if (obj.parent.disabled) {
16414                 obj.disabled = true;
16415             }
16416             obj.parent.modules.add(obj);
16417         }, this);
16418     },
16419     
16420      /**
16421      * make a list of modules to build.
16422      * @return {Array} list of modules. 
16423      */ 
16424     
16425     buildOrder : function()
16426     {
16427         var _this = this;
16428         var cmp = function(a,b) {   
16429             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16430         };
16431         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16432             throw "No top level modules to build";
16433         }
16434         
16435         // make a flat list in order of modules to build.
16436         var mods = this.topModule ? [ this.topModule ] : [];
16437                 
16438         
16439         // elmodules (is a list of DOM based modules )
16440         Roo.each(this.elmodules, function(e) {
16441             mods.push(e);
16442             if (!this.topModule &&
16443                 typeof(e.parent) == 'string' &&
16444                 e.parent.substring(0,1) == '#' &&
16445                 Roo.get(e.parent.substr(1))
16446                ) {
16447                 
16448                 _this.topModule = e;
16449             }
16450             
16451         });
16452
16453         
16454         // add modules to their parents..
16455         var addMod = function(m) {
16456             Roo.debug && Roo.log("build Order: add: " + m.name);
16457                 
16458             mods.push(m);
16459             if (m.modules && !m.disabled) {
16460                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16461                 m.modules.keySort('ASC',  cmp );
16462                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16463     
16464                 m.modules.each(addMod);
16465             } else {
16466                 Roo.debug && Roo.log("build Order: no child modules");
16467             }
16468             // not sure if this is used any more..
16469             if (m.finalize) {
16470                 m.finalize.name = m.name + " (clean up) ";
16471                 mods.push(m.finalize);
16472             }
16473             
16474         }
16475         if (this.topModule && this.topModule.modules) { 
16476             this.topModule.modules.keySort('ASC',  cmp );
16477             this.topModule.modules.each(addMod);
16478         } 
16479         return mods;
16480     },
16481     
16482      /**
16483      * Build the registered modules.
16484      * @param {Object} parent element.
16485      * @param {Function} optional method to call after module has been added.
16486      * 
16487      */ 
16488    
16489     build : function(opts) 
16490     {
16491         
16492         if (typeof(opts) != 'undefined') {
16493             Roo.apply(this,opts);
16494         }
16495         
16496         this.preBuild();
16497         var mods = this.buildOrder();
16498       
16499         //this.allmods = mods;
16500         //Roo.debug && Roo.log(mods);
16501         //return;
16502         if (!mods.length) { // should not happen
16503             throw "NO modules!!!";
16504         }
16505         
16506         
16507         var msg = "Building Interface...";
16508         // flash it up as modal - so we store the mask!?
16509         if (!this.hideProgress && Roo.MessageBox) {
16510             Roo.MessageBox.show({ title: 'loading' });
16511             Roo.MessageBox.show({
16512                title: "Please wait...",
16513                msg: msg,
16514                width:450,
16515                progress:true,
16516                closable:false,
16517                modal: false
16518               
16519             });
16520         }
16521         var total = mods.length;
16522         
16523         var _this = this;
16524         var progressRun = function() {
16525             if (!mods.length) {
16526                 Roo.debug && Roo.log('hide?');
16527                 if (!this.hideProgress && Roo.MessageBox) {
16528                     Roo.MessageBox.hide();
16529                 }
16530                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16531                 
16532                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16533                 
16534                 // THE END...
16535                 return false;   
16536             }
16537             
16538             var m = mods.shift();
16539             
16540             
16541             Roo.debug && Roo.log(m);
16542             // not sure if this is supported any more.. - modules that are are just function
16543             if (typeof(m) == 'function') { 
16544                 m.call(this);
16545                 return progressRun.defer(10, _this);
16546             } 
16547             
16548             
16549             msg = "Building Interface " + (total  - mods.length) + 
16550                     " of " + total + 
16551                     (m.name ? (' - ' + m.name) : '');
16552                         Roo.debug && Roo.log(msg);
16553             if (!_this.hideProgress &&  Roo.MessageBox) { 
16554                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16555             }
16556             
16557          
16558             // is the module disabled?
16559             var disabled = (typeof(m.disabled) == 'function') ?
16560                 m.disabled.call(m.module.disabled) : m.disabled;    
16561             
16562             
16563             if (disabled) {
16564                 return progressRun(); // we do not update the display!
16565             }
16566             
16567             // now build 
16568             
16569                         
16570                         
16571             m.render();
16572             // it's 10 on top level, and 1 on others??? why...
16573             return progressRun.defer(10, _this);
16574              
16575         }
16576         progressRun.defer(1, _this);
16577      
16578         
16579         
16580     },
16581         
16582         
16583         /**
16584          * Event Object.
16585          *
16586          *
16587          */
16588         event: false, 
16589     /**
16590          * wrapper for event.on - aliased later..  
16591          * Typically use to register a event handler for register:
16592          *
16593          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16594          *
16595          */
16596     on : false
16597    
16598     
16599     
16600 });
16601
16602 Roo.XComponent.event = new Roo.util.Observable({
16603                 events : { 
16604                         /**
16605                          * @event register
16606                          * Fires when an Component is registered,
16607                          * set the disable property on the Component to stop registration.
16608                          * @param {Roo.XComponent} c the component being registerd.
16609                          * 
16610                          */
16611                         'register' : true,
16612             /**
16613                          * @event beforebuild
16614                          * Fires before each Component is built
16615                          * can be used to apply permissions.
16616                          * @param {Roo.XComponent} c the component being registerd.
16617                          * 
16618                          */
16619                         'beforebuild' : true,
16620                         /**
16621                          * @event buildcomplete
16622                          * Fires on the top level element when all elements have been built
16623                          * @param {Roo.XComponent} the top level component.
16624                          */
16625                         'buildcomplete' : true
16626                         
16627                 }
16628 });
16629
16630 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16631  //
16632  /**
16633  * marked - a markdown parser
16634  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16635  * https://github.com/chjj/marked
16636  */
16637
16638
16639 /**
16640  *
16641  * Roo.Markdown - is a very crude wrapper around marked..
16642  *
16643  * usage:
16644  * 
16645  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16646  * 
16647  * Note: move the sample code to the bottom of this
16648  * file before uncommenting it.
16649  *
16650  */
16651
16652 Roo.Markdown = {};
16653 Roo.Markdown.toHtml = function(text) {
16654     
16655     var c = new Roo.Markdown.marked.setOptions({
16656             renderer: new Roo.Markdown.marked.Renderer(),
16657             gfm: true,
16658             tables: true,
16659             breaks: false,
16660             pedantic: false,
16661             sanitize: false,
16662             smartLists: true,
16663             smartypants: false
16664           });
16665     // A FEW HACKS!!?
16666     
16667     text = text.replace(/\\\n/g,' ');
16668     return Roo.Markdown.marked(text);
16669 };
16670 //
16671 // converter
16672 //
16673 // Wraps all "globals" so that the only thing
16674 // exposed is makeHtml().
16675 //
16676 (function() {
16677     
16678     /**
16679      * Block-Level Grammar
16680      */
16681     
16682     var block = {
16683       newline: /^\n+/,
16684       code: /^( {4}[^\n]+\n*)+/,
16685       fences: noop,
16686       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16687       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16688       nptable: noop,
16689       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16690       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16691       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16692       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16693       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16694       table: noop,
16695       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16696       text: /^[^\n]+/
16697     };
16698     
16699     block.bullet = /(?:[*+-]|\d+\.)/;
16700     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16701     block.item = replace(block.item, 'gm')
16702       (/bull/g, block.bullet)
16703       ();
16704     
16705     block.list = replace(block.list)
16706       (/bull/g, block.bullet)
16707       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16708       ('def', '\\n+(?=' + block.def.source + ')')
16709       ();
16710     
16711     block.blockquote = replace(block.blockquote)
16712       ('def', block.def)
16713       ();
16714     
16715     block._tag = '(?!(?:'
16716       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16717       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16718       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16719     
16720     block.html = replace(block.html)
16721       ('comment', /<!--[\s\S]*?-->/)
16722       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16723       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16724       (/tag/g, block._tag)
16725       ();
16726     
16727     block.paragraph = replace(block.paragraph)
16728       ('hr', block.hr)
16729       ('heading', block.heading)
16730       ('lheading', block.lheading)
16731       ('blockquote', block.blockquote)
16732       ('tag', '<' + block._tag)
16733       ('def', block.def)
16734       ();
16735     
16736     /**
16737      * Normal Block Grammar
16738      */
16739     
16740     block.normal = merge({}, block);
16741     
16742     /**
16743      * GFM Block Grammar
16744      */
16745     
16746     block.gfm = merge({}, block.normal, {
16747       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16748       paragraph: /^/,
16749       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16750     });
16751     
16752     block.gfm.paragraph = replace(block.paragraph)
16753       ('(?!', '(?!'
16754         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16755         + block.list.source.replace('\\1', '\\3') + '|')
16756       ();
16757     
16758     /**
16759      * GFM + Tables Block Grammar
16760      */
16761     
16762     block.tables = merge({}, block.gfm, {
16763       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16764       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16765     });
16766     
16767     /**
16768      * Block Lexer
16769      */
16770     
16771     function Lexer(options) {
16772       this.tokens = [];
16773       this.tokens.links = {};
16774       this.options = options || marked.defaults;
16775       this.rules = block.normal;
16776     
16777       if (this.options.gfm) {
16778         if (this.options.tables) {
16779           this.rules = block.tables;
16780         } else {
16781           this.rules = block.gfm;
16782         }
16783       }
16784     }
16785     
16786     /**
16787      * Expose Block Rules
16788      */
16789     
16790     Lexer.rules = block;
16791     
16792     /**
16793      * Static Lex Method
16794      */
16795     
16796     Lexer.lex = function(src, options) {
16797       var lexer = new Lexer(options);
16798       return lexer.lex(src);
16799     };
16800     
16801     /**
16802      * Preprocessing
16803      */
16804     
16805     Lexer.prototype.lex = function(src) {
16806       src = src
16807         .replace(/\r\n|\r/g, '\n')
16808         .replace(/\t/g, '    ')
16809         .replace(/\u00a0/g, ' ')
16810         .replace(/\u2424/g, '\n');
16811     
16812       return this.token(src, true);
16813     };
16814     
16815     /**
16816      * Lexing
16817      */
16818     
16819     Lexer.prototype.token = function(src, top, bq) {
16820       var src = src.replace(/^ +$/gm, '')
16821         , next
16822         , loose
16823         , cap
16824         , bull
16825         , b
16826         , item
16827         , space
16828         , i
16829         , l;
16830     
16831       while (src) {
16832         // newline
16833         if (cap = this.rules.newline.exec(src)) {
16834           src = src.substring(cap[0].length);
16835           if (cap[0].length > 1) {
16836             this.tokens.push({
16837               type: 'space'
16838             });
16839           }
16840         }
16841     
16842         // code
16843         if (cap = this.rules.code.exec(src)) {
16844           src = src.substring(cap[0].length);
16845           cap = cap[0].replace(/^ {4}/gm, '');
16846           this.tokens.push({
16847             type: 'code',
16848             text: !this.options.pedantic
16849               ? cap.replace(/\n+$/, '')
16850               : cap
16851           });
16852           continue;
16853         }
16854     
16855         // fences (gfm)
16856         if (cap = this.rules.fences.exec(src)) {
16857           src = src.substring(cap[0].length);
16858           this.tokens.push({
16859             type: 'code',
16860             lang: cap[2],
16861             text: cap[3] || ''
16862           });
16863           continue;
16864         }
16865     
16866         // heading
16867         if (cap = this.rules.heading.exec(src)) {
16868           src = src.substring(cap[0].length);
16869           this.tokens.push({
16870             type: 'heading',
16871             depth: cap[1].length,
16872             text: cap[2]
16873           });
16874           continue;
16875         }
16876     
16877         // table no leading pipe (gfm)
16878         if (top && (cap = this.rules.nptable.exec(src))) {
16879           src = src.substring(cap[0].length);
16880     
16881           item = {
16882             type: 'table',
16883             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16884             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16885             cells: cap[3].replace(/\n$/, '').split('\n')
16886           };
16887     
16888           for (i = 0; i < item.align.length; i++) {
16889             if (/^ *-+: *$/.test(item.align[i])) {
16890               item.align[i] = 'right';
16891             } else if (/^ *:-+: *$/.test(item.align[i])) {
16892               item.align[i] = 'center';
16893             } else if (/^ *:-+ *$/.test(item.align[i])) {
16894               item.align[i] = 'left';
16895             } else {
16896               item.align[i] = null;
16897             }
16898           }
16899     
16900           for (i = 0; i < item.cells.length; i++) {
16901             item.cells[i] = item.cells[i].split(/ *\| */);
16902           }
16903     
16904           this.tokens.push(item);
16905     
16906           continue;
16907         }
16908     
16909         // lheading
16910         if (cap = this.rules.lheading.exec(src)) {
16911           src = src.substring(cap[0].length);
16912           this.tokens.push({
16913             type: 'heading',
16914             depth: cap[2] === '=' ? 1 : 2,
16915             text: cap[1]
16916           });
16917           continue;
16918         }
16919     
16920         // hr
16921         if (cap = this.rules.hr.exec(src)) {
16922           src = src.substring(cap[0].length);
16923           this.tokens.push({
16924             type: 'hr'
16925           });
16926           continue;
16927         }
16928     
16929         // blockquote
16930         if (cap = this.rules.blockquote.exec(src)) {
16931           src = src.substring(cap[0].length);
16932     
16933           this.tokens.push({
16934             type: 'blockquote_start'
16935           });
16936     
16937           cap = cap[0].replace(/^ *> ?/gm, '');
16938     
16939           // Pass `top` to keep the current
16940           // "toplevel" state. This is exactly
16941           // how markdown.pl works.
16942           this.token(cap, top, true);
16943     
16944           this.tokens.push({
16945             type: 'blockquote_end'
16946           });
16947     
16948           continue;
16949         }
16950     
16951         // list
16952         if (cap = this.rules.list.exec(src)) {
16953           src = src.substring(cap[0].length);
16954           bull = cap[2];
16955     
16956           this.tokens.push({
16957             type: 'list_start',
16958             ordered: bull.length > 1
16959           });
16960     
16961           // Get each top-level item.
16962           cap = cap[0].match(this.rules.item);
16963     
16964           next = false;
16965           l = cap.length;
16966           i = 0;
16967     
16968           for (; i < l; i++) {
16969             item = cap[i];
16970     
16971             // Remove the list item's bullet
16972             // so it is seen as the next token.
16973             space = item.length;
16974             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16975     
16976             // Outdent whatever the
16977             // list item contains. Hacky.
16978             if (~item.indexOf('\n ')) {
16979               space -= item.length;
16980               item = !this.options.pedantic
16981                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16982                 : item.replace(/^ {1,4}/gm, '');
16983             }
16984     
16985             // Determine whether the next list item belongs here.
16986             // Backpedal if it does not belong in this list.
16987             if (this.options.smartLists && i !== l - 1) {
16988               b = block.bullet.exec(cap[i + 1])[0];
16989               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16990                 src = cap.slice(i + 1).join('\n') + src;
16991                 i = l - 1;
16992               }
16993             }
16994     
16995             // Determine whether item is loose or not.
16996             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16997             // for discount behavior.
16998             loose = next || /\n\n(?!\s*$)/.test(item);
16999             if (i !== l - 1) {
17000               next = item.charAt(item.length - 1) === '\n';
17001               if (!loose) { loose = next; }
17002             }
17003     
17004             this.tokens.push({
17005               type: loose
17006                 ? 'loose_item_start'
17007                 : 'list_item_start'
17008             });
17009     
17010             // Recurse.
17011             this.token(item, false, bq);
17012     
17013             this.tokens.push({
17014               type: 'list_item_end'
17015             });
17016           }
17017     
17018           this.tokens.push({
17019             type: 'list_end'
17020           });
17021     
17022           continue;
17023         }
17024     
17025         // html
17026         if (cap = this.rules.html.exec(src)) {
17027           src = src.substring(cap[0].length);
17028           this.tokens.push({
17029             type: this.options.sanitize
17030               ? 'paragraph'
17031               : 'html',
17032             pre: !this.options.sanitizer
17033               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17034             text: cap[0]
17035           });
17036           continue;
17037         }
17038     
17039         // def
17040         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17041           src = src.substring(cap[0].length);
17042           this.tokens.links[cap[1].toLowerCase()] = {
17043             href: cap[2],
17044             title: cap[3]
17045           };
17046           continue;
17047         }
17048     
17049         // table (gfm)
17050         if (top && (cap = this.rules.table.exec(src))) {
17051           src = src.substring(cap[0].length);
17052     
17053           item = {
17054             type: 'table',
17055             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17056             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17057             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17058           };
17059     
17060           for (i = 0; i < item.align.length; i++) {
17061             if (/^ *-+: *$/.test(item.align[i])) {
17062               item.align[i] = 'right';
17063             } else if (/^ *:-+: *$/.test(item.align[i])) {
17064               item.align[i] = 'center';
17065             } else if (/^ *:-+ *$/.test(item.align[i])) {
17066               item.align[i] = 'left';
17067             } else {
17068               item.align[i] = null;
17069             }
17070           }
17071     
17072           for (i = 0; i < item.cells.length; i++) {
17073             item.cells[i] = item.cells[i]
17074               .replace(/^ *\| *| *\| *$/g, '')
17075               .split(/ *\| */);
17076           }
17077     
17078           this.tokens.push(item);
17079     
17080           continue;
17081         }
17082     
17083         // top-level paragraph
17084         if (top && (cap = this.rules.paragraph.exec(src))) {
17085           src = src.substring(cap[0].length);
17086           this.tokens.push({
17087             type: 'paragraph',
17088             text: cap[1].charAt(cap[1].length - 1) === '\n'
17089               ? cap[1].slice(0, -1)
17090               : cap[1]
17091           });
17092           continue;
17093         }
17094     
17095         // text
17096         if (cap = this.rules.text.exec(src)) {
17097           // Top-level should never reach here.
17098           src = src.substring(cap[0].length);
17099           this.tokens.push({
17100             type: 'text',
17101             text: cap[0]
17102           });
17103           continue;
17104         }
17105     
17106         if (src) {
17107           throw new
17108             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17109         }
17110       }
17111     
17112       return this.tokens;
17113     };
17114     
17115     /**
17116      * Inline-Level Grammar
17117      */
17118     
17119     var inline = {
17120       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17121       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17122       url: noop,
17123       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17124       link: /^!?\[(inside)\]\(href\)/,
17125       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17126       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17127       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17128       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17129       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17130       br: /^ {2,}\n(?!\s*$)/,
17131       del: noop,
17132       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17133     };
17134     
17135     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17136     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17137     
17138     inline.link = replace(inline.link)
17139       ('inside', inline._inside)
17140       ('href', inline._href)
17141       ();
17142     
17143     inline.reflink = replace(inline.reflink)
17144       ('inside', inline._inside)
17145       ();
17146     
17147     /**
17148      * Normal Inline Grammar
17149      */
17150     
17151     inline.normal = merge({}, inline);
17152     
17153     /**
17154      * Pedantic Inline Grammar
17155      */
17156     
17157     inline.pedantic = merge({}, inline.normal, {
17158       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17159       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17160     });
17161     
17162     /**
17163      * GFM Inline Grammar
17164      */
17165     
17166     inline.gfm = merge({}, inline.normal, {
17167       escape: replace(inline.escape)('])', '~|])')(),
17168       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17169       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17170       text: replace(inline.text)
17171         (']|', '~]|')
17172         ('|', '|https?://|')
17173         ()
17174     });
17175     
17176     /**
17177      * GFM + Line Breaks Inline Grammar
17178      */
17179     
17180     inline.breaks = merge({}, inline.gfm, {
17181       br: replace(inline.br)('{2,}', '*')(),
17182       text: replace(inline.gfm.text)('{2,}', '*')()
17183     });
17184     
17185     /**
17186      * Inline Lexer & Compiler
17187      */
17188     
17189     function InlineLexer(links, options) {
17190       this.options = options || marked.defaults;
17191       this.links = links;
17192       this.rules = inline.normal;
17193       this.renderer = this.options.renderer || new Renderer;
17194       this.renderer.options = this.options;
17195     
17196       if (!this.links) {
17197         throw new
17198           Error('Tokens array requires a `links` property.');
17199       }
17200     
17201       if (this.options.gfm) {
17202         if (this.options.breaks) {
17203           this.rules = inline.breaks;
17204         } else {
17205           this.rules = inline.gfm;
17206         }
17207       } else if (this.options.pedantic) {
17208         this.rules = inline.pedantic;
17209       }
17210     }
17211     
17212     /**
17213      * Expose Inline Rules
17214      */
17215     
17216     InlineLexer.rules = inline;
17217     
17218     /**
17219      * Static Lexing/Compiling Method
17220      */
17221     
17222     InlineLexer.output = function(src, links, options) {
17223       var inline = new InlineLexer(links, options);
17224       return inline.output(src);
17225     };
17226     
17227     /**
17228      * Lexing/Compiling
17229      */
17230     
17231     InlineLexer.prototype.output = function(src) {
17232       var out = ''
17233         , link
17234         , text
17235         , href
17236         , cap;
17237     
17238       while (src) {
17239         // escape
17240         if (cap = this.rules.escape.exec(src)) {
17241           src = src.substring(cap[0].length);
17242           out += cap[1];
17243           continue;
17244         }
17245     
17246         // autolink
17247         if (cap = this.rules.autolink.exec(src)) {
17248           src = src.substring(cap[0].length);
17249           if (cap[2] === '@') {
17250             text = cap[1].charAt(6) === ':'
17251               ? this.mangle(cap[1].substring(7))
17252               : this.mangle(cap[1]);
17253             href = this.mangle('mailto:') + text;
17254           } else {
17255             text = escape(cap[1]);
17256             href = text;
17257           }
17258           out += this.renderer.link(href, null, text);
17259           continue;
17260         }
17261     
17262         // url (gfm)
17263         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17264           src = src.substring(cap[0].length);
17265           text = escape(cap[1]);
17266           href = text;
17267           out += this.renderer.link(href, null, text);
17268           continue;
17269         }
17270     
17271         // tag
17272         if (cap = this.rules.tag.exec(src)) {
17273           if (!this.inLink && /^<a /i.test(cap[0])) {
17274             this.inLink = true;
17275           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17276             this.inLink = false;
17277           }
17278           src = src.substring(cap[0].length);
17279           out += this.options.sanitize
17280             ? this.options.sanitizer
17281               ? this.options.sanitizer(cap[0])
17282               : escape(cap[0])
17283             : cap[0];
17284           continue;
17285         }
17286     
17287         // link
17288         if (cap = this.rules.link.exec(src)) {
17289           src = src.substring(cap[0].length);
17290           this.inLink = true;
17291           out += this.outputLink(cap, {
17292             href: cap[2],
17293             title: cap[3]
17294           });
17295           this.inLink = false;
17296           continue;
17297         }
17298     
17299         // reflink, nolink
17300         if ((cap = this.rules.reflink.exec(src))
17301             || (cap = this.rules.nolink.exec(src))) {
17302           src = src.substring(cap[0].length);
17303           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17304           link = this.links[link.toLowerCase()];
17305           if (!link || !link.href) {
17306             out += cap[0].charAt(0);
17307             src = cap[0].substring(1) + src;
17308             continue;
17309           }
17310           this.inLink = true;
17311           out += this.outputLink(cap, link);
17312           this.inLink = false;
17313           continue;
17314         }
17315     
17316         // strong
17317         if (cap = this.rules.strong.exec(src)) {
17318           src = src.substring(cap[0].length);
17319           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17320           continue;
17321         }
17322     
17323         // em
17324         if (cap = this.rules.em.exec(src)) {
17325           src = src.substring(cap[0].length);
17326           out += this.renderer.em(this.output(cap[2] || cap[1]));
17327           continue;
17328         }
17329     
17330         // code
17331         if (cap = this.rules.code.exec(src)) {
17332           src = src.substring(cap[0].length);
17333           out += this.renderer.codespan(escape(cap[2], true));
17334           continue;
17335         }
17336     
17337         // br
17338         if (cap = this.rules.br.exec(src)) {
17339           src = src.substring(cap[0].length);
17340           out += this.renderer.br();
17341           continue;
17342         }
17343     
17344         // del (gfm)
17345         if (cap = this.rules.del.exec(src)) {
17346           src = src.substring(cap[0].length);
17347           out += this.renderer.del(this.output(cap[1]));
17348           continue;
17349         }
17350     
17351         // text
17352         if (cap = this.rules.text.exec(src)) {
17353           src = src.substring(cap[0].length);
17354           out += this.renderer.text(escape(this.smartypants(cap[0])));
17355           continue;
17356         }
17357     
17358         if (src) {
17359           throw new
17360             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17361         }
17362       }
17363     
17364       return out;
17365     };
17366     
17367     /**
17368      * Compile Link
17369      */
17370     
17371     InlineLexer.prototype.outputLink = function(cap, link) {
17372       var href = escape(link.href)
17373         , title = link.title ? escape(link.title) : null;
17374     
17375       return cap[0].charAt(0) !== '!'
17376         ? this.renderer.link(href, title, this.output(cap[1]))
17377         : this.renderer.image(href, title, escape(cap[1]));
17378     };
17379     
17380     /**
17381      * Smartypants Transformations
17382      */
17383     
17384     InlineLexer.prototype.smartypants = function(text) {
17385       if (!this.options.smartypants)  { return text; }
17386       return text
17387         // em-dashes
17388         .replace(/---/g, '\u2014')
17389         // en-dashes
17390         .replace(/--/g, '\u2013')
17391         // opening singles
17392         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17393         // closing singles & apostrophes
17394         .replace(/'/g, '\u2019')
17395         // opening doubles
17396         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17397         // closing doubles
17398         .replace(/"/g, '\u201d')
17399         // ellipses
17400         .replace(/\.{3}/g, '\u2026');
17401     };
17402     
17403     /**
17404      * Mangle Links
17405      */
17406     
17407     InlineLexer.prototype.mangle = function(text) {
17408       if (!this.options.mangle) { return text; }
17409       var out = ''
17410         , l = text.length
17411         , i = 0
17412         , ch;
17413     
17414       for (; i < l; i++) {
17415         ch = text.charCodeAt(i);
17416         if (Math.random() > 0.5) {
17417           ch = 'x' + ch.toString(16);
17418         }
17419         out += '&#' + ch + ';';
17420       }
17421     
17422       return out;
17423     };
17424     
17425     /**
17426      * Renderer
17427      */
17428     
17429     function Renderer(options) {
17430       this.options = options || {};
17431     }
17432     
17433     Renderer.prototype.code = function(code, lang, escaped) {
17434       if (this.options.highlight) {
17435         var out = this.options.highlight(code, lang);
17436         if (out != null && out !== code) {
17437           escaped = true;
17438           code = out;
17439         }
17440       } else {
17441             // hack!!! - it's already escapeD?
17442             escaped = true;
17443       }
17444     
17445       if (!lang) {
17446         return '<pre><code>'
17447           + (escaped ? code : escape(code, true))
17448           + '\n</code></pre>';
17449       }
17450     
17451       return '<pre><code class="'
17452         + this.options.langPrefix
17453         + escape(lang, true)
17454         + '">'
17455         + (escaped ? code : escape(code, true))
17456         + '\n</code></pre>\n';
17457     };
17458     
17459     Renderer.prototype.blockquote = function(quote) {
17460       return '<blockquote>\n' + quote + '</blockquote>\n';
17461     };
17462     
17463     Renderer.prototype.html = function(html) {
17464       return html;
17465     };
17466     
17467     Renderer.prototype.heading = function(text, level, raw) {
17468       return '<h'
17469         + level
17470         + ' id="'
17471         + this.options.headerPrefix
17472         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17473         + '">'
17474         + text
17475         + '</h'
17476         + level
17477         + '>\n';
17478     };
17479     
17480     Renderer.prototype.hr = function() {
17481       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17482     };
17483     
17484     Renderer.prototype.list = function(body, ordered) {
17485       var type = ordered ? 'ol' : 'ul';
17486       return '<' + type + '>\n' + body + '</' + type + '>\n';
17487     };
17488     
17489     Renderer.prototype.listitem = function(text) {
17490       return '<li>' + text + '</li>\n';
17491     };
17492     
17493     Renderer.prototype.paragraph = function(text) {
17494       return '<p>' + text + '</p>\n';
17495     };
17496     
17497     Renderer.prototype.table = function(header, body) {
17498       return '<table class="table table-striped">\n'
17499         + '<thead>\n'
17500         + header
17501         + '</thead>\n'
17502         + '<tbody>\n'
17503         + body
17504         + '</tbody>\n'
17505         + '</table>\n';
17506     };
17507     
17508     Renderer.prototype.tablerow = function(content) {
17509       return '<tr>\n' + content + '</tr>\n';
17510     };
17511     
17512     Renderer.prototype.tablecell = function(content, flags) {
17513       var type = flags.header ? 'th' : 'td';
17514       var tag = flags.align
17515         ? '<' + type + ' style="text-align:' + flags.align + '">'
17516         : '<' + type + '>';
17517       return tag + content + '</' + type + '>\n';
17518     };
17519     
17520     // span level renderer
17521     Renderer.prototype.strong = function(text) {
17522       return '<strong>' + text + '</strong>';
17523     };
17524     
17525     Renderer.prototype.em = function(text) {
17526       return '<em>' + text + '</em>';
17527     };
17528     
17529     Renderer.prototype.codespan = function(text) {
17530       return '<code>' + text + '</code>';
17531     };
17532     
17533     Renderer.prototype.br = function() {
17534       return this.options.xhtml ? '<br/>' : '<br>';
17535     };
17536     
17537     Renderer.prototype.del = function(text) {
17538       return '<del>' + text + '</del>';
17539     };
17540     
17541     Renderer.prototype.link = function(href, title, text) {
17542       if (this.options.sanitize) {
17543         try {
17544           var prot = decodeURIComponent(unescape(href))
17545             .replace(/[^\w:]/g, '')
17546             .toLowerCase();
17547         } catch (e) {
17548           return '';
17549         }
17550         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17551           return '';
17552         }
17553       }
17554       var out = '<a href="' + href + '"';
17555       if (title) {
17556         out += ' title="' + title + '"';
17557       }
17558       out += '>' + text + '</a>';
17559       return out;
17560     };
17561     
17562     Renderer.prototype.image = function(href, title, text) {
17563       var out = '<img src="' + href + '" alt="' + text + '"';
17564       if (title) {
17565         out += ' title="' + title + '"';
17566       }
17567       out += this.options.xhtml ? '/>' : '>';
17568       return out;
17569     };
17570     
17571     Renderer.prototype.text = function(text) {
17572       return text;
17573     };
17574     
17575     /**
17576      * Parsing & Compiling
17577      */
17578     
17579     function Parser(options) {
17580       this.tokens = [];
17581       this.token = null;
17582       this.options = options || marked.defaults;
17583       this.options.renderer = this.options.renderer || new Renderer;
17584       this.renderer = this.options.renderer;
17585       this.renderer.options = this.options;
17586     }
17587     
17588     /**
17589      * Static Parse Method
17590      */
17591     
17592     Parser.parse = function(src, options, renderer) {
17593       var parser = new Parser(options, renderer);
17594       return parser.parse(src);
17595     };
17596     
17597     /**
17598      * Parse Loop
17599      */
17600     
17601     Parser.prototype.parse = function(src) {
17602       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17603       this.tokens = src.reverse();
17604     
17605       var out = '';
17606       while (this.next()) {
17607         out += this.tok();
17608       }
17609     
17610       return out;
17611     };
17612     
17613     /**
17614      * Next Token
17615      */
17616     
17617     Parser.prototype.next = function() {
17618       return this.token = this.tokens.pop();
17619     };
17620     
17621     /**
17622      * Preview Next Token
17623      */
17624     
17625     Parser.prototype.peek = function() {
17626       return this.tokens[this.tokens.length - 1] || 0;
17627     };
17628     
17629     /**
17630      * Parse Text Tokens
17631      */
17632     
17633     Parser.prototype.parseText = function() {
17634       var body = this.token.text;
17635     
17636       while (this.peek().type === 'text') {
17637         body += '\n' + this.next().text;
17638       }
17639     
17640       return this.inline.output(body);
17641     };
17642     
17643     /**
17644      * Parse Current Token
17645      */
17646     
17647     Parser.prototype.tok = function() {
17648       switch (this.token.type) {
17649         case 'space': {
17650           return '';
17651         }
17652         case 'hr': {
17653           return this.renderer.hr();
17654         }
17655         case 'heading': {
17656           return this.renderer.heading(
17657             this.inline.output(this.token.text),
17658             this.token.depth,
17659             this.token.text);
17660         }
17661         case 'code': {
17662           return this.renderer.code(this.token.text,
17663             this.token.lang,
17664             this.token.escaped);
17665         }
17666         case 'table': {
17667           var header = ''
17668             , body = ''
17669             , i
17670             , row
17671             , cell
17672             , flags
17673             , j;
17674     
17675           // header
17676           cell = '';
17677           for (i = 0; i < this.token.header.length; i++) {
17678             flags = { header: true, align: this.token.align[i] };
17679             cell += this.renderer.tablecell(
17680               this.inline.output(this.token.header[i]),
17681               { header: true, align: this.token.align[i] }
17682             );
17683           }
17684           header += this.renderer.tablerow(cell);
17685     
17686           for (i = 0; i < this.token.cells.length; i++) {
17687             row = this.token.cells[i];
17688     
17689             cell = '';
17690             for (j = 0; j < row.length; j++) {
17691               cell += this.renderer.tablecell(
17692                 this.inline.output(row[j]),
17693                 { header: false, align: this.token.align[j] }
17694               );
17695             }
17696     
17697             body += this.renderer.tablerow(cell);
17698           }
17699           return this.renderer.table(header, body);
17700         }
17701         case 'blockquote_start': {
17702           var body = '';
17703     
17704           while (this.next().type !== 'blockquote_end') {
17705             body += this.tok();
17706           }
17707     
17708           return this.renderer.blockquote(body);
17709         }
17710         case 'list_start': {
17711           var body = ''
17712             , ordered = this.token.ordered;
17713     
17714           while (this.next().type !== 'list_end') {
17715             body += this.tok();
17716           }
17717     
17718           return this.renderer.list(body, ordered);
17719         }
17720         case 'list_item_start': {
17721           var body = '';
17722     
17723           while (this.next().type !== 'list_item_end') {
17724             body += this.token.type === 'text'
17725               ? this.parseText()
17726               : this.tok();
17727           }
17728     
17729           return this.renderer.listitem(body);
17730         }
17731         case 'loose_item_start': {
17732           var body = '';
17733     
17734           while (this.next().type !== 'list_item_end') {
17735             body += this.tok();
17736           }
17737     
17738           return this.renderer.listitem(body);
17739         }
17740         case 'html': {
17741           var html = !this.token.pre && !this.options.pedantic
17742             ? this.inline.output(this.token.text)
17743             : this.token.text;
17744           return this.renderer.html(html);
17745         }
17746         case 'paragraph': {
17747           return this.renderer.paragraph(this.inline.output(this.token.text));
17748         }
17749         case 'text': {
17750           return this.renderer.paragraph(this.parseText());
17751         }
17752       }
17753     };
17754     
17755     /**
17756      * Helpers
17757      */
17758     
17759     function escape(html, encode) {
17760       return html
17761         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17762         .replace(/</g, '&lt;')
17763         .replace(/>/g, '&gt;')
17764         .replace(/"/g, '&quot;')
17765         .replace(/'/g, '&#39;');
17766     }
17767     
17768     function unescape(html) {
17769         // explicitly match decimal, hex, and named HTML entities 
17770       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17771         n = n.toLowerCase();
17772         if (n === 'colon') { return ':'; }
17773         if (n.charAt(0) === '#') {
17774           return n.charAt(1) === 'x'
17775             ? String.fromCharCode(parseInt(n.substring(2), 16))
17776             : String.fromCharCode(+n.substring(1));
17777         }
17778         return '';
17779       });
17780     }
17781     
17782     function replace(regex, opt) {
17783       regex = regex.source;
17784       opt = opt || '';
17785       return function self(name, val) {
17786         if (!name) { return new RegExp(regex, opt); }
17787         val = val.source || val;
17788         val = val.replace(/(^|[^\[])\^/g, '$1');
17789         regex = regex.replace(name, val);
17790         return self;
17791       };
17792     }
17793     
17794     function noop() {}
17795     noop.exec = noop;
17796     
17797     function merge(obj) {
17798       var i = 1
17799         , target
17800         , key;
17801     
17802       for (; i < arguments.length; i++) {
17803         target = arguments[i];
17804         for (key in target) {
17805           if (Object.prototype.hasOwnProperty.call(target, key)) {
17806             obj[key] = target[key];
17807           }
17808         }
17809       }
17810     
17811       return obj;
17812     }
17813     
17814     
17815     /**
17816      * Marked
17817      */
17818     
17819     function marked(src, opt, callback) {
17820       if (callback || typeof opt === 'function') {
17821         if (!callback) {
17822           callback = opt;
17823           opt = null;
17824         }
17825     
17826         opt = merge({}, marked.defaults, opt || {});
17827     
17828         var highlight = opt.highlight
17829           , tokens
17830           , pending
17831           , i = 0;
17832     
17833         try {
17834           tokens = Lexer.lex(src, opt)
17835         } catch (e) {
17836           return callback(e);
17837         }
17838     
17839         pending = tokens.length;
17840     
17841         var done = function(err) {
17842           if (err) {
17843             opt.highlight = highlight;
17844             return callback(err);
17845           }
17846     
17847           var out;
17848     
17849           try {
17850             out = Parser.parse(tokens, opt);
17851           } catch (e) {
17852             err = e;
17853           }
17854     
17855           opt.highlight = highlight;
17856     
17857           return err
17858             ? callback(err)
17859             : callback(null, out);
17860         };
17861     
17862         if (!highlight || highlight.length < 3) {
17863           return done();
17864         }
17865     
17866         delete opt.highlight;
17867     
17868         if (!pending) { return done(); }
17869     
17870         for (; i < tokens.length; i++) {
17871           (function(token) {
17872             if (token.type !== 'code') {
17873               return --pending || done();
17874             }
17875             return highlight(token.text, token.lang, function(err, code) {
17876               if (err) { return done(err); }
17877               if (code == null || code === token.text) {
17878                 return --pending || done();
17879               }
17880               token.text = code;
17881               token.escaped = true;
17882               --pending || done();
17883             });
17884           })(tokens[i]);
17885         }
17886     
17887         return;
17888       }
17889       try {
17890         if (opt) { opt = merge({}, marked.defaults, opt); }
17891         return Parser.parse(Lexer.lex(src, opt), opt);
17892       } catch (e) {
17893         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17894         if ((opt || marked.defaults).silent) {
17895           return '<p>An error occured:</p><pre>'
17896             + escape(e.message + '', true)
17897             + '</pre>';
17898         }
17899         throw e;
17900       }
17901     }
17902     
17903     /**
17904      * Options
17905      */
17906     
17907     marked.options =
17908     marked.setOptions = function(opt) {
17909       merge(marked.defaults, opt);
17910       return marked;
17911     };
17912     
17913     marked.defaults = {
17914       gfm: true,
17915       tables: true,
17916       breaks: false,
17917       pedantic: false,
17918       sanitize: false,
17919       sanitizer: null,
17920       mangle: true,
17921       smartLists: false,
17922       silent: false,
17923       highlight: null,
17924       langPrefix: 'lang-',
17925       smartypants: false,
17926       headerPrefix: '',
17927       renderer: new Renderer,
17928       xhtml: false
17929     };
17930     
17931     /**
17932      * Expose
17933      */
17934     
17935     marked.Parser = Parser;
17936     marked.parser = Parser.parse;
17937     
17938     marked.Renderer = Renderer;
17939     
17940     marked.Lexer = Lexer;
17941     marked.lexer = Lexer.lex;
17942     
17943     marked.InlineLexer = InlineLexer;
17944     marked.inlineLexer = InlineLexer.output;
17945     
17946     marked.parse = marked;
17947     
17948     Roo.Markdown.marked = marked;
17949
17950 })();/*
17951  * Based on:
17952  * Ext JS Library 1.1.1
17953  * Copyright(c) 2006-2007, Ext JS, LLC.
17954  *
17955  * Originally Released Under LGPL - original licence link has changed is not relivant.
17956  *
17957  * Fork - LGPL
17958  * <script type="text/javascript">
17959  */
17960
17961
17962
17963 /*
17964  * These classes are derivatives of the similarly named classes in the YUI Library.
17965  * The original license:
17966  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17967  * Code licensed under the BSD License:
17968  * http://developer.yahoo.net/yui/license.txt
17969  */
17970
17971 (function() {
17972
17973 var Event=Roo.EventManager;
17974 var Dom=Roo.lib.Dom;
17975
17976 /**
17977  * @class Roo.dd.DragDrop
17978  * @extends Roo.util.Observable
17979  * Defines the interface and base operation of items that that can be
17980  * dragged or can be drop targets.  It was designed to be extended, overriding
17981  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17982  * Up to three html elements can be associated with a DragDrop instance:
17983  * <ul>
17984  * <li>linked element: the element that is passed into the constructor.
17985  * This is the element which defines the boundaries for interaction with
17986  * other DragDrop objects.</li>
17987  * <li>handle element(s): The drag operation only occurs if the element that
17988  * was clicked matches a handle element.  By default this is the linked
17989  * element, but there are times that you will want only a portion of the
17990  * linked element to initiate the drag operation, and the setHandleElId()
17991  * method provides a way to define this.</li>
17992  * <li>drag element: this represents the element that would be moved along
17993  * with the cursor during a drag operation.  By default, this is the linked
17994  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
17995  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17996  * </li>
17997  * </ul>
17998  * This class should not be instantiated until the onload event to ensure that
17999  * the associated elements are available.
18000  * The following would define a DragDrop obj that would interact with any
18001  * other DragDrop obj in the "group1" group:
18002  * <pre>
18003  *  dd = new Roo.dd.DragDrop("div1", "group1");
18004  * </pre>
18005  * Since none of the event handlers have been implemented, nothing would
18006  * actually happen if you were to run the code above.  Normally you would
18007  * override this class or one of the default implementations, but you can
18008  * also override the methods you want on an instance of the class...
18009  * <pre>
18010  *  dd.onDragDrop = function(e, id) {
18011  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18012  *  }
18013  * </pre>
18014  * @constructor
18015  * @param {String} id of the element that is linked to this instance
18016  * @param {String} sGroup the group of related DragDrop objects
18017  * @param {object} config an object containing configurable attributes
18018  *                Valid properties for DragDrop:
18019  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18020  */
18021 Roo.dd.DragDrop = function(id, sGroup, config) {
18022     if (id) {
18023         this.init(id, sGroup, config);
18024     }
18025     
18026 };
18027
18028 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18029
18030     /**
18031      * The id of the element associated with this object.  This is what we
18032      * refer to as the "linked element" because the size and position of
18033      * this element is used to determine when the drag and drop objects have
18034      * interacted.
18035      * @property id
18036      * @type String
18037      */
18038     id: null,
18039
18040     /**
18041      * Configuration attributes passed into the constructor
18042      * @property config
18043      * @type object
18044      */
18045     config: null,
18046
18047     /**
18048      * The id of the element that will be dragged.  By default this is same
18049      * as the linked element , but could be changed to another element. Ex:
18050      * Roo.dd.DDProxy
18051      * @property dragElId
18052      * @type String
18053      * @private
18054      */
18055     dragElId: null,
18056
18057     /**
18058      * the id of the element that initiates the drag operation.  By default
18059      * this is the linked element, but could be changed to be a child of this
18060      * element.  This lets us do things like only starting the drag when the
18061      * header element within the linked html element is clicked.
18062      * @property handleElId
18063      * @type String
18064      * @private
18065      */
18066     handleElId: null,
18067
18068     /**
18069      * An associative array of HTML tags that will be ignored if clicked.
18070      * @property invalidHandleTypes
18071      * @type {string: string}
18072      */
18073     invalidHandleTypes: null,
18074
18075     /**
18076      * An associative array of ids for elements that will be ignored if clicked
18077      * @property invalidHandleIds
18078      * @type {string: string}
18079      */
18080     invalidHandleIds: null,
18081
18082     /**
18083      * An indexted array of css class names for elements that will be ignored
18084      * if clicked.
18085      * @property invalidHandleClasses
18086      * @type string[]
18087      */
18088     invalidHandleClasses: null,
18089
18090     /**
18091      * The linked element's absolute X position at the time the drag was
18092      * started
18093      * @property startPageX
18094      * @type int
18095      * @private
18096      */
18097     startPageX: 0,
18098
18099     /**
18100      * The linked element's absolute X position at the time the drag was
18101      * started
18102      * @property startPageY
18103      * @type int
18104      * @private
18105      */
18106     startPageY: 0,
18107
18108     /**
18109      * The group defines a logical collection of DragDrop objects that are
18110      * related.  Instances only get events when interacting with other
18111      * DragDrop object in the same group.  This lets us define multiple
18112      * groups using a single DragDrop subclass if we want.
18113      * @property groups
18114      * @type {string: string}
18115      */
18116     groups: null,
18117
18118     /**
18119      * Individual drag/drop instances can be locked.  This will prevent
18120      * onmousedown start drag.
18121      * @property locked
18122      * @type boolean
18123      * @private
18124      */
18125     locked: false,
18126
18127     /**
18128      * Lock this instance
18129      * @method lock
18130      */
18131     lock: function() { this.locked = true; },
18132
18133     /**
18134      * Unlock this instace
18135      * @method unlock
18136      */
18137     unlock: function() { this.locked = false; },
18138
18139     /**
18140      * By default, all insances can be a drop target.  This can be disabled by
18141      * setting isTarget to false.
18142      * @method isTarget
18143      * @type boolean
18144      */
18145     isTarget: true,
18146
18147     /**
18148      * The padding configured for this drag and drop object for calculating
18149      * the drop zone intersection with this object.
18150      * @method padding
18151      * @type int[]
18152      */
18153     padding: null,
18154
18155     /**
18156      * Cached reference to the linked element
18157      * @property _domRef
18158      * @private
18159      */
18160     _domRef: null,
18161
18162     /**
18163      * Internal typeof flag
18164      * @property __ygDragDrop
18165      * @private
18166      */
18167     __ygDragDrop: true,
18168
18169     /**
18170      * Set to true when horizontal contraints are applied
18171      * @property constrainX
18172      * @type boolean
18173      * @private
18174      */
18175     constrainX: false,
18176
18177     /**
18178      * Set to true when vertical contraints are applied
18179      * @property constrainY
18180      * @type boolean
18181      * @private
18182      */
18183     constrainY: false,
18184
18185     /**
18186      * The left constraint
18187      * @property minX
18188      * @type int
18189      * @private
18190      */
18191     minX: 0,
18192
18193     /**
18194      * The right constraint
18195      * @property maxX
18196      * @type int
18197      * @private
18198      */
18199     maxX: 0,
18200
18201     /**
18202      * The up constraint
18203      * @property minY
18204      * @type int
18205      * @type int
18206      * @private
18207      */
18208     minY: 0,
18209
18210     /**
18211      * The down constraint
18212      * @property maxY
18213      * @type int
18214      * @private
18215      */
18216     maxY: 0,
18217
18218     /**
18219      * Maintain offsets when we resetconstraints.  Set to true when you want
18220      * the position of the element relative to its parent to stay the same
18221      * when the page changes
18222      *
18223      * @property maintainOffset
18224      * @type boolean
18225      */
18226     maintainOffset: false,
18227
18228     /**
18229      * Array of pixel locations the element will snap to if we specified a
18230      * horizontal graduation/interval.  This array is generated automatically
18231      * when you define a tick interval.
18232      * @property xTicks
18233      * @type int[]
18234      */
18235     xTicks: null,
18236
18237     /**
18238      * Array of pixel locations the element will snap to if we specified a
18239      * vertical graduation/interval.  This array is generated automatically
18240      * when you define a tick interval.
18241      * @property yTicks
18242      * @type int[]
18243      */
18244     yTicks: null,
18245
18246     /**
18247      * By default the drag and drop instance will only respond to the primary
18248      * button click (left button for a right-handed mouse).  Set to true to
18249      * allow drag and drop to start with any mouse click that is propogated
18250      * by the browser
18251      * @property primaryButtonOnly
18252      * @type boolean
18253      */
18254     primaryButtonOnly: true,
18255
18256     /**
18257      * The availabe property is false until the linked dom element is accessible.
18258      * @property available
18259      * @type boolean
18260      */
18261     available: false,
18262
18263     /**
18264      * By default, drags can only be initiated if the mousedown occurs in the
18265      * region the linked element is.  This is done in part to work around a
18266      * bug in some browsers that mis-report the mousedown if the previous
18267      * mouseup happened outside of the window.  This property is set to true
18268      * if outer handles are defined.
18269      *
18270      * @property hasOuterHandles
18271      * @type boolean
18272      * @default false
18273      */
18274     hasOuterHandles: false,
18275
18276     /**
18277      * Code that executes immediately before the startDrag event
18278      * @method b4StartDrag
18279      * @private
18280      */
18281     b4StartDrag: function(x, y) { },
18282
18283     /**
18284      * Abstract method called after a drag/drop object is clicked
18285      * and the drag or mousedown time thresholds have beeen met.
18286      * @method startDrag
18287      * @param {int} X click location
18288      * @param {int} Y click location
18289      */
18290     startDrag: function(x, y) { /* override this */ },
18291
18292     /**
18293      * Code that executes immediately before the onDrag event
18294      * @method b4Drag
18295      * @private
18296      */
18297     b4Drag: function(e) { },
18298
18299     /**
18300      * Abstract method called during the onMouseMove event while dragging an
18301      * object.
18302      * @method onDrag
18303      * @param {Event} e the mousemove event
18304      */
18305     onDrag: function(e) { /* override this */ },
18306
18307     /**
18308      * Abstract method called when this element fist begins hovering over
18309      * another DragDrop obj
18310      * @method onDragEnter
18311      * @param {Event} e the mousemove event
18312      * @param {String|DragDrop[]} id In POINT mode, the element
18313      * id this is hovering over.  In INTERSECT mode, an array of one or more
18314      * dragdrop items being hovered over.
18315      */
18316     onDragEnter: function(e, id) { /* override this */ },
18317
18318     /**
18319      * Code that executes immediately before the onDragOver event
18320      * @method b4DragOver
18321      * @private
18322      */
18323     b4DragOver: function(e) { },
18324
18325     /**
18326      * Abstract method called when this element is hovering over another
18327      * DragDrop obj
18328      * @method onDragOver
18329      * @param {Event} e the mousemove event
18330      * @param {String|DragDrop[]} id In POINT mode, the element
18331      * id this is hovering over.  In INTERSECT mode, an array of dd items
18332      * being hovered over.
18333      */
18334     onDragOver: function(e, id) { /* override this */ },
18335
18336     /**
18337      * Code that executes immediately before the onDragOut event
18338      * @method b4DragOut
18339      * @private
18340      */
18341     b4DragOut: function(e) { },
18342
18343     /**
18344      * Abstract method called when we are no longer hovering over an element
18345      * @method onDragOut
18346      * @param {Event} e the mousemove event
18347      * @param {String|DragDrop[]} id In POINT mode, the element
18348      * id this was hovering over.  In INTERSECT mode, an array of dd items
18349      * that the mouse is no longer over.
18350      */
18351     onDragOut: function(e, id) { /* override this */ },
18352
18353     /**
18354      * Code that executes immediately before the onDragDrop event
18355      * @method b4DragDrop
18356      * @private
18357      */
18358     b4DragDrop: function(e) { },
18359
18360     /**
18361      * Abstract method called when this item is dropped on another DragDrop
18362      * obj
18363      * @method onDragDrop
18364      * @param {Event} e the mouseup event
18365      * @param {String|DragDrop[]} id In POINT mode, the element
18366      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18367      * was dropped on.
18368      */
18369     onDragDrop: function(e, id) { /* override this */ },
18370
18371     /**
18372      * Abstract method called when this item is dropped on an area with no
18373      * drop target
18374      * @method onInvalidDrop
18375      * @param {Event} e the mouseup event
18376      */
18377     onInvalidDrop: function(e) { /* override this */ },
18378
18379     /**
18380      * Code that executes immediately before the endDrag event
18381      * @method b4EndDrag
18382      * @private
18383      */
18384     b4EndDrag: function(e) { },
18385
18386     /**
18387      * Fired when we are done dragging the object
18388      * @method endDrag
18389      * @param {Event} e the mouseup event
18390      */
18391     endDrag: function(e) { /* override this */ },
18392
18393     /**
18394      * Code executed immediately before the onMouseDown event
18395      * @method b4MouseDown
18396      * @param {Event} e the mousedown event
18397      * @private
18398      */
18399     b4MouseDown: function(e) {  },
18400
18401     /**
18402      * Event handler that fires when a drag/drop obj gets a mousedown
18403      * @method onMouseDown
18404      * @param {Event} e the mousedown event
18405      */
18406     onMouseDown: function(e) { /* override this */ },
18407
18408     /**
18409      * Event handler that fires when a drag/drop obj gets a mouseup
18410      * @method onMouseUp
18411      * @param {Event} e the mouseup event
18412      */
18413     onMouseUp: function(e) { /* override this */ },
18414
18415     /**
18416      * Override the onAvailable method to do what is needed after the initial
18417      * position was determined.
18418      * @method onAvailable
18419      */
18420     onAvailable: function () {
18421     },
18422
18423     /*
18424      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18425      * @type Object
18426      */
18427     defaultPadding : {left:0, right:0, top:0, bottom:0},
18428
18429     /*
18430      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18431  *
18432  * Usage:
18433  <pre><code>
18434  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18435                 { dragElId: "existingProxyDiv" });
18436  dd.startDrag = function(){
18437      this.constrainTo("parent-id");
18438  };
18439  </code></pre>
18440  * Or you can initalize it using the {@link Roo.Element} object:
18441  <pre><code>
18442  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18443      startDrag : function(){
18444          this.constrainTo("parent-id");
18445      }
18446  });
18447  </code></pre>
18448      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18449      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18450      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18451      * an object containing the sides to pad. For example: {right:10, bottom:10}
18452      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18453      */
18454     constrainTo : function(constrainTo, pad, inContent){
18455         if(typeof pad == "number"){
18456             pad = {left: pad, right:pad, top:pad, bottom:pad};
18457         }
18458         pad = pad || this.defaultPadding;
18459         var b = Roo.get(this.getEl()).getBox();
18460         var ce = Roo.get(constrainTo);
18461         var s = ce.getScroll();
18462         var c, cd = ce.dom;
18463         if(cd == document.body){
18464             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18465         }else{
18466             xy = ce.getXY();
18467             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18468         }
18469
18470
18471         var topSpace = b.y - c.y;
18472         var leftSpace = b.x - c.x;
18473
18474         this.resetConstraints();
18475         this.setXConstraint(leftSpace - (pad.left||0), // left
18476                 c.width - leftSpace - b.width - (pad.right||0) //right
18477         );
18478         this.setYConstraint(topSpace - (pad.top||0), //top
18479                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18480         );
18481     },
18482
18483     /**
18484      * Returns a reference to the linked element
18485      * @method getEl
18486      * @return {HTMLElement} the html element
18487      */
18488     getEl: function() {
18489         if (!this._domRef) {
18490             this._domRef = Roo.getDom(this.id);
18491         }
18492
18493         return this._domRef;
18494     },
18495
18496     /**
18497      * Returns a reference to the actual element to drag.  By default this is
18498      * the same as the html element, but it can be assigned to another
18499      * element. An example of this can be found in Roo.dd.DDProxy
18500      * @method getDragEl
18501      * @return {HTMLElement} the html element
18502      */
18503     getDragEl: function() {
18504         return Roo.getDom(this.dragElId);
18505     },
18506
18507     /**
18508      * Sets up the DragDrop object.  Must be called in the constructor of any
18509      * Roo.dd.DragDrop subclass
18510      * @method init
18511      * @param id the id of the linked element
18512      * @param {String} sGroup the group of related items
18513      * @param {object} config configuration attributes
18514      */
18515     init: function(id, sGroup, config) {
18516         this.initTarget(id, sGroup, config);
18517         if (!Roo.isTouch) {
18518             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18519         }
18520         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18521         // Event.on(this.id, "selectstart", Event.preventDefault);
18522     },
18523
18524     /**
18525      * Initializes Targeting functionality only... the object does not
18526      * get a mousedown handler.
18527      * @method initTarget
18528      * @param id the id of the linked element
18529      * @param {String} sGroup the group of related items
18530      * @param {object} config configuration attributes
18531      */
18532     initTarget: function(id, sGroup, config) {
18533
18534         // configuration attributes
18535         this.config = config || {};
18536
18537         // create a local reference to the drag and drop manager
18538         this.DDM = Roo.dd.DDM;
18539         // initialize the groups array
18540         this.groups = {};
18541
18542         // assume that we have an element reference instead of an id if the
18543         // parameter is not a string
18544         if (typeof id !== "string") {
18545             id = Roo.id(id);
18546         }
18547
18548         // set the id
18549         this.id = id;
18550
18551         // add to an interaction group
18552         this.addToGroup((sGroup) ? sGroup : "default");
18553
18554         // We don't want to register this as the handle with the manager
18555         // so we just set the id rather than calling the setter.
18556         this.handleElId = id;
18557
18558         // the linked element is the element that gets dragged by default
18559         this.setDragElId(id);
18560
18561         // by default, clicked anchors will not start drag operations.
18562         this.invalidHandleTypes = { A: "A" };
18563         this.invalidHandleIds = {};
18564         this.invalidHandleClasses = [];
18565
18566         this.applyConfig();
18567
18568         this.handleOnAvailable();
18569     },
18570
18571     /**
18572      * Applies the configuration parameters that were passed into the constructor.
18573      * This is supposed to happen at each level through the inheritance chain.  So
18574      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18575      * DragDrop in order to get all of the parameters that are available in
18576      * each object.
18577      * @method applyConfig
18578      */
18579     applyConfig: function() {
18580
18581         // configurable properties:
18582         //    padding, isTarget, maintainOffset, primaryButtonOnly
18583         this.padding           = this.config.padding || [0, 0, 0, 0];
18584         this.isTarget          = (this.config.isTarget !== false);
18585         this.maintainOffset    = (this.config.maintainOffset);
18586         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18587
18588     },
18589
18590     /**
18591      * Executed when the linked element is available
18592      * @method handleOnAvailable
18593      * @private
18594      */
18595     handleOnAvailable: function() {
18596         this.available = true;
18597         this.resetConstraints();
18598         this.onAvailable();
18599     },
18600
18601      /**
18602      * Configures the padding for the target zone in px.  Effectively expands
18603      * (or reduces) the virtual object size for targeting calculations.
18604      * Supports css-style shorthand; if only one parameter is passed, all sides
18605      * will have that padding, and if only two are passed, the top and bottom
18606      * will have the first param, the left and right the second.
18607      * @method setPadding
18608      * @param {int} iTop    Top pad
18609      * @param {int} iRight  Right pad
18610      * @param {int} iBot    Bot pad
18611      * @param {int} iLeft   Left pad
18612      */
18613     setPadding: function(iTop, iRight, iBot, iLeft) {
18614         // this.padding = [iLeft, iRight, iTop, iBot];
18615         if (!iRight && 0 !== iRight) {
18616             this.padding = [iTop, iTop, iTop, iTop];
18617         } else if (!iBot && 0 !== iBot) {
18618             this.padding = [iTop, iRight, iTop, iRight];
18619         } else {
18620             this.padding = [iTop, iRight, iBot, iLeft];
18621         }
18622     },
18623
18624     /**
18625      * Stores the initial placement of the linked element.
18626      * @method setInitialPosition
18627      * @param {int} diffX   the X offset, default 0
18628      * @param {int} diffY   the Y offset, default 0
18629      */
18630     setInitPosition: function(diffX, diffY) {
18631         var el = this.getEl();
18632
18633         if (!this.DDM.verifyEl(el)) {
18634             return;
18635         }
18636
18637         var dx = diffX || 0;
18638         var dy = diffY || 0;
18639
18640         var p = Dom.getXY( el );
18641
18642         this.initPageX = p[0] - dx;
18643         this.initPageY = p[1] - dy;
18644
18645         this.lastPageX = p[0];
18646         this.lastPageY = p[1];
18647
18648
18649         this.setStartPosition(p);
18650     },
18651
18652     /**
18653      * Sets the start position of the element.  This is set when the obj
18654      * is initialized, the reset when a drag is started.
18655      * @method setStartPosition
18656      * @param pos current position (from previous lookup)
18657      * @private
18658      */
18659     setStartPosition: function(pos) {
18660         var p = pos || Dom.getXY( this.getEl() );
18661         this.deltaSetXY = null;
18662
18663         this.startPageX = p[0];
18664         this.startPageY = p[1];
18665     },
18666
18667     /**
18668      * Add this instance to a group of related drag/drop objects.  All
18669      * instances belong to at least one group, and can belong to as many
18670      * groups as needed.
18671      * @method addToGroup
18672      * @param sGroup {string} the name of the group
18673      */
18674     addToGroup: function(sGroup) {
18675         this.groups[sGroup] = true;
18676         this.DDM.regDragDrop(this, sGroup);
18677     },
18678
18679     /**
18680      * Remove's this instance from the supplied interaction group
18681      * @method removeFromGroup
18682      * @param {string}  sGroup  The group to drop
18683      */
18684     removeFromGroup: function(sGroup) {
18685         if (this.groups[sGroup]) {
18686             delete this.groups[sGroup];
18687         }
18688
18689         this.DDM.removeDDFromGroup(this, sGroup);
18690     },
18691
18692     /**
18693      * Allows you to specify that an element other than the linked element
18694      * will be moved with the cursor during a drag
18695      * @method setDragElId
18696      * @param id {string} the id of the element that will be used to initiate the drag
18697      */
18698     setDragElId: function(id) {
18699         this.dragElId = id;
18700     },
18701
18702     /**
18703      * Allows you to specify a child of the linked element that should be
18704      * used to initiate the drag operation.  An example of this would be if
18705      * you have a content div with text and links.  Clicking anywhere in the
18706      * content area would normally start the drag operation.  Use this method
18707      * to specify that an element inside of the content div is the element
18708      * that starts the drag operation.
18709      * @method setHandleElId
18710      * @param id {string} the id of the element that will be used to
18711      * initiate the drag.
18712      */
18713     setHandleElId: function(id) {
18714         if (typeof id !== "string") {
18715             id = Roo.id(id);
18716         }
18717         this.handleElId = id;
18718         this.DDM.regHandle(this.id, id);
18719     },
18720
18721     /**
18722      * Allows you to set an element outside of the linked element as a drag
18723      * handle
18724      * @method setOuterHandleElId
18725      * @param id the id of the element that will be used to initiate the drag
18726      */
18727     setOuterHandleElId: function(id) {
18728         if (typeof id !== "string") {
18729             id = Roo.id(id);
18730         }
18731         Event.on(id, "mousedown",
18732                 this.handleMouseDown, this);
18733         this.setHandleElId(id);
18734
18735         this.hasOuterHandles = true;
18736     },
18737
18738     /**
18739      * Remove all drag and drop hooks for this element
18740      * @method unreg
18741      */
18742     unreg: function() {
18743         Event.un(this.id, "mousedown",
18744                 this.handleMouseDown);
18745         Event.un(this.id, "touchstart",
18746                 this.handleMouseDown);
18747         this._domRef = null;
18748         this.DDM._remove(this);
18749     },
18750
18751     destroy : function(){
18752         this.unreg();
18753     },
18754
18755     /**
18756      * Returns true if this instance is locked, or the drag drop mgr is locked
18757      * (meaning that all drag/drop is disabled on the page.)
18758      * @method isLocked
18759      * @return {boolean} true if this obj or all drag/drop is locked, else
18760      * false
18761      */
18762     isLocked: function() {
18763         return (this.DDM.isLocked() || this.locked);
18764     },
18765
18766     /**
18767      * Fired when this object is clicked
18768      * @method handleMouseDown
18769      * @param {Event} e
18770      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18771      * @private
18772      */
18773     handleMouseDown: function(e, oDD){
18774      
18775         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18776             //Roo.log('not touch/ button !=0');
18777             return;
18778         }
18779         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18780             return; // double touch..
18781         }
18782         
18783
18784         if (this.isLocked()) {
18785             //Roo.log('locked');
18786             return;
18787         }
18788
18789         this.DDM.refreshCache(this.groups);
18790 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18791         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18792         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18793             //Roo.log('no outer handes or not over target');
18794                 // do nothing.
18795         } else {
18796 //            Roo.log('check validator');
18797             if (this.clickValidator(e)) {
18798 //                Roo.log('validate success');
18799                 // set the initial element position
18800                 this.setStartPosition();
18801
18802
18803                 this.b4MouseDown(e);
18804                 this.onMouseDown(e);
18805
18806                 this.DDM.handleMouseDown(e, this);
18807
18808                 this.DDM.stopEvent(e);
18809             } else {
18810
18811
18812             }
18813         }
18814     },
18815
18816     clickValidator: function(e) {
18817         var target = e.getTarget();
18818         return ( this.isValidHandleChild(target) &&
18819                     (this.id == this.handleElId ||
18820                         this.DDM.handleWasClicked(target, this.id)) );
18821     },
18822
18823     /**
18824      * Allows you to specify a tag name that should not start a drag operation
18825      * when clicked.  This is designed to facilitate embedding links within a
18826      * drag handle that do something other than start the drag.
18827      * @method addInvalidHandleType
18828      * @param {string} tagName the type of element to exclude
18829      */
18830     addInvalidHandleType: function(tagName) {
18831         var type = tagName.toUpperCase();
18832         this.invalidHandleTypes[type] = type;
18833     },
18834
18835     /**
18836      * Lets you to specify an element id for a child of a drag handle
18837      * that should not initiate a drag
18838      * @method addInvalidHandleId
18839      * @param {string} id the element id of the element you wish to ignore
18840      */
18841     addInvalidHandleId: function(id) {
18842         if (typeof id !== "string") {
18843             id = Roo.id(id);
18844         }
18845         this.invalidHandleIds[id] = id;
18846     },
18847
18848     /**
18849      * Lets you specify a css class of elements that will not initiate a drag
18850      * @method addInvalidHandleClass
18851      * @param {string} cssClass the class of the elements you wish to ignore
18852      */
18853     addInvalidHandleClass: function(cssClass) {
18854         this.invalidHandleClasses.push(cssClass);
18855     },
18856
18857     /**
18858      * Unsets an excluded tag name set by addInvalidHandleType
18859      * @method removeInvalidHandleType
18860      * @param {string} tagName the type of element to unexclude
18861      */
18862     removeInvalidHandleType: function(tagName) {
18863         var type = tagName.toUpperCase();
18864         // this.invalidHandleTypes[type] = null;
18865         delete this.invalidHandleTypes[type];
18866     },
18867
18868     /**
18869      * Unsets an invalid handle id
18870      * @method removeInvalidHandleId
18871      * @param {string} id the id of the element to re-enable
18872      */
18873     removeInvalidHandleId: function(id) {
18874         if (typeof id !== "string") {
18875             id = Roo.id(id);
18876         }
18877         delete this.invalidHandleIds[id];
18878     },
18879
18880     /**
18881      * Unsets an invalid css class
18882      * @method removeInvalidHandleClass
18883      * @param {string} cssClass the class of the element(s) you wish to
18884      * re-enable
18885      */
18886     removeInvalidHandleClass: function(cssClass) {
18887         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18888             if (this.invalidHandleClasses[i] == cssClass) {
18889                 delete this.invalidHandleClasses[i];
18890             }
18891         }
18892     },
18893
18894     /**
18895      * Checks the tag exclusion list to see if this click should be ignored
18896      * @method isValidHandleChild
18897      * @param {HTMLElement} node the HTMLElement to evaluate
18898      * @return {boolean} true if this is a valid tag type, false if not
18899      */
18900     isValidHandleChild: function(node) {
18901
18902         var valid = true;
18903         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18904         var nodeName;
18905         try {
18906             nodeName = node.nodeName.toUpperCase();
18907         } catch(e) {
18908             nodeName = node.nodeName;
18909         }
18910         valid = valid && !this.invalidHandleTypes[nodeName];
18911         valid = valid && !this.invalidHandleIds[node.id];
18912
18913         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18914             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18915         }
18916
18917
18918         return valid;
18919
18920     },
18921
18922     /**
18923      * Create the array of horizontal tick marks if an interval was specified
18924      * in setXConstraint().
18925      * @method setXTicks
18926      * @private
18927      */
18928     setXTicks: function(iStartX, iTickSize) {
18929         this.xTicks = [];
18930         this.xTickSize = iTickSize;
18931
18932         var tickMap = {};
18933
18934         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18935             if (!tickMap[i]) {
18936                 this.xTicks[this.xTicks.length] = i;
18937                 tickMap[i] = true;
18938             }
18939         }
18940
18941         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18942             if (!tickMap[i]) {
18943                 this.xTicks[this.xTicks.length] = i;
18944                 tickMap[i] = true;
18945             }
18946         }
18947
18948         this.xTicks.sort(this.DDM.numericSort) ;
18949     },
18950
18951     /**
18952      * Create the array of vertical tick marks if an interval was specified in
18953      * setYConstraint().
18954      * @method setYTicks
18955      * @private
18956      */
18957     setYTicks: function(iStartY, iTickSize) {
18958         this.yTicks = [];
18959         this.yTickSize = iTickSize;
18960
18961         var tickMap = {};
18962
18963         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18964             if (!tickMap[i]) {
18965                 this.yTicks[this.yTicks.length] = i;
18966                 tickMap[i] = true;
18967             }
18968         }
18969
18970         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18971             if (!tickMap[i]) {
18972                 this.yTicks[this.yTicks.length] = i;
18973                 tickMap[i] = true;
18974             }
18975         }
18976
18977         this.yTicks.sort(this.DDM.numericSort) ;
18978     },
18979
18980     /**
18981      * By default, the element can be dragged any place on the screen.  Use
18982      * this method to limit the horizontal travel of the element.  Pass in
18983      * 0,0 for the parameters if you want to lock the drag to the y axis.
18984      * @method setXConstraint
18985      * @param {int} iLeft the number of pixels the element can move to the left
18986      * @param {int} iRight the number of pixels the element can move to the
18987      * right
18988      * @param {int} iTickSize optional parameter for specifying that the
18989      * element
18990      * should move iTickSize pixels at a time.
18991      */
18992     setXConstraint: function(iLeft, iRight, iTickSize) {
18993         this.leftConstraint = iLeft;
18994         this.rightConstraint = iRight;
18995
18996         this.minX = this.initPageX - iLeft;
18997         this.maxX = this.initPageX + iRight;
18998         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18999
19000         this.constrainX = true;
19001     },
19002
19003     /**
19004      * Clears any constraints applied to this instance.  Also clears ticks
19005      * since they can't exist independent of a constraint at this time.
19006      * @method clearConstraints
19007      */
19008     clearConstraints: function() {
19009         this.constrainX = false;
19010         this.constrainY = false;
19011         this.clearTicks();
19012     },
19013
19014     /**
19015      * Clears any tick interval defined for this instance
19016      * @method clearTicks
19017      */
19018     clearTicks: function() {
19019         this.xTicks = null;
19020         this.yTicks = null;
19021         this.xTickSize = 0;
19022         this.yTickSize = 0;
19023     },
19024
19025     /**
19026      * By default, the element can be dragged any place on the screen.  Set
19027      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19028      * parameters if you want to lock the drag to the x axis.
19029      * @method setYConstraint
19030      * @param {int} iUp the number of pixels the element can move up
19031      * @param {int} iDown the number of pixels the element can move down
19032      * @param {int} iTickSize optional parameter for specifying that the
19033      * element should move iTickSize pixels at a time.
19034      */
19035     setYConstraint: function(iUp, iDown, iTickSize) {
19036         this.topConstraint = iUp;
19037         this.bottomConstraint = iDown;
19038
19039         this.minY = this.initPageY - iUp;
19040         this.maxY = this.initPageY + iDown;
19041         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19042
19043         this.constrainY = true;
19044
19045     },
19046
19047     /**
19048      * resetConstraints must be called if you manually reposition a dd element.
19049      * @method resetConstraints
19050      * @param {boolean} maintainOffset
19051      */
19052     resetConstraints: function() {
19053
19054
19055         // Maintain offsets if necessary
19056         if (this.initPageX || this.initPageX === 0) {
19057             // figure out how much this thing has moved
19058             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19059             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19060
19061             this.setInitPosition(dx, dy);
19062
19063         // This is the first time we have detected the element's position
19064         } else {
19065             this.setInitPosition();
19066         }
19067
19068         if (this.constrainX) {
19069             this.setXConstraint( this.leftConstraint,
19070                                  this.rightConstraint,
19071                                  this.xTickSize        );
19072         }
19073
19074         if (this.constrainY) {
19075             this.setYConstraint( this.topConstraint,
19076                                  this.bottomConstraint,
19077                                  this.yTickSize         );
19078         }
19079     },
19080
19081     /**
19082      * Normally the drag element is moved pixel by pixel, but we can specify
19083      * that it move a number of pixels at a time.  This method resolves the
19084      * location when we have it set up like this.
19085      * @method getTick
19086      * @param {int} val where we want to place the object
19087      * @param {int[]} tickArray sorted array of valid points
19088      * @return {int} the closest tick
19089      * @private
19090      */
19091     getTick: function(val, tickArray) {
19092
19093         if (!tickArray) {
19094             // If tick interval is not defined, it is effectively 1 pixel,
19095             // so we return the value passed to us.
19096             return val;
19097         } else if (tickArray[0] >= val) {
19098             // The value is lower than the first tick, so we return the first
19099             // tick.
19100             return tickArray[0];
19101         } else {
19102             for (var i=0, len=tickArray.length; i<len; ++i) {
19103                 var next = i + 1;
19104                 if (tickArray[next] && tickArray[next] >= val) {
19105                     var diff1 = val - tickArray[i];
19106                     var diff2 = tickArray[next] - val;
19107                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19108                 }
19109             }
19110
19111             // The value is larger than the last tick, so we return the last
19112             // tick.
19113             return tickArray[tickArray.length - 1];
19114         }
19115     },
19116
19117     /**
19118      * toString method
19119      * @method toString
19120      * @return {string} string representation of the dd obj
19121      */
19122     toString: function() {
19123         return ("DragDrop " + this.id);
19124     }
19125
19126 });
19127
19128 })();
19129 /*
19130  * Based on:
19131  * Ext JS Library 1.1.1
19132  * Copyright(c) 2006-2007, Ext JS, LLC.
19133  *
19134  * Originally Released Under LGPL - original licence link has changed is not relivant.
19135  *
19136  * Fork - LGPL
19137  * <script type="text/javascript">
19138  */
19139
19140
19141 /**
19142  * The drag and drop utility provides a framework for building drag and drop
19143  * applications.  In addition to enabling drag and drop for specific elements,
19144  * the drag and drop elements are tracked by the manager class, and the
19145  * interactions between the various elements are tracked during the drag and
19146  * the implementing code is notified about these important moments.
19147  */
19148
19149 // Only load the library once.  Rewriting the manager class would orphan
19150 // existing drag and drop instances.
19151 if (!Roo.dd.DragDropMgr) {
19152
19153 /**
19154  * @class Roo.dd.DragDropMgr
19155  * DragDropMgr is a singleton that tracks the element interaction for
19156  * all DragDrop items in the window.  Generally, you will not call
19157  * this class directly, but it does have helper methods that could
19158  * be useful in your DragDrop implementations.
19159  * @singleton
19160  */
19161 Roo.dd.DragDropMgr = function() {
19162
19163     var Event = Roo.EventManager;
19164
19165     return {
19166
19167         /**
19168          * Two dimensional Array of registered DragDrop objects.  The first
19169          * dimension is the DragDrop item group, the second the DragDrop
19170          * object.
19171          * @property ids
19172          * @type {string: string}
19173          * @private
19174          * @static
19175          */
19176         ids: {},
19177
19178         /**
19179          * Array of element ids defined as drag handles.  Used to determine
19180          * if the element that generated the mousedown event is actually the
19181          * handle and not the html element itself.
19182          * @property handleIds
19183          * @type {string: string}
19184          * @private
19185          * @static
19186          */
19187         handleIds: {},
19188
19189         /**
19190          * the DragDrop object that is currently being dragged
19191          * @property dragCurrent
19192          * @type DragDrop
19193          * @private
19194          * @static
19195          **/
19196         dragCurrent: null,
19197
19198         /**
19199          * the DragDrop object(s) that are being hovered over
19200          * @property dragOvers
19201          * @type Array
19202          * @private
19203          * @static
19204          */
19205         dragOvers: {},
19206
19207         /**
19208          * the X distance between the cursor and the object being dragged
19209          * @property deltaX
19210          * @type int
19211          * @private
19212          * @static
19213          */
19214         deltaX: 0,
19215
19216         /**
19217          * the Y distance between the cursor and the object being dragged
19218          * @property deltaY
19219          * @type int
19220          * @private
19221          * @static
19222          */
19223         deltaY: 0,
19224
19225         /**
19226          * Flag to determine if we should prevent the default behavior of the
19227          * events we define. By default this is true, but this can be set to
19228          * false if you need the default behavior (not recommended)
19229          * @property preventDefault
19230          * @type boolean
19231          * @static
19232          */
19233         preventDefault: true,
19234
19235         /**
19236          * Flag to determine if we should stop the propagation of the events
19237          * we generate. This is true by default but you may want to set it to
19238          * false if the html element contains other features that require the
19239          * mouse click.
19240          * @property stopPropagation
19241          * @type boolean
19242          * @static
19243          */
19244         stopPropagation: true,
19245
19246         /**
19247          * Internal flag that is set to true when drag and drop has been
19248          * intialized
19249          * @property initialized
19250          * @private
19251          * @static
19252          */
19253         initalized: false,
19254
19255         /**
19256          * All drag and drop can be disabled.
19257          * @property locked
19258          * @private
19259          * @static
19260          */
19261         locked: false,
19262
19263         /**
19264          * Called the first time an element is registered.
19265          * @method init
19266          * @private
19267          * @static
19268          */
19269         init: function() {
19270             this.initialized = true;
19271         },
19272
19273         /**
19274          * In point mode, drag and drop interaction is defined by the
19275          * location of the cursor during the drag/drop
19276          * @property POINT
19277          * @type int
19278          * @static
19279          */
19280         POINT: 0,
19281
19282         /**
19283          * In intersect mode, drag and drop interactio nis defined by the
19284          * overlap of two or more drag and drop objects.
19285          * @property INTERSECT
19286          * @type int
19287          * @static
19288          */
19289         INTERSECT: 1,
19290
19291         /**
19292          * The current drag and drop mode.  Default: POINT
19293          * @property mode
19294          * @type int
19295          * @static
19296          */
19297         mode: 0,
19298
19299         /**
19300          * Runs method on all drag and drop objects
19301          * @method _execOnAll
19302          * @private
19303          * @static
19304          */
19305         _execOnAll: function(sMethod, args) {
19306             for (var i in this.ids) {
19307                 for (var j in this.ids[i]) {
19308                     var oDD = this.ids[i][j];
19309                     if (! this.isTypeOfDD(oDD)) {
19310                         continue;
19311                     }
19312                     oDD[sMethod].apply(oDD, args);
19313                 }
19314             }
19315         },
19316
19317         /**
19318          * Drag and drop initialization.  Sets up the global event handlers
19319          * @method _onLoad
19320          * @private
19321          * @static
19322          */
19323         _onLoad: function() {
19324
19325             this.init();
19326
19327             if (!Roo.isTouch) {
19328                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19329                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19330             }
19331             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19332             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19333             
19334             Event.on(window,   "unload",    this._onUnload, this, true);
19335             Event.on(window,   "resize",    this._onResize, this, true);
19336             // Event.on(window,   "mouseout",    this._test);
19337
19338         },
19339
19340         /**
19341          * Reset constraints on all drag and drop objs
19342          * @method _onResize
19343          * @private
19344          * @static
19345          */
19346         _onResize: function(e) {
19347             this._execOnAll("resetConstraints", []);
19348         },
19349
19350         /**
19351          * Lock all drag and drop functionality
19352          * @method lock
19353          * @static
19354          */
19355         lock: function() { this.locked = true; },
19356
19357         /**
19358          * Unlock all drag and drop functionality
19359          * @method unlock
19360          * @static
19361          */
19362         unlock: function() { this.locked = false; },
19363
19364         /**
19365          * Is drag and drop locked?
19366          * @method isLocked
19367          * @return {boolean} True if drag and drop is locked, false otherwise.
19368          * @static
19369          */
19370         isLocked: function() { return this.locked; },
19371
19372         /**
19373          * Location cache that is set for all drag drop objects when a drag is
19374          * initiated, cleared when the drag is finished.
19375          * @property locationCache
19376          * @private
19377          * @static
19378          */
19379         locationCache: {},
19380
19381         /**
19382          * Set useCache to false if you want to force object the lookup of each
19383          * drag and drop linked element constantly during a drag.
19384          * @property useCache
19385          * @type boolean
19386          * @static
19387          */
19388         useCache: true,
19389
19390         /**
19391          * The number of pixels that the mouse needs to move after the
19392          * mousedown before the drag is initiated.  Default=3;
19393          * @property clickPixelThresh
19394          * @type int
19395          * @static
19396          */
19397         clickPixelThresh: 3,
19398
19399         /**
19400          * The number of milliseconds after the mousedown event to initiate the
19401          * drag if we don't get a mouseup event. Default=1000
19402          * @property clickTimeThresh
19403          * @type int
19404          * @static
19405          */
19406         clickTimeThresh: 350,
19407
19408         /**
19409          * Flag that indicates that either the drag pixel threshold or the
19410          * mousdown time threshold has been met
19411          * @property dragThreshMet
19412          * @type boolean
19413          * @private
19414          * @static
19415          */
19416         dragThreshMet: false,
19417
19418         /**
19419          * Timeout used for the click time threshold
19420          * @property clickTimeout
19421          * @type Object
19422          * @private
19423          * @static
19424          */
19425         clickTimeout: null,
19426
19427         /**
19428          * The X position of the mousedown event stored for later use when a
19429          * drag threshold is met.
19430          * @property startX
19431          * @type int
19432          * @private
19433          * @static
19434          */
19435         startX: 0,
19436
19437         /**
19438          * The Y position of the mousedown event stored for later use when a
19439          * drag threshold is met.
19440          * @property startY
19441          * @type int
19442          * @private
19443          * @static
19444          */
19445         startY: 0,
19446
19447         /**
19448          * Each DragDrop instance must be registered with the DragDropMgr.
19449          * This is executed in DragDrop.init()
19450          * @method regDragDrop
19451          * @param {DragDrop} oDD the DragDrop object to register
19452          * @param {String} sGroup the name of the group this element belongs to
19453          * @static
19454          */
19455         regDragDrop: function(oDD, sGroup) {
19456             if (!this.initialized) { this.init(); }
19457
19458             if (!this.ids[sGroup]) {
19459                 this.ids[sGroup] = {};
19460             }
19461             this.ids[sGroup][oDD.id] = oDD;
19462         },
19463
19464         /**
19465          * Removes the supplied dd instance from the supplied group. Executed
19466          * by DragDrop.removeFromGroup, so don't call this function directly.
19467          * @method removeDDFromGroup
19468          * @private
19469          * @static
19470          */
19471         removeDDFromGroup: function(oDD, sGroup) {
19472             if (!this.ids[sGroup]) {
19473                 this.ids[sGroup] = {};
19474             }
19475
19476             var obj = this.ids[sGroup];
19477             if (obj && obj[oDD.id]) {
19478                 delete obj[oDD.id];
19479             }
19480         },
19481
19482         /**
19483          * Unregisters a drag and drop item.  This is executed in
19484          * DragDrop.unreg, use that method instead of calling this directly.
19485          * @method _remove
19486          * @private
19487          * @static
19488          */
19489         _remove: function(oDD) {
19490             for (var g in oDD.groups) {
19491                 if (g && this.ids[g][oDD.id]) {
19492                     delete this.ids[g][oDD.id];
19493                 }
19494             }
19495             delete this.handleIds[oDD.id];
19496         },
19497
19498         /**
19499          * Each DragDrop handle element must be registered.  This is done
19500          * automatically when executing DragDrop.setHandleElId()
19501          * @method regHandle
19502          * @param {String} sDDId the DragDrop id this element is a handle for
19503          * @param {String} sHandleId the id of the element that is the drag
19504          * handle
19505          * @static
19506          */
19507         regHandle: function(sDDId, sHandleId) {
19508             if (!this.handleIds[sDDId]) {
19509                 this.handleIds[sDDId] = {};
19510             }
19511             this.handleIds[sDDId][sHandleId] = sHandleId;
19512         },
19513
19514         /**
19515          * Utility function to determine if a given element has been
19516          * registered as a drag drop item.
19517          * @method isDragDrop
19518          * @param {String} id the element id to check
19519          * @return {boolean} true if this element is a DragDrop item,
19520          * false otherwise
19521          * @static
19522          */
19523         isDragDrop: function(id) {
19524             return ( this.getDDById(id) ) ? true : false;
19525         },
19526
19527         /**
19528          * Returns the drag and drop instances that are in all groups the
19529          * passed in instance belongs to.
19530          * @method getRelated
19531          * @param {DragDrop} p_oDD the obj to get related data for
19532          * @param {boolean} bTargetsOnly if true, only return targetable objs
19533          * @return {DragDrop[]} the related instances
19534          * @static
19535          */
19536         getRelated: function(p_oDD, bTargetsOnly) {
19537             var oDDs = [];
19538             for (var i in p_oDD.groups) {
19539                 for (j in this.ids[i]) {
19540                     var dd = this.ids[i][j];
19541                     if (! this.isTypeOfDD(dd)) {
19542                         continue;
19543                     }
19544                     if (!bTargetsOnly || dd.isTarget) {
19545                         oDDs[oDDs.length] = dd;
19546                     }
19547                 }
19548             }
19549
19550             return oDDs;
19551         },
19552
19553         /**
19554          * Returns true if the specified dd target is a legal target for
19555          * the specifice drag obj
19556          * @method isLegalTarget
19557          * @param {DragDrop} the drag obj
19558          * @param {DragDrop} the target
19559          * @return {boolean} true if the target is a legal target for the
19560          * dd obj
19561          * @static
19562          */
19563         isLegalTarget: function (oDD, oTargetDD) {
19564             var targets = this.getRelated(oDD, true);
19565             for (var i=0, len=targets.length;i<len;++i) {
19566                 if (targets[i].id == oTargetDD.id) {
19567                     return true;
19568                 }
19569             }
19570
19571             return false;
19572         },
19573
19574         /**
19575          * My goal is to be able to transparently determine if an object is
19576          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19577          * returns "object", oDD.constructor.toString() always returns
19578          * "DragDrop" and not the name of the subclass.  So for now it just
19579          * evaluates a well-known variable in DragDrop.
19580          * @method isTypeOfDD
19581          * @param {Object} the object to evaluate
19582          * @return {boolean} true if typeof oDD = DragDrop
19583          * @static
19584          */
19585         isTypeOfDD: function (oDD) {
19586             return (oDD && oDD.__ygDragDrop);
19587         },
19588
19589         /**
19590          * Utility function to determine if a given element has been
19591          * registered as a drag drop handle for the given Drag Drop object.
19592          * @method isHandle
19593          * @param {String} id the element id to check
19594          * @return {boolean} true if this element is a DragDrop handle, false
19595          * otherwise
19596          * @static
19597          */
19598         isHandle: function(sDDId, sHandleId) {
19599             return ( this.handleIds[sDDId] &&
19600                             this.handleIds[sDDId][sHandleId] );
19601         },
19602
19603         /**
19604          * Returns the DragDrop instance for a given id
19605          * @method getDDById
19606          * @param {String} id the id of the DragDrop object
19607          * @return {DragDrop} the drag drop object, null if it is not found
19608          * @static
19609          */
19610         getDDById: function(id) {
19611             for (var i in this.ids) {
19612                 if (this.ids[i][id]) {
19613                     return this.ids[i][id];
19614                 }
19615             }
19616             return null;
19617         },
19618
19619         /**
19620          * Fired after a registered DragDrop object gets the mousedown event.
19621          * Sets up the events required to track the object being dragged
19622          * @method handleMouseDown
19623          * @param {Event} e the event
19624          * @param oDD the DragDrop object being dragged
19625          * @private
19626          * @static
19627          */
19628         handleMouseDown: function(e, oDD) {
19629             if(Roo.QuickTips){
19630                 Roo.QuickTips.disable();
19631             }
19632             this.currentTarget = e.getTarget();
19633
19634             this.dragCurrent = oDD;
19635
19636             var el = oDD.getEl();
19637
19638             // track start position
19639             this.startX = e.getPageX();
19640             this.startY = e.getPageY();
19641
19642             this.deltaX = this.startX - el.offsetLeft;
19643             this.deltaY = this.startY - el.offsetTop;
19644
19645             this.dragThreshMet = false;
19646
19647             this.clickTimeout = setTimeout(
19648                     function() {
19649                         var DDM = Roo.dd.DDM;
19650                         DDM.startDrag(DDM.startX, DDM.startY);
19651                     },
19652                     this.clickTimeThresh );
19653         },
19654
19655         /**
19656          * Fired when either the drag pixel threshol or the mousedown hold
19657          * time threshold has been met.
19658          * @method startDrag
19659          * @param x {int} the X position of the original mousedown
19660          * @param y {int} the Y position of the original mousedown
19661          * @static
19662          */
19663         startDrag: function(x, y) {
19664             clearTimeout(this.clickTimeout);
19665             if (this.dragCurrent) {
19666                 this.dragCurrent.b4StartDrag(x, y);
19667                 this.dragCurrent.startDrag(x, y);
19668             }
19669             this.dragThreshMet = true;
19670         },
19671
19672         /**
19673          * Internal function to handle the mouseup event.  Will be invoked
19674          * from the context of the document.
19675          * @method handleMouseUp
19676          * @param {Event} e the event
19677          * @private
19678          * @static
19679          */
19680         handleMouseUp: function(e) {
19681
19682             if(Roo.QuickTips){
19683                 Roo.QuickTips.enable();
19684             }
19685             if (! this.dragCurrent) {
19686                 return;
19687             }
19688
19689             clearTimeout(this.clickTimeout);
19690
19691             if (this.dragThreshMet) {
19692                 this.fireEvents(e, true);
19693             } else {
19694             }
19695
19696             this.stopDrag(e);
19697
19698             this.stopEvent(e);
19699         },
19700
19701         /**
19702          * Utility to stop event propagation and event default, if these
19703          * features are turned on.
19704          * @method stopEvent
19705          * @param {Event} e the event as returned by this.getEvent()
19706          * @static
19707          */
19708         stopEvent: function(e){
19709             if(this.stopPropagation) {
19710                 e.stopPropagation();
19711             }
19712
19713             if (this.preventDefault) {
19714                 e.preventDefault();
19715             }
19716         },
19717
19718         /**
19719          * Internal function to clean up event handlers after the drag
19720          * operation is complete
19721          * @method stopDrag
19722          * @param {Event} e the event
19723          * @private
19724          * @static
19725          */
19726         stopDrag: function(e) {
19727             // Fire the drag end event for the item that was dragged
19728             if (this.dragCurrent) {
19729                 if (this.dragThreshMet) {
19730                     this.dragCurrent.b4EndDrag(e);
19731                     this.dragCurrent.endDrag(e);
19732                 }
19733
19734                 this.dragCurrent.onMouseUp(e);
19735             }
19736
19737             this.dragCurrent = null;
19738             this.dragOvers = {};
19739         },
19740
19741         /**
19742          * Internal function to handle the mousemove event.  Will be invoked
19743          * from the context of the html element.
19744          *
19745          * @TODO figure out what we can do about mouse events lost when the
19746          * user drags objects beyond the window boundary.  Currently we can
19747          * detect this in internet explorer by verifying that the mouse is
19748          * down during the mousemove event.  Firefox doesn't give us the
19749          * button state on the mousemove event.
19750          * @method handleMouseMove
19751          * @param {Event} e the event
19752          * @private
19753          * @static
19754          */
19755         handleMouseMove: function(e) {
19756             if (! this.dragCurrent) {
19757                 return true;
19758             }
19759
19760             // var button = e.which || e.button;
19761
19762             // check for IE mouseup outside of page boundary
19763             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19764                 this.stopEvent(e);
19765                 return this.handleMouseUp(e);
19766             }
19767
19768             if (!this.dragThreshMet) {
19769                 var diffX = Math.abs(this.startX - e.getPageX());
19770                 var diffY = Math.abs(this.startY - e.getPageY());
19771                 if (diffX > this.clickPixelThresh ||
19772                             diffY > this.clickPixelThresh) {
19773                     this.startDrag(this.startX, this.startY);
19774                 }
19775             }
19776
19777             if (this.dragThreshMet) {
19778                 this.dragCurrent.b4Drag(e);
19779                 this.dragCurrent.onDrag(e);
19780                 if(!this.dragCurrent.moveOnly){
19781                     this.fireEvents(e, false);
19782                 }
19783             }
19784
19785             this.stopEvent(e);
19786
19787             return true;
19788         },
19789
19790         /**
19791          * Iterates over all of the DragDrop elements to find ones we are
19792          * hovering over or dropping on
19793          * @method fireEvents
19794          * @param {Event} e the event
19795          * @param {boolean} isDrop is this a drop op or a mouseover op?
19796          * @private
19797          * @static
19798          */
19799         fireEvents: function(e, isDrop) {
19800             var dc = this.dragCurrent;
19801
19802             // If the user did the mouse up outside of the window, we could
19803             // get here even though we have ended the drag.
19804             if (!dc || dc.isLocked()) {
19805                 return;
19806             }
19807
19808             var pt = e.getPoint();
19809
19810             // cache the previous dragOver array
19811             var oldOvers = [];
19812
19813             var outEvts   = [];
19814             var overEvts  = [];
19815             var dropEvts  = [];
19816             var enterEvts = [];
19817
19818             // Check to see if the object(s) we were hovering over is no longer
19819             // being hovered over so we can fire the onDragOut event
19820             for (var i in this.dragOvers) {
19821
19822                 var ddo = this.dragOvers[i];
19823
19824                 if (! this.isTypeOfDD(ddo)) {
19825                     continue;
19826                 }
19827
19828                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19829                     outEvts.push( ddo );
19830                 }
19831
19832                 oldOvers[i] = true;
19833                 delete this.dragOvers[i];
19834             }
19835
19836             for (var sGroup in dc.groups) {
19837
19838                 if ("string" != typeof sGroup) {
19839                     continue;
19840                 }
19841
19842                 for (i in this.ids[sGroup]) {
19843                     var oDD = this.ids[sGroup][i];
19844                     if (! this.isTypeOfDD(oDD)) {
19845                         continue;
19846                     }
19847
19848                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19849                         if (this.isOverTarget(pt, oDD, this.mode)) {
19850                             // look for drop interactions
19851                             if (isDrop) {
19852                                 dropEvts.push( oDD );
19853                             // look for drag enter and drag over interactions
19854                             } else {
19855
19856                                 // initial drag over: dragEnter fires
19857                                 if (!oldOvers[oDD.id]) {
19858                                     enterEvts.push( oDD );
19859                                 // subsequent drag overs: dragOver fires
19860                                 } else {
19861                                     overEvts.push( oDD );
19862                                 }
19863
19864                                 this.dragOvers[oDD.id] = oDD;
19865                             }
19866                         }
19867                     }
19868                 }
19869             }
19870
19871             if (this.mode) {
19872                 if (outEvts.length) {
19873                     dc.b4DragOut(e, outEvts);
19874                     dc.onDragOut(e, outEvts);
19875                 }
19876
19877                 if (enterEvts.length) {
19878                     dc.onDragEnter(e, enterEvts);
19879                 }
19880
19881                 if (overEvts.length) {
19882                     dc.b4DragOver(e, overEvts);
19883                     dc.onDragOver(e, overEvts);
19884                 }
19885
19886                 if (dropEvts.length) {
19887                     dc.b4DragDrop(e, dropEvts);
19888                     dc.onDragDrop(e, dropEvts);
19889                 }
19890
19891             } else {
19892                 // fire dragout events
19893                 var len = 0;
19894                 for (i=0, len=outEvts.length; i<len; ++i) {
19895                     dc.b4DragOut(e, outEvts[i].id);
19896                     dc.onDragOut(e, outEvts[i].id);
19897                 }
19898
19899                 // fire enter events
19900                 for (i=0,len=enterEvts.length; i<len; ++i) {
19901                     // dc.b4DragEnter(e, oDD.id);
19902                     dc.onDragEnter(e, enterEvts[i].id);
19903                 }
19904
19905                 // fire over events
19906                 for (i=0,len=overEvts.length; i<len; ++i) {
19907                     dc.b4DragOver(e, overEvts[i].id);
19908                     dc.onDragOver(e, overEvts[i].id);
19909                 }
19910
19911                 // fire drop events
19912                 for (i=0, len=dropEvts.length; i<len; ++i) {
19913                     dc.b4DragDrop(e, dropEvts[i].id);
19914                     dc.onDragDrop(e, dropEvts[i].id);
19915                 }
19916
19917             }
19918
19919             // notify about a drop that did not find a target
19920             if (isDrop && !dropEvts.length) {
19921                 dc.onInvalidDrop(e);
19922             }
19923
19924         },
19925
19926         /**
19927          * Helper function for getting the best match from the list of drag
19928          * and drop objects returned by the drag and drop events when we are
19929          * in INTERSECT mode.  It returns either the first object that the
19930          * cursor is over, or the object that has the greatest overlap with
19931          * the dragged element.
19932          * @method getBestMatch
19933          * @param  {DragDrop[]} dds The array of drag and drop objects
19934          * targeted
19935          * @return {DragDrop}       The best single match
19936          * @static
19937          */
19938         getBestMatch: function(dds) {
19939             var winner = null;
19940             // Return null if the input is not what we expect
19941             //if (!dds || !dds.length || dds.length == 0) {
19942                // winner = null;
19943             // If there is only one item, it wins
19944             //} else if (dds.length == 1) {
19945
19946             var len = dds.length;
19947
19948             if (len == 1) {
19949                 winner = dds[0];
19950             } else {
19951                 // Loop through the targeted items
19952                 for (var i=0; i<len; ++i) {
19953                     var dd = dds[i];
19954                     // If the cursor is over the object, it wins.  If the
19955                     // cursor is over multiple matches, the first one we come
19956                     // to wins.
19957                     if (dd.cursorIsOver) {
19958                         winner = dd;
19959                         break;
19960                     // Otherwise the object with the most overlap wins
19961                     } else {
19962                         if (!winner ||
19963                             winner.overlap.getArea() < dd.overlap.getArea()) {
19964                             winner = dd;
19965                         }
19966                     }
19967                 }
19968             }
19969
19970             return winner;
19971         },
19972
19973         /**
19974          * Refreshes the cache of the top-left and bottom-right points of the
19975          * drag and drop objects in the specified group(s).  This is in the
19976          * format that is stored in the drag and drop instance, so typical
19977          * usage is:
19978          * <code>
19979          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19980          * </code>
19981          * Alternatively:
19982          * <code>
19983          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19984          * </code>
19985          * @TODO this really should be an indexed array.  Alternatively this
19986          * method could accept both.
19987          * @method refreshCache
19988          * @param {Object} groups an associative array of groups to refresh
19989          * @static
19990          */
19991         refreshCache: function(groups) {
19992             for (var sGroup in groups) {
19993                 if ("string" != typeof sGroup) {
19994                     continue;
19995                 }
19996                 for (var i in this.ids[sGroup]) {
19997                     var oDD = this.ids[sGroup][i];
19998
19999                     if (this.isTypeOfDD(oDD)) {
20000                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20001                         var loc = this.getLocation(oDD);
20002                         if (loc) {
20003                             this.locationCache[oDD.id] = loc;
20004                         } else {
20005                             delete this.locationCache[oDD.id];
20006                             // this will unregister the drag and drop object if
20007                             // the element is not in a usable state
20008                             // oDD.unreg();
20009                         }
20010                     }
20011                 }
20012             }
20013         },
20014
20015         /**
20016          * This checks to make sure an element exists and is in the DOM.  The
20017          * main purpose is to handle cases where innerHTML is used to remove
20018          * drag and drop objects from the DOM.  IE provides an 'unspecified
20019          * error' when trying to access the offsetParent of such an element
20020          * @method verifyEl
20021          * @param {HTMLElement} el the element to check
20022          * @return {boolean} true if the element looks usable
20023          * @static
20024          */
20025         verifyEl: function(el) {
20026             if (el) {
20027                 var parent;
20028                 if(Roo.isIE){
20029                     try{
20030                         parent = el.offsetParent;
20031                     }catch(e){}
20032                 }else{
20033                     parent = el.offsetParent;
20034                 }
20035                 if (parent) {
20036                     return true;
20037                 }
20038             }
20039
20040             return false;
20041         },
20042
20043         /**
20044          * Returns a Region object containing the drag and drop element's position
20045          * and size, including the padding configured for it
20046          * @method getLocation
20047          * @param {DragDrop} oDD the drag and drop object to get the
20048          *                       location for
20049          * @return {Roo.lib.Region} a Region object representing the total area
20050          *                             the element occupies, including any padding
20051          *                             the instance is configured for.
20052          * @static
20053          */
20054         getLocation: function(oDD) {
20055             if (! this.isTypeOfDD(oDD)) {
20056                 return null;
20057             }
20058
20059             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20060
20061             try {
20062                 pos= Roo.lib.Dom.getXY(el);
20063             } catch (e) { }
20064
20065             if (!pos) {
20066                 return null;
20067             }
20068
20069             x1 = pos[0];
20070             x2 = x1 + el.offsetWidth;
20071             y1 = pos[1];
20072             y2 = y1 + el.offsetHeight;
20073
20074             t = y1 - oDD.padding[0];
20075             r = x2 + oDD.padding[1];
20076             b = y2 + oDD.padding[2];
20077             l = x1 - oDD.padding[3];
20078
20079             return new Roo.lib.Region( t, r, b, l );
20080         },
20081
20082         /**
20083          * Checks the cursor location to see if it over the target
20084          * @method isOverTarget
20085          * @param {Roo.lib.Point} pt The point to evaluate
20086          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20087          * @return {boolean} true if the mouse is over the target
20088          * @private
20089          * @static
20090          */
20091         isOverTarget: function(pt, oTarget, intersect) {
20092             // use cache if available
20093             var loc = this.locationCache[oTarget.id];
20094             if (!loc || !this.useCache) {
20095                 loc = this.getLocation(oTarget);
20096                 this.locationCache[oTarget.id] = loc;
20097
20098             }
20099
20100             if (!loc) {
20101                 return false;
20102             }
20103
20104             oTarget.cursorIsOver = loc.contains( pt );
20105
20106             // DragDrop is using this as a sanity check for the initial mousedown
20107             // in this case we are done.  In POINT mode, if the drag obj has no
20108             // contraints, we are also done. Otherwise we need to evaluate the
20109             // location of the target as related to the actual location of the
20110             // dragged element.
20111             var dc = this.dragCurrent;
20112             if (!dc || !dc.getTargetCoord ||
20113                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20114                 return oTarget.cursorIsOver;
20115             }
20116
20117             oTarget.overlap = null;
20118
20119             // Get the current location of the drag element, this is the
20120             // location of the mouse event less the delta that represents
20121             // where the original mousedown happened on the element.  We
20122             // need to consider constraints and ticks as well.
20123             var pos = dc.getTargetCoord(pt.x, pt.y);
20124
20125             var el = dc.getDragEl();
20126             var curRegion = new Roo.lib.Region( pos.y,
20127                                                    pos.x + el.offsetWidth,
20128                                                    pos.y + el.offsetHeight,
20129                                                    pos.x );
20130
20131             var overlap = curRegion.intersect(loc);
20132
20133             if (overlap) {
20134                 oTarget.overlap = overlap;
20135                 return (intersect) ? true : oTarget.cursorIsOver;
20136             } else {
20137                 return false;
20138             }
20139         },
20140
20141         /**
20142          * unload event handler
20143          * @method _onUnload
20144          * @private
20145          * @static
20146          */
20147         _onUnload: function(e, me) {
20148             Roo.dd.DragDropMgr.unregAll();
20149         },
20150
20151         /**
20152          * Cleans up the drag and drop events and objects.
20153          * @method unregAll
20154          * @private
20155          * @static
20156          */
20157         unregAll: function() {
20158
20159             if (this.dragCurrent) {
20160                 this.stopDrag();
20161                 this.dragCurrent = null;
20162             }
20163
20164             this._execOnAll("unreg", []);
20165
20166             for (i in this.elementCache) {
20167                 delete this.elementCache[i];
20168             }
20169
20170             this.elementCache = {};
20171             this.ids = {};
20172         },
20173
20174         /**
20175          * A cache of DOM elements
20176          * @property elementCache
20177          * @private
20178          * @static
20179          */
20180         elementCache: {},
20181
20182         /**
20183          * Get the wrapper for the DOM element specified
20184          * @method getElWrapper
20185          * @param {String} id the id of the element to get
20186          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20187          * @private
20188          * @deprecated This wrapper isn't that useful
20189          * @static
20190          */
20191         getElWrapper: function(id) {
20192             var oWrapper = this.elementCache[id];
20193             if (!oWrapper || !oWrapper.el) {
20194                 oWrapper = this.elementCache[id] =
20195                     new this.ElementWrapper(Roo.getDom(id));
20196             }
20197             return oWrapper;
20198         },
20199
20200         /**
20201          * Returns the actual DOM element
20202          * @method getElement
20203          * @param {String} id the id of the elment to get
20204          * @return {Object} The element
20205          * @deprecated use Roo.getDom instead
20206          * @static
20207          */
20208         getElement: function(id) {
20209             return Roo.getDom(id);
20210         },
20211
20212         /**
20213          * Returns the style property for the DOM element (i.e.,
20214          * document.getElById(id).style)
20215          * @method getCss
20216          * @param {String} id the id of the elment to get
20217          * @return {Object} The style property of the element
20218          * @deprecated use Roo.getDom instead
20219          * @static
20220          */
20221         getCss: function(id) {
20222             var el = Roo.getDom(id);
20223             return (el) ? el.style : null;
20224         },
20225
20226         /**
20227          * Inner class for cached elements
20228          * @class DragDropMgr.ElementWrapper
20229          * @for DragDropMgr
20230          * @private
20231          * @deprecated
20232          */
20233         ElementWrapper: function(el) {
20234                 /**
20235                  * The element
20236                  * @property el
20237                  */
20238                 this.el = el || null;
20239                 /**
20240                  * The element id
20241                  * @property id
20242                  */
20243                 this.id = this.el && el.id;
20244                 /**
20245                  * A reference to the style property
20246                  * @property css
20247                  */
20248                 this.css = this.el && el.style;
20249             },
20250
20251         /**
20252          * Returns the X position of an html element
20253          * @method getPosX
20254          * @param el the element for which to get the position
20255          * @return {int} the X coordinate
20256          * @for DragDropMgr
20257          * @deprecated use Roo.lib.Dom.getX instead
20258          * @static
20259          */
20260         getPosX: function(el) {
20261             return Roo.lib.Dom.getX(el);
20262         },
20263
20264         /**
20265          * Returns the Y position of an html element
20266          * @method getPosY
20267          * @param el the element for which to get the position
20268          * @return {int} the Y coordinate
20269          * @deprecated use Roo.lib.Dom.getY instead
20270          * @static
20271          */
20272         getPosY: function(el) {
20273             return Roo.lib.Dom.getY(el);
20274         },
20275
20276         /**
20277          * Swap two nodes.  In IE, we use the native method, for others we
20278          * emulate the IE behavior
20279          * @method swapNode
20280          * @param n1 the first node to swap
20281          * @param n2 the other node to swap
20282          * @static
20283          */
20284         swapNode: function(n1, n2) {
20285             if (n1.swapNode) {
20286                 n1.swapNode(n2);
20287             } else {
20288                 var p = n2.parentNode;
20289                 var s = n2.nextSibling;
20290
20291                 if (s == n1) {
20292                     p.insertBefore(n1, n2);
20293                 } else if (n2 == n1.nextSibling) {
20294                     p.insertBefore(n2, n1);
20295                 } else {
20296                     n1.parentNode.replaceChild(n2, n1);
20297                     p.insertBefore(n1, s);
20298                 }
20299             }
20300         },
20301
20302         /**
20303          * Returns the current scroll position
20304          * @method getScroll
20305          * @private
20306          * @static
20307          */
20308         getScroll: function () {
20309             var t, l, dde=document.documentElement, db=document.body;
20310             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20311                 t = dde.scrollTop;
20312                 l = dde.scrollLeft;
20313             } else if (db) {
20314                 t = db.scrollTop;
20315                 l = db.scrollLeft;
20316             } else {
20317
20318             }
20319             return { top: t, left: l };
20320         },
20321
20322         /**
20323          * Returns the specified element style property
20324          * @method getStyle
20325          * @param {HTMLElement} el          the element
20326          * @param {string}      styleProp   the style property
20327          * @return {string} The value of the style property
20328          * @deprecated use Roo.lib.Dom.getStyle
20329          * @static
20330          */
20331         getStyle: function(el, styleProp) {
20332             return Roo.fly(el).getStyle(styleProp);
20333         },
20334
20335         /**
20336          * Gets the scrollTop
20337          * @method getScrollTop
20338          * @return {int} the document's scrollTop
20339          * @static
20340          */
20341         getScrollTop: function () { return this.getScroll().top; },
20342
20343         /**
20344          * Gets the scrollLeft
20345          * @method getScrollLeft
20346          * @return {int} the document's scrollTop
20347          * @static
20348          */
20349         getScrollLeft: function () { return this.getScroll().left; },
20350
20351         /**
20352          * Sets the x/y position of an element to the location of the
20353          * target element.
20354          * @method moveToEl
20355          * @param {HTMLElement} moveEl      The element to move
20356          * @param {HTMLElement} targetEl    The position reference element
20357          * @static
20358          */
20359         moveToEl: function (moveEl, targetEl) {
20360             var aCoord = Roo.lib.Dom.getXY(targetEl);
20361             Roo.lib.Dom.setXY(moveEl, aCoord);
20362         },
20363
20364         /**
20365          * Numeric array sort function
20366          * @method numericSort
20367          * @static
20368          */
20369         numericSort: function(a, b) { return (a - b); },
20370
20371         /**
20372          * Internal counter
20373          * @property _timeoutCount
20374          * @private
20375          * @static
20376          */
20377         _timeoutCount: 0,
20378
20379         /**
20380          * Trying to make the load order less important.  Without this we get
20381          * an error if this file is loaded before the Event Utility.
20382          * @method _addListeners
20383          * @private
20384          * @static
20385          */
20386         _addListeners: function() {
20387             var DDM = Roo.dd.DDM;
20388             if ( Roo.lib.Event && document ) {
20389                 DDM._onLoad();
20390             } else {
20391                 if (DDM._timeoutCount > 2000) {
20392                 } else {
20393                     setTimeout(DDM._addListeners, 10);
20394                     if (document && document.body) {
20395                         DDM._timeoutCount += 1;
20396                     }
20397                 }
20398             }
20399         },
20400
20401         /**
20402          * Recursively searches the immediate parent and all child nodes for
20403          * the handle element in order to determine wheter or not it was
20404          * clicked.
20405          * @method handleWasClicked
20406          * @param node the html element to inspect
20407          * @static
20408          */
20409         handleWasClicked: function(node, id) {
20410             if (this.isHandle(id, node.id)) {
20411                 return true;
20412             } else {
20413                 // check to see if this is a text node child of the one we want
20414                 var p = node.parentNode;
20415
20416                 while (p) {
20417                     if (this.isHandle(id, p.id)) {
20418                         return true;
20419                     } else {
20420                         p = p.parentNode;
20421                     }
20422                 }
20423             }
20424
20425             return false;
20426         }
20427
20428     };
20429
20430 }();
20431
20432 // shorter alias, save a few bytes
20433 Roo.dd.DDM = Roo.dd.DragDropMgr;
20434 Roo.dd.DDM._addListeners();
20435
20436 }/*
20437  * Based on:
20438  * Ext JS Library 1.1.1
20439  * Copyright(c) 2006-2007, Ext JS, LLC.
20440  *
20441  * Originally Released Under LGPL - original licence link has changed is not relivant.
20442  *
20443  * Fork - LGPL
20444  * <script type="text/javascript">
20445  */
20446
20447 /**
20448  * @class Roo.dd.DD
20449  * A DragDrop implementation where the linked element follows the
20450  * mouse cursor during a drag.
20451  * @extends Roo.dd.DragDrop
20452  * @constructor
20453  * @param {String} id the id of the linked element
20454  * @param {String} sGroup the group of related DragDrop items
20455  * @param {object} config an object containing configurable attributes
20456  *                Valid properties for DD:
20457  *                    scroll
20458  */
20459 Roo.dd.DD = function(id, sGroup, config) {
20460     if (id) {
20461         this.init(id, sGroup, config);
20462     }
20463 };
20464
20465 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20466
20467     /**
20468      * When set to true, the utility automatically tries to scroll the browser
20469      * window wehn a drag and drop element is dragged near the viewport boundary.
20470      * Defaults to true.
20471      * @property scroll
20472      * @type boolean
20473      */
20474     scroll: true,
20475
20476     /**
20477      * Sets the pointer offset to the distance between the linked element's top
20478      * left corner and the location the element was clicked
20479      * @method autoOffset
20480      * @param {int} iPageX the X coordinate of the click
20481      * @param {int} iPageY the Y coordinate of the click
20482      */
20483     autoOffset: function(iPageX, iPageY) {
20484         var x = iPageX - this.startPageX;
20485         var y = iPageY - this.startPageY;
20486         this.setDelta(x, y);
20487     },
20488
20489     /**
20490      * Sets the pointer offset.  You can call this directly to force the
20491      * offset to be in a particular location (e.g., pass in 0,0 to set it
20492      * to the center of the object)
20493      * @method setDelta
20494      * @param {int} iDeltaX the distance from the left
20495      * @param {int} iDeltaY the distance from the top
20496      */
20497     setDelta: function(iDeltaX, iDeltaY) {
20498         this.deltaX = iDeltaX;
20499         this.deltaY = iDeltaY;
20500     },
20501
20502     /**
20503      * Sets the drag element to the location of the mousedown or click event,
20504      * maintaining the cursor location relative to the location on the element
20505      * that was clicked.  Override this if you want to place the element in a
20506      * location other than where the cursor is.
20507      * @method setDragElPos
20508      * @param {int} iPageX the X coordinate of the mousedown or drag event
20509      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20510      */
20511     setDragElPos: function(iPageX, iPageY) {
20512         // the first time we do this, we are going to check to make sure
20513         // the element has css positioning
20514
20515         var el = this.getDragEl();
20516         this.alignElWithMouse(el, iPageX, iPageY);
20517     },
20518
20519     /**
20520      * Sets the element to the location of the mousedown or click event,
20521      * maintaining the cursor location relative to the location on the element
20522      * that was clicked.  Override this if you want to place the element in a
20523      * location other than where the cursor is.
20524      * @method alignElWithMouse
20525      * @param {HTMLElement} el the element to move
20526      * @param {int} iPageX the X coordinate of the mousedown or drag event
20527      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20528      */
20529     alignElWithMouse: function(el, iPageX, iPageY) {
20530         var oCoord = this.getTargetCoord(iPageX, iPageY);
20531         var fly = el.dom ? el : Roo.fly(el);
20532         if (!this.deltaSetXY) {
20533             var aCoord = [oCoord.x, oCoord.y];
20534             fly.setXY(aCoord);
20535             var newLeft = fly.getLeft(true);
20536             var newTop  = fly.getTop(true);
20537             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20538         } else {
20539             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20540         }
20541
20542         this.cachePosition(oCoord.x, oCoord.y);
20543         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20544         return oCoord;
20545     },
20546
20547     /**
20548      * Saves the most recent position so that we can reset the constraints and
20549      * tick marks on-demand.  We need to know this so that we can calculate the
20550      * number of pixels the element is offset from its original position.
20551      * @method cachePosition
20552      * @param iPageX the current x position (optional, this just makes it so we
20553      * don't have to look it up again)
20554      * @param iPageY the current y position (optional, this just makes it so we
20555      * don't have to look it up again)
20556      */
20557     cachePosition: function(iPageX, iPageY) {
20558         if (iPageX) {
20559             this.lastPageX = iPageX;
20560             this.lastPageY = iPageY;
20561         } else {
20562             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20563             this.lastPageX = aCoord[0];
20564             this.lastPageY = aCoord[1];
20565         }
20566     },
20567
20568     /**
20569      * Auto-scroll the window if the dragged object has been moved beyond the
20570      * visible window boundary.
20571      * @method autoScroll
20572      * @param {int} x the drag element's x position
20573      * @param {int} y the drag element's y position
20574      * @param {int} h the height of the drag element
20575      * @param {int} w the width of the drag element
20576      * @private
20577      */
20578     autoScroll: function(x, y, h, w) {
20579
20580         if (this.scroll) {
20581             // The client height
20582             var clientH = Roo.lib.Dom.getViewWidth();
20583
20584             // The client width
20585             var clientW = Roo.lib.Dom.getViewHeight();
20586
20587             // The amt scrolled down
20588             var st = this.DDM.getScrollTop();
20589
20590             // The amt scrolled right
20591             var sl = this.DDM.getScrollLeft();
20592
20593             // Location of the bottom of the element
20594             var bot = h + y;
20595
20596             // Location of the right of the element
20597             var right = w + x;
20598
20599             // The distance from the cursor to the bottom of the visible area,
20600             // adjusted so that we don't scroll if the cursor is beyond the
20601             // element drag constraints
20602             var toBot = (clientH + st - y - this.deltaY);
20603
20604             // The distance from the cursor to the right of the visible area
20605             var toRight = (clientW + sl - x - this.deltaX);
20606
20607
20608             // How close to the edge the cursor must be before we scroll
20609             // var thresh = (document.all) ? 100 : 40;
20610             var thresh = 40;
20611
20612             // How many pixels to scroll per autoscroll op.  This helps to reduce
20613             // clunky scrolling. IE is more sensitive about this ... it needs this
20614             // value to be higher.
20615             var scrAmt = (document.all) ? 80 : 30;
20616
20617             // Scroll down if we are near the bottom of the visible page and the
20618             // obj extends below the crease
20619             if ( bot > clientH && toBot < thresh ) {
20620                 window.scrollTo(sl, st + scrAmt);
20621             }
20622
20623             // Scroll up if the window is scrolled down and the top of the object
20624             // goes above the top border
20625             if ( y < st && st > 0 && y - st < thresh ) {
20626                 window.scrollTo(sl, st - scrAmt);
20627             }
20628
20629             // Scroll right if the obj is beyond the right border and the cursor is
20630             // near the border.
20631             if ( right > clientW && toRight < thresh ) {
20632                 window.scrollTo(sl + scrAmt, st);
20633             }
20634
20635             // Scroll left if the window has been scrolled to the right and the obj
20636             // extends past the left border
20637             if ( x < sl && sl > 0 && x - sl < thresh ) {
20638                 window.scrollTo(sl - scrAmt, st);
20639             }
20640         }
20641     },
20642
20643     /**
20644      * Finds the location the element should be placed if we want to move
20645      * it to where the mouse location less the click offset would place us.
20646      * @method getTargetCoord
20647      * @param {int} iPageX the X coordinate of the click
20648      * @param {int} iPageY the Y coordinate of the click
20649      * @return an object that contains the coordinates (Object.x and Object.y)
20650      * @private
20651      */
20652     getTargetCoord: function(iPageX, iPageY) {
20653
20654
20655         var x = iPageX - this.deltaX;
20656         var y = iPageY - this.deltaY;
20657
20658         if (this.constrainX) {
20659             if (x < this.minX) { x = this.minX; }
20660             if (x > this.maxX) { x = this.maxX; }
20661         }
20662
20663         if (this.constrainY) {
20664             if (y < this.minY) { y = this.minY; }
20665             if (y > this.maxY) { y = this.maxY; }
20666         }
20667
20668         x = this.getTick(x, this.xTicks);
20669         y = this.getTick(y, this.yTicks);
20670
20671
20672         return {x:x, y:y};
20673     },
20674
20675     /*
20676      * Sets up config options specific to this class. Overrides
20677      * Roo.dd.DragDrop, but all versions of this method through the
20678      * inheritance chain are called
20679      */
20680     applyConfig: function() {
20681         Roo.dd.DD.superclass.applyConfig.call(this);
20682         this.scroll = (this.config.scroll !== false);
20683     },
20684
20685     /*
20686      * Event that fires prior to the onMouseDown event.  Overrides
20687      * Roo.dd.DragDrop.
20688      */
20689     b4MouseDown: function(e) {
20690         // this.resetConstraints();
20691         this.autoOffset(e.getPageX(),
20692                             e.getPageY());
20693     },
20694
20695     /*
20696      * Event that fires prior to the onDrag event.  Overrides
20697      * Roo.dd.DragDrop.
20698      */
20699     b4Drag: function(e) {
20700         this.setDragElPos(e.getPageX(),
20701                             e.getPageY());
20702     },
20703
20704     toString: function() {
20705         return ("DD " + this.id);
20706     }
20707
20708     //////////////////////////////////////////////////////////////////////////
20709     // Debugging ygDragDrop events that can be overridden
20710     //////////////////////////////////////////////////////////////////////////
20711     /*
20712     startDrag: function(x, y) {
20713     },
20714
20715     onDrag: function(e) {
20716     },
20717
20718     onDragEnter: function(e, id) {
20719     },
20720
20721     onDragOver: function(e, id) {
20722     },
20723
20724     onDragOut: function(e, id) {
20725     },
20726
20727     onDragDrop: function(e, id) {
20728     },
20729
20730     endDrag: function(e) {
20731     }
20732
20733     */
20734
20735 });/*
20736  * Based on:
20737  * Ext JS Library 1.1.1
20738  * Copyright(c) 2006-2007, Ext JS, LLC.
20739  *
20740  * Originally Released Under LGPL - original licence link has changed is not relivant.
20741  *
20742  * Fork - LGPL
20743  * <script type="text/javascript">
20744  */
20745
20746 /**
20747  * @class Roo.dd.DDProxy
20748  * A DragDrop implementation that inserts an empty, bordered div into
20749  * the document that follows the cursor during drag operations.  At the time of
20750  * the click, the frame div is resized to the dimensions of the linked html
20751  * element, and moved to the exact location of the linked element.
20752  *
20753  * References to the "frame" element refer to the single proxy element that
20754  * was created to be dragged in place of all DDProxy elements on the
20755  * page.
20756  *
20757  * @extends Roo.dd.DD
20758  * @constructor
20759  * @param {String} id the id of the linked html element
20760  * @param {String} sGroup the group of related DragDrop objects
20761  * @param {object} config an object containing configurable attributes
20762  *                Valid properties for DDProxy in addition to those in DragDrop:
20763  *                   resizeFrame, centerFrame, dragElId
20764  */
20765 Roo.dd.DDProxy = function(id, sGroup, config) {
20766     if (id) {
20767         this.init(id, sGroup, config);
20768         this.initFrame();
20769     }
20770 };
20771
20772 /**
20773  * The default drag frame div id
20774  * @property Roo.dd.DDProxy.dragElId
20775  * @type String
20776  * @static
20777  */
20778 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20779
20780 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20781
20782     /**
20783      * By default we resize the drag frame to be the same size as the element
20784      * we want to drag (this is to get the frame effect).  We can turn it off
20785      * if we want a different behavior.
20786      * @property resizeFrame
20787      * @type boolean
20788      */
20789     resizeFrame: true,
20790
20791     /**
20792      * By default the frame is positioned exactly where the drag element is, so
20793      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20794      * you do not have constraints on the obj is to have the drag frame centered
20795      * around the cursor.  Set centerFrame to true for this effect.
20796      * @property centerFrame
20797      * @type boolean
20798      */
20799     centerFrame: false,
20800
20801     /**
20802      * Creates the proxy element if it does not yet exist
20803      * @method createFrame
20804      */
20805     createFrame: function() {
20806         var self = this;
20807         var body = document.body;
20808
20809         if (!body || !body.firstChild) {
20810             setTimeout( function() { self.createFrame(); }, 50 );
20811             return;
20812         }
20813
20814         var div = this.getDragEl();
20815
20816         if (!div) {
20817             div    = document.createElement("div");
20818             div.id = this.dragElId;
20819             var s  = div.style;
20820
20821             s.position   = "absolute";
20822             s.visibility = "hidden";
20823             s.cursor     = "move";
20824             s.border     = "2px solid #aaa";
20825             s.zIndex     = 999;
20826
20827             // appendChild can blow up IE if invoked prior to the window load event
20828             // while rendering a table.  It is possible there are other scenarios
20829             // that would cause this to happen as well.
20830             body.insertBefore(div, body.firstChild);
20831         }
20832     },
20833
20834     /**
20835      * Initialization for the drag frame element.  Must be called in the
20836      * constructor of all subclasses
20837      * @method initFrame
20838      */
20839     initFrame: function() {
20840         this.createFrame();
20841     },
20842
20843     applyConfig: function() {
20844         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20845
20846         this.resizeFrame = (this.config.resizeFrame !== false);
20847         this.centerFrame = (this.config.centerFrame);
20848         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20849     },
20850
20851     /**
20852      * Resizes the drag frame to the dimensions of the clicked object, positions
20853      * it over the object, and finally displays it
20854      * @method showFrame
20855      * @param {int} iPageX X click position
20856      * @param {int} iPageY Y click position
20857      * @private
20858      */
20859     showFrame: function(iPageX, iPageY) {
20860         var el = this.getEl();
20861         var dragEl = this.getDragEl();
20862         var s = dragEl.style;
20863
20864         this._resizeProxy();
20865
20866         if (this.centerFrame) {
20867             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20868                            Math.round(parseInt(s.height, 10)/2) );
20869         }
20870
20871         this.setDragElPos(iPageX, iPageY);
20872
20873         Roo.fly(dragEl).show();
20874     },
20875
20876     /**
20877      * The proxy is automatically resized to the dimensions of the linked
20878      * element when a drag is initiated, unless resizeFrame is set to false
20879      * @method _resizeProxy
20880      * @private
20881      */
20882     _resizeProxy: function() {
20883         if (this.resizeFrame) {
20884             var el = this.getEl();
20885             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20886         }
20887     },
20888
20889     // overrides Roo.dd.DragDrop
20890     b4MouseDown: function(e) {
20891         var x = e.getPageX();
20892         var y = e.getPageY();
20893         this.autoOffset(x, y);
20894         this.setDragElPos(x, y);
20895     },
20896
20897     // overrides Roo.dd.DragDrop
20898     b4StartDrag: function(x, y) {
20899         // show the drag frame
20900         this.showFrame(x, y);
20901     },
20902
20903     // overrides Roo.dd.DragDrop
20904     b4EndDrag: function(e) {
20905         Roo.fly(this.getDragEl()).hide();
20906     },
20907
20908     // overrides Roo.dd.DragDrop
20909     // By default we try to move the element to the last location of the frame.
20910     // This is so that the default behavior mirrors that of Roo.dd.DD.
20911     endDrag: function(e) {
20912
20913         var lel = this.getEl();
20914         var del = this.getDragEl();
20915
20916         // Show the drag frame briefly so we can get its position
20917         del.style.visibility = "";
20918
20919         this.beforeMove();
20920         // Hide the linked element before the move to get around a Safari
20921         // rendering bug.
20922         lel.style.visibility = "hidden";
20923         Roo.dd.DDM.moveToEl(lel, del);
20924         del.style.visibility = "hidden";
20925         lel.style.visibility = "";
20926
20927         this.afterDrag();
20928     },
20929
20930     beforeMove : function(){
20931
20932     },
20933
20934     afterDrag : function(){
20935
20936     },
20937
20938     toString: function() {
20939         return ("DDProxy " + this.id);
20940     }
20941
20942 });
20943 /*
20944  * Based on:
20945  * Ext JS Library 1.1.1
20946  * Copyright(c) 2006-2007, Ext JS, LLC.
20947  *
20948  * Originally Released Under LGPL - original licence link has changed is not relivant.
20949  *
20950  * Fork - LGPL
20951  * <script type="text/javascript">
20952  */
20953
20954  /**
20955  * @class Roo.dd.DDTarget
20956  * A DragDrop implementation that does not move, but can be a drop
20957  * target.  You would get the same result by simply omitting implementation
20958  * for the event callbacks, but this way we reduce the processing cost of the
20959  * event listener and the callbacks.
20960  * @extends Roo.dd.DragDrop
20961  * @constructor
20962  * @param {String} id the id of the element that is a drop target
20963  * @param {String} sGroup the group of related DragDrop objects
20964  * @param {object} config an object containing configurable attributes
20965  *                 Valid properties for DDTarget in addition to those in
20966  *                 DragDrop:
20967  *                    none
20968  */
20969 Roo.dd.DDTarget = function(id, sGroup, config) {
20970     if (id) {
20971         this.initTarget(id, sGroup, config);
20972     }
20973     if (config.listeners || config.events) { 
20974        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20975             listeners : config.listeners || {}, 
20976             events : config.events || {} 
20977         });    
20978     }
20979 };
20980
20981 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20982 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20983     toString: function() {
20984         return ("DDTarget " + this.id);
20985     }
20986 });
20987 /*
20988  * Based on:
20989  * Ext JS Library 1.1.1
20990  * Copyright(c) 2006-2007, Ext JS, LLC.
20991  *
20992  * Originally Released Under LGPL - original licence link has changed is not relivant.
20993  *
20994  * Fork - LGPL
20995  * <script type="text/javascript">
20996  */
20997  
20998
20999 /**
21000  * @class Roo.dd.ScrollManager
21001  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21002  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21003  * @singleton
21004  */
21005 Roo.dd.ScrollManager = function(){
21006     var ddm = Roo.dd.DragDropMgr;
21007     var els = {};
21008     var dragEl = null;
21009     var proc = {};
21010     
21011     
21012     
21013     var onStop = function(e){
21014         dragEl = null;
21015         clearProc();
21016     };
21017     
21018     var triggerRefresh = function(){
21019         if(ddm.dragCurrent){
21020              ddm.refreshCache(ddm.dragCurrent.groups);
21021         }
21022     };
21023     
21024     var doScroll = function(){
21025         if(ddm.dragCurrent){
21026             var dds = Roo.dd.ScrollManager;
21027             if(!dds.animate){
21028                 if(proc.el.scroll(proc.dir, dds.increment)){
21029                     triggerRefresh();
21030                 }
21031             }else{
21032                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21033             }
21034         }
21035     };
21036     
21037     var clearProc = function(){
21038         if(proc.id){
21039             clearInterval(proc.id);
21040         }
21041         proc.id = 0;
21042         proc.el = null;
21043         proc.dir = "";
21044     };
21045     
21046     var startProc = function(el, dir){
21047          Roo.log('scroll startproc');
21048         clearProc();
21049         proc.el = el;
21050         proc.dir = dir;
21051         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21052     };
21053     
21054     var onFire = function(e, isDrop){
21055        
21056         if(isDrop || !ddm.dragCurrent){ return; }
21057         var dds = Roo.dd.ScrollManager;
21058         if(!dragEl || dragEl != ddm.dragCurrent){
21059             dragEl = ddm.dragCurrent;
21060             // refresh regions on drag start
21061             dds.refreshCache();
21062         }
21063         
21064         var xy = Roo.lib.Event.getXY(e);
21065         var pt = new Roo.lib.Point(xy[0], xy[1]);
21066         for(var id in els){
21067             var el = els[id], r = el._region;
21068             if(r && r.contains(pt) && el.isScrollable()){
21069                 if(r.bottom - pt.y <= dds.thresh){
21070                     if(proc.el != el){
21071                         startProc(el, "down");
21072                     }
21073                     return;
21074                 }else if(r.right - pt.x <= dds.thresh){
21075                     if(proc.el != el){
21076                         startProc(el, "left");
21077                     }
21078                     return;
21079                 }else if(pt.y - r.top <= dds.thresh){
21080                     if(proc.el != el){
21081                         startProc(el, "up");
21082                     }
21083                     return;
21084                 }else if(pt.x - r.left <= dds.thresh){
21085                     if(proc.el != el){
21086                         startProc(el, "right");
21087                     }
21088                     return;
21089                 }
21090             }
21091         }
21092         clearProc();
21093     };
21094     
21095     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21096     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21097     
21098     return {
21099         /**
21100          * Registers new overflow element(s) to auto scroll
21101          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21102          */
21103         register : function(el){
21104             if(el instanceof Array){
21105                 for(var i = 0, len = el.length; i < len; i++) {
21106                         this.register(el[i]);
21107                 }
21108             }else{
21109                 el = Roo.get(el);
21110                 els[el.id] = el;
21111             }
21112             Roo.dd.ScrollManager.els = els;
21113         },
21114         
21115         /**
21116          * Unregisters overflow element(s) so they are no longer scrolled
21117          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21118          */
21119         unregister : function(el){
21120             if(el instanceof Array){
21121                 for(var i = 0, len = el.length; i < len; i++) {
21122                         this.unregister(el[i]);
21123                 }
21124             }else{
21125                 el = Roo.get(el);
21126                 delete els[el.id];
21127             }
21128         },
21129         
21130         /**
21131          * The number of pixels from the edge of a container the pointer needs to be to 
21132          * trigger scrolling (defaults to 25)
21133          * @type Number
21134          */
21135         thresh : 25,
21136         
21137         /**
21138          * The number of pixels to scroll in each scroll increment (defaults to 50)
21139          * @type Number
21140          */
21141         increment : 100,
21142         
21143         /**
21144          * The frequency of scrolls in milliseconds (defaults to 500)
21145          * @type Number
21146          */
21147         frequency : 500,
21148         
21149         /**
21150          * True to animate the scroll (defaults to true)
21151          * @type Boolean
21152          */
21153         animate: true,
21154         
21155         /**
21156          * The animation duration in seconds - 
21157          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21158          * @type Number
21159          */
21160         animDuration: .4,
21161         
21162         /**
21163          * Manually trigger a cache refresh.
21164          */
21165         refreshCache : function(){
21166             for(var id in els){
21167                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21168                     els[id]._region = els[id].getRegion();
21169                 }
21170             }
21171         }
21172     };
21173 }();/*
21174  * Based on:
21175  * Ext JS Library 1.1.1
21176  * Copyright(c) 2006-2007, Ext JS, LLC.
21177  *
21178  * Originally Released Under LGPL - original licence link has changed is not relivant.
21179  *
21180  * Fork - LGPL
21181  * <script type="text/javascript">
21182  */
21183  
21184
21185 /**
21186  * @class Roo.dd.Registry
21187  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21188  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21189  * @singleton
21190  */
21191 Roo.dd.Registry = function(){
21192     var elements = {}; 
21193     var handles = {}; 
21194     var autoIdSeed = 0;
21195
21196     var getId = function(el, autogen){
21197         if(typeof el == "string"){
21198             return el;
21199         }
21200         var id = el.id;
21201         if(!id && autogen !== false){
21202             id = "roodd-" + (++autoIdSeed);
21203             el.id = id;
21204         }
21205         return id;
21206     };
21207     
21208     return {
21209     /**
21210      * Register a drag drop element
21211      * @param {String|HTMLElement} element The id or DOM node to register
21212      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21213      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21214      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21215      * populated in the data object (if applicable):
21216      * <pre>
21217 Value      Description<br />
21218 ---------  ------------------------------------------<br />
21219 handles    Array of DOM nodes that trigger dragging<br />
21220            for the element being registered<br />
21221 isHandle   True if the element passed in triggers<br />
21222            dragging itself, else false
21223 </pre>
21224      */
21225         register : function(el, data){
21226             data = data || {};
21227             if(typeof el == "string"){
21228                 el = document.getElementById(el);
21229             }
21230             data.ddel = el;
21231             elements[getId(el)] = data;
21232             if(data.isHandle !== false){
21233                 handles[data.ddel.id] = data;
21234             }
21235             if(data.handles){
21236                 var hs = data.handles;
21237                 for(var i = 0, len = hs.length; i < len; i++){
21238                         handles[getId(hs[i])] = data;
21239                 }
21240             }
21241         },
21242
21243     /**
21244      * Unregister a drag drop element
21245      * @param {String|HTMLElement}  element The id or DOM node to unregister
21246      */
21247         unregister : function(el){
21248             var id = getId(el, false);
21249             var data = elements[id];
21250             if(data){
21251                 delete elements[id];
21252                 if(data.handles){
21253                     var hs = data.handles;
21254                     for(var i = 0, len = hs.length; i < len; i++){
21255                         delete handles[getId(hs[i], false)];
21256                     }
21257                 }
21258             }
21259         },
21260
21261     /**
21262      * Returns the handle registered for a DOM Node by id
21263      * @param {String|HTMLElement} id The DOM node or id to look up
21264      * @return {Object} handle The custom handle data
21265      */
21266         getHandle : function(id){
21267             if(typeof id != "string"){ // must be element?
21268                 id = id.id;
21269             }
21270             return handles[id];
21271         },
21272
21273     /**
21274      * Returns the handle that is registered for the DOM node that is the target of the event
21275      * @param {Event} e The event
21276      * @return {Object} handle The custom handle data
21277      */
21278         getHandleFromEvent : function(e){
21279             var t = Roo.lib.Event.getTarget(e);
21280             return t ? handles[t.id] : null;
21281         },
21282
21283     /**
21284      * Returns a custom data object that is registered for a DOM node by id
21285      * @param {String|HTMLElement} id The DOM node or id to look up
21286      * @return {Object} data The custom data
21287      */
21288         getTarget : function(id){
21289             if(typeof id != "string"){ // must be element?
21290                 id = id.id;
21291             }
21292             return elements[id];
21293         },
21294
21295     /**
21296      * Returns a custom data object that is registered for the DOM node that is the target of the event
21297      * @param {Event} e The event
21298      * @return {Object} data The custom data
21299      */
21300         getTargetFromEvent : function(e){
21301             var t = Roo.lib.Event.getTarget(e);
21302             return t ? elements[t.id] || handles[t.id] : null;
21303         }
21304     };
21305 }();/*
21306  * Based on:
21307  * Ext JS Library 1.1.1
21308  * Copyright(c) 2006-2007, Ext JS, LLC.
21309  *
21310  * Originally Released Under LGPL - original licence link has changed is not relivant.
21311  *
21312  * Fork - LGPL
21313  * <script type="text/javascript">
21314  */
21315  
21316
21317 /**
21318  * @class Roo.dd.StatusProxy
21319  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21320  * default drag proxy used by all Roo.dd components.
21321  * @constructor
21322  * @param {Object} config
21323  */
21324 Roo.dd.StatusProxy = function(config){
21325     Roo.apply(this, config);
21326     this.id = this.id || Roo.id();
21327     this.el = new Roo.Layer({
21328         dh: {
21329             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21330                 {tag: "div", cls: "x-dd-drop-icon"},
21331                 {tag: "div", cls: "x-dd-drag-ghost"}
21332             ]
21333         }, 
21334         shadow: !config || config.shadow !== false
21335     });
21336     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21337     this.dropStatus = this.dropNotAllowed;
21338 };
21339
21340 Roo.dd.StatusProxy.prototype = {
21341     /**
21342      * @cfg {String} dropAllowed
21343      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21344      */
21345     dropAllowed : "x-dd-drop-ok",
21346     /**
21347      * @cfg {String} dropNotAllowed
21348      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21349      */
21350     dropNotAllowed : "x-dd-drop-nodrop",
21351
21352     /**
21353      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21354      * over the current target element.
21355      * @param {String} cssClass The css class for the new drop status indicator image
21356      */
21357     setStatus : function(cssClass){
21358         cssClass = cssClass || this.dropNotAllowed;
21359         if(this.dropStatus != cssClass){
21360             this.el.replaceClass(this.dropStatus, cssClass);
21361             this.dropStatus = cssClass;
21362         }
21363     },
21364
21365     /**
21366      * Resets the status indicator to the default dropNotAllowed value
21367      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21368      */
21369     reset : function(clearGhost){
21370         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21371         this.dropStatus = this.dropNotAllowed;
21372         if(clearGhost){
21373             this.ghost.update("");
21374         }
21375     },
21376
21377     /**
21378      * Updates the contents of the ghost element
21379      * @param {String} html The html that will replace the current innerHTML of the ghost element
21380      */
21381     update : function(html){
21382         if(typeof html == "string"){
21383             this.ghost.update(html);
21384         }else{
21385             this.ghost.update("");
21386             html.style.margin = "0";
21387             this.ghost.dom.appendChild(html);
21388         }
21389         // ensure float = none set?? cant remember why though.
21390         var el = this.ghost.dom.firstChild;
21391                 if(el){
21392                         Roo.fly(el).setStyle('float', 'none');
21393                 }
21394     },
21395     
21396     /**
21397      * Returns the underlying proxy {@link Roo.Layer}
21398      * @return {Roo.Layer} el
21399     */
21400     getEl : function(){
21401         return this.el;
21402     },
21403
21404     /**
21405      * Returns the ghost element
21406      * @return {Roo.Element} el
21407      */
21408     getGhost : function(){
21409         return this.ghost;
21410     },
21411
21412     /**
21413      * Hides the proxy
21414      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21415      */
21416     hide : function(clear){
21417         this.el.hide();
21418         if(clear){
21419             this.reset(true);
21420         }
21421     },
21422
21423     /**
21424      * Stops the repair animation if it's currently running
21425      */
21426     stop : function(){
21427         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21428             this.anim.stop();
21429         }
21430     },
21431
21432     /**
21433      * Displays this proxy
21434      */
21435     show : function(){
21436         this.el.show();
21437     },
21438
21439     /**
21440      * Force the Layer to sync its shadow and shim positions to the element
21441      */
21442     sync : function(){
21443         this.el.sync();
21444     },
21445
21446     /**
21447      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21448      * invalid drop operation by the item being dragged.
21449      * @param {Array} xy The XY position of the element ([x, y])
21450      * @param {Function} callback The function to call after the repair is complete
21451      * @param {Object} scope The scope in which to execute the callback
21452      */
21453     repair : function(xy, callback, scope){
21454         this.callback = callback;
21455         this.scope = scope;
21456         if(xy && this.animRepair !== false){
21457             this.el.addClass("x-dd-drag-repair");
21458             this.el.hideUnders(true);
21459             this.anim = this.el.shift({
21460                 duration: this.repairDuration || .5,
21461                 easing: 'easeOut',
21462                 xy: xy,
21463                 stopFx: true,
21464                 callback: this.afterRepair,
21465                 scope: this
21466             });
21467         }else{
21468             this.afterRepair();
21469         }
21470     },
21471
21472     // private
21473     afterRepair : function(){
21474         this.hide(true);
21475         if(typeof this.callback == "function"){
21476             this.callback.call(this.scope || this);
21477         }
21478         this.callback = null;
21479         this.scope = null;
21480     }
21481 };/*
21482  * Based on:
21483  * Ext JS Library 1.1.1
21484  * Copyright(c) 2006-2007, Ext JS, LLC.
21485  *
21486  * Originally Released Under LGPL - original licence link has changed is not relivant.
21487  *
21488  * Fork - LGPL
21489  * <script type="text/javascript">
21490  */
21491
21492 /**
21493  * @class Roo.dd.DragSource
21494  * @extends Roo.dd.DDProxy
21495  * A simple class that provides the basic implementation needed to make any element draggable.
21496  * @constructor
21497  * @param {String/HTMLElement/Element} el The container element
21498  * @param {Object} config
21499  */
21500 Roo.dd.DragSource = function(el, config){
21501     this.el = Roo.get(el);
21502     this.dragData = {};
21503     
21504     Roo.apply(this, config);
21505     
21506     if(!this.proxy){
21507         this.proxy = new Roo.dd.StatusProxy();
21508     }
21509
21510     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21511           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21512     
21513     this.dragging = false;
21514 };
21515
21516 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21517     /**
21518      * @cfg {String} dropAllowed
21519      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21520      */
21521     dropAllowed : "x-dd-drop-ok",
21522     /**
21523      * @cfg {String} dropNotAllowed
21524      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21525      */
21526     dropNotAllowed : "x-dd-drop-nodrop",
21527
21528     /**
21529      * Returns the data object associated with this drag source
21530      * @return {Object} data An object containing arbitrary data
21531      */
21532     getDragData : function(e){
21533         return this.dragData;
21534     },
21535
21536     // private
21537     onDragEnter : function(e, id){
21538         var target = Roo.dd.DragDropMgr.getDDById(id);
21539         this.cachedTarget = target;
21540         if(this.beforeDragEnter(target, e, id) !== false){
21541             if(target.isNotifyTarget){
21542                 var status = target.notifyEnter(this, e, this.dragData);
21543                 this.proxy.setStatus(status);
21544             }else{
21545                 this.proxy.setStatus(this.dropAllowed);
21546             }
21547             
21548             if(this.afterDragEnter){
21549                 /**
21550                  * An empty function by default, but provided so that you can perform a custom action
21551                  * when the dragged item enters the drop target by providing an implementation.
21552                  * @param {Roo.dd.DragDrop} target The drop target
21553                  * @param {Event} e The event object
21554                  * @param {String} id The id of the dragged element
21555                  * @method afterDragEnter
21556                  */
21557                 this.afterDragEnter(target, e, id);
21558             }
21559         }
21560     },
21561
21562     /**
21563      * An empty function by default, but provided so that you can perform a custom action
21564      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21565      * @param {Roo.dd.DragDrop} target The drop target
21566      * @param {Event} e The event object
21567      * @param {String} id The id of the dragged element
21568      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21569      */
21570     beforeDragEnter : function(target, e, id){
21571         return true;
21572     },
21573
21574     // private
21575     alignElWithMouse: function() {
21576         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21577         this.proxy.sync();
21578     },
21579
21580     // private
21581     onDragOver : function(e, id){
21582         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21583         if(this.beforeDragOver(target, e, id) !== false){
21584             if(target.isNotifyTarget){
21585                 var status = target.notifyOver(this, e, this.dragData);
21586                 this.proxy.setStatus(status);
21587             }
21588
21589             if(this.afterDragOver){
21590                 /**
21591                  * An empty function by default, but provided so that you can perform a custom action
21592                  * while the dragged item is over the drop target by providing an implementation.
21593                  * @param {Roo.dd.DragDrop} target The drop target
21594                  * @param {Event} e The event object
21595                  * @param {String} id The id of the dragged element
21596                  * @method afterDragOver
21597                  */
21598                 this.afterDragOver(target, e, id);
21599             }
21600         }
21601     },
21602
21603     /**
21604      * An empty function by default, but provided so that you can perform a custom action
21605      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21606      * @param {Roo.dd.DragDrop} target The drop target
21607      * @param {Event} e The event object
21608      * @param {String} id The id of the dragged element
21609      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21610      */
21611     beforeDragOver : function(target, e, id){
21612         return true;
21613     },
21614
21615     // private
21616     onDragOut : function(e, id){
21617         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21618         if(this.beforeDragOut(target, e, id) !== false){
21619             if(target.isNotifyTarget){
21620                 target.notifyOut(this, e, this.dragData);
21621             }
21622             this.proxy.reset();
21623             if(this.afterDragOut){
21624                 /**
21625                  * An empty function by default, but provided so that you can perform a custom action
21626                  * after the dragged item is dragged out of the target without dropping.
21627                  * @param {Roo.dd.DragDrop} target The drop target
21628                  * @param {Event} e The event object
21629                  * @param {String} id The id of the dragged element
21630                  * @method afterDragOut
21631                  */
21632                 this.afterDragOut(target, e, id);
21633             }
21634         }
21635         this.cachedTarget = null;
21636     },
21637
21638     /**
21639      * An empty function by default, but provided so that you can perform a custom action before the dragged
21640      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21641      * @param {Roo.dd.DragDrop} target The drop target
21642      * @param {Event} e The event object
21643      * @param {String} id The id of the dragged element
21644      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21645      */
21646     beforeDragOut : function(target, e, id){
21647         return true;
21648     },
21649     
21650     // private
21651     onDragDrop : function(e, id){
21652         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21653         if(this.beforeDragDrop(target, e, id) !== false){
21654             if(target.isNotifyTarget){
21655                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21656                     this.onValidDrop(target, e, id);
21657                 }else{
21658                     this.onInvalidDrop(target, e, id);
21659                 }
21660             }else{
21661                 this.onValidDrop(target, e, id);
21662             }
21663             
21664             if(this.afterDragDrop){
21665                 /**
21666                  * An empty function by default, but provided so that you can perform a custom action
21667                  * after a valid drag drop has occurred by providing an implementation.
21668                  * @param {Roo.dd.DragDrop} target The drop target
21669                  * @param {Event} e The event object
21670                  * @param {String} id The id of the dropped element
21671                  * @method afterDragDrop
21672                  */
21673                 this.afterDragDrop(target, e, id);
21674             }
21675         }
21676         delete this.cachedTarget;
21677     },
21678
21679     /**
21680      * An empty function by default, but provided so that you can perform a custom action before the dragged
21681      * item is dropped onto the target and optionally cancel the onDragDrop.
21682      * @param {Roo.dd.DragDrop} target The drop target
21683      * @param {Event} e The event object
21684      * @param {String} id The id of the dragged element
21685      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21686      */
21687     beforeDragDrop : function(target, e, id){
21688         return true;
21689     },
21690
21691     // private
21692     onValidDrop : function(target, e, id){
21693         this.hideProxy();
21694         if(this.afterValidDrop){
21695             /**
21696              * An empty function by default, but provided so that you can perform a custom action
21697              * after a valid drop has occurred by providing an implementation.
21698              * @param {Object} target The target DD 
21699              * @param {Event} e The event object
21700              * @param {String} id The id of the dropped element
21701              * @method afterInvalidDrop
21702              */
21703             this.afterValidDrop(target, e, id);
21704         }
21705     },
21706
21707     // private
21708     getRepairXY : function(e, data){
21709         return this.el.getXY();  
21710     },
21711
21712     // private
21713     onInvalidDrop : function(target, e, id){
21714         this.beforeInvalidDrop(target, e, id);
21715         if(this.cachedTarget){
21716             if(this.cachedTarget.isNotifyTarget){
21717                 this.cachedTarget.notifyOut(this, e, this.dragData);
21718             }
21719             this.cacheTarget = null;
21720         }
21721         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21722
21723         if(this.afterInvalidDrop){
21724             /**
21725              * An empty function by default, but provided so that you can perform a custom action
21726              * after an invalid drop has occurred by providing an implementation.
21727              * @param {Event} e The event object
21728              * @param {String} id The id of the dropped element
21729              * @method afterInvalidDrop
21730              */
21731             this.afterInvalidDrop(e, id);
21732         }
21733     },
21734
21735     // private
21736     afterRepair : function(){
21737         if(Roo.enableFx){
21738             this.el.highlight(this.hlColor || "c3daf9");
21739         }
21740         this.dragging = false;
21741     },
21742
21743     /**
21744      * An empty function by default, but provided so that you can perform a custom action after an invalid
21745      * drop has occurred.
21746      * @param {Roo.dd.DragDrop} target The drop target
21747      * @param {Event} e The event object
21748      * @param {String} id The id of the dragged element
21749      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21750      */
21751     beforeInvalidDrop : function(target, e, id){
21752         return true;
21753     },
21754
21755     // private
21756     handleMouseDown : function(e){
21757         if(this.dragging) {
21758             return;
21759         }
21760         var data = this.getDragData(e);
21761         if(data && this.onBeforeDrag(data, e) !== false){
21762             this.dragData = data;
21763             this.proxy.stop();
21764             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21765         } 
21766     },
21767
21768     /**
21769      * An empty function by default, but provided so that you can perform a custom action before the initial
21770      * drag event begins and optionally cancel it.
21771      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21772      * @param {Event} e The event object
21773      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21774      */
21775     onBeforeDrag : function(data, e){
21776         return true;
21777     },
21778
21779     /**
21780      * An empty function by default, but provided so that you can perform a custom action once the initial
21781      * drag event has begun.  The drag cannot be canceled from this function.
21782      * @param {Number} x The x position of the click on the dragged object
21783      * @param {Number} y The y position of the click on the dragged object
21784      */
21785     onStartDrag : Roo.emptyFn,
21786
21787     // private - YUI override
21788     startDrag : function(x, y){
21789         this.proxy.reset();
21790         this.dragging = true;
21791         this.proxy.update("");
21792         this.onInitDrag(x, y);
21793         this.proxy.show();
21794     },
21795
21796     // private
21797     onInitDrag : function(x, y){
21798         var clone = this.el.dom.cloneNode(true);
21799         clone.id = Roo.id(); // prevent duplicate ids
21800         this.proxy.update(clone);
21801         this.onStartDrag(x, y);
21802         return true;
21803     },
21804
21805     /**
21806      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21807      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21808      */
21809     getProxy : function(){
21810         return this.proxy;  
21811     },
21812
21813     /**
21814      * Hides the drag source's {@link Roo.dd.StatusProxy}
21815      */
21816     hideProxy : function(){
21817         this.proxy.hide();  
21818         this.proxy.reset(true);
21819         this.dragging = false;
21820     },
21821
21822     // private
21823     triggerCacheRefresh : function(){
21824         Roo.dd.DDM.refreshCache(this.groups);
21825     },
21826
21827     // private - override to prevent hiding
21828     b4EndDrag: function(e) {
21829     },
21830
21831     // private - override to prevent moving
21832     endDrag : function(e){
21833         this.onEndDrag(this.dragData, e);
21834     },
21835
21836     // private
21837     onEndDrag : function(data, e){
21838     },
21839     
21840     // private - pin to cursor
21841     autoOffset : function(x, y) {
21842         this.setDelta(-12, -20);
21843     }    
21844 });/*
21845  * Based on:
21846  * Ext JS Library 1.1.1
21847  * Copyright(c) 2006-2007, Ext JS, LLC.
21848  *
21849  * Originally Released Under LGPL - original licence link has changed is not relivant.
21850  *
21851  * Fork - LGPL
21852  * <script type="text/javascript">
21853  */
21854
21855
21856 /**
21857  * @class Roo.dd.DropTarget
21858  * @extends Roo.dd.DDTarget
21859  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21860  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21861  * @constructor
21862  * @param {String/HTMLElement/Element} el The container element
21863  * @param {Object} config
21864  */
21865 Roo.dd.DropTarget = function(el, config){
21866     this.el = Roo.get(el);
21867     
21868     var listeners = false; ;
21869     if (config && config.listeners) {
21870         listeners= config.listeners;
21871         delete config.listeners;
21872     }
21873     Roo.apply(this, config);
21874     
21875     if(this.containerScroll){
21876         Roo.dd.ScrollManager.register(this.el);
21877     }
21878     this.addEvents( {
21879          /**
21880          * @scope Roo.dd.DropTarget
21881          */
21882          
21883          /**
21884          * @event enter
21885          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21886          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21887          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21888          * 
21889          * IMPORTANT : it should set this.overClass and this.dropAllowed
21890          * 
21891          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21892          * @param {Event} e The event
21893          * @param {Object} data An object containing arbitrary data supplied by the drag source
21894          */
21895         "enter" : true,
21896         
21897          /**
21898          * @event over
21899          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21900          * This method will be called on every mouse movement while the drag source is over the drop target.
21901          * This default implementation simply returns the dropAllowed config value.
21902          * 
21903          * IMPORTANT : it should set this.dropAllowed
21904          * 
21905          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21906          * @param {Event} e The event
21907          * @param {Object} data An object containing arbitrary data supplied by the drag source
21908          
21909          */
21910         "over" : true,
21911         /**
21912          * @event out
21913          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21914          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21915          * overClass (if any) from the drop element.
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          "out" : true,
21922          
21923         /**
21924          * @event drop
21925          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21926          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21927          * implementation that does something to process the drop event and returns true so that the drag source's
21928          * repair action does not run.
21929          * 
21930          * IMPORTANT : it should set this.success
21931          * 
21932          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21933          * @param {Event} e The event
21934          * @param {Object} data An object containing arbitrary data supplied by the drag source
21935         */
21936          "drop" : true
21937     });
21938             
21939      
21940     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21941         this.el.dom, 
21942         this.ddGroup || this.group,
21943         {
21944             isTarget: true,
21945             listeners : listeners || {} 
21946            
21947         
21948         }
21949     );
21950
21951 };
21952
21953 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21954     /**
21955      * @cfg {String} overClass
21956      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21957      */
21958      /**
21959      * @cfg {String} ddGroup
21960      * The drag drop group to handle drop events for
21961      */
21962      
21963     /**
21964      * @cfg {String} dropAllowed
21965      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21966      */
21967     dropAllowed : "x-dd-drop-ok",
21968     /**
21969      * @cfg {String} dropNotAllowed
21970      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21971      */
21972     dropNotAllowed : "x-dd-drop-nodrop",
21973     /**
21974      * @cfg {boolean} success
21975      * set this after drop listener.. 
21976      */
21977     success : false,
21978     /**
21979      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21980      * if the drop point is valid for over/enter..
21981      */
21982     valid : false,
21983     // private
21984     isTarget : true,
21985
21986     // private
21987     isNotifyTarget : true,
21988     
21989     /**
21990      * @hide
21991      */
21992     notifyEnter : function(dd, e, data)
21993     {
21994         this.valid = true;
21995         this.fireEvent('enter', dd, e, data);
21996         if(this.overClass){
21997             this.el.addClass(this.overClass);
21998         }
21999         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22000             this.valid ? this.dropAllowed : this.dropNotAllowed
22001         );
22002     },
22003
22004     /**
22005      * @hide
22006      */
22007     notifyOver : function(dd, e, data)
22008     {
22009         this.valid = true;
22010         this.fireEvent('over', dd, e, data);
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     notifyOut : function(dd, e, data)
22020     {
22021         this.fireEvent('out', dd, e, data);
22022         if(this.overClass){
22023             this.el.removeClass(this.overClass);
22024         }
22025     },
22026
22027     /**
22028      * @hide
22029      */
22030     notifyDrop : function(dd, e, data)
22031     {
22032         this.success = false;
22033         this.fireEvent('drop', dd, e, data);
22034         return this.success;
22035     }
22036 });/*
22037  * Based on:
22038  * Ext JS Library 1.1.1
22039  * Copyright(c) 2006-2007, Ext JS, LLC.
22040  *
22041  * Originally Released Under LGPL - original licence link has changed is not relivant.
22042  *
22043  * Fork - LGPL
22044  * <script type="text/javascript">
22045  */
22046
22047
22048 /**
22049  * @class Roo.dd.DragZone
22050  * @extends Roo.dd.DragSource
22051  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22052  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22053  * @constructor
22054  * @param {String/HTMLElement/Element} el The container element
22055  * @param {Object} config
22056  */
22057 Roo.dd.DragZone = function(el, config){
22058     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22059     if(this.containerScroll){
22060         Roo.dd.ScrollManager.register(this.el);
22061     }
22062 };
22063
22064 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22065     /**
22066      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22067      * for auto scrolling during drag operations.
22068      */
22069     /**
22070      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22071      * method after a failed drop (defaults to "c3daf9" - light blue)
22072      */
22073
22074     /**
22075      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22076      * for a valid target to drag based on the mouse down. Override this method
22077      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22078      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22079      * @param {EventObject} e The mouse down event
22080      * @return {Object} The dragData
22081      */
22082     getDragData : function(e){
22083         return Roo.dd.Registry.getHandleFromEvent(e);
22084     },
22085     
22086     /**
22087      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22088      * this.dragData.ddel
22089      * @param {Number} x The x position of the click on the dragged object
22090      * @param {Number} y The y position of the click on the dragged object
22091      * @return {Boolean} true to continue the drag, false to cancel
22092      */
22093     onInitDrag : function(x, y){
22094         this.proxy.update(this.dragData.ddel.cloneNode(true));
22095         this.onStartDrag(x, y);
22096         return true;
22097     },
22098     
22099     /**
22100      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22101      */
22102     afterRepair : function(){
22103         if(Roo.enableFx){
22104             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22105         }
22106         this.dragging = false;
22107     },
22108
22109     /**
22110      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22111      * the XY of this.dragData.ddel
22112      * @param {EventObject} e The mouse up event
22113      * @return {Array} The xy location (e.g. [100, 200])
22114      */
22115     getRepairXY : function(e){
22116         return Roo.Element.fly(this.dragData.ddel).getXY();  
22117     }
22118 });/*
22119  * Based on:
22120  * Ext JS Library 1.1.1
22121  * Copyright(c) 2006-2007, Ext JS, LLC.
22122  *
22123  * Originally Released Under LGPL - original licence link has changed is not relivant.
22124  *
22125  * Fork - LGPL
22126  * <script type="text/javascript">
22127  */
22128 /**
22129  * @class Roo.dd.DropZone
22130  * @extends Roo.dd.DropTarget
22131  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22132  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22133  * @constructor
22134  * @param {String/HTMLElement/Element} el The container element
22135  * @param {Object} config
22136  */
22137 Roo.dd.DropZone = function(el, config){
22138     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22139 };
22140
22141 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22142     /**
22143      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22144      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22145      * provide your own custom lookup.
22146      * @param {Event} e The event
22147      * @return {Object} data The custom data
22148      */
22149     getTargetFromEvent : function(e){
22150         return Roo.dd.Registry.getTargetFromEvent(e);
22151     },
22152
22153     /**
22154      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22155      * that it has registered.  This method has no default implementation and should be overridden to provide
22156      * node-specific processing if necessary.
22157      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22158      * {@link #getTargetFromEvent} for this node)
22159      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22160      * @param {Event} e The event
22161      * @param {Object} data An object containing arbitrary data supplied by the drag source
22162      */
22163     onNodeEnter : function(n, dd, e, data){
22164         
22165     },
22166
22167     /**
22168      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22169      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22170      * overridden to provide the proper feedback.
22171      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22172      * {@link #getTargetFromEvent} for this node)
22173      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22174      * @param {Event} e The event
22175      * @param {Object} data An object containing arbitrary data supplied by the drag source
22176      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22177      * underlying {@link Roo.dd.StatusProxy} can be updated
22178      */
22179     onNodeOver : function(n, dd, e, data){
22180         return this.dropAllowed;
22181     },
22182
22183     /**
22184      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22185      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22186      * node-specific processing if necessary.
22187      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22188      * {@link #getTargetFromEvent} for this node)
22189      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22190      * @param {Event} e The event
22191      * @param {Object} data An object containing arbitrary data supplied by the drag source
22192      */
22193     onNodeOut : function(n, dd, e, data){
22194         
22195     },
22196
22197     /**
22198      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22199      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22200      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22201      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22202      * {@link #getTargetFromEvent} for this node)
22203      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22204      * @param {Event} e The event
22205      * @param {Object} data An object containing arbitrary data supplied by the drag source
22206      * @return {Boolean} True if the drop was valid, else false
22207      */
22208     onNodeDrop : function(n, dd, e, data){
22209         return false;
22210     },
22211
22212     /**
22213      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22214      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22215      * it should be overridden to provide the proper feedback if necessary.
22216      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22217      * @param {Event} e The event
22218      * @param {Object} data An object containing arbitrary data supplied by the drag source
22219      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22220      * underlying {@link Roo.dd.StatusProxy} can be updated
22221      */
22222     onContainerOver : function(dd, e, data){
22223         return this.dropNotAllowed;
22224     },
22225
22226     /**
22227      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22228      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22229      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22230      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22231      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22232      * @param {Event} e The event
22233      * @param {Object} data An object containing arbitrary data supplied by the drag source
22234      * @return {Boolean} True if the drop was valid, else false
22235      */
22236     onContainerDrop : function(dd, e, data){
22237         return false;
22238     },
22239
22240     /**
22241      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22242      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22243      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22244      * you should override this method and provide a custom implementation.
22245      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22246      * @param {Event} e The event
22247      * @param {Object} data An object containing arbitrary data supplied by the drag source
22248      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22249      * underlying {@link Roo.dd.StatusProxy} can be updated
22250      */
22251     notifyEnter : function(dd, e, data){
22252         return this.dropNotAllowed;
22253     },
22254
22255     /**
22256      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22257      * This method will be called on every mouse movement while the drag source is over the drop zone.
22258      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22259      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22260      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22261      * registered node, it will call {@link #onContainerOver}.
22262      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22263      * @param {Event} e The event
22264      * @param {Object} data An object containing arbitrary data supplied by the drag source
22265      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22266      * underlying {@link Roo.dd.StatusProxy} can be updated
22267      */
22268     notifyOver : function(dd, e, data){
22269         var n = this.getTargetFromEvent(e);
22270         if(!n){ // not over valid drop target
22271             if(this.lastOverNode){
22272                 this.onNodeOut(this.lastOverNode, dd, e, data);
22273                 this.lastOverNode = null;
22274             }
22275             return this.onContainerOver(dd, e, data);
22276         }
22277         if(this.lastOverNode != n){
22278             if(this.lastOverNode){
22279                 this.onNodeOut(this.lastOverNode, dd, e, data);
22280             }
22281             this.onNodeEnter(n, dd, e, data);
22282             this.lastOverNode = n;
22283         }
22284         return this.onNodeOver(n, dd, e, data);
22285     },
22286
22287     /**
22288      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22289      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22290      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22291      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22292      * @param {Event} e The event
22293      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22294      */
22295     notifyOut : function(dd, e, data){
22296         if(this.lastOverNode){
22297             this.onNodeOut(this.lastOverNode, dd, e, data);
22298             this.lastOverNode = null;
22299         }
22300     },
22301
22302     /**
22303      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22304      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22305      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22306      * otherwise it will call {@link #onContainerDrop}.
22307      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22308      * @param {Event} e The event
22309      * @param {Object} data An object containing arbitrary data supplied by the drag source
22310      * @return {Boolean} True if the drop was valid, else false
22311      */
22312     notifyDrop : function(dd, e, data){
22313         if(this.lastOverNode){
22314             this.onNodeOut(this.lastOverNode, dd, e, data);
22315             this.lastOverNode = null;
22316         }
22317         var n = this.getTargetFromEvent(e);
22318         return n ?
22319             this.onNodeDrop(n, dd, e, data) :
22320             this.onContainerDrop(dd, e, data);
22321     },
22322
22323     // private
22324     triggerCacheRefresh : function(){
22325         Roo.dd.DDM.refreshCache(this.groups);
22326     }  
22327 });