roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isGecko = !isSafari && ua.indexOf("gecko") > -1,
61         isBorderBox = isIE && !isStrict,
62         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64         isLinux = (ua.indexOf("linux") != -1),
65         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66         isIOS = /iphone|ipad/.test(ua),
67         isAndroid = /android/.test(ua),
68         isTouch =  (function() {
69             try {
70                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
71                     window.addEventListener('touchstart', function __set_has_touch__ () {
72                         Roo.isTouch = true;
73                         window.removeEventListener('touchstart', __set_has_touch__);
74                     });
75                     return false; // no touch on chrome!?
76                 }
77                 document.createEvent("TouchEvent");  
78                 return true;  
79             } catch (e) {  
80                 return false;  
81             } 
82             
83         })();
84     // remove css image flicker
85         if(isIE && !isIE7){
86         try{
87             document.execCommand("BackgroundImageCache", false, true);
88         }catch(e){}
89     }
90     
91     Roo.apply(Roo, {
92         /**
93          * True if the browser is in strict mode
94          * @type Boolean
95          */
96         isStrict : isStrict,
97         /**
98          * True if the page is running over SSL
99          * @type Boolean
100          */
101         isSecure : isSecure,
102         /**
103          * True when the document is fully initialized and ready for action
104          * @type Boolean
105          */
106         isReady : false,
107         /**
108          * Turn on debugging output (currently only the factory uses this)
109          * @type Boolean
110          */
111         
112         debug: false,
113
114         /**
115          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
116          * @type Boolean
117          */
118         enableGarbageCollector : true,
119
120         /**
121          * True to automatically purge event listeners after uncaching an element (defaults to false).
122          * Note: this only happens if enableGarbageCollector is true.
123          * @type Boolean
124          */
125         enableListenerCollection:false,
126
127         /**
128          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
129          * the IE insecure content warning (defaults to javascript:false).
130          * @type String
131          */
132         SSL_SECURE_URL : "javascript:false",
133
134         /**
135          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
136          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
137          * @type String
138          */
139         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
140
141         emptyFn : function(){},
142         
143         /**
144          * Copies all the properties of config to obj if they don't already exist.
145          * @param {Object} obj The receiver of the properties
146          * @param {Object} config The source of the properties
147          * @return {Object} returns obj
148          */
149         applyIf : function(o, c){
150             if(o && c){
151                 for(var p in c){
152                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
153                 }
154             }
155             return o;
156         },
157
158         /**
159          * Applies event listeners to elements by selectors when the document is ready.
160          * The event name is specified with an @ suffix.
161 <pre><code>
162 Roo.addBehaviors({
163    // add a listener for click on all anchors in element with id foo
164    '#foo a@click' : function(e, t){
165        // do something
166    },
167
168    // add the same listener to multiple selectors (separated by comma BEFORE the @)
169    '#foo a, #bar span.some-class@mouseover' : function(){
170        // do something
171    }
172 });
173 </code></pre>
174          * @param {Object} obj The list of behaviors to apply
175          */
176         addBehaviors : function(o){
177             if(!Roo.isReady){
178                 Roo.onReady(function(){
179                     Roo.addBehaviors(o);
180                 });
181                 return;
182             }
183             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
184             for(var b in o){
185                 var parts = b.split('@');
186                 if(parts[1]){ // for Object prototype breakers
187                     var s = parts[0];
188                     if(!cache[s]){
189                         cache[s] = Roo.select(s);
190                     }
191                     cache[s].on(parts[1], o[b]);
192                 }
193             }
194             cache = null;
195         },
196
197         /**
198          * Generates unique ids. If the element already has an id, it is unchanged
199          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
200          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
201          * @return {String} The generated Id.
202          */
203         id : function(el, prefix){
204             prefix = prefix || "roo-gen";
205             el = Roo.getDom(el);
206             var id = prefix + (++idSeed);
207             return el ? (el.id ? el.id : (el.id = id)) : id;
208         },
209          
210        
211         /**
212          * Extends one class with another class and optionally overrides members with the passed literal. This class
213          * also adds the function "override()" to the class that can be used to override
214          * members on an instance.
215          * @param {Object} subclass The class inheriting the functionality
216          * @param {Object} superclass The class being extended
217          * @param {Object} overrides (optional) A literal with members
218          * @method extend
219          */
220         extend : function(){
221             // inline overrides
222             var io = function(o){
223                 for(var m in o){
224                     this[m] = o[m];
225                 }
226             };
227             return function(sb, sp, overrides){
228                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
229                     overrides = sp;
230                     sp = sb;
231                     sb = function(){sp.apply(this, arguments);};
232                 }
233                 var F = function(){}, sbp, spp = sp.prototype;
234                 F.prototype = spp;
235                 sbp = sb.prototype = new F();
236                 sbp.constructor=sb;
237                 sb.superclass=spp;
238                 
239                 if(spp.constructor == Object.prototype.constructor){
240                     spp.constructor=sp;
241                    
242                 }
243                 
244                 sb.override = function(o){
245                     Roo.override(sb, o);
246                 };
247                 sbp.override = io;
248                 Roo.override(sb, overrides);
249                 return sb;
250             };
251         }(),
252
253         /**
254          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
255          * Usage:<pre><code>
256 Roo.override(MyClass, {
257     newMethod1: function(){
258         // etc.
259     },
260     newMethod2: function(foo){
261         // etc.
262     }
263 });
264  </code></pre>
265          * @param {Object} origclass The class to override
266          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
267          * containing one or more methods.
268          * @method override
269          */
270         override : function(origclass, overrides){
271             if(overrides){
272                 var p = origclass.prototype;
273                 for(var method in overrides){
274                     p[method] = overrides[method];
275                 }
276             }
277         },
278         /**
279          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
280          * <pre><code>
281 Roo.namespace('Company', 'Company.data');
282 Company.Widget = function() { ... }
283 Company.data.CustomStore = function(config) { ... }
284 </code></pre>
285          * @param {String} namespace1
286          * @param {String} namespace2
287          * @param {String} etc
288          * @method namespace
289          */
290         namespace : function(){
291             var a=arguments, o=null, i, j, d, rt;
292             for (i=0; i<a.length; ++i) {
293                 d=a[i].split(".");
294                 rt = d[0];
295                 /** eval:var:o */
296                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
297                 for (j=1; j<d.length; ++j) {
298                     o[d[j]]=o[d[j]] || {};
299                     o=o[d[j]];
300                 }
301             }
302         },
303         /**
304          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
305          * <pre><code>
306 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
307 Roo.factory(conf, Roo.data);
308 </code></pre>
309          * @param {String} classname
310          * @param {String} namespace (optional)
311          * @method factory
312          */
313          
314         factory : function(c, ns)
315         {
316             // no xtype, no ns or c.xns - or forced off by c.xns
317             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
318                 return c;
319             }
320             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
321             if (c.constructor == ns[c.xtype]) {// already created...
322                 return c;
323             }
324             if (ns[c.xtype]) {
325                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
326                 var ret = new ns[c.xtype](c);
327                 ret.xns = false;
328                 return ret;
329             }
330             c.xns = false; // prevent recursion..
331             return c;
332         },
333          /**
334          * Logs to console if it can.
335          *
336          * @param {String|Object} string
337          * @method log
338          */
339         log : function(s)
340         {
341             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
342                 return; // alerT?
343             }
344             console.log(s);
345             
346         },
347         /**
348          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
349          * @param {Object} o
350          * @return {String}
351          */
352         urlEncode : function(o){
353             if(!o){
354                 return "";
355             }
356             var buf = [];
357             for(var key in o){
358                 var ov = o[key], k = Roo.encodeURIComponent(key);
359                 var type = typeof ov;
360                 if(type == 'undefined'){
361                     buf.push(k, "=&");
362                 }else if(type != "function" && type != "object"){
363                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
364                 }else if(ov instanceof Array){
365                     if (ov.length) {
366                             for(var i = 0, len = ov.length; i < len; i++) {
367                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
368                             }
369                         } else {
370                             buf.push(k, "=&");
371                         }
372                 }
373             }
374             buf.pop();
375             return buf.join("");
376         },
377          /**
378          * Safe version of encodeURIComponent
379          * @param {String} data 
380          * @return {String} 
381          */
382         
383         encodeURIComponent : function (data)
384         {
385             try {
386                 return encodeURIComponent(data);
387             } catch(e) {} // should be an uri encode error.
388             
389             if (data == '' || data == null){
390                return '';
391             }
392             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
393             function nibble_to_hex(nibble){
394                 var chars = '0123456789ABCDEF';
395                 return chars.charAt(nibble);
396             }
397             data = data.toString();
398             var buffer = '';
399             for(var i=0; i<data.length; i++){
400                 var c = data.charCodeAt(i);
401                 var bs = new Array();
402                 if (c > 0x10000){
403                         // 4 bytes
404                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
405                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
406                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
407                     bs[3] = 0x80 | (c & 0x3F);
408                 }else if (c > 0x800){
409                          // 3 bytes
410                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
411                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
412                     bs[2] = 0x80 | (c & 0x3F);
413                 }else if (c > 0x80){
414                        // 2 bytes
415                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
416                     bs[1] = 0x80 | (c & 0x3F);
417                 }else{
418                         // 1 byte
419                     bs[0] = c;
420                 }
421                 for(var j=0; j<bs.length; j++){
422                     var b = bs[j];
423                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
424                             + nibble_to_hex(b &0x0F);
425                     buffer += '%'+hex;
426                }
427             }
428             return buffer;    
429              
430         },
431
432         /**
433          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
434          * @param {String} string
435          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
436          * @return {Object} A literal with members
437          */
438         urlDecode : function(string, overwrite){
439             if(!string || !string.length){
440                 return {};
441             }
442             var obj = {};
443             var pairs = string.split('&');
444             var pair, name, value;
445             for(var i = 0, len = pairs.length; i < len; i++){
446                 pair = pairs[i].split('=');
447                 name = decodeURIComponent(pair[0]);
448                 value = decodeURIComponent(pair[1]);
449                 if(overwrite !== true){
450                     if(typeof obj[name] == "undefined"){
451                         obj[name] = value;
452                     }else if(typeof obj[name] == "string"){
453                         obj[name] = [obj[name]];
454                         obj[name].push(value);
455                     }else{
456                         obj[name].push(value);
457                     }
458                 }else{
459                     obj[name] = value;
460                 }
461             }
462             return obj;
463         },
464
465         /**
466          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
467          * passed array is not really an array, your function is called once with it.
468          * The supplied function is called with (Object item, Number index, Array allItems).
469          * @param {Array/NodeList/Mixed} array
470          * @param {Function} fn
471          * @param {Object} scope
472          */
473         each : function(array, fn, scope){
474             if(typeof array.length == "undefined" || typeof array == "string"){
475                 array = [array];
476             }
477             for(var i = 0, len = array.length; i < len; i++){
478                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
479             }
480         },
481
482         // deprecated
483         combine : function(){
484             var as = arguments, l = as.length, r = [];
485             for(var i = 0; i < l; i++){
486                 var a = as[i];
487                 if(a instanceof Array){
488                     r = r.concat(a);
489                 }else if(a.length !== undefined && !a.substr){
490                     r = r.concat(Array.prototype.slice.call(a, 0));
491                 }else{
492                     r.push(a);
493                 }
494             }
495             return r;
496         },
497
498         /**
499          * Escapes the passed string for use in a regular expression
500          * @param {String} str
501          * @return {String}
502          */
503         escapeRe : function(s) {
504             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
505         },
506
507         // internal
508         callback : function(cb, scope, args, delay){
509             if(typeof cb == "function"){
510                 if(delay){
511                     cb.defer(delay, scope, args || []);
512                 }else{
513                     cb.apply(scope, args || []);
514                 }
515             }
516         },
517
518         /**
519          * Return the dom node for the passed string (id), dom node, or Roo.Element
520          * @param {String/HTMLElement/Roo.Element} el
521          * @return HTMLElement
522          */
523         getDom : function(el){
524             if(!el){
525                 return null;
526             }
527             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
528         },
529
530         /**
531         * Shorthand for {@link Roo.ComponentMgr#get}
532         * @param {String} id
533         * @return Roo.Component
534         */
535         getCmp : function(id){
536             return Roo.ComponentMgr.get(id);
537         },
538          
539         num : function(v, defaultValue){
540             if(typeof v != 'number'){
541                 return defaultValue;
542             }
543             return v;
544         },
545
546         destroy : function(){
547             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
548                 var as = a[i];
549                 if(as){
550                     if(as.dom){
551                         as.removeAllListeners();
552                         as.remove();
553                         continue;
554                     }
555                     if(typeof as.purgeListeners == 'function'){
556                         as.purgeListeners();
557                     }
558                     if(typeof as.destroy == 'function'){
559                         as.destroy();
560                     }
561                 }
562             }
563         },
564
565         // inpired by a similar function in mootools library
566         /**
567          * Returns the type of object that is passed in. If the object passed in is null or undefined it
568          * return false otherwise it returns one of the following values:<ul>
569          * <li><b>string</b>: If the object passed is a string</li>
570          * <li><b>number</b>: If the object passed is a number</li>
571          * <li><b>boolean</b>: If the object passed is a boolean value</li>
572          * <li><b>function</b>: If the object passed is a function reference</li>
573          * <li><b>object</b>: If the object passed is an object</li>
574          * <li><b>array</b>: If the object passed is an array</li>
575          * <li><b>regexp</b>: If the object passed is a regular expression</li>
576          * <li><b>element</b>: If the object passed is a DOM Element</li>
577          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
578          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
579          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
580          * @param {Mixed} object
581          * @return {String}
582          */
583         type : function(o){
584             if(o === undefined || o === null){
585                 return false;
586             }
587             if(o.htmlElement){
588                 return 'element';
589             }
590             var t = typeof o;
591             if(t == 'object' && o.nodeName) {
592                 switch(o.nodeType) {
593                     case 1: return 'element';
594                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
595                 }
596             }
597             if(t == 'object' || t == 'function') {
598                 switch(o.constructor) {
599                     case Array: return 'array';
600                     case RegExp: return 'regexp';
601                 }
602                 if(typeof o.length == 'number' && typeof o.item == 'function') {
603                     return 'nodelist';
604                 }
605             }
606             return t;
607         },
608
609         /**
610          * Returns true if the passed value is null, undefined or an empty string (optional).
611          * @param {Mixed} value The value to test
612          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
613          * @return {Boolean}
614          */
615         isEmpty : function(v, allowBlank){
616             return v === null || v === undefined || (!allowBlank ? v === '' : false);
617         },
618         
619         /** @type Boolean */
620         isOpera : isOpera,
621         /** @type Boolean */
622         isSafari : isSafari,
623         /** @type Boolean */
624         isFirefox : isFirefox,
625         /** @type Boolean */
626         isIE : isIE,
627         /** @type Boolean */
628         isIE7 : isIE7,
629         /** @type Boolean */
630         isIE11 : isIE11,
631         /** @type Boolean */
632         isGecko : isGecko,
633         /** @type Boolean */
634         isBorderBox : isBorderBox,
635         /** @type Boolean */
636         isWindows : isWindows,
637         /** @type Boolean */
638         isLinux : isLinux,
639         /** @type Boolean */
640         isMac : isMac,
641         /** @type Boolean */
642         isIOS : isIOS,
643         /** @type Boolean */
644         isAndroid : isAndroid,
645         /** @type Boolean */
646         isTouch : isTouch,
647
648         /**
649          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
650          * you may want to set this to true.
651          * @type Boolean
652          */
653         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
654         
655         
656                 
657         /**
658          * Selects a single element as a Roo Element
659          * This is about as close as you can get to jQuery's $('do crazy stuff')
660          * @param {String} selector The selector/xpath query
661          * @param {Node} root (optional) The start of the query (defaults to document).
662          * @return {Roo.Element}
663          */
664         selectNode : function(selector, root) 
665         {
666             var node = Roo.DomQuery.selectNode(selector,root);
667             return node ? Roo.get(node) : new Roo.Element(false);
668         }
669         
670     });
671
672
673 })();
674
675 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
676                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
677                 "Roo.app", "Roo.ux",
678                 "Roo.bootstrap",
679                 "Roo.bootstrap.dash");
680 /*
681  * Based on:
682  * Ext JS Library 1.1.1
683  * Copyright(c) 2006-2007, Ext JS, LLC.
684  *
685  * Originally Released Under LGPL - original licence link has changed is not relivant.
686  *
687  * Fork - LGPL
688  * <script type="text/javascript">
689  */
690
691 (function() {    
692     // wrappedn so fnCleanup is not in global scope...
693     if(Roo.isIE) {
694         function fnCleanUp() {
695             var p = Function.prototype;
696             delete p.createSequence;
697             delete p.defer;
698             delete p.createDelegate;
699             delete p.createCallback;
700             delete p.createInterceptor;
701
702             window.detachEvent("onunload", fnCleanUp);
703         }
704         window.attachEvent("onunload", fnCleanUp);
705     }
706 })();
707
708
709 /**
710  * @class Function
711  * These functions are available on every Function object (any JavaScript function).
712  */
713 Roo.apply(Function.prototype, {
714      /**
715      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
716      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
717      * Will create a function that is bound to those 2 args.
718      * @return {Function} The new function
719     */
720     createCallback : function(/*args...*/){
721         // make args available, in function below
722         var args = arguments;
723         var method = this;
724         return function() {
725             return method.apply(window, args);
726         };
727     },
728
729     /**
730      * Creates a delegate (callback) that sets the scope to obj.
731      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
732      * Will create a function that is automatically scoped to this.
733      * @param {Object} obj (optional) The object for which the scope is set
734      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
735      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
736      *                                             if a number the args are inserted at the specified position
737      * @return {Function} The new function
738      */
739     createDelegate : function(obj, args, appendArgs){
740         var method = this;
741         return function() {
742             var callArgs = args || arguments;
743             if(appendArgs === true){
744                 callArgs = Array.prototype.slice.call(arguments, 0);
745                 callArgs = callArgs.concat(args);
746             }else if(typeof appendArgs == "number"){
747                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
748                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
749                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
750             }
751             return method.apply(obj || window, callArgs);
752         };
753     },
754
755     /**
756      * Calls this function after the number of millseconds specified.
757      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
758      * @param {Object} obj (optional) The object for which the scope is set
759      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761      *                                             if a number the args are inserted at the specified position
762      * @return {Number} The timeout id that can be used with clearTimeout
763      */
764     defer : function(millis, obj, args, appendArgs){
765         var fn = this.createDelegate(obj, args, appendArgs);
766         if(millis){
767             return setTimeout(fn, millis);
768         }
769         fn();
770         return 0;
771     },
772     /**
773      * Create a combined function call sequence of the original function + the passed function.
774      * The resulting function returns the results of the original function.
775      * The passed fcn is called with the parameters of the original function
776      * @param {Function} fcn The function to sequence
777      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
778      * @return {Function} The new function
779      */
780     createSequence : function(fcn, scope){
781         if(typeof fcn != "function"){
782             return this;
783         }
784         var method = this;
785         return function() {
786             var retval = method.apply(this || window, arguments);
787             fcn.apply(scope || this || window, arguments);
788             return retval;
789         };
790     },
791
792     /**
793      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
794      * The resulting function returns the results of the original function.
795      * The passed fcn is called with the parameters of the original function.
796      * @addon
797      * @param {Function} fcn The function to call before the original
798      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
799      * @return {Function} The new function
800      */
801     createInterceptor : function(fcn, scope){
802         if(typeof fcn != "function"){
803             return this;
804         }
805         var method = this;
806         return function() {
807             fcn.target = this;
808             fcn.method = method;
809             if(fcn.apply(scope || this || window, arguments) === false){
810                 return;
811             }
812             return method.apply(this || window, arguments);
813         };
814     }
815 });
816 /*
817  * Based on:
818  * Ext JS Library 1.1.1
819  * Copyright(c) 2006-2007, Ext JS, LLC.
820  *
821  * Originally Released Under LGPL - original licence link has changed is not relivant.
822  *
823  * Fork - LGPL
824  * <script type="text/javascript">
825  */
826
827 Roo.applyIf(String, {
828     
829     /** @scope String */
830     
831     /**
832      * Escapes the passed string for ' and \
833      * @param {String} string The string to escape
834      * @return {String} The escaped string
835      * @static
836      */
837     escape : function(string) {
838         return string.replace(/('|\\)/g, "\\$1");
839     },
840
841     /**
842      * Pads the left side of a string with a specified character.  This is especially useful
843      * for normalizing number and date strings.  Example usage:
844      * <pre><code>
845 var s = String.leftPad('123', 5, '0');
846 // s now contains the string: '00123'
847 </code></pre>
848      * @param {String} string The original string
849      * @param {Number} size The total length of the output string
850      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
851      * @return {String} The padded string
852      * @static
853      */
854     leftPad : function (val, size, ch) {
855         var result = new String(val);
856         if(ch === null || ch === undefined || ch === '') {
857             ch = " ";
858         }
859         while (result.length < size) {
860             result = ch + result;
861         }
862         return result;
863     },
864
865     /**
866      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
867      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
868      * <pre><code>
869 var cls = 'my-class', text = 'Some text';
870 var s = String.format('<div class="{0}">{1}</div>', cls, text);
871 // s now contains the string: '<div class="my-class">Some text</div>'
872 </code></pre>
873      * @param {String} string The tokenized string to be formatted
874      * @param {String} value1 The value to replace token {0}
875      * @param {String} value2 Etc...
876      * @return {String} The formatted string
877      * @static
878      */
879     format : function(format){
880         var args = Array.prototype.slice.call(arguments, 1);
881         return format.replace(/\{(\d+)\}/g, function(m, i){
882             return Roo.util.Format.htmlEncode(args[i]);
883         });
884     }
885 });
886
887 /**
888  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
889  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
890  * they are already different, the first value passed in is returned.  Note that this method returns the new value
891  * but does not change the current string.
892  * <pre><code>
893 // alternate sort directions
894 sort = sort.toggle('ASC', 'DESC');
895
896 // instead of conditional logic:
897 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
898 </code></pre>
899  * @param {String} value The value to compare to the current string
900  * @param {String} other The new value to use if the string already equals the first value passed in
901  * @return {String} The new value
902  */
903  
904 String.prototype.toggle = function(value, other){
905     return this == value ? other : value;
906 };/*
907  * Based on:
908  * Ext JS Library 1.1.1
909  * Copyright(c) 2006-2007, Ext JS, LLC.
910  *
911  * Originally Released Under LGPL - original licence link has changed is not relivant.
912  *
913  * Fork - LGPL
914  * <script type="text/javascript">
915  */
916
917  /**
918  * @class Number
919  */
920 Roo.applyIf(Number.prototype, {
921     /**
922      * Checks whether or not the current number is within a desired range.  If the number is already within the
923      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
924      * exceeded.  Note that this method returns the constrained value but does not change the current number.
925      * @param {Number} min The minimum number in the range
926      * @param {Number} max The maximum number in the range
927      * @return {Number} The constrained value if outside the range, otherwise the current value
928      */
929     constrain : function(min, max){
930         return Math.min(Math.max(this, min), max);
931     }
932 });/*
933  * Based on:
934  * Ext JS Library 1.1.1
935  * Copyright(c) 2006-2007, Ext JS, LLC.
936  *
937  * Originally Released Under LGPL - original licence link has changed is not relivant.
938  *
939  * Fork - LGPL
940  * <script type="text/javascript">
941  */
942  /**
943  * @class Array
944  */
945 Roo.applyIf(Array.prototype, {
946     /**
947      * 
948      * Checks whether or not the specified object exists in the array.
949      * @param {Object} o The object to check for
950      * @return {Number} The index of o in the array (or -1 if it is not found)
951      */
952     indexOf : function(o){
953        for (var i = 0, len = this.length; i < len; i++){
954               if(this[i] == o) { return i; }
955        }
956            return -1;
957     },
958
959     /**
960      * Removes the specified object from the array.  If the object is not found nothing happens.
961      * @param {Object} o The object to remove
962      */
963     remove : function(o){
964        var index = this.indexOf(o);
965        if(index != -1){
966            this.splice(index, 1);
967        }
968     },
969     /**
970      * Map (JS 1.6 compatibility)
971      * @param {Function} function  to call
972      */
973     map : function(fun )
974     {
975         var len = this.length >>> 0;
976         if (typeof fun != "function") {
977             throw new TypeError();
978         }
979         var res = new Array(len);
980         var thisp = arguments[1];
981         for (var i = 0; i < len; i++)
982         {
983             if (i in this) {
984                 res[i] = fun.call(thisp, this[i], i, this);
985             }
986         }
987
988         return res;
989     }
990     
991 });
992
993
994  
995 /*
996  * Based on:
997  * Ext JS Library 1.1.1
998  * Copyright(c) 2006-2007, Ext JS, LLC.
999  *
1000  * Originally Released Under LGPL - original licence link has changed is not relivant.
1001  *
1002  * Fork - LGPL
1003  * <script type="text/javascript">
1004  */
1005
1006 /**
1007  * @class Date
1008  *
1009  * The date parsing and format syntax is a subset of
1010  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1011  * supported will provide results equivalent to their PHP versions.
1012  *
1013  * Following is the list of all currently supported formats:
1014  *<pre>
1015 Sample date:
1016 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1017
1018 Format  Output      Description
1019 ------  ----------  --------------------------------------------------------------
1020   d      10         Day of the month, 2 digits with leading zeros
1021   D      Wed        A textual representation of a day, three letters
1022   j      10         Day of the month without leading zeros
1023   l      Wednesday  A full textual representation of the day of the week
1024   S      th         English ordinal day of month suffix, 2 chars (use with j)
1025   w      3          Numeric representation of the day of the week
1026   z      9          The julian date, or day of the year (0-365)
1027   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1028   F      January    A full textual representation of the month
1029   m      01         Numeric representation of a month, with leading zeros
1030   M      Jan        Month name abbreviation, three letters
1031   n      1          Numeric representation of a month, without leading zeros
1032   t      31         Number of days in the given month
1033   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1034   Y      2007       A full numeric representation of a year, 4 digits
1035   y      07         A two digit representation of a year
1036   a      pm         Lowercase Ante meridiem and Post meridiem
1037   A      PM         Uppercase Ante meridiem and Post meridiem
1038   g      3          12-hour format of an hour without leading zeros
1039   G      15         24-hour format of an hour without leading zeros
1040   h      03         12-hour format of an hour with leading zeros
1041   H      15         24-hour format of an hour with leading zeros
1042   i      05         Minutes with leading zeros
1043   s      01         Seconds, with leading zeros
1044   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1045   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1046   T      CST        Timezone setting of the machine running the code
1047   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1048 </pre>
1049  *
1050  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1051  * <pre><code>
1052 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1053 document.write(dt.format('Y-m-d'));                         //2007-01-10
1054 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1055 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1056  </code></pre>
1057  *
1058  * Here are some standard date/time patterns that you might find helpful.  They
1059  * are not part of the source of Date.js, but to use them you can simply copy this
1060  * block of code into any script that is included after Date.js and they will also become
1061  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1062  * <pre><code>
1063 Date.patterns = {
1064     ISO8601Long:"Y-m-d H:i:s",
1065     ISO8601Short:"Y-m-d",
1066     ShortDate: "n/j/Y",
1067     LongDate: "l, F d, Y",
1068     FullDateTime: "l, F d, Y g:i:s A",
1069     MonthDay: "F d",
1070     ShortTime: "g:i A",
1071     LongTime: "g:i:s A",
1072     SortableDateTime: "Y-m-d\\TH:i:s",
1073     UniversalSortableDateTime: "Y-m-d H:i:sO",
1074     YearMonth: "F, Y"
1075 };
1076 </code></pre>
1077  *
1078  * Example usage:
1079  * <pre><code>
1080 var dt = new Date();
1081 document.write(dt.format(Date.patterns.ShortDate));
1082  </code></pre>
1083  */
1084
1085 /*
1086  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1087  * They generate precompiled functions from date formats instead of parsing and
1088  * processing the pattern every time you format a date.  These functions are available
1089  * on every Date object (any javascript function).
1090  *
1091  * The original article and download are here:
1092  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1093  *
1094  */
1095  
1096  
1097  // was in core
1098 /**
1099  Returns the number of milliseconds between this date and date
1100  @param {Date} date (optional) Defaults to now
1101  @return {Number} The diff in milliseconds
1102  @member Date getElapsed
1103  */
1104 Date.prototype.getElapsed = function(date) {
1105         return Math.abs((date || new Date()).getTime()-this.getTime());
1106 };
1107 // was in date file..
1108
1109
1110 // private
1111 Date.parseFunctions = {count:0};
1112 // private
1113 Date.parseRegexes = [];
1114 // private
1115 Date.formatFunctions = {count:0};
1116
1117 // private
1118 Date.prototype.dateFormat = function(format) {
1119     if (Date.formatFunctions[format] == null) {
1120         Date.createNewFormat(format);
1121     }
1122     var func = Date.formatFunctions[format];
1123     return this[func]();
1124 };
1125
1126
1127 /**
1128  * Formats a date given the supplied format string
1129  * @param {String} format The format string
1130  * @return {String} The formatted date
1131  * @method
1132  */
1133 Date.prototype.format = Date.prototype.dateFormat;
1134
1135 // private
1136 Date.createNewFormat = function(format) {
1137     var funcName = "format" + Date.formatFunctions.count++;
1138     Date.formatFunctions[format] = funcName;
1139     var code = "Date.prototype." + funcName + " = function(){return ";
1140     var special = false;
1141     var ch = '';
1142     for (var i = 0; i < format.length; ++i) {
1143         ch = format.charAt(i);
1144         if (!special && ch == "\\") {
1145             special = true;
1146         }
1147         else if (special) {
1148             special = false;
1149             code += "'" + String.escape(ch) + "' + ";
1150         }
1151         else {
1152             code += Date.getFormatCode(ch);
1153         }
1154     }
1155     /** eval:var:zzzzzzzzzzzzz */
1156     eval(code.substring(0, code.length - 3) + ";}");
1157 };
1158
1159 // private
1160 Date.getFormatCode = function(character) {
1161     switch (character) {
1162     case "d":
1163         return "String.leftPad(this.getDate(), 2, '0') + ";
1164     case "D":
1165         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1166     case "j":
1167         return "this.getDate() + ";
1168     case "l":
1169         return "Date.dayNames[this.getDay()] + ";
1170     case "S":
1171         return "this.getSuffix() + ";
1172     case "w":
1173         return "this.getDay() + ";
1174     case "z":
1175         return "this.getDayOfYear() + ";
1176     case "W":
1177         return "this.getWeekOfYear() + ";
1178     case "F":
1179         return "Date.monthNames[this.getMonth()] + ";
1180     case "m":
1181         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1182     case "M":
1183         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1184     case "n":
1185         return "(this.getMonth() + 1) + ";
1186     case "t":
1187         return "this.getDaysInMonth() + ";
1188     case "L":
1189         return "(this.isLeapYear() ? 1 : 0) + ";
1190     case "Y":
1191         return "this.getFullYear() + ";
1192     case "y":
1193         return "('' + this.getFullYear()).substring(2, 4) + ";
1194     case "a":
1195         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1196     case "A":
1197         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1198     case "g":
1199         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1200     case "G":
1201         return "this.getHours() + ";
1202     case "h":
1203         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1204     case "H":
1205         return "String.leftPad(this.getHours(), 2, '0') + ";
1206     case "i":
1207         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1208     case "s":
1209         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1210     case "O":
1211         return "this.getGMTOffset() + ";
1212     case "P":
1213         return "this.getGMTColonOffset() + ";
1214     case "T":
1215         return "this.getTimezone() + ";
1216     case "Z":
1217         return "(this.getTimezoneOffset() * -60) + ";
1218     default:
1219         return "'" + String.escape(character) + "' + ";
1220     }
1221 };
1222
1223 /**
1224  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1225  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1226  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1227  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1228  * string or the parse operation will fail.
1229  * Example Usage:
1230 <pre><code>
1231 //dt = Fri May 25 2007 (current date)
1232 var dt = new Date();
1233
1234 //dt = Thu May 25 2006 (today's month/day in 2006)
1235 dt = Date.parseDate("2006", "Y");
1236
1237 //dt = Sun Jan 15 2006 (all date parts specified)
1238 dt = Date.parseDate("2006-1-15", "Y-m-d");
1239
1240 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1241 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1242 </code></pre>
1243  * @param {String} input The unparsed date as a string
1244  * @param {String} format The format the date is in
1245  * @return {Date} The parsed date
1246  * @static
1247  */
1248 Date.parseDate = function(input, format) {
1249     if (Date.parseFunctions[format] == null) {
1250         Date.createParser(format);
1251     }
1252     var func = Date.parseFunctions[format];
1253     return Date[func](input);
1254 };
1255 /**
1256  * @private
1257  */
1258
1259 Date.createParser = function(format) {
1260     var funcName = "parse" + Date.parseFunctions.count++;
1261     var regexNum = Date.parseRegexes.length;
1262     var currentGroup = 1;
1263     Date.parseFunctions[format] = funcName;
1264
1265     var code = "Date." + funcName + " = function(input){\n"
1266         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1267         + "var d = new Date();\n"
1268         + "y = d.getFullYear();\n"
1269         + "m = d.getMonth();\n"
1270         + "d = d.getDate();\n"
1271         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1272         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1273         + "if (results && results.length > 0) {";
1274     var regex = "";
1275
1276     var special = false;
1277     var ch = '';
1278     for (var i = 0; i < format.length; ++i) {
1279         ch = format.charAt(i);
1280         if (!special && ch == "\\") {
1281             special = true;
1282         }
1283         else if (special) {
1284             special = false;
1285             regex += String.escape(ch);
1286         }
1287         else {
1288             var obj = Date.formatCodeToRegex(ch, currentGroup);
1289             currentGroup += obj.g;
1290             regex += obj.s;
1291             if (obj.g && obj.c) {
1292                 code += obj.c;
1293             }
1294         }
1295     }
1296
1297     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1298         + "{v = new Date(y, m, d, h, i, s);}\n"
1299         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1300         + "{v = new Date(y, m, d, h, i);}\n"
1301         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1302         + "{v = new Date(y, m, d, h);}\n"
1303         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1304         + "{v = new Date(y, m, d);}\n"
1305         + "else if (y >= 0 && m >= 0)\n"
1306         + "{v = new Date(y, m);}\n"
1307         + "else if (y >= 0)\n"
1308         + "{v = new Date(y);}\n"
1309         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1310         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1311         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1312         + ";}";
1313
1314     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1315     /** eval:var:zzzzzzzzzzzzz */
1316     eval(code);
1317 };
1318
1319 // private
1320 Date.formatCodeToRegex = function(character, currentGroup) {
1321     switch (character) {
1322     case "D":
1323         return {g:0,
1324         c:null,
1325         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1326     case "j":
1327         return {g:1,
1328             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1329             s:"(\\d{1,2})"}; // day of month without leading zeroes
1330     case "d":
1331         return {g:1,
1332             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1333             s:"(\\d{2})"}; // day of month with leading zeroes
1334     case "l":
1335         return {g:0,
1336             c:null,
1337             s:"(?:" + Date.dayNames.join("|") + ")"};
1338     case "S":
1339         return {g:0,
1340             c:null,
1341             s:"(?:st|nd|rd|th)"};
1342     case "w":
1343         return {g:0,
1344             c:null,
1345             s:"\\d"};
1346     case "z":
1347         return {g:0,
1348             c:null,
1349             s:"(?:\\d{1,3})"};
1350     case "W":
1351         return {g:0,
1352             c:null,
1353             s:"(?:\\d{2})"};
1354     case "F":
1355         return {g:1,
1356             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1357             s:"(" + Date.monthNames.join("|") + ")"};
1358     case "M":
1359         return {g:1,
1360             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1361             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1362     case "n":
1363         return {g:1,
1364             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1365             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1366     case "m":
1367         return {g:1,
1368             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1369             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1370     case "t":
1371         return {g:0,
1372             c:null,
1373             s:"\\d{1,2}"};
1374     case "L":
1375         return {g:0,
1376             c:null,
1377             s:"(?:1|0)"};
1378     case "Y":
1379         return {g:1,
1380             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1381             s:"(\\d{4})"};
1382     case "y":
1383         return {g:1,
1384             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1385                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1386             s:"(\\d{1,2})"};
1387     case "a":
1388         return {g:1,
1389             c:"if (results[" + currentGroup + "] == 'am') {\n"
1390                 + "if (h == 12) { h = 0; }\n"
1391                 + "} else { if (h < 12) { h += 12; }}",
1392             s:"(am|pm)"};
1393     case "A":
1394         return {g:1,
1395             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1396                 + "if (h == 12) { h = 0; }\n"
1397                 + "} else { if (h < 12) { h += 12; }}",
1398             s:"(AM|PM)"};
1399     case "g":
1400     case "G":
1401         return {g:1,
1402             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1403             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1404     case "h":
1405     case "H":
1406         return {g:1,
1407             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1408             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1409     case "i":
1410         return {g:1,
1411             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1412             s:"(\\d{2})"};
1413     case "s":
1414         return {g:1,
1415             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1416             s:"(\\d{2})"};
1417     case "O":
1418         return {g:1,
1419             c:[
1420                 "o = results[", currentGroup, "];\n",
1421                 "var sn = o.substring(0,1);\n", // get + / - sign
1422                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1423                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1424                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1425                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1426             ].join(""),
1427             s:"([+\-]\\d{2,4})"};
1428     
1429     
1430     case "P":
1431         return {g:1,
1432                 c:[
1433                    "o = results[", currentGroup, "];\n",
1434                    "var sn = o.substring(0,1);\n",
1435                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1436                    "var mn = o.substring(4,6) % 60;\n",
1437                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1438                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1439             ].join(""),
1440             s:"([+\-]\\d{4})"};
1441     case "T":
1442         return {g:0,
1443             c:null,
1444             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1445     case "Z":
1446         return {g:1,
1447             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1448                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1449             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1450     default:
1451         return {g:0,
1452             c:null,
1453             s:String.escape(character)};
1454     }
1455 };
1456
1457 /**
1458  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1459  * @return {String} The abbreviated timezone name (e.g. 'CST')
1460  */
1461 Date.prototype.getTimezone = function() {
1462     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1463 };
1464
1465 /**
1466  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1467  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1468  */
1469 Date.prototype.getGMTOffset = function() {
1470     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1471         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1472         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1473 };
1474
1475 /**
1476  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1477  * @return {String} 2-characters representing hours and 2-characters representing minutes
1478  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1479  */
1480 Date.prototype.getGMTColonOffset = function() {
1481         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1482                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1483                 + ":"
1484                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1485 }
1486
1487 /**
1488  * Get the numeric day number of the year, adjusted for leap year.
1489  * @return {Number} 0 through 364 (365 in leap years)
1490  */
1491 Date.prototype.getDayOfYear = function() {
1492     var num = 0;
1493     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1494     for (var i = 0; i < this.getMonth(); ++i) {
1495         num += Date.daysInMonth[i];
1496     }
1497     return num + this.getDate() - 1;
1498 };
1499
1500 /**
1501  * Get the string representation of the numeric week number of the year
1502  * (equivalent to the format specifier 'W').
1503  * @return {String} '00' through '52'
1504  */
1505 Date.prototype.getWeekOfYear = function() {
1506     // Skip to Thursday of this week
1507     var now = this.getDayOfYear() + (4 - this.getDay());
1508     // Find the first Thursday of the year
1509     var jan1 = new Date(this.getFullYear(), 0, 1);
1510     var then = (7 - jan1.getDay() + 4);
1511     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1512 };
1513
1514 /**
1515  * Whether or not the current date is in a leap year.
1516  * @return {Boolean} True if the current date is in a leap year, else false
1517  */
1518 Date.prototype.isLeapYear = function() {
1519     var year = this.getFullYear();
1520     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1521 };
1522
1523 /**
1524  * Get the first day of the current month, adjusted for leap year.  The returned value
1525  * is the numeric day index within the week (0-6) which can be used in conjunction with
1526  * the {@link #monthNames} array to retrieve the textual day name.
1527  * Example:
1528  *<pre><code>
1529 var dt = new Date('1/10/2007');
1530 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1531 </code></pre>
1532  * @return {Number} The day number (0-6)
1533  */
1534 Date.prototype.getFirstDayOfMonth = function() {
1535     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1536     return (day < 0) ? (day + 7) : day;
1537 };
1538
1539 /**
1540  * Get the last day of the current month, adjusted for leap year.  The returned value
1541  * is the numeric day index within the week (0-6) which can be used in conjunction with
1542  * the {@link #monthNames} array to retrieve the textual day name.
1543  * Example:
1544  *<pre><code>
1545 var dt = new Date('1/10/2007');
1546 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1547 </code></pre>
1548  * @return {Number} The day number (0-6)
1549  */
1550 Date.prototype.getLastDayOfMonth = function() {
1551     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1552     return (day < 0) ? (day + 7) : day;
1553 };
1554
1555
1556 /**
1557  * Get the first date of this date's month
1558  * @return {Date}
1559  */
1560 Date.prototype.getFirstDateOfMonth = function() {
1561     return new Date(this.getFullYear(), this.getMonth(), 1);
1562 };
1563
1564 /**
1565  * Get the last date of this date's month
1566  * @return {Date}
1567  */
1568 Date.prototype.getLastDateOfMonth = function() {
1569     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1570 };
1571 /**
1572  * Get the number of days in the current month, adjusted for leap year.
1573  * @return {Number} The number of days in the month
1574  */
1575 Date.prototype.getDaysInMonth = function() {
1576     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1577     return Date.daysInMonth[this.getMonth()];
1578 };
1579
1580 /**
1581  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1582  * @return {String} 'st, 'nd', 'rd' or 'th'
1583  */
1584 Date.prototype.getSuffix = function() {
1585     switch (this.getDate()) {
1586         case 1:
1587         case 21:
1588         case 31:
1589             return "st";
1590         case 2:
1591         case 22:
1592             return "nd";
1593         case 3:
1594         case 23:
1595             return "rd";
1596         default:
1597             return "th";
1598     }
1599 };
1600
1601 // private
1602 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1603
1604 /**
1605  * An array of textual month names.
1606  * Override these values for international dates, for example...
1607  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1608  * @type Array
1609  * @static
1610  */
1611 Date.monthNames =
1612    ["January",
1613     "February",
1614     "March",
1615     "April",
1616     "May",
1617     "June",
1618     "July",
1619     "August",
1620     "September",
1621     "October",
1622     "November",
1623     "December"];
1624
1625 /**
1626  * An array of textual day names.
1627  * Override these values for international dates, for example...
1628  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1629  * @type Array
1630  * @static
1631  */
1632 Date.dayNames =
1633    ["Sunday",
1634     "Monday",
1635     "Tuesday",
1636     "Wednesday",
1637     "Thursday",
1638     "Friday",
1639     "Saturday"];
1640
1641 // private
1642 Date.y2kYear = 50;
1643 // private
1644 Date.monthNumbers = {
1645     Jan:0,
1646     Feb:1,
1647     Mar:2,
1648     Apr:3,
1649     May:4,
1650     Jun:5,
1651     Jul:6,
1652     Aug:7,
1653     Sep:8,
1654     Oct:9,
1655     Nov:10,
1656     Dec:11};
1657
1658 /**
1659  * Creates and returns a new Date instance with the exact same date value as the called instance.
1660  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1661  * variable will also be changed.  When the intention is to create a new variable that will not
1662  * modify the original instance, you should create a clone.
1663  *
1664  * Example of correctly cloning a date:
1665  * <pre><code>
1666 //wrong way:
1667 var orig = new Date('10/1/2006');
1668 var copy = orig;
1669 copy.setDate(5);
1670 document.write(orig);  //returns 'Thu Oct 05 2006'!
1671
1672 //correct way:
1673 var orig = new Date('10/1/2006');
1674 var copy = orig.clone();
1675 copy.setDate(5);
1676 document.write(orig);  //returns 'Thu Oct 01 2006'
1677 </code></pre>
1678  * @return {Date} The new Date instance
1679  */
1680 Date.prototype.clone = function() {
1681         return new Date(this.getTime());
1682 };
1683
1684 /**
1685  * Clears any time information from this date
1686  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1687  @return {Date} this or the clone
1688  */
1689 Date.prototype.clearTime = function(clone){
1690     if(clone){
1691         return this.clone().clearTime();
1692     }
1693     this.setHours(0);
1694     this.setMinutes(0);
1695     this.setSeconds(0);
1696     this.setMilliseconds(0);
1697     return this;
1698 };
1699
1700 // private
1701 // safari setMonth is broken -- check that this is only donw once...
1702 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1703     Date.brokenSetMonth = Date.prototype.setMonth;
1704         Date.prototype.setMonth = function(num){
1705                 if(num <= -1){
1706                         var n = Math.ceil(-num);
1707                         var back_year = Math.ceil(n/12);
1708                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1709                         this.setFullYear(this.getFullYear() - back_year);
1710                         return Date.brokenSetMonth.call(this, month);
1711                 } else {
1712                         return Date.brokenSetMonth.apply(this, arguments);
1713                 }
1714         };
1715 }
1716
1717 /** Date interval constant 
1718 * @static 
1719 * @type String */
1720 Date.MILLI = "ms";
1721 /** Date interval constant 
1722 * @static 
1723 * @type String */
1724 Date.SECOND = "s";
1725 /** Date interval constant 
1726 * @static 
1727 * @type String */
1728 Date.MINUTE = "mi";
1729 /** Date interval constant 
1730 * @static 
1731 * @type String */
1732 Date.HOUR = "h";
1733 /** Date interval constant 
1734 * @static 
1735 * @type String */
1736 Date.DAY = "d";
1737 /** Date interval constant 
1738 * @static 
1739 * @type String */
1740 Date.MONTH = "mo";
1741 /** Date interval constant 
1742 * @static 
1743 * @type String */
1744 Date.YEAR = "y";
1745
1746 /**
1747  * Provides a convenient method of performing basic date arithmetic.  This method
1748  * does not modify the Date instance being called - it creates and returns
1749  * a new Date instance containing the resulting date value.
1750  *
1751  * Examples:
1752  * <pre><code>
1753 //Basic usage:
1754 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1755 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1756
1757 //Negative values will subtract correctly:
1758 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1759 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1760
1761 //You can even chain several calls together in one line!
1762 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1763 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1764  </code></pre>
1765  *
1766  * @param {String} interval   A valid date interval enum value
1767  * @param {Number} value      The amount to add to the current date
1768  * @return {Date} The new Date instance
1769  */
1770 Date.prototype.add = function(interval, value){
1771   var d = this.clone();
1772   if (!interval || value === 0) { return d; }
1773   switch(interval.toLowerCase()){
1774     case Date.MILLI:
1775       d.setMilliseconds(this.getMilliseconds() + value);
1776       break;
1777     case Date.SECOND:
1778       d.setSeconds(this.getSeconds() + value);
1779       break;
1780     case Date.MINUTE:
1781       d.setMinutes(this.getMinutes() + value);
1782       break;
1783     case Date.HOUR:
1784       d.setHours(this.getHours() + value);
1785       break;
1786     case Date.DAY:
1787       d.setDate(this.getDate() + value);
1788       break;
1789     case Date.MONTH:
1790       var day = this.getDate();
1791       if(day > 28){
1792           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1793       }
1794       d.setDate(day);
1795       d.setMonth(this.getMonth() + value);
1796       break;
1797     case Date.YEAR:
1798       d.setFullYear(this.getFullYear() + value);
1799       break;
1800   }
1801   return d;
1802 };
1803 /*
1804  * Based on:
1805  * Ext JS Library 1.1.1
1806  * Copyright(c) 2006-2007, Ext JS, LLC.
1807  *
1808  * Originally Released Under LGPL - original licence link has changed is not relivant.
1809  *
1810  * Fork - LGPL
1811  * <script type="text/javascript">
1812  */
1813
1814 /**
1815  * @class Roo.lib.Dom
1816  * @static
1817  * 
1818  * Dom utils (from YIU afaik)
1819  * 
1820  **/
1821 Roo.lib.Dom = {
1822     /**
1823      * Get the view width
1824      * @param {Boolean} full True will get the full document, otherwise it's the view width
1825      * @return {Number} The width
1826      */
1827      
1828     getViewWidth : function(full) {
1829         return full ? this.getDocumentWidth() : this.getViewportWidth();
1830     },
1831     /**
1832      * Get the view height
1833      * @param {Boolean} full True will get the full document, otherwise it's the view height
1834      * @return {Number} The height
1835      */
1836     getViewHeight : function(full) {
1837         return full ? this.getDocumentHeight() : this.getViewportHeight();
1838     },
1839
1840     getDocumentHeight: function() {
1841         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1842         return Math.max(scrollHeight, this.getViewportHeight());
1843     },
1844
1845     getDocumentWidth: function() {
1846         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1847         return Math.max(scrollWidth, this.getViewportWidth());
1848     },
1849
1850     getViewportHeight: function() {
1851         var height = self.innerHeight;
1852         var mode = document.compatMode;
1853
1854         if ((mode || Roo.isIE) && !Roo.isOpera) {
1855             height = (mode == "CSS1Compat") ?
1856                      document.documentElement.clientHeight :
1857                      document.body.clientHeight;
1858         }
1859
1860         return height;
1861     },
1862
1863     getViewportWidth: function() {
1864         var width = self.innerWidth;
1865         var mode = document.compatMode;
1866
1867         if (mode || Roo.isIE) {
1868             width = (mode == "CSS1Compat") ?
1869                     document.documentElement.clientWidth :
1870                     document.body.clientWidth;
1871         }
1872         return width;
1873     },
1874
1875     isAncestor : function(p, c) {
1876         p = Roo.getDom(p);
1877         c = Roo.getDom(c);
1878         if (!p || !c) {
1879             return false;
1880         }
1881
1882         if (p.contains && !Roo.isSafari) {
1883             return p.contains(c);
1884         } else if (p.compareDocumentPosition) {
1885             return !!(p.compareDocumentPosition(c) & 16);
1886         } else {
1887             var parent = c.parentNode;
1888             while (parent) {
1889                 if (parent == p) {
1890                     return true;
1891                 }
1892                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1893                     return false;
1894                 }
1895                 parent = parent.parentNode;
1896             }
1897             return false;
1898         }
1899     },
1900
1901     getRegion : function(el) {
1902         return Roo.lib.Region.getRegion(el);
1903     },
1904
1905     getY : function(el) {
1906         return this.getXY(el)[1];
1907     },
1908
1909     getX : function(el) {
1910         return this.getXY(el)[0];
1911     },
1912
1913     getXY : function(el) {
1914         var p, pe, b, scroll, bd = document.body;
1915         el = Roo.getDom(el);
1916         var fly = Roo.lib.AnimBase.fly;
1917         if (el.getBoundingClientRect) {
1918             b = el.getBoundingClientRect();
1919             scroll = fly(document).getScroll();
1920             return [b.left + scroll.left, b.top + scroll.top];
1921         }
1922         var x = 0, y = 0;
1923
1924         p = el;
1925
1926         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1927
1928         while (p) {
1929
1930             x += p.offsetLeft;
1931             y += p.offsetTop;
1932
1933             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1934                 hasAbsolute = true;
1935             }
1936
1937             if (Roo.isGecko) {
1938                 pe = fly(p);
1939
1940                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1941                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1942
1943
1944                 x += bl;
1945                 y += bt;
1946
1947
1948                 if (p != el && pe.getStyle('overflow') != 'visible') {
1949                     x += bl;
1950                     y += bt;
1951                 }
1952             }
1953             p = p.offsetParent;
1954         }
1955
1956         if (Roo.isSafari && hasAbsolute) {
1957             x -= bd.offsetLeft;
1958             y -= bd.offsetTop;
1959         }
1960
1961         if (Roo.isGecko && !hasAbsolute) {
1962             var dbd = fly(bd);
1963             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1964             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1965         }
1966
1967         p = el.parentNode;
1968         while (p && p != bd) {
1969             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1970                 x -= p.scrollLeft;
1971                 y -= p.scrollTop;
1972             }
1973             p = p.parentNode;
1974         }
1975         return [x, y];
1976     },
1977  
1978   
1979
1980
1981     setXY : function(el, xy) {
1982         el = Roo.fly(el, '_setXY');
1983         el.position();
1984         var pts = el.translatePoints(xy);
1985         if (xy[0] !== false) {
1986             el.dom.style.left = pts.left + "px";
1987         }
1988         if (xy[1] !== false) {
1989             el.dom.style.top = pts.top + "px";
1990         }
1991     },
1992
1993     setX : function(el, x) {
1994         this.setXY(el, [x, false]);
1995     },
1996
1997     setY : function(el, y) {
1998         this.setXY(el, [false, y]);
1999     }
2000 };
2001 /*
2002  * Portions of this file are based on pieces of Yahoo User Interface Library
2003  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2004  * YUI licensed under the BSD License:
2005  * http://developer.yahoo.net/yui/license.txt
2006  * <script type="text/javascript">
2007  *
2008  */
2009
2010 Roo.lib.Event = function() {
2011     var loadComplete = false;
2012     var listeners = [];
2013     var unloadListeners = [];
2014     var retryCount = 0;
2015     var onAvailStack = [];
2016     var counter = 0;
2017     var lastError = null;
2018
2019     return {
2020         POLL_RETRYS: 200,
2021         POLL_INTERVAL: 20,
2022         EL: 0,
2023         TYPE: 1,
2024         FN: 2,
2025         WFN: 3,
2026         OBJ: 3,
2027         ADJ_SCOPE: 4,
2028         _interval: null,
2029
2030         startInterval: function() {
2031             if (!this._interval) {
2032                 var self = this;
2033                 var callback = function() {
2034                     self._tryPreloadAttach();
2035                 };
2036                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2037
2038             }
2039         },
2040
2041         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2042             onAvailStack.push({ id:         p_id,
2043                 fn:         p_fn,
2044                 obj:        p_obj,
2045                 override:   p_override,
2046                 checkReady: false    });
2047
2048             retryCount = this.POLL_RETRYS;
2049             this.startInterval();
2050         },
2051
2052
2053         addListener: function(el, eventName, fn) {
2054             el = Roo.getDom(el);
2055             if (!el || !fn) {
2056                 return false;
2057             }
2058
2059             if ("unload" == eventName) {
2060                 unloadListeners[unloadListeners.length] =
2061                 [el, eventName, fn];
2062                 return true;
2063             }
2064
2065             var wrappedFn = function(e) {
2066                 return fn(Roo.lib.Event.getEvent(e));
2067             };
2068
2069             var li = [el, eventName, fn, wrappedFn];
2070
2071             var index = listeners.length;
2072             listeners[index] = li;
2073
2074             this.doAdd(el, eventName, wrappedFn, false);
2075             return true;
2076
2077         },
2078
2079
2080         removeListener: function(el, eventName, fn) {
2081             var i, len;
2082
2083             el = Roo.getDom(el);
2084
2085             if(!fn) {
2086                 return this.purgeElement(el, false, eventName);
2087             }
2088
2089
2090             if ("unload" == eventName) {
2091
2092                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2093                     var li = unloadListeners[i];
2094                     if (li &&
2095                         li[0] == el &&
2096                         li[1] == eventName &&
2097                         li[2] == fn) {
2098                         unloadListeners.splice(i, 1);
2099                         return true;
2100                     }
2101                 }
2102
2103                 return false;
2104             }
2105
2106             var cacheItem = null;
2107
2108
2109             var index = arguments[3];
2110
2111             if ("undefined" == typeof index) {
2112                 index = this._getCacheIndex(el, eventName, fn);
2113             }
2114
2115             if (index >= 0) {
2116                 cacheItem = listeners[index];
2117             }
2118
2119             if (!el || !cacheItem) {
2120                 return false;
2121             }
2122
2123             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2124
2125             delete listeners[index][this.WFN];
2126             delete listeners[index][this.FN];
2127             listeners.splice(index, 1);
2128
2129             return true;
2130
2131         },
2132
2133
2134         getTarget: function(ev, resolveTextNode) {
2135             ev = ev.browserEvent || ev;
2136             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2137             var t = ev.target || ev.srcElement;
2138             return this.resolveTextNode(t);
2139         },
2140
2141
2142         resolveTextNode: function(node) {
2143             if (Roo.isSafari && node && 3 == node.nodeType) {
2144                 return node.parentNode;
2145             } else {
2146                 return node;
2147             }
2148         },
2149
2150
2151         getPageX: function(ev) {
2152             ev = ev.browserEvent || ev;
2153             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2154             var x = ev.pageX;
2155             if (!x && 0 !== x) {
2156                 x = ev.clientX || 0;
2157
2158                 if (Roo.isIE) {
2159                     x += this.getScroll()[1];
2160                 }
2161             }
2162
2163             return x;
2164         },
2165
2166
2167         getPageY: function(ev) {
2168             ev = ev.browserEvent || ev;
2169             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2170             var y = ev.pageY;
2171             if (!y && 0 !== y) {
2172                 y = ev.clientY || 0;
2173
2174                 if (Roo.isIE) {
2175                     y += this.getScroll()[0];
2176                 }
2177             }
2178
2179
2180             return y;
2181         },
2182
2183
2184         getXY: function(ev) {
2185             ev = ev.browserEvent || ev;
2186             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2187             return [this.getPageX(ev), this.getPageY(ev)];
2188         },
2189
2190
2191         getRelatedTarget: function(ev) {
2192             ev = ev.browserEvent || ev;
2193             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2194             var t = ev.relatedTarget;
2195             if (!t) {
2196                 if (ev.type == "mouseout") {
2197                     t = ev.toElement;
2198                 } else if (ev.type == "mouseover") {
2199                     t = ev.fromElement;
2200                 }
2201             }
2202
2203             return this.resolveTextNode(t);
2204         },
2205
2206
2207         getTime: function(ev) {
2208             ev = ev.browserEvent || ev;
2209             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2210             if (!ev.time) {
2211                 var t = new Date().getTime();
2212                 try {
2213                     ev.time = t;
2214                 } catch(ex) {
2215                     this.lastError = ex;
2216                     return t;
2217                 }
2218             }
2219
2220             return ev.time;
2221         },
2222
2223
2224         stopEvent: function(ev) {
2225             this.stopPropagation(ev);
2226             this.preventDefault(ev);
2227         },
2228
2229
2230         stopPropagation: function(ev) {
2231             ev = ev.browserEvent || ev;
2232             if (ev.stopPropagation) {
2233                 ev.stopPropagation();
2234             } else {
2235                 ev.cancelBubble = true;
2236             }
2237         },
2238
2239
2240         preventDefault: function(ev) {
2241             ev = ev.browserEvent || ev;
2242             if(ev.preventDefault) {
2243                 ev.preventDefault();
2244             } else {
2245                 ev.returnValue = false;
2246             }
2247         },
2248
2249
2250         getEvent: function(e) {
2251             var ev = e || window.event;
2252             if (!ev) {
2253                 var c = this.getEvent.caller;
2254                 while (c) {
2255                     ev = c.arguments[0];
2256                     if (ev && Event == ev.constructor) {
2257                         break;
2258                     }
2259                     c = c.caller;
2260                 }
2261             }
2262             return ev;
2263         },
2264
2265
2266         getCharCode: function(ev) {
2267             ev = ev.browserEvent || ev;
2268             return ev.charCode || ev.keyCode || 0;
2269         },
2270
2271
2272         _getCacheIndex: function(el, eventName, fn) {
2273             for (var i = 0,len = listeners.length; i < len; ++i) {
2274                 var li = listeners[i];
2275                 if (li &&
2276                     li[this.FN] == fn &&
2277                     li[this.EL] == el &&
2278                     li[this.TYPE] == eventName) {
2279                     return i;
2280                 }
2281             }
2282
2283             return -1;
2284         },
2285
2286
2287         elCache: {},
2288
2289
2290         getEl: function(id) {
2291             return document.getElementById(id);
2292         },
2293
2294
2295         clearCache: function() {
2296         },
2297
2298
2299         _load: function(e) {
2300             loadComplete = true;
2301             var EU = Roo.lib.Event;
2302
2303
2304             if (Roo.isIE) {
2305                 EU.doRemove(window, "load", EU._load);
2306             }
2307         },
2308
2309
2310         _tryPreloadAttach: function() {
2311
2312             if (this.locked) {
2313                 return false;
2314             }
2315
2316             this.locked = true;
2317
2318
2319             var tryAgain = !loadComplete;
2320             if (!tryAgain) {
2321                 tryAgain = (retryCount > 0);
2322             }
2323
2324
2325             var notAvail = [];
2326             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2327                 var item = onAvailStack[i];
2328                 if (item) {
2329                     var el = this.getEl(item.id);
2330
2331                     if (el) {
2332                         if (!item.checkReady ||
2333                             loadComplete ||
2334                             el.nextSibling ||
2335                             (document && document.body)) {
2336
2337                             var scope = el;
2338                             if (item.override) {
2339                                 if (item.override === true) {
2340                                     scope = item.obj;
2341                                 } else {
2342                                     scope = item.override;
2343                                 }
2344                             }
2345                             item.fn.call(scope, item.obj);
2346                             onAvailStack[i] = null;
2347                         }
2348                     } else {
2349                         notAvail.push(item);
2350                     }
2351                 }
2352             }
2353
2354             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2355
2356             if (tryAgain) {
2357
2358                 this.startInterval();
2359             } else {
2360                 clearInterval(this._interval);
2361                 this._interval = null;
2362             }
2363
2364             this.locked = false;
2365
2366             return true;
2367
2368         },
2369
2370
2371         purgeElement: function(el, recurse, eventName) {
2372             var elListeners = this.getListeners(el, eventName);
2373             if (elListeners) {
2374                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2375                     var l = elListeners[i];
2376                     this.removeListener(el, l.type, l.fn);
2377                 }
2378             }
2379
2380             if (recurse && el && el.childNodes) {
2381                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2382                     this.purgeElement(el.childNodes[i], recurse, eventName);
2383                 }
2384             }
2385         },
2386
2387
2388         getListeners: function(el, eventName) {
2389             var results = [], searchLists;
2390             if (!eventName) {
2391                 searchLists = [listeners, unloadListeners];
2392             } else if (eventName == "unload") {
2393                 searchLists = [unloadListeners];
2394             } else {
2395                 searchLists = [listeners];
2396             }
2397
2398             for (var j = 0; j < searchLists.length; ++j) {
2399                 var searchList = searchLists[j];
2400                 if (searchList && searchList.length > 0) {
2401                     for (var i = 0,len = searchList.length; i < len; ++i) {
2402                         var l = searchList[i];
2403                         if (l && l[this.EL] === el &&
2404                             (!eventName || eventName === l[this.TYPE])) {
2405                             results.push({
2406                                 type:   l[this.TYPE],
2407                                 fn:     l[this.FN],
2408                                 obj:    l[this.OBJ],
2409                                 adjust: l[this.ADJ_SCOPE],
2410                                 index:  i
2411                             });
2412                         }
2413                     }
2414                 }
2415             }
2416
2417             return (results.length) ? results : null;
2418         },
2419
2420
2421         _unload: function(e) {
2422
2423             var EU = Roo.lib.Event, i, j, l, len, index;
2424
2425             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2426                 l = unloadListeners[i];
2427                 if (l) {
2428                     var scope = window;
2429                     if (l[EU.ADJ_SCOPE]) {
2430                         if (l[EU.ADJ_SCOPE] === true) {
2431                             scope = l[EU.OBJ];
2432                         } else {
2433                             scope = l[EU.ADJ_SCOPE];
2434                         }
2435                     }
2436                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2437                     unloadListeners[i] = null;
2438                     l = null;
2439                     scope = null;
2440                 }
2441             }
2442
2443             unloadListeners = null;
2444
2445             if (listeners && listeners.length > 0) {
2446                 j = listeners.length;
2447                 while (j) {
2448                     index = j - 1;
2449                     l = listeners[index];
2450                     if (l) {
2451                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2452                                 l[EU.FN], index);
2453                     }
2454                     j = j - 1;
2455                 }
2456                 l = null;
2457
2458                 EU.clearCache();
2459             }
2460
2461             EU.doRemove(window, "unload", EU._unload);
2462
2463         },
2464
2465
2466         getScroll: function() {
2467             var dd = document.documentElement, db = document.body;
2468             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2469                 return [dd.scrollTop, dd.scrollLeft];
2470             } else if (db) {
2471                 return [db.scrollTop, db.scrollLeft];
2472             } else {
2473                 return [0, 0];
2474             }
2475         },
2476
2477
2478         doAdd: function () {
2479             if (window.addEventListener) {
2480                 return function(el, eventName, fn, capture) {
2481                     el.addEventListener(eventName, fn, (capture));
2482                 };
2483             } else if (window.attachEvent) {
2484                 return function(el, eventName, fn, capture) {
2485                     el.attachEvent("on" + eventName, fn);
2486                 };
2487             } else {
2488                 return function() {
2489                 };
2490             }
2491         }(),
2492
2493
2494         doRemove: function() {
2495             if (window.removeEventListener) {
2496                 return function (el, eventName, fn, capture) {
2497                     el.removeEventListener(eventName, fn, (capture));
2498                 };
2499             } else if (window.detachEvent) {
2500                 return function (el, eventName, fn) {
2501                     el.detachEvent("on" + eventName, fn);
2502                 };
2503             } else {
2504                 return function() {
2505                 };
2506             }
2507         }()
2508     };
2509     
2510 }();
2511 (function() {     
2512    
2513     var E = Roo.lib.Event;
2514     E.on = E.addListener;
2515     E.un = E.removeListener;
2516
2517     if (document && document.body) {
2518         E._load();
2519     } else {
2520         E.doAdd(window, "load", E._load);
2521     }
2522     E.doAdd(window, "unload", E._unload);
2523     E._tryPreloadAttach();
2524 })();
2525
2526 /*
2527  * Portions of this file are based on pieces of Yahoo User Interface Library
2528  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2529  * YUI licensed under the BSD License:
2530  * http://developer.yahoo.net/yui/license.txt
2531  * <script type="text/javascript">
2532  *
2533  */
2534
2535 (function() {
2536     /**
2537      * @class Roo.lib.Ajax
2538      *
2539      */
2540     Roo.lib.Ajax = {
2541         /**
2542          * @static 
2543          */
2544         request : function(method, uri, cb, data, options) {
2545             if(options){
2546                 var hs = options.headers;
2547                 if(hs){
2548                     for(var h in hs){
2549                         if(hs.hasOwnProperty(h)){
2550                             this.initHeader(h, hs[h], false);
2551                         }
2552                     }
2553                 }
2554                 if(options.xmlData){
2555                     this.initHeader('Content-Type', 'text/xml', false);
2556                     method = 'POST';
2557                     data = options.xmlData;
2558                 }
2559             }
2560
2561             return this.asyncRequest(method, uri, cb, data);
2562         },
2563
2564         serializeForm : function(form) {
2565             if(typeof form == 'string') {
2566                 form = (document.getElementById(form) || document.forms[form]);
2567             }
2568
2569             var el, name, val, disabled, data = '', hasSubmit = false;
2570             for (var i = 0; i < form.elements.length; i++) {
2571                 el = form.elements[i];
2572                 disabled = form.elements[i].disabled;
2573                 name = form.elements[i].name;
2574                 val = form.elements[i].value;
2575
2576                 if (!disabled && name){
2577                     switch (el.type)
2578                             {
2579                         case 'select-one':
2580                         case 'select-multiple':
2581                             for (var j = 0; j < el.options.length; j++) {
2582                                 if (el.options[j].selected) {
2583                                     if (Roo.isIE) {
2584                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2585                                     }
2586                                     else {
2587                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2588                                     }
2589                                 }
2590                             }
2591                             break;
2592                         case 'radio':
2593                         case 'checkbox':
2594                             if (el.checked) {
2595                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2596                             }
2597                             break;
2598                         case 'file':
2599
2600                         case undefined:
2601
2602                         case 'reset':
2603
2604                         case 'button':
2605
2606                             break;
2607                         case 'submit':
2608                             if(hasSubmit == false) {
2609                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2610                                 hasSubmit = true;
2611                             }
2612                             break;
2613                         default:
2614                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2615                             break;
2616                     }
2617                 }
2618             }
2619             data = data.substr(0, data.length - 1);
2620             return data;
2621         },
2622
2623         headers:{},
2624
2625         hasHeaders:false,
2626
2627         useDefaultHeader:true,
2628
2629         defaultPostHeader:'application/x-www-form-urlencoded',
2630
2631         useDefaultXhrHeader:true,
2632
2633         defaultXhrHeader:'XMLHttpRequest',
2634
2635         hasDefaultHeaders:true,
2636
2637         defaultHeaders:{},
2638
2639         poll:{},
2640
2641         timeout:{},
2642
2643         pollInterval:50,
2644
2645         transactionId:0,
2646
2647         setProgId:function(id)
2648         {
2649             this.activeX.unshift(id);
2650         },
2651
2652         setDefaultPostHeader:function(b)
2653         {
2654             this.useDefaultHeader = b;
2655         },
2656
2657         setDefaultXhrHeader:function(b)
2658         {
2659             this.useDefaultXhrHeader = b;
2660         },
2661
2662         setPollingInterval:function(i)
2663         {
2664             if (typeof i == 'number' && isFinite(i)) {
2665                 this.pollInterval = i;
2666             }
2667         },
2668
2669         createXhrObject:function(transactionId)
2670         {
2671             var obj,http;
2672             try
2673             {
2674
2675                 http = new XMLHttpRequest();
2676
2677                 obj = { conn:http, tId:transactionId };
2678             }
2679             catch(e)
2680             {
2681                 for (var i = 0; i < this.activeX.length; ++i) {
2682                     try
2683                     {
2684
2685                         http = new ActiveXObject(this.activeX[i]);
2686
2687                         obj = { conn:http, tId:transactionId };
2688                         break;
2689                     }
2690                     catch(e) {
2691                     }
2692                 }
2693             }
2694             finally
2695             {
2696                 return obj;
2697             }
2698         },
2699
2700         getConnectionObject:function()
2701         {
2702             var o;
2703             var tId = this.transactionId;
2704
2705             try
2706             {
2707                 o = this.createXhrObject(tId);
2708                 if (o) {
2709                     this.transactionId++;
2710                 }
2711             }
2712             catch(e) {
2713             }
2714             finally
2715             {
2716                 return o;
2717             }
2718         },
2719
2720         asyncRequest:function(method, uri, callback, postData)
2721         {
2722             var o = this.getConnectionObject();
2723
2724             if (!o) {
2725                 return null;
2726             }
2727             else {
2728                 o.conn.open(method, uri, true);
2729
2730                 if (this.useDefaultXhrHeader) {
2731                     if (!this.defaultHeaders['X-Requested-With']) {
2732                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2733                     }
2734                 }
2735
2736                 if(postData && this.useDefaultHeader){
2737                     this.initHeader('Content-Type', this.defaultPostHeader);
2738                 }
2739
2740                  if (this.hasDefaultHeaders || this.hasHeaders) {
2741                     this.setHeader(o);
2742                 }
2743
2744                 this.handleReadyState(o, callback);
2745                 o.conn.send(postData || null);
2746
2747                 return o;
2748             }
2749         },
2750
2751         handleReadyState:function(o, callback)
2752         {
2753             var oConn = this;
2754
2755             if (callback && callback.timeout) {
2756                 
2757                 this.timeout[o.tId] = window.setTimeout(function() {
2758                     oConn.abort(o, callback, true);
2759                 }, callback.timeout);
2760             }
2761
2762             this.poll[o.tId] = window.setInterval(
2763                     function() {
2764                         if (o.conn && o.conn.readyState == 4) {
2765                             window.clearInterval(oConn.poll[o.tId]);
2766                             delete oConn.poll[o.tId];
2767
2768                             if(callback && callback.timeout) {
2769                                 window.clearTimeout(oConn.timeout[o.tId]);
2770                                 delete oConn.timeout[o.tId];
2771                             }
2772
2773                             oConn.handleTransactionResponse(o, callback);
2774                         }
2775                     }
2776                     , this.pollInterval);
2777         },
2778
2779         handleTransactionResponse:function(o, callback, isAbort)
2780         {
2781
2782             if (!callback) {
2783                 this.releaseObject(o);
2784                 return;
2785             }
2786
2787             var httpStatus, responseObject;
2788
2789             try
2790             {
2791                 if (o.conn.status !== undefined && o.conn.status != 0) {
2792                     httpStatus = o.conn.status;
2793                 }
2794                 else {
2795                     httpStatus = 13030;
2796                 }
2797             }
2798             catch(e) {
2799
2800
2801                 httpStatus = 13030;
2802             }
2803
2804             if (httpStatus >= 200 && httpStatus < 300) {
2805                 responseObject = this.createResponseObject(o, callback.argument);
2806                 if (callback.success) {
2807                     if (!callback.scope) {
2808                         callback.success(responseObject);
2809                     }
2810                     else {
2811
2812
2813                         callback.success.apply(callback.scope, [responseObject]);
2814                     }
2815                 }
2816             }
2817             else {
2818                 switch (httpStatus) {
2819
2820                     case 12002:
2821                     case 12029:
2822                     case 12030:
2823                     case 12031:
2824                     case 12152:
2825                     case 13030:
2826                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2827                         if (callback.failure) {
2828                             if (!callback.scope) {
2829                                 callback.failure(responseObject);
2830                             }
2831                             else {
2832                                 callback.failure.apply(callback.scope, [responseObject]);
2833                             }
2834                         }
2835                         break;
2836                     default:
2837                         responseObject = this.createResponseObject(o, callback.argument);
2838                         if (callback.failure) {
2839                             if (!callback.scope) {
2840                                 callback.failure(responseObject);
2841                             }
2842                             else {
2843                                 callback.failure.apply(callback.scope, [responseObject]);
2844                             }
2845                         }
2846                 }
2847             }
2848
2849             this.releaseObject(o);
2850             responseObject = null;
2851         },
2852
2853         createResponseObject:function(o, callbackArg)
2854         {
2855             var obj = {};
2856             var headerObj = {};
2857
2858             try
2859             {
2860                 var headerStr = o.conn.getAllResponseHeaders();
2861                 var header = headerStr.split('\n');
2862                 for (var i = 0; i < header.length; i++) {
2863                     var delimitPos = header[i].indexOf(':');
2864                     if (delimitPos != -1) {
2865                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2866                     }
2867                 }
2868             }
2869             catch(e) {
2870             }
2871
2872             obj.tId = o.tId;
2873             obj.status = o.conn.status;
2874             obj.statusText = o.conn.statusText;
2875             obj.getResponseHeader = headerObj;
2876             obj.getAllResponseHeaders = headerStr;
2877             obj.responseText = o.conn.responseText;
2878             obj.responseXML = o.conn.responseXML;
2879
2880             if (typeof callbackArg !== undefined) {
2881                 obj.argument = callbackArg;
2882             }
2883
2884             return obj;
2885         },
2886
2887         createExceptionObject:function(tId, callbackArg, isAbort)
2888         {
2889             var COMM_CODE = 0;
2890             var COMM_ERROR = 'communication failure';
2891             var ABORT_CODE = -1;
2892             var ABORT_ERROR = 'transaction aborted';
2893
2894             var obj = {};
2895
2896             obj.tId = tId;
2897             if (isAbort) {
2898                 obj.status = ABORT_CODE;
2899                 obj.statusText = ABORT_ERROR;
2900             }
2901             else {
2902                 obj.status = COMM_CODE;
2903                 obj.statusText = COMM_ERROR;
2904             }
2905
2906             if (callbackArg) {
2907                 obj.argument = callbackArg;
2908             }
2909
2910             return obj;
2911         },
2912
2913         initHeader:function(label, value, isDefault)
2914         {
2915             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2916
2917             if (headerObj[label] === undefined) {
2918                 headerObj[label] = value;
2919             }
2920             else {
2921
2922
2923                 headerObj[label] = value + "," + headerObj[label];
2924             }
2925
2926             if (isDefault) {
2927                 this.hasDefaultHeaders = true;
2928             }
2929             else {
2930                 this.hasHeaders = true;
2931             }
2932         },
2933
2934
2935         setHeader:function(o)
2936         {
2937             if (this.hasDefaultHeaders) {
2938                 for (var prop in this.defaultHeaders) {
2939                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2940                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2941                     }
2942                 }
2943             }
2944
2945             if (this.hasHeaders) {
2946                 for (var prop in this.headers) {
2947                     if (this.headers.hasOwnProperty(prop)) {
2948                         o.conn.setRequestHeader(prop, this.headers[prop]);
2949                     }
2950                 }
2951                 this.headers = {};
2952                 this.hasHeaders = false;
2953             }
2954         },
2955
2956         resetDefaultHeaders:function() {
2957             delete this.defaultHeaders;
2958             this.defaultHeaders = {};
2959             this.hasDefaultHeaders = false;
2960         },
2961
2962         abort:function(o, callback, isTimeout)
2963         {
2964             if(this.isCallInProgress(o)) {
2965                 o.conn.abort();
2966                 window.clearInterval(this.poll[o.tId]);
2967                 delete this.poll[o.tId];
2968                 if (isTimeout) {
2969                     delete this.timeout[o.tId];
2970                 }
2971
2972                 this.handleTransactionResponse(o, callback, true);
2973
2974                 return true;
2975             }
2976             else {
2977                 return false;
2978             }
2979         },
2980
2981
2982         isCallInProgress:function(o)
2983         {
2984             if (o && o.conn) {
2985                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2986             }
2987             else {
2988
2989                 return false;
2990             }
2991         },
2992
2993
2994         releaseObject:function(o)
2995         {
2996
2997             o.conn = null;
2998
2999             o = null;
3000         },
3001
3002         activeX:[
3003         'MSXML2.XMLHTTP.3.0',
3004         'MSXML2.XMLHTTP',
3005         'Microsoft.XMLHTTP'
3006         ]
3007
3008
3009     };
3010 })();/*
3011  * Portions of this file are based on pieces of Yahoo User Interface Library
3012  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3013  * YUI licensed under the BSD License:
3014  * http://developer.yahoo.net/yui/license.txt
3015  * <script type="text/javascript">
3016  *
3017  */
3018
3019 Roo.lib.Region = function(t, r, b, l) {
3020     this.top = t;
3021     this[1] = t;
3022     this.right = r;
3023     this.bottom = b;
3024     this.left = l;
3025     this[0] = l;
3026 };
3027
3028
3029 Roo.lib.Region.prototype = {
3030     contains : function(region) {
3031         return ( region.left >= this.left &&
3032                  region.right <= this.right &&
3033                  region.top >= this.top &&
3034                  region.bottom <= this.bottom    );
3035
3036     },
3037
3038     getArea : function() {
3039         return ( (this.bottom - this.top) * (this.right - this.left) );
3040     },
3041
3042     intersect : function(region) {
3043         var t = Math.max(this.top, region.top);
3044         var r = Math.min(this.right, region.right);
3045         var b = Math.min(this.bottom, region.bottom);
3046         var l = Math.max(this.left, region.left);
3047
3048         if (b >= t && r >= l) {
3049             return new Roo.lib.Region(t, r, b, l);
3050         } else {
3051             return null;
3052         }
3053     },
3054     union : function(region) {
3055         var t = Math.min(this.top, region.top);
3056         var r = Math.max(this.right, region.right);
3057         var b = Math.max(this.bottom, region.bottom);
3058         var l = Math.min(this.left, region.left);
3059
3060         return new Roo.lib.Region(t, r, b, l);
3061     },
3062
3063     adjust : function(t, l, b, r) {
3064         this.top += t;
3065         this.left += l;
3066         this.right += r;
3067         this.bottom += b;
3068         return this;
3069     }
3070 };
3071
3072 Roo.lib.Region.getRegion = function(el) {
3073     var p = Roo.lib.Dom.getXY(el);
3074
3075     var t = p[1];
3076     var r = p[0] + el.offsetWidth;
3077     var b = p[1] + el.offsetHeight;
3078     var l = p[0];
3079
3080     return new Roo.lib.Region(t, r, b, l);
3081 };
3082 /*
3083  * Portions of this file are based on pieces of Yahoo User Interface Library
3084  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3085  * YUI licensed under the BSD License:
3086  * http://developer.yahoo.net/yui/license.txt
3087  * <script type="text/javascript">
3088  *
3089  */
3090 //@@dep Roo.lib.Region
3091
3092
3093 Roo.lib.Point = function(x, y) {
3094     if (x instanceof Array) {
3095         y = x[1];
3096         x = x[0];
3097     }
3098     this.x = this.right = this.left = this[0] = x;
3099     this.y = this.top = this.bottom = this[1] = y;
3100 };
3101
3102 Roo.lib.Point.prototype = new Roo.lib.Region();
3103 /*
3104  * Portions of this file are based on pieces of Yahoo User Interface Library
3105  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3106  * YUI licensed under the BSD License:
3107  * http://developer.yahoo.net/yui/license.txt
3108  * <script type="text/javascript">
3109  *
3110  */
3111  
3112 (function() {   
3113
3114     Roo.lib.Anim = {
3115         scroll : function(el, args, duration, easing, cb, scope) {
3116             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3117         },
3118
3119         motion : function(el, args, duration, easing, cb, scope) {
3120             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3121         },
3122
3123         color : function(el, args, duration, easing, cb, scope) {
3124             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3125         },
3126
3127         run : function(el, args, duration, easing, cb, scope, type) {
3128             type = type || Roo.lib.AnimBase;
3129             if (typeof easing == "string") {
3130                 easing = Roo.lib.Easing[easing];
3131             }
3132             var anim = new type(el, args, duration, easing);
3133             anim.animateX(function() {
3134                 Roo.callback(cb, scope);
3135             });
3136             return anim;
3137         }
3138     };
3139 })();/*
3140  * Portions of this file are based on pieces of Yahoo User Interface Library
3141  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3142  * YUI licensed under the BSD License:
3143  * http://developer.yahoo.net/yui/license.txt
3144  * <script type="text/javascript">
3145  *
3146  */
3147
3148 (function() {    
3149     var libFlyweight;
3150     
3151     function fly(el) {
3152         if (!libFlyweight) {
3153             libFlyweight = new Roo.Element.Flyweight();
3154         }
3155         libFlyweight.dom = el;
3156         return libFlyweight;
3157     }
3158
3159     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3160     
3161    
3162     
3163     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3164         if (el) {
3165             this.init(el, attributes, duration, method);
3166         }
3167     };
3168
3169     Roo.lib.AnimBase.fly = fly;
3170     
3171     
3172     
3173     Roo.lib.AnimBase.prototype = {
3174
3175         toString: function() {
3176             var el = this.getEl();
3177             var id = el.id || el.tagName;
3178             return ("Anim " + id);
3179         },
3180
3181         patterns: {
3182             noNegatives:        /width|height|opacity|padding/i,
3183             offsetAttribute:  /^((width|height)|(top|left))$/,
3184             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3185             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3186         },
3187
3188
3189         doMethod: function(attr, start, end) {
3190             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3191         },
3192
3193
3194         setAttribute: function(attr, val, unit) {
3195             if (this.patterns.noNegatives.test(attr)) {
3196                 val = (val > 0) ? val : 0;
3197             }
3198
3199             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3200         },
3201
3202
3203         getAttribute: function(attr) {
3204             var el = this.getEl();
3205             var val = fly(el).getStyle(attr);
3206
3207             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3208                 return parseFloat(val);
3209             }
3210
3211             var a = this.patterns.offsetAttribute.exec(attr) || [];
3212             var pos = !!( a[3] );
3213             var box = !!( a[2] );
3214
3215
3216             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3217                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3218             } else {
3219                 val = 0;
3220             }
3221
3222             return val;
3223         },
3224
3225
3226         getDefaultUnit: function(attr) {
3227             if (this.patterns.defaultUnit.test(attr)) {
3228                 return 'px';
3229             }
3230
3231             return '';
3232         },
3233
3234         animateX : function(callback, scope) {
3235             var f = function() {
3236                 this.onComplete.removeListener(f);
3237                 if (typeof callback == "function") {
3238                     callback.call(scope || this, this);
3239                 }
3240             };
3241             this.onComplete.addListener(f, this);
3242             this.animate();
3243         },
3244
3245
3246         setRuntimeAttribute: function(attr) {
3247             var start;
3248             var end;
3249             var attributes = this.attributes;
3250
3251             this.runtimeAttributes[attr] = {};
3252
3253             var isset = function(prop) {
3254                 return (typeof prop !== 'undefined');
3255             };
3256
3257             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3258                 return false;
3259             }
3260
3261             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3262
3263
3264             if (isset(attributes[attr]['to'])) {
3265                 end = attributes[attr]['to'];
3266             } else if (isset(attributes[attr]['by'])) {
3267                 if (start.constructor == Array) {
3268                     end = [];
3269                     for (var i = 0, len = start.length; i < len; ++i) {
3270                         end[i] = start[i] + attributes[attr]['by'][i];
3271                     }
3272                 } else {
3273                     end = start + attributes[attr]['by'];
3274                 }
3275             }
3276
3277             this.runtimeAttributes[attr].start = start;
3278             this.runtimeAttributes[attr].end = end;
3279
3280
3281             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3282         },
3283
3284
3285         init: function(el, attributes, duration, method) {
3286
3287             var isAnimated = false;
3288
3289
3290             var startTime = null;
3291
3292
3293             var actualFrames = 0;
3294
3295
3296             el = Roo.getDom(el);
3297
3298
3299             this.attributes = attributes || {};
3300
3301
3302             this.duration = duration || 1;
3303
3304
3305             this.method = method || Roo.lib.Easing.easeNone;
3306
3307
3308             this.useSeconds = true;
3309
3310
3311             this.currentFrame = 0;
3312
3313
3314             this.totalFrames = Roo.lib.AnimMgr.fps;
3315
3316
3317             this.getEl = function() {
3318                 return el;
3319             };
3320
3321
3322             this.isAnimated = function() {
3323                 return isAnimated;
3324             };
3325
3326
3327             this.getStartTime = function() {
3328                 return startTime;
3329             };
3330
3331             this.runtimeAttributes = {};
3332
3333
3334             this.animate = function() {
3335                 if (this.isAnimated()) {
3336                     return false;
3337                 }
3338
3339                 this.currentFrame = 0;
3340
3341                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3342
3343                 Roo.lib.AnimMgr.registerElement(this);
3344             };
3345
3346
3347             this.stop = function(finish) {
3348                 if (finish) {
3349                     this.currentFrame = this.totalFrames;
3350                     this._onTween.fire();
3351                 }
3352                 Roo.lib.AnimMgr.stop(this);
3353             };
3354
3355             var onStart = function() {
3356                 this.onStart.fire();
3357
3358                 this.runtimeAttributes = {};
3359                 for (var attr in this.attributes) {
3360                     this.setRuntimeAttribute(attr);
3361                 }
3362
3363                 isAnimated = true;
3364                 actualFrames = 0;
3365                 startTime = new Date();
3366             };
3367
3368
3369             var onTween = function() {
3370                 var data = {
3371                     duration: new Date() - this.getStartTime(),
3372                     currentFrame: this.currentFrame
3373                 };
3374
3375                 data.toString = function() {
3376                     return (
3377                             'duration: ' + data.duration +
3378                             ', currentFrame: ' + data.currentFrame
3379                             );
3380                 };
3381
3382                 this.onTween.fire(data);
3383
3384                 var runtimeAttributes = this.runtimeAttributes;
3385
3386                 for (var attr in runtimeAttributes) {
3387                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3388                 }
3389
3390                 actualFrames += 1;
3391             };
3392
3393             var onComplete = function() {
3394                 var actual_duration = (new Date() - startTime) / 1000 ;
3395
3396                 var data = {
3397                     duration: actual_duration,
3398                     frames: actualFrames,
3399                     fps: actualFrames / actual_duration
3400                 };
3401
3402                 data.toString = function() {
3403                     return (
3404                             'duration: ' + data.duration +
3405                             ', frames: ' + data.frames +
3406                             ', fps: ' + data.fps
3407                             );
3408                 };
3409
3410                 isAnimated = false;
3411                 actualFrames = 0;
3412                 this.onComplete.fire(data);
3413             };
3414
3415
3416             this._onStart = new Roo.util.Event(this);
3417             this.onStart = new Roo.util.Event(this);
3418             this.onTween = new Roo.util.Event(this);
3419             this._onTween = new Roo.util.Event(this);
3420             this.onComplete = new Roo.util.Event(this);
3421             this._onComplete = new Roo.util.Event(this);
3422             this._onStart.addListener(onStart);
3423             this._onTween.addListener(onTween);
3424             this._onComplete.addListener(onComplete);
3425         }
3426     };
3427 })();
3428 /*
3429  * Portions of this file are based on pieces of Yahoo User Interface Library
3430  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3431  * YUI licensed under the BSD License:
3432  * http://developer.yahoo.net/yui/license.txt
3433  * <script type="text/javascript">
3434  *
3435  */
3436
3437 Roo.lib.AnimMgr = new function() {
3438
3439     var thread = null;
3440
3441
3442     var queue = [];
3443
3444
3445     var tweenCount = 0;
3446
3447
3448     this.fps = 1000;
3449
3450
3451     this.delay = 1;
3452
3453
3454     this.registerElement = function(tween) {
3455         queue[queue.length] = tween;
3456         tweenCount += 1;
3457         tween._onStart.fire();
3458         this.start();
3459     };
3460
3461
3462     this.unRegister = function(tween, index) {
3463         tween._onComplete.fire();
3464         index = index || getIndex(tween);
3465         if (index != -1) {
3466             queue.splice(index, 1);
3467         }
3468
3469         tweenCount -= 1;
3470         if (tweenCount <= 0) {
3471             this.stop();
3472         }
3473     };
3474
3475
3476     this.start = function() {
3477         if (thread === null) {
3478             thread = setInterval(this.run, this.delay);
3479         }
3480     };
3481
3482
3483     this.stop = function(tween) {
3484         if (!tween) {
3485             clearInterval(thread);
3486
3487             for (var i = 0, len = queue.length; i < len; ++i) {
3488                 if (queue[0].isAnimated()) {
3489                     this.unRegister(queue[0], 0);
3490                 }
3491             }
3492
3493             queue = [];
3494             thread = null;
3495             tweenCount = 0;
3496         }
3497         else {
3498             this.unRegister(tween);
3499         }
3500     };
3501
3502
3503     this.run = function() {
3504         for (var i = 0, len = queue.length; i < len; ++i) {
3505             var tween = queue[i];
3506             if (!tween || !tween.isAnimated()) {
3507                 continue;
3508             }
3509
3510             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3511             {
3512                 tween.currentFrame += 1;
3513
3514                 if (tween.useSeconds) {
3515                     correctFrame(tween);
3516                 }
3517                 tween._onTween.fire();
3518             }
3519             else {
3520                 Roo.lib.AnimMgr.stop(tween, i);
3521             }
3522         }
3523     };
3524
3525     var getIndex = function(anim) {
3526         for (var i = 0, len = queue.length; i < len; ++i) {
3527             if (queue[i] == anim) {
3528                 return i;
3529             }
3530         }
3531         return -1;
3532     };
3533
3534
3535     var correctFrame = function(tween) {
3536         var frames = tween.totalFrames;
3537         var frame = tween.currentFrame;
3538         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3539         var elapsed = (new Date() - tween.getStartTime());
3540         var tweak = 0;
3541
3542         if (elapsed < tween.duration * 1000) {
3543             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3544         } else {
3545             tweak = frames - (frame + 1);
3546         }
3547         if (tweak > 0 && isFinite(tweak)) {
3548             if (tween.currentFrame + tweak >= frames) {
3549                 tweak = frames - (frame + 1);
3550             }
3551
3552             tween.currentFrame += tweak;
3553         }
3554     };
3555 };
3556
3557     /*
3558  * Portions of this file are based on pieces of Yahoo User Interface Library
3559  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3560  * YUI licensed under the BSD License:
3561  * http://developer.yahoo.net/yui/license.txt
3562  * <script type="text/javascript">
3563  *
3564  */
3565 Roo.lib.Bezier = new function() {
3566
3567         this.getPosition = function(points, t) {
3568             var n = points.length;
3569             var tmp = [];
3570
3571             for (var i = 0; i < n; ++i) {
3572                 tmp[i] = [points[i][0], points[i][1]];
3573             }
3574
3575             for (var j = 1; j < n; ++j) {
3576                 for (i = 0; i < n - j; ++i) {
3577                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3578                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3579                 }
3580             }
3581
3582             return [ tmp[0][0], tmp[0][1] ];
3583
3584         };
3585     };/*
3586  * Portions of this file are based on pieces of Yahoo User Interface Library
3587  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3588  * YUI licensed under the BSD License:
3589  * http://developer.yahoo.net/yui/license.txt
3590  * <script type="text/javascript">
3591  *
3592  */
3593 (function() {
3594
3595     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3596         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3597     };
3598
3599     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3600
3601     var fly = Roo.lib.AnimBase.fly;
3602     var Y = Roo.lib;
3603     var superclass = Y.ColorAnim.superclass;
3604     var proto = Y.ColorAnim.prototype;
3605
3606     proto.toString = function() {
3607         var el = this.getEl();
3608         var id = el.id || el.tagName;
3609         return ("ColorAnim " + id);
3610     };
3611
3612     proto.patterns.color = /color$/i;
3613     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3614     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3615     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3616     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3617
3618
3619     proto.parseColor = function(s) {
3620         if (s.length == 3) {
3621             return s;
3622         }
3623
3624         var c = this.patterns.hex.exec(s);
3625         if (c && c.length == 4) {
3626             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3627         }
3628
3629         c = this.patterns.rgb.exec(s);
3630         if (c && c.length == 4) {
3631             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3632         }
3633
3634         c = this.patterns.hex3.exec(s);
3635         if (c && c.length == 4) {
3636             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3637         }
3638
3639         return null;
3640     };
3641     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3642     proto.getAttribute = function(attr) {
3643         var el = this.getEl();
3644         if (this.patterns.color.test(attr)) {
3645             var val = fly(el).getStyle(attr);
3646
3647             if (this.patterns.transparent.test(val)) {
3648                 var parent = el.parentNode;
3649                 val = fly(parent).getStyle(attr);
3650
3651                 while (parent && this.patterns.transparent.test(val)) {
3652                     parent = parent.parentNode;
3653                     val = fly(parent).getStyle(attr);
3654                     if (parent.tagName.toUpperCase() == 'HTML') {
3655                         val = '#fff';
3656                     }
3657                 }
3658             }
3659         } else {
3660             val = superclass.getAttribute.call(this, attr);
3661         }
3662
3663         return val;
3664     };
3665     proto.getAttribute = function(attr) {
3666         var el = this.getEl();
3667         if (this.patterns.color.test(attr)) {
3668             var val = fly(el).getStyle(attr);
3669
3670             if (this.patterns.transparent.test(val)) {
3671                 var parent = el.parentNode;
3672                 val = fly(parent).getStyle(attr);
3673
3674                 while (parent && this.patterns.transparent.test(val)) {
3675                     parent = parent.parentNode;
3676                     val = fly(parent).getStyle(attr);
3677                     if (parent.tagName.toUpperCase() == 'HTML') {
3678                         val = '#fff';
3679                     }
3680                 }
3681             }
3682         } else {
3683             val = superclass.getAttribute.call(this, attr);
3684         }
3685
3686         return val;
3687     };
3688
3689     proto.doMethod = function(attr, start, end) {
3690         var val;
3691
3692         if (this.patterns.color.test(attr)) {
3693             val = [];
3694             for (var i = 0, len = start.length; i < len; ++i) {
3695                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3696             }
3697
3698             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3699         }
3700         else {
3701             val = superclass.doMethod.call(this, attr, start, end);
3702         }
3703
3704         return val;
3705     };
3706
3707     proto.setRuntimeAttribute = function(attr) {
3708         superclass.setRuntimeAttribute.call(this, attr);
3709
3710         if (this.patterns.color.test(attr)) {
3711             var attributes = this.attributes;
3712             var start = this.parseColor(this.runtimeAttributes[attr].start);
3713             var end = this.parseColor(this.runtimeAttributes[attr].end);
3714
3715             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3716                 end = this.parseColor(attributes[attr].by);
3717
3718                 for (var i = 0, len = start.length; i < len; ++i) {
3719                     end[i] = start[i] + end[i];
3720                 }
3721             }
3722
3723             this.runtimeAttributes[attr].start = start;
3724             this.runtimeAttributes[attr].end = end;
3725         }
3726     };
3727 })();
3728
3729 /*
3730  * Portions of this file are based on pieces of Yahoo User Interface Library
3731  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3732  * YUI licensed under the BSD License:
3733  * http://developer.yahoo.net/yui/license.txt
3734  * <script type="text/javascript">
3735  *
3736  */
3737 Roo.lib.Easing = {
3738
3739
3740     easeNone: function (t, b, c, d) {
3741         return c * t / d + b;
3742     },
3743
3744
3745     easeIn: function (t, b, c, d) {
3746         return c * (t /= d) * t + b;
3747     },
3748
3749
3750     easeOut: function (t, b, c, d) {
3751         return -c * (t /= d) * (t - 2) + b;
3752     },
3753
3754
3755     easeBoth: function (t, b, c, d) {
3756         if ((t /= d / 2) < 1) {
3757             return c / 2 * t * t + b;
3758         }
3759
3760         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3761     },
3762
3763
3764     easeInStrong: function (t, b, c, d) {
3765         return c * (t /= d) * t * t * t + b;
3766     },
3767
3768
3769     easeOutStrong: function (t, b, c, d) {
3770         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3771     },
3772
3773
3774     easeBothStrong: function (t, b, c, d) {
3775         if ((t /= d / 2) < 1) {
3776             return c / 2 * t * t * t * t + b;
3777         }
3778
3779         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3780     },
3781
3782
3783
3784     elasticIn: function (t, b, c, d, a, p) {
3785         if (t == 0) {
3786             return b;
3787         }
3788         if ((t /= d) == 1) {
3789             return b + c;
3790         }
3791         if (!p) {
3792             p = d * .3;
3793         }
3794
3795         if (!a || a < Math.abs(c)) {
3796             a = c;
3797             var s = p / 4;
3798         }
3799         else {
3800             var s = p / (2 * Math.PI) * Math.asin(c / a);
3801         }
3802
3803         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3804     },
3805
3806
3807     elasticOut: function (t, b, c, d, a, p) {
3808         if (t == 0) {
3809             return b;
3810         }
3811         if ((t /= d) == 1) {
3812             return b + c;
3813         }
3814         if (!p) {
3815             p = d * .3;
3816         }
3817
3818         if (!a || a < Math.abs(c)) {
3819             a = c;
3820             var s = p / 4;
3821         }
3822         else {
3823             var s = p / (2 * Math.PI) * Math.asin(c / a);
3824         }
3825
3826         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3827     },
3828
3829
3830     elasticBoth: function (t, b, c, d, a, p) {
3831         if (t == 0) {
3832             return b;
3833         }
3834
3835         if ((t /= d / 2) == 2) {
3836             return b + c;
3837         }
3838
3839         if (!p) {
3840             p = d * (.3 * 1.5);
3841         }
3842
3843         if (!a || a < Math.abs(c)) {
3844             a = c;
3845             var s = p / 4;
3846         }
3847         else {
3848             var s = p / (2 * Math.PI) * Math.asin(c / a);
3849         }
3850
3851         if (t < 1) {
3852             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3853                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3854         }
3855         return a * Math.pow(2, -10 * (t -= 1)) *
3856                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3857     },
3858
3859
3860
3861     backIn: function (t, b, c, d, s) {
3862         if (typeof s == 'undefined') {
3863             s = 1.70158;
3864         }
3865         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3866     },
3867
3868
3869     backOut: function (t, b, c, d, s) {
3870         if (typeof s == 'undefined') {
3871             s = 1.70158;
3872         }
3873         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3874     },
3875
3876
3877     backBoth: function (t, b, c, d, s) {
3878         if (typeof s == 'undefined') {
3879             s = 1.70158;
3880         }
3881
3882         if ((t /= d / 2 ) < 1) {
3883             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3884         }
3885         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3886     },
3887
3888
3889     bounceIn: function (t, b, c, d) {
3890         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3891     },
3892
3893
3894     bounceOut: function (t, b, c, d) {
3895         if ((t /= d) < (1 / 2.75)) {
3896             return c * (7.5625 * t * t) + b;
3897         } else if (t < (2 / 2.75)) {
3898             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3899         } else if (t < (2.5 / 2.75)) {
3900             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3901         }
3902         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3903     },
3904
3905
3906     bounceBoth: function (t, b, c, d) {
3907         if (t < d / 2) {
3908             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3909         }
3910         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3911     }
3912 };/*
3913  * Portions of this file are based on pieces of Yahoo User Interface Library
3914  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3915  * YUI licensed under the BSD License:
3916  * http://developer.yahoo.net/yui/license.txt
3917  * <script type="text/javascript">
3918  *
3919  */
3920     (function() {
3921         Roo.lib.Motion = function(el, attributes, duration, method) {
3922             if (el) {
3923                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3924             }
3925         };
3926
3927         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3928
3929
3930         var Y = Roo.lib;
3931         var superclass = Y.Motion.superclass;
3932         var proto = Y.Motion.prototype;
3933
3934         proto.toString = function() {
3935             var el = this.getEl();
3936             var id = el.id || el.tagName;
3937             return ("Motion " + id);
3938         };
3939
3940         proto.patterns.points = /^points$/i;
3941
3942         proto.setAttribute = function(attr, val, unit) {
3943             if (this.patterns.points.test(attr)) {
3944                 unit = unit || 'px';
3945                 superclass.setAttribute.call(this, 'left', val[0], unit);
3946                 superclass.setAttribute.call(this, 'top', val[1], unit);
3947             } else {
3948                 superclass.setAttribute.call(this, attr, val, unit);
3949             }
3950         };
3951
3952         proto.getAttribute = function(attr) {
3953             if (this.patterns.points.test(attr)) {
3954                 var val = [
3955                         superclass.getAttribute.call(this, 'left'),
3956                         superclass.getAttribute.call(this, 'top')
3957                         ];
3958             } else {
3959                 val = superclass.getAttribute.call(this, attr);
3960             }
3961
3962             return val;
3963         };
3964
3965         proto.doMethod = function(attr, start, end) {
3966             var val = null;
3967
3968             if (this.patterns.points.test(attr)) {
3969                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3970                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3971             } else {
3972                 val = superclass.doMethod.call(this, attr, start, end);
3973             }
3974             return val;
3975         };
3976
3977         proto.setRuntimeAttribute = function(attr) {
3978             if (this.patterns.points.test(attr)) {
3979                 var el = this.getEl();
3980                 var attributes = this.attributes;
3981                 var start;
3982                 var control = attributes['points']['control'] || [];
3983                 var end;
3984                 var i, len;
3985
3986                 if (control.length > 0 && !(control[0] instanceof Array)) {
3987                     control = [control];
3988                 } else {
3989                     var tmp = [];
3990                     for (i = 0,len = control.length; i < len; ++i) {
3991                         tmp[i] = control[i];
3992                     }
3993                     control = tmp;
3994                 }
3995
3996                 Roo.fly(el).position();
3997
3998                 if (isset(attributes['points']['from'])) {
3999                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4000                 }
4001                 else {
4002                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4003                 }
4004
4005                 start = this.getAttribute('points');
4006
4007
4008                 if (isset(attributes['points']['to'])) {
4009                     end = translateValues.call(this, attributes['points']['to'], start);
4010
4011                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4012                     for (i = 0,len = control.length; i < len; ++i) {
4013                         control[i] = translateValues.call(this, control[i], start);
4014                     }
4015
4016
4017                 } else if (isset(attributes['points']['by'])) {
4018                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4019
4020                     for (i = 0,len = control.length; i < len; ++i) {
4021                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4022                     }
4023                 }
4024
4025                 this.runtimeAttributes[attr] = [start];
4026
4027                 if (control.length > 0) {
4028                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4029                 }
4030
4031                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4032             }
4033             else {
4034                 superclass.setRuntimeAttribute.call(this, attr);
4035             }
4036         };
4037
4038         var translateValues = function(val, start) {
4039             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4040             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4041
4042             return val;
4043         };
4044
4045         var isset = function(prop) {
4046             return (typeof prop !== 'undefined');
4047         };
4048     })();
4049 /*
4050  * Portions of this file are based on pieces of Yahoo User Interface Library
4051  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4052  * YUI licensed under the BSD License:
4053  * http://developer.yahoo.net/yui/license.txt
4054  * <script type="text/javascript">
4055  *
4056  */
4057     (function() {
4058         Roo.lib.Scroll = function(el, attributes, duration, method) {
4059             if (el) {
4060                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4061             }
4062         };
4063
4064         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4065
4066
4067         var Y = Roo.lib;
4068         var superclass = Y.Scroll.superclass;
4069         var proto = Y.Scroll.prototype;
4070
4071         proto.toString = function() {
4072             var el = this.getEl();
4073             var id = el.id || el.tagName;
4074             return ("Scroll " + id);
4075         };
4076
4077         proto.doMethod = function(attr, start, end) {
4078             var val = null;
4079
4080             if (attr == 'scroll') {
4081                 val = [
4082                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4083                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4084                         ];
4085
4086             } else {
4087                 val = superclass.doMethod.call(this, attr, start, end);
4088             }
4089             return val;
4090         };
4091
4092         proto.getAttribute = function(attr) {
4093             var val = null;
4094             var el = this.getEl();
4095
4096             if (attr == 'scroll') {
4097                 val = [ el.scrollLeft, el.scrollTop ];
4098             } else {
4099                 val = superclass.getAttribute.call(this, attr);
4100             }
4101
4102             return val;
4103         };
4104
4105         proto.setAttribute = function(attr, val, unit) {
4106             var el = this.getEl();
4107
4108             if (attr == 'scroll') {
4109                 el.scrollLeft = val[0];
4110                 el.scrollTop = val[1];
4111             } else {
4112                 superclass.setAttribute.call(this, attr, val, unit);
4113             }
4114         };
4115     })();
4116 /*
4117  * Based on:
4118  * Ext JS Library 1.1.1
4119  * Copyright(c) 2006-2007, Ext JS, LLC.
4120  *
4121  * Originally Released Under LGPL - original licence link has changed is not relivant.
4122  *
4123  * Fork - LGPL
4124  * <script type="text/javascript">
4125  */
4126
4127
4128 // nasty IE9 hack - what a pile of crap that is..
4129
4130  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4131     Range.prototype.createContextualFragment = function (html) {
4132         var doc = window.document;
4133         var container = doc.createElement("div");
4134         container.innerHTML = html;
4135         var frag = doc.createDocumentFragment(), n;
4136         while ((n = container.firstChild)) {
4137             frag.appendChild(n);
4138         }
4139         return frag;
4140     };
4141 }
4142
4143 /**
4144  * @class Roo.DomHelper
4145  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4146  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4147  * @singleton
4148  */
4149 Roo.DomHelper = function(){
4150     var tempTableEl = null;
4151     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4152     var tableRe = /^table|tbody|tr|td$/i;
4153     var xmlns = {};
4154     // build as innerHTML where available
4155     /** @ignore */
4156     var createHtml = function(o){
4157         if(typeof o == 'string'){
4158             return o;
4159         }
4160         var b = "";
4161         if(!o.tag){
4162             o.tag = "div";
4163         }
4164         b += "<" + o.tag;
4165         for(var attr in o){
4166             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4167             if(attr == "style"){
4168                 var s = o["style"];
4169                 if(typeof s == "function"){
4170                     s = s.call();
4171                 }
4172                 if(typeof s == "string"){
4173                     b += ' style="' + s + '"';
4174                 }else if(typeof s == "object"){
4175                     b += ' style="';
4176                     for(var key in s){
4177                         if(typeof s[key] != "function"){
4178                             b += key + ":" + s[key] + ";";
4179                         }
4180                     }
4181                     b += '"';
4182                 }
4183             }else{
4184                 if(attr == "cls"){
4185                     b += ' class="' + o["cls"] + '"';
4186                 }else if(attr == "htmlFor"){
4187                     b += ' for="' + o["htmlFor"] + '"';
4188                 }else{
4189                     b += " " + attr + '="' + o[attr] + '"';
4190                 }
4191             }
4192         }
4193         if(emptyTags.test(o.tag)){
4194             b += "/>";
4195         }else{
4196             b += ">";
4197             var cn = o.children || o.cn;
4198             if(cn){
4199                 //http://bugs.kde.org/show_bug.cgi?id=71506
4200                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4201                     for(var i = 0, len = cn.length; i < len; i++) {
4202                         b += createHtml(cn[i], b);
4203                     }
4204                 }else{
4205                     b += createHtml(cn, b);
4206                 }
4207             }
4208             if(o.html){
4209                 b += o.html;
4210             }
4211             b += "</" + o.tag + ">";
4212         }
4213         return b;
4214     };
4215
4216     // build as dom
4217     /** @ignore */
4218     var createDom = function(o, parentNode){
4219          
4220         // defininition craeted..
4221         var ns = false;
4222         if (o.ns && o.ns != 'html') {
4223                
4224             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4225                 xmlns[o.ns] = o.xmlns;
4226                 ns = o.xmlns;
4227             }
4228             if (typeof(xmlns[o.ns]) == 'undefined') {
4229                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4230             }
4231             ns = xmlns[o.ns];
4232         }
4233         
4234         
4235         if (typeof(o) == 'string') {
4236             return parentNode.appendChild(document.createTextNode(o));
4237         }
4238         o.tag = o.tag || div;
4239         if (o.ns && Roo.isIE) {
4240             ns = false;
4241             o.tag = o.ns + ':' + o.tag;
4242             
4243         }
4244         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4245         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4246         for(var attr in o){
4247             
4248             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4249                     attr == "style" || typeof o[attr] == "function") { continue; }
4250                     
4251             if(attr=="cls" && Roo.isIE){
4252                 el.className = o["cls"];
4253             }else{
4254                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4255                 else { 
4256                     el[attr] = o[attr];
4257                 }
4258             }
4259         }
4260         Roo.DomHelper.applyStyles(el, o.style);
4261         var cn = o.children || o.cn;
4262         if(cn){
4263             //http://bugs.kde.org/show_bug.cgi?id=71506
4264              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4265                 for(var i = 0, len = cn.length; i < len; i++) {
4266                     createDom(cn[i], el);
4267                 }
4268             }else{
4269                 createDom(cn, el);
4270             }
4271         }
4272         if(o.html){
4273             el.innerHTML = o.html;
4274         }
4275         if(parentNode){
4276            parentNode.appendChild(el);
4277         }
4278         return el;
4279     };
4280
4281     var ieTable = function(depth, s, h, e){
4282         tempTableEl.innerHTML = [s, h, e].join('');
4283         var i = -1, el = tempTableEl;
4284         while(++i < depth){
4285             el = el.firstChild;
4286         }
4287         return el;
4288     };
4289
4290     // kill repeat to save bytes
4291     var ts = '<table>',
4292         te = '</table>',
4293         tbs = ts+'<tbody>',
4294         tbe = '</tbody>'+te,
4295         trs = tbs + '<tr>',
4296         tre = '</tr>'+tbe;
4297
4298     /**
4299      * @ignore
4300      * Nasty code for IE's broken table implementation
4301      */
4302     var insertIntoTable = function(tag, where, el, html){
4303         if(!tempTableEl){
4304             tempTableEl = document.createElement('div');
4305         }
4306         var node;
4307         var before = null;
4308         if(tag == 'td'){
4309             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4310                 return;
4311             }
4312             if(where == 'beforebegin'){
4313                 before = el;
4314                 el = el.parentNode;
4315             } else{
4316                 before = el.nextSibling;
4317                 el = el.parentNode;
4318             }
4319             node = ieTable(4, trs, html, tre);
4320         }
4321         else if(tag == 'tr'){
4322             if(where == 'beforebegin'){
4323                 before = el;
4324                 el = el.parentNode;
4325                 node = ieTable(3, tbs, html, tbe);
4326             } else if(where == 'afterend'){
4327                 before = el.nextSibling;
4328                 el = el.parentNode;
4329                 node = ieTable(3, tbs, html, tbe);
4330             } else{ // INTO a TR
4331                 if(where == 'afterbegin'){
4332                     before = el.firstChild;
4333                 }
4334                 node = ieTable(4, trs, html, tre);
4335             }
4336         } else if(tag == 'tbody'){
4337             if(where == 'beforebegin'){
4338                 before = el;
4339                 el = el.parentNode;
4340                 node = ieTable(2, ts, html, te);
4341             } else if(where == 'afterend'){
4342                 before = el.nextSibling;
4343                 el = el.parentNode;
4344                 node = ieTable(2, ts, html, te);
4345             } else{
4346                 if(where == 'afterbegin'){
4347                     before = el.firstChild;
4348                 }
4349                 node = ieTable(3, tbs, html, tbe);
4350             }
4351         } else{ // TABLE
4352             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4353                 return;
4354             }
4355             if(where == 'afterbegin'){
4356                 before = el.firstChild;
4357             }
4358             node = ieTable(2, ts, html, te);
4359         }
4360         el.insertBefore(node, before);
4361         return node;
4362     };
4363
4364     return {
4365     /** True to force the use of DOM instead of html fragments @type Boolean */
4366     useDom : false,
4367
4368     /**
4369      * Returns the markup for the passed Element(s) config
4370      * @param {Object} o The Dom object spec (and children)
4371      * @return {String}
4372      */
4373     markup : function(o){
4374         return createHtml(o);
4375     },
4376
4377     /**
4378      * Applies a style specification to an element
4379      * @param {String/HTMLElement} el The element to apply styles to
4380      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4381      * a function which returns such a specification.
4382      */
4383     applyStyles : function(el, styles){
4384         if(styles){
4385            el = Roo.fly(el);
4386            if(typeof styles == "string"){
4387                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4388                var matches;
4389                while ((matches = re.exec(styles)) != null){
4390                    el.setStyle(matches[1], matches[2]);
4391                }
4392            }else if (typeof styles == "object"){
4393                for (var style in styles){
4394                   el.setStyle(style, styles[style]);
4395                }
4396            }else if (typeof styles == "function"){
4397                 Roo.DomHelper.applyStyles(el, styles.call());
4398            }
4399         }
4400     },
4401
4402     /**
4403      * Inserts an HTML fragment into the Dom
4404      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4405      * @param {HTMLElement} el The context element
4406      * @param {String} html The HTML fragmenet
4407      * @return {HTMLElement} The new node
4408      */
4409     insertHtml : function(where, el, html){
4410         where = where.toLowerCase();
4411         if(el.insertAdjacentHTML){
4412             if(tableRe.test(el.tagName)){
4413                 var rs;
4414                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4415                     return rs;
4416                 }
4417             }
4418             switch(where){
4419                 case "beforebegin":
4420                     el.insertAdjacentHTML('BeforeBegin', html);
4421                     return el.previousSibling;
4422                 case "afterbegin":
4423                     el.insertAdjacentHTML('AfterBegin', html);
4424                     return el.firstChild;
4425                 case "beforeend":
4426                     el.insertAdjacentHTML('BeforeEnd', html);
4427                     return el.lastChild;
4428                 case "afterend":
4429                     el.insertAdjacentHTML('AfterEnd', html);
4430                     return el.nextSibling;
4431             }
4432             throw 'Illegal insertion point -> "' + where + '"';
4433         }
4434         var range = el.ownerDocument.createRange();
4435         var frag;
4436         switch(where){
4437              case "beforebegin":
4438                 range.setStartBefore(el);
4439                 frag = range.createContextualFragment(html);
4440                 el.parentNode.insertBefore(frag, el);
4441                 return el.previousSibling;
4442              case "afterbegin":
4443                 if(el.firstChild){
4444                     range.setStartBefore(el.firstChild);
4445                     frag = range.createContextualFragment(html);
4446                     el.insertBefore(frag, el.firstChild);
4447                     return el.firstChild;
4448                 }else{
4449                     el.innerHTML = html;
4450                     return el.firstChild;
4451                 }
4452             case "beforeend":
4453                 if(el.lastChild){
4454                     range.setStartAfter(el.lastChild);
4455                     frag = range.createContextualFragment(html);
4456                     el.appendChild(frag);
4457                     return el.lastChild;
4458                 }else{
4459                     el.innerHTML = html;
4460                     return el.lastChild;
4461                 }
4462             case "afterend":
4463                 range.setStartAfter(el);
4464                 frag = range.createContextualFragment(html);
4465                 el.parentNode.insertBefore(frag, el.nextSibling);
4466                 return el.nextSibling;
4467             }
4468             throw 'Illegal insertion point -> "' + where + '"';
4469     },
4470
4471     /**
4472      * Creates new Dom element(s) and inserts them before el
4473      * @param {String/HTMLElement/Element} el The context element
4474      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4475      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4476      * @return {HTMLElement/Roo.Element} The new node
4477      */
4478     insertBefore : function(el, o, returnElement){
4479         return this.doInsert(el, o, returnElement, "beforeBegin");
4480     },
4481
4482     /**
4483      * Creates new Dom element(s) and inserts them after el
4484      * @param {String/HTMLElement/Element} el The context element
4485      * @param {Object} o The Dom object spec (and children)
4486      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4487      * @return {HTMLElement/Roo.Element} The new node
4488      */
4489     insertAfter : function(el, o, returnElement){
4490         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4491     },
4492
4493     /**
4494      * Creates new Dom element(s) and inserts them as the first child of el
4495      * @param {String/HTMLElement/Element} el The context element
4496      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4497      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4498      * @return {HTMLElement/Roo.Element} The new node
4499      */
4500     insertFirst : function(el, o, returnElement){
4501         return this.doInsert(el, o, returnElement, "afterBegin");
4502     },
4503
4504     // private
4505     doInsert : function(el, o, returnElement, pos, sibling){
4506         el = Roo.getDom(el);
4507         var newNode;
4508         if(this.useDom || o.ns){
4509             newNode = createDom(o, null);
4510             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4511         }else{
4512             var html = createHtml(o);
4513             newNode = this.insertHtml(pos, el, html);
4514         }
4515         return returnElement ? Roo.get(newNode, true) : newNode;
4516     },
4517
4518     /**
4519      * Creates new Dom element(s) and appends them to el
4520      * @param {String/HTMLElement/Element} el The context element
4521      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4522      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4523      * @return {HTMLElement/Roo.Element} The new node
4524      */
4525     append : function(el, o, returnElement){
4526         el = Roo.getDom(el);
4527         var newNode;
4528         if(this.useDom || o.ns){
4529             newNode = createDom(o, null);
4530             el.appendChild(newNode);
4531         }else{
4532             var html = createHtml(o);
4533             newNode = this.insertHtml("beforeEnd", el, html);
4534         }
4535         return returnElement ? Roo.get(newNode, true) : newNode;
4536     },
4537
4538     /**
4539      * Creates new Dom element(s) and overwrites the contents of el with them
4540      * @param {String/HTMLElement/Element} el The context element
4541      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4542      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4543      * @return {HTMLElement/Roo.Element} The new node
4544      */
4545     overwrite : function(el, o, returnElement){
4546         el = Roo.getDom(el);
4547         if (o.ns) {
4548           
4549             while (el.childNodes.length) {
4550                 el.removeChild(el.firstChild);
4551             }
4552             createDom(o, el);
4553         } else {
4554             el.innerHTML = createHtml(o);   
4555         }
4556         
4557         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4558     },
4559
4560     /**
4561      * Creates a new Roo.DomHelper.Template from the Dom object spec
4562      * @param {Object} o The Dom object spec (and children)
4563      * @return {Roo.DomHelper.Template} The new template
4564      */
4565     createTemplate : function(o){
4566         var html = createHtml(o);
4567         return new Roo.Template(html);
4568     }
4569     };
4570 }();
4571 /*
4572  * Based on:
4573  * Ext JS Library 1.1.1
4574  * Copyright(c) 2006-2007, Ext JS, LLC.
4575  *
4576  * Originally Released Under LGPL - original licence link has changed is not relivant.
4577  *
4578  * Fork - LGPL
4579  * <script type="text/javascript">
4580  */
4581  
4582 /**
4583 * @class Roo.Template
4584 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4585 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4586 * Usage:
4587 <pre><code>
4588 var t = new Roo.Template({
4589     html :  '&lt;div name="{id}"&gt;' + 
4590         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4591         '&lt;/div&gt;',
4592     myformat: function (value, allValues) {
4593         return 'XX' + value;
4594     }
4595 });
4596 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4597 </code></pre>
4598 * For more information see this blog post with examples:
4599 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4600      - Create Elements using DOM, HTML fragments and Templates</a>. 
4601 * @constructor
4602 * @param {Object} cfg - Configuration object.
4603 */
4604 Roo.Template = function(cfg){
4605     // BC!
4606     if(cfg instanceof Array){
4607         cfg = cfg.join("");
4608     }else if(arguments.length > 1){
4609         cfg = Array.prototype.join.call(arguments, "");
4610     }
4611     
4612     
4613     if (typeof(cfg) == 'object') {
4614         Roo.apply(this,cfg)
4615     } else {
4616         // bc
4617         this.html = cfg;
4618     }
4619     if (this.url) {
4620         this.load();
4621     }
4622     
4623 };
4624 Roo.Template.prototype = {
4625     
4626     /**
4627      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4628      *                    it should be fixed so that template is observable...
4629      */
4630     url : false,
4631     /**
4632      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4633      */
4634     html : '',
4635     /**
4636      * Returns an HTML fragment of this template with the specified values applied.
4637      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4638      * @return {String} The HTML fragment
4639      */
4640     applyTemplate : function(values){
4641         try {
4642            
4643             if(this.compiled){
4644                 return this.compiled(values);
4645             }
4646             var useF = this.disableFormats !== true;
4647             var fm = Roo.util.Format, tpl = this;
4648             var fn = function(m, name, format, args){
4649                 if(format && useF){
4650                     if(format.substr(0, 5) == "this."){
4651                         return tpl.call(format.substr(5), values[name], values);
4652                     }else{
4653                         if(args){
4654                             // quoted values are required for strings in compiled templates, 
4655                             // but for non compiled we need to strip them
4656                             // quoted reversed for jsmin
4657                             var re = /^\s*['"](.*)["']\s*$/;
4658                             args = args.split(',');
4659                             for(var i = 0, len = args.length; i < len; i++){
4660                                 args[i] = args[i].replace(re, "$1");
4661                             }
4662                             args = [values[name]].concat(args);
4663                         }else{
4664                             args = [values[name]];
4665                         }
4666                         return fm[format].apply(fm, args);
4667                     }
4668                 }else{
4669                     return values[name] !== undefined ? values[name] : "";
4670                 }
4671             };
4672             return this.html.replace(this.re, fn);
4673         } catch (e) {
4674             Roo.log(e);
4675             throw e;
4676         }
4677          
4678     },
4679     
4680     loading : false,
4681       
4682     load : function ()
4683     {
4684          
4685         if (this.loading) {
4686             return;
4687         }
4688         var _t = this;
4689         
4690         this.loading = true;
4691         this.compiled = false;
4692         
4693         var cx = new Roo.data.Connection();
4694         cx.request({
4695             url : this.url,
4696             method : 'GET',
4697             success : function (response) {
4698                 _t.loading = false;
4699                 _t.html = response.responseText;
4700                 _t.url = false;
4701                 _t.compile();
4702              },
4703             failure : function(response) {
4704                 Roo.log("Template failed to load from " + _t.url);
4705                 _t.loading = false;
4706             }
4707         });
4708     },
4709
4710     /**
4711      * Sets the HTML used as the template and optionally compiles it.
4712      * @param {String} html
4713      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4714      * @return {Roo.Template} this
4715      */
4716     set : function(html, compile){
4717         this.html = html;
4718         this.compiled = null;
4719         if(compile){
4720             this.compile();
4721         }
4722         return this;
4723     },
4724     
4725     /**
4726      * True to disable format functions (defaults to false)
4727      * @type Boolean
4728      */
4729     disableFormats : false,
4730     
4731     /**
4732     * The regular expression used to match template variables 
4733     * @type RegExp
4734     * @property 
4735     */
4736     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4737     
4738     /**
4739      * Compiles the template into an internal function, eliminating the RegEx overhead.
4740      * @return {Roo.Template} this
4741      */
4742     compile : function(){
4743         var fm = Roo.util.Format;
4744         var useF = this.disableFormats !== true;
4745         var sep = Roo.isGecko ? "+" : ",";
4746         var fn = function(m, name, format, args){
4747             if(format && useF){
4748                 args = args ? ',' + args : "";
4749                 if(format.substr(0, 5) != "this."){
4750                     format = "fm." + format + '(';
4751                 }else{
4752                     format = 'this.call("'+ format.substr(5) + '", ';
4753                     args = ", values";
4754                 }
4755             }else{
4756                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4757             }
4758             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4759         };
4760         var body;
4761         // branched to use + in gecko and [].join() in others
4762         if(Roo.isGecko){
4763             body = "this.compiled = function(values){ return '" +
4764                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4765                     "';};";
4766         }else{
4767             body = ["this.compiled = function(values){ return ['"];
4768             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4769             body.push("'].join('');};");
4770             body = body.join('');
4771         }
4772         /**
4773          * eval:var:values
4774          * eval:var:fm
4775          */
4776         eval(body);
4777         return this;
4778     },
4779     
4780     // private function used to call members
4781     call : function(fnName, value, allValues){
4782         return this[fnName](value, allValues);
4783     },
4784     
4785     /**
4786      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4787      * @param {String/HTMLElement/Roo.Element} el The context element
4788      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4789      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4790      * @return {HTMLElement/Roo.Element} The new node or Element
4791      */
4792     insertFirst: function(el, values, returnElement){
4793         return this.doInsert('afterBegin', el, values, returnElement);
4794     },
4795
4796     /**
4797      * Applies the supplied values to the template and inserts the new node(s) before el.
4798      * @param {String/HTMLElement/Roo.Element} el The context element
4799      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4800      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4801      * @return {HTMLElement/Roo.Element} The new node or Element
4802      */
4803     insertBefore: function(el, values, returnElement){
4804         return this.doInsert('beforeBegin', el, values, returnElement);
4805     },
4806
4807     /**
4808      * Applies the supplied values to the template and inserts the new node(s) after el.
4809      * @param {String/HTMLElement/Roo.Element} el The context element
4810      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4811      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4812      * @return {HTMLElement/Roo.Element} The new node or Element
4813      */
4814     insertAfter : function(el, values, returnElement){
4815         return this.doInsert('afterEnd', el, values, returnElement);
4816     },
4817     
4818     /**
4819      * Applies the supplied values to the template and appends the new node(s) to el.
4820      * @param {String/HTMLElement/Roo.Element} el The context element
4821      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4822      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4823      * @return {HTMLElement/Roo.Element} The new node or Element
4824      */
4825     append : function(el, values, returnElement){
4826         return this.doInsert('beforeEnd', el, values, returnElement);
4827     },
4828
4829     doInsert : function(where, el, values, returnEl){
4830         el = Roo.getDom(el);
4831         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4832         return returnEl ? Roo.get(newNode, true) : newNode;
4833     },
4834
4835     /**
4836      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4837      * @param {String/HTMLElement/Roo.Element} el The context element
4838      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4839      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4840      * @return {HTMLElement/Roo.Element} The new node or Element
4841      */
4842     overwrite : function(el, values, returnElement){
4843         el = Roo.getDom(el);
4844         el.innerHTML = this.applyTemplate(values);
4845         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4846     }
4847 };
4848 /**
4849  * Alias for {@link #applyTemplate}
4850  * @method
4851  */
4852 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4853
4854 // backwards compat
4855 Roo.DomHelper.Template = Roo.Template;
4856
4857 /**
4858  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4859  * @param {String/HTMLElement} el A DOM element or its id
4860  * @returns {Roo.Template} The created template
4861  * @static
4862  */
4863 Roo.Template.from = function(el){
4864     el = Roo.getDom(el);
4865     return new Roo.Template(el.value || el.innerHTML);
4866 };/*
4867  * Based on:
4868  * Ext JS Library 1.1.1
4869  * Copyright(c) 2006-2007, Ext JS, LLC.
4870  *
4871  * Originally Released Under LGPL - original licence link has changed is not relivant.
4872  *
4873  * Fork - LGPL
4874  * <script type="text/javascript">
4875  */
4876  
4877
4878 /*
4879  * This is code is also distributed under MIT license for use
4880  * with jQuery and prototype JavaScript libraries.
4881  */
4882 /**
4883  * @class Roo.DomQuery
4884 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4885 <p>
4886 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4887
4888 <p>
4889 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4890 </p>
4891 <h4>Element Selectors:</h4>
4892 <ul class="list">
4893     <li> <b>*</b> any element</li>
4894     <li> <b>E</b> an element with the tag E</li>
4895     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4896     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4897     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4898     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4899 </ul>
4900 <h4>Attribute Selectors:</h4>
4901 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4902 <ul class="list">
4903     <li> <b>E[foo]</b> has an attribute "foo"</li>
4904     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4905     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4906     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4907     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4908     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4909     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4910 </ul>
4911 <h4>Pseudo Classes:</h4>
4912 <ul class="list">
4913     <li> <b>E:first-child</b> E is the first child of its parent</li>
4914     <li> <b>E:last-child</b> E is the last child of its parent</li>
4915     <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4916     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4917     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4918     <li> <b>E:only-child</b> E is the only child of its parent</li>
4919     <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4920     <li> <b>E:first</b> the first E in the resultset</li>
4921     <li> <b>E:last</b> the last E in the resultset</li>
4922     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4923     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4924     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4925     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4926     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4927     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4928     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4929     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4930     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4931 </ul>
4932 <h4>CSS Value Selectors:</h4>
4933 <ul class="list">
4934     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4935     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4936     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4937     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4938     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4939     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4940 </ul>
4941  * @singleton
4942  */
4943 Roo.DomQuery = function(){
4944     var cache = {}, simpleCache = {}, valueCache = {};
4945     var nonSpace = /\S/;
4946     var trimRe = /^\s+|\s+$/g;
4947     var tplRe = /\{(\d+)\}/g;
4948     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4949     var tagTokenRe = /^(#)?([\w-\*]+)/;
4950     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4951
4952     function child(p, index){
4953         var i = 0;
4954         var n = p.firstChild;
4955         while(n){
4956             if(n.nodeType == 1){
4957                if(++i == index){
4958                    return n;
4959                }
4960             }
4961             n = n.nextSibling;
4962         }
4963         return null;
4964     };
4965
4966     function next(n){
4967         while((n = n.nextSibling) && n.nodeType != 1);
4968         return n;
4969     };
4970
4971     function prev(n){
4972         while((n = n.previousSibling) && n.nodeType != 1);
4973         return n;
4974     };
4975
4976     function children(d){
4977         var n = d.firstChild, ni = -1;
4978             while(n){
4979                 var nx = n.nextSibling;
4980                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4981                     d.removeChild(n);
4982                 }else{
4983                     n.nodeIndex = ++ni;
4984                 }
4985                 n = nx;
4986             }
4987             return this;
4988         };
4989
4990     function byClassName(c, a, v){
4991         if(!v){
4992             return c;
4993         }
4994         var r = [], ri = -1, cn;
4995         for(var i = 0, ci; ci = c[i]; i++){
4996             if((' '+ci.className+' ').indexOf(v) != -1){
4997                 r[++ri] = ci;
4998             }
4999         }
5000         return r;
5001     };
5002
5003     function attrValue(n, attr){
5004         if(!n.tagName && typeof n.length != "undefined"){
5005             n = n[0];
5006         }
5007         if(!n){
5008             return null;
5009         }
5010         if(attr == "for"){
5011             return n.htmlFor;
5012         }
5013         if(attr == "class" || attr == "className"){
5014             return n.className;
5015         }
5016         return n.getAttribute(attr) || n[attr];
5017
5018     };
5019
5020     function getNodes(ns, mode, tagName){
5021         var result = [], ri = -1, cs;
5022         if(!ns){
5023             return result;
5024         }
5025         tagName = tagName || "*";
5026         if(typeof ns.getElementsByTagName != "undefined"){
5027             ns = [ns];
5028         }
5029         if(!mode){
5030             for(var i = 0, ni; ni = ns[i]; i++){
5031                 cs = ni.getElementsByTagName(tagName);
5032                 for(var j = 0, ci; ci = cs[j]; j++){
5033                     result[++ri] = ci;
5034                 }
5035             }
5036         }else if(mode == "/" || mode == ">"){
5037             var utag = tagName.toUpperCase();
5038             for(var i = 0, ni, cn; ni = ns[i]; i++){
5039                 cn = ni.children || ni.childNodes;
5040                 for(var j = 0, cj; cj = cn[j]; j++){
5041                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5042                         result[++ri] = cj;
5043                     }
5044                 }
5045             }
5046         }else if(mode == "+"){
5047             var utag = tagName.toUpperCase();
5048             for(var i = 0, n; n = ns[i]; i++){
5049                 while((n = n.nextSibling) && n.nodeType != 1);
5050                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5051                     result[++ri] = n;
5052                 }
5053             }
5054         }else if(mode == "~"){
5055             for(var i = 0, n; n = ns[i]; i++){
5056                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5057                 if(n){
5058                     result[++ri] = n;
5059                 }
5060             }
5061         }
5062         return result;
5063     };
5064
5065     function concat(a, b){
5066         if(b.slice){
5067             return a.concat(b);
5068         }
5069         for(var i = 0, l = b.length; i < l; i++){
5070             a[a.length] = b[i];
5071         }
5072         return a;
5073     }
5074
5075     function byTag(cs, tagName){
5076         if(cs.tagName || cs == document){
5077             cs = [cs];
5078         }
5079         if(!tagName){
5080             return cs;
5081         }
5082         var r = [], ri = -1;
5083         tagName = tagName.toLowerCase();
5084         for(var i = 0, ci; ci = cs[i]; i++){
5085             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5086                 r[++ri] = ci;
5087             }
5088         }
5089         return r;
5090     };
5091
5092     function byId(cs, attr, id){
5093         if(cs.tagName || cs == document){
5094             cs = [cs];
5095         }
5096         if(!id){
5097             return cs;
5098         }
5099         var r = [], ri = -1;
5100         for(var i = 0,ci; ci = cs[i]; i++){
5101             if(ci && ci.id == id){
5102                 r[++ri] = ci;
5103                 return r;
5104             }
5105         }
5106         return r;
5107     };
5108
5109     function byAttribute(cs, attr, value, op, custom){
5110         var r = [], ri = -1, st = custom=="{";
5111         var f = Roo.DomQuery.operators[op];
5112         for(var i = 0, ci; ci = cs[i]; i++){
5113             var a;
5114             if(st){
5115                 a = Roo.DomQuery.getStyle(ci, attr);
5116             }
5117             else if(attr == "class" || attr == "className"){
5118                 a = ci.className;
5119             }else if(attr == "for"){
5120                 a = ci.htmlFor;
5121             }else if(attr == "href"){
5122                 a = ci.getAttribute("href", 2);
5123             }else{
5124                 a = ci.getAttribute(attr);
5125             }
5126             if((f && f(a, value)) || (!f && a)){
5127                 r[++ri] = ci;
5128             }
5129         }
5130         return r;
5131     };
5132
5133     function byPseudo(cs, name, value){
5134         return Roo.DomQuery.pseudos[name](cs, value);
5135     };
5136
5137     // This is for IE MSXML which does not support expandos.
5138     // IE runs the same speed using setAttribute, however FF slows way down
5139     // and Safari completely fails so they need to continue to use expandos.
5140     var isIE = window.ActiveXObject ? true : false;
5141
5142     // this eval is stop the compressor from
5143     // renaming the variable to something shorter
5144     
5145     /** eval:var:batch */
5146     var batch = 30803; 
5147
5148     var key = 30803;
5149
5150     function nodupIEXml(cs){
5151         var d = ++key;
5152         cs[0].setAttribute("_nodup", d);
5153         var r = [cs[0]];
5154         for(var i = 1, len = cs.length; i < len; i++){
5155             var c = cs[i];
5156             if(!c.getAttribute("_nodup") != d){
5157                 c.setAttribute("_nodup", d);
5158                 r[r.length] = c;
5159             }
5160         }
5161         for(var i = 0, len = cs.length; i < len; i++){
5162             cs[i].removeAttribute("_nodup");
5163         }
5164         return r;
5165     }
5166
5167     function nodup(cs){
5168         if(!cs){
5169             return [];
5170         }
5171         var len = cs.length, c, i, r = cs, cj, ri = -1;
5172         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5173             return cs;
5174         }
5175         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5176             return nodupIEXml(cs);
5177         }
5178         var d = ++key;
5179         cs[0]._nodup = d;
5180         for(i = 1; c = cs[i]; i++){
5181             if(c._nodup != d){
5182                 c._nodup = d;
5183             }else{
5184                 r = [];
5185                 for(var j = 0; j < i; j++){
5186                     r[++ri] = cs[j];
5187                 }
5188                 for(j = i+1; cj = cs[j]; j++){
5189                     if(cj._nodup != d){
5190                         cj._nodup = d;
5191                         r[++ri] = cj;
5192                     }
5193                 }
5194                 return r;
5195             }
5196         }
5197         return r;
5198     }
5199
5200     function quickDiffIEXml(c1, c2){
5201         var d = ++key;
5202         for(var i = 0, len = c1.length; i < len; i++){
5203             c1[i].setAttribute("_qdiff", d);
5204         }
5205         var r = [];
5206         for(var i = 0, len = c2.length; i < len; i++){
5207             if(c2[i].getAttribute("_qdiff") != d){
5208                 r[r.length] = c2[i];
5209             }
5210         }
5211         for(var i = 0, len = c1.length; i < len; i++){
5212            c1[i].removeAttribute("_qdiff");
5213         }
5214         return r;
5215     }
5216
5217     function quickDiff(c1, c2){
5218         var len1 = c1.length;
5219         if(!len1){
5220             return c2;
5221         }
5222         if(isIE && c1[0].selectSingleNode){
5223             return quickDiffIEXml(c1, c2);
5224         }
5225         var d = ++key;
5226         for(var i = 0; i < len1; i++){
5227             c1[i]._qdiff = d;
5228         }
5229         var r = [];
5230         for(var i = 0, len = c2.length; i < len; i++){
5231             if(c2[i]._qdiff != d){
5232                 r[r.length] = c2[i];
5233             }
5234         }
5235         return r;
5236     }
5237
5238     function quickId(ns, mode, root, id){
5239         if(ns == root){
5240            var d = root.ownerDocument || root;
5241            return d.getElementById(id);
5242         }
5243         ns = getNodes(ns, mode, "*");
5244         return byId(ns, null, id);
5245     }
5246
5247     return {
5248         getStyle : function(el, name){
5249             return Roo.fly(el).getStyle(name);
5250         },
5251         /**
5252          * Compiles a selector/xpath query into a reusable function. The returned function
5253          * takes one parameter "root" (optional), which is the context node from where the query should start.
5254          * @param {String} selector The selector/xpath query
5255          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5256          * @return {Function}
5257          */
5258         compile : function(path, type){
5259             type = type || "select";
5260             
5261             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5262             var q = path, mode, lq;
5263             var tk = Roo.DomQuery.matchers;
5264             var tklen = tk.length;
5265             var mm;
5266
5267             // accept leading mode switch
5268             var lmode = q.match(modeRe);
5269             if(lmode && lmode[1]){
5270                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5271                 q = q.replace(lmode[1], "");
5272             }
5273             // strip leading slashes
5274             while(path.substr(0, 1)=="/"){
5275                 path = path.substr(1);
5276             }
5277
5278             while(q && lq != q){
5279                 lq = q;
5280                 var tm = q.match(tagTokenRe);
5281                 if(type == "select"){
5282                     if(tm){
5283                         if(tm[1] == "#"){
5284                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5285                         }else{
5286                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5287                         }
5288                         q = q.replace(tm[0], "");
5289                     }else if(q.substr(0, 1) != '@'){
5290                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5291                     }
5292                 }else{
5293                     if(tm){
5294                         if(tm[1] == "#"){
5295                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5296                         }else{
5297                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5298                         }
5299                         q = q.replace(tm[0], "");
5300                     }
5301                 }
5302                 while(!(mm = q.match(modeRe))){
5303                     var matched = false;
5304                     for(var j = 0; j < tklen; j++){
5305                         var t = tk[j];
5306                         var m = q.match(t.re);
5307                         if(m){
5308                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5309                                                     return m[i];
5310                                                 });
5311                             q = q.replace(m[0], "");
5312                             matched = true;
5313                             break;
5314                         }
5315                     }
5316                     // prevent infinite loop on bad selector
5317                     if(!matched){
5318                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5319                     }
5320                 }
5321                 if(mm[1]){
5322                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5323                     q = q.replace(mm[1], "");
5324                 }
5325             }
5326             fn[fn.length] = "return nodup(n);\n}";
5327             
5328              /** 
5329               * list of variables that need from compression as they are used by eval.
5330              *  eval:var:batch 
5331              *  eval:var:nodup
5332              *  eval:var:byTag
5333              *  eval:var:ById
5334              *  eval:var:getNodes
5335              *  eval:var:quickId
5336              *  eval:var:mode
5337              *  eval:var:root
5338              *  eval:var:n
5339              *  eval:var:byClassName
5340              *  eval:var:byPseudo
5341              *  eval:var:byAttribute
5342              *  eval:var:attrValue
5343              * 
5344              **/ 
5345             eval(fn.join(""));
5346             return f;
5347         },
5348
5349         /**
5350          * Selects a group of elements.
5351          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5352          * @param {Node} root (optional) The start of the query (defaults to document).
5353          * @return {Array}
5354          */
5355         select : function(path, root, type){
5356             if(!root || root == document){
5357                 root = document;
5358             }
5359             if(typeof root == "string"){
5360                 root = document.getElementById(root);
5361             }
5362             var paths = path.split(",");
5363             var results = [];
5364             for(var i = 0, len = paths.length; i < len; i++){
5365                 var p = paths[i].replace(trimRe, "");
5366                 if(!cache[p]){
5367                     cache[p] = Roo.DomQuery.compile(p);
5368                     if(!cache[p]){
5369                         throw p + " is not a valid selector";
5370                     }
5371                 }
5372                 var result = cache[p](root);
5373                 if(result && result != document){
5374                     results = results.concat(result);
5375                 }
5376             }
5377             if(paths.length > 1){
5378                 return nodup(results);
5379             }
5380             return results;
5381         },
5382
5383         /**
5384          * Selects a single element.
5385          * @param {String} selector The selector/xpath query
5386          * @param {Node} root (optional) The start of the query (defaults to document).
5387          * @return {Element}
5388          */
5389         selectNode : function(path, root){
5390             return Roo.DomQuery.select(path, root)[0];
5391         },
5392
5393         /**
5394          * Selects the value of a node, optionally replacing null with the defaultValue.
5395          * @param {String} selector The selector/xpath query
5396          * @param {Node} root (optional) The start of the query (defaults to document).
5397          * @param {String} defaultValue
5398          */
5399         selectValue : function(path, root, defaultValue){
5400             path = path.replace(trimRe, "");
5401             if(!valueCache[path]){
5402                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5403             }
5404             var n = valueCache[path](root);
5405             n = n[0] ? n[0] : n;
5406             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5407             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5408         },
5409
5410         /**
5411          * Selects the value of a node, parsing integers and floats.
5412          * @param {String} selector The selector/xpath query
5413          * @param {Node} root (optional) The start of the query (defaults to document).
5414          * @param {Number} defaultValue
5415          * @return {Number}
5416          */
5417         selectNumber : function(path, root, defaultValue){
5418             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5419             return parseFloat(v);
5420         },
5421
5422         /**
5423          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5424          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5425          * @param {String} selector The simple selector to test
5426          * @return {Boolean}
5427          */
5428         is : function(el, ss){
5429             if(typeof el == "string"){
5430                 el = document.getElementById(el);
5431             }
5432             var isArray = (el instanceof Array);
5433             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5434             return isArray ? (result.length == el.length) : (result.length > 0);
5435         },
5436
5437         /**
5438          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5439          * @param {Array} el An array of elements to filter
5440          * @param {String} selector The simple selector to test
5441          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5442          * the selector instead of the ones that match
5443          * @return {Array}
5444          */
5445         filter : function(els, ss, nonMatches){
5446             ss = ss.replace(trimRe, "");
5447             if(!simpleCache[ss]){
5448                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5449             }
5450             var result = simpleCache[ss](els);
5451             return nonMatches ? quickDiff(result, els) : result;
5452         },
5453
5454         /**
5455          * Collection of matching regular expressions and code snippets.
5456          */
5457         matchers : [{
5458                 re: /^\.([\w-]+)/,
5459                 select: 'n = byClassName(n, null, " {1} ");'
5460             }, {
5461                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5462                 select: 'n = byPseudo(n, "{1}", "{2}");'
5463             },{
5464                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5465                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5466             }, {
5467                 re: /^#([\w-]+)/,
5468                 select: 'n = byId(n, null, "{1}");'
5469             },{
5470                 re: /^@([\w-]+)/,
5471                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5472             }
5473         ],
5474
5475         /**
5476          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5477          * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, &gt; &lt;.
5478          */
5479         operators : {
5480             "=" : function(a, v){
5481                 return a == v;
5482             },
5483             "!=" : function(a, v){
5484                 return a != v;
5485             },
5486             "^=" : function(a, v){
5487                 return a && a.substr(0, v.length) == v;
5488             },
5489             "$=" : function(a, v){
5490                 return a && a.substr(a.length-v.length) == v;
5491             },
5492             "*=" : function(a, v){
5493                 return a && a.indexOf(v) !== -1;
5494             },
5495             "%=" : function(a, v){
5496                 return (a % v) == 0;
5497             },
5498             "|=" : function(a, v){
5499                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5500             },
5501             "~=" : function(a, v){
5502                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5503             }
5504         },
5505
5506         /**
5507          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5508          * and the argument (if any) supplied in the selector.
5509          */
5510         pseudos : {
5511             "first-child" : function(c){
5512                 var r = [], ri = -1, n;
5513                 for(var i = 0, ci; ci = n = c[i]; i++){
5514                     while((n = n.previousSibling) && n.nodeType != 1);
5515                     if(!n){
5516                         r[++ri] = ci;
5517                     }
5518                 }
5519                 return r;
5520             },
5521
5522             "last-child" : function(c){
5523                 var r = [], ri = -1, n;
5524                 for(var i = 0, ci; ci = n = c[i]; i++){
5525                     while((n = n.nextSibling) && n.nodeType != 1);
5526                     if(!n){
5527                         r[++ri] = ci;
5528                     }
5529                 }
5530                 return r;
5531             },
5532
5533             "nth-child" : function(c, a) {
5534                 var r = [], ri = -1;
5535                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5536                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5537                 for(var i = 0, n; n = c[i]; i++){
5538                     var pn = n.parentNode;
5539                     if (batch != pn._batch) {
5540                         var j = 0;
5541                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5542                             if(cn.nodeType == 1){
5543                                cn.nodeIndex = ++j;
5544                             }
5545                         }
5546                         pn._batch = batch;
5547                     }
5548                     if (f == 1) {
5549                         if (l == 0 || n.nodeIndex == l){
5550                             r[++ri] = n;
5551                         }
5552                     } else if ((n.nodeIndex + l) % f == 0){
5553                         r[++ri] = n;
5554                     }
5555                 }
5556
5557                 return r;
5558             },
5559
5560             "only-child" : function(c){
5561                 var r = [], ri = -1;;
5562                 for(var i = 0, ci; ci = c[i]; i++){
5563                     if(!prev(ci) && !next(ci)){
5564                         r[++ri] = ci;
5565                     }
5566                 }
5567                 return r;
5568             },
5569
5570             "empty" : function(c){
5571                 var r = [], ri = -1;
5572                 for(var i = 0, ci; ci = c[i]; i++){
5573                     var cns = ci.childNodes, j = 0, cn, empty = true;
5574                     while(cn = cns[j]){
5575                         ++j;
5576                         if(cn.nodeType == 1 || cn.nodeType == 3){
5577                             empty = false;
5578                             break;
5579                         }
5580                     }
5581                     if(empty){
5582                         r[++ri] = ci;
5583                     }
5584                 }
5585                 return r;
5586             },
5587
5588             "contains" : function(c, v){
5589                 var r = [], ri = -1;
5590                 for(var i = 0, ci; ci = c[i]; i++){
5591                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5592                         r[++ri] = ci;
5593                     }
5594                 }
5595                 return r;
5596             },
5597
5598             "nodeValue" : function(c, v){
5599                 var r = [], ri = -1;
5600                 for(var i = 0, ci; ci = c[i]; i++){
5601                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5602                         r[++ri] = ci;
5603                     }
5604                 }
5605                 return r;
5606             },
5607
5608             "checked" : function(c){
5609                 var r = [], ri = -1;
5610                 for(var i = 0, ci; ci = c[i]; i++){
5611                     if(ci.checked == true){
5612                         r[++ri] = ci;
5613                     }
5614                 }
5615                 return r;
5616             },
5617
5618             "not" : function(c, ss){
5619                 return Roo.DomQuery.filter(c, ss, true);
5620             },
5621
5622             "odd" : function(c){
5623                 return this["nth-child"](c, "odd");
5624             },
5625
5626             "even" : function(c){
5627                 return this["nth-child"](c, "even");
5628             },
5629
5630             "nth" : function(c, a){
5631                 return c[a-1] || [];
5632             },
5633
5634             "first" : function(c){
5635                 return c[0] || [];
5636             },
5637
5638             "last" : function(c){
5639                 return c[c.length-1] || [];
5640             },
5641
5642             "has" : function(c, ss){
5643                 var s = Roo.DomQuery.select;
5644                 var r = [], ri = -1;
5645                 for(var i = 0, ci; ci = c[i]; i++){
5646                     if(s(ss, ci).length > 0){
5647                         r[++ri] = ci;
5648                     }
5649                 }
5650                 return r;
5651             },
5652
5653             "next" : function(c, ss){
5654                 var is = Roo.DomQuery.is;
5655                 var r = [], ri = -1;
5656                 for(var i = 0, ci; ci = c[i]; i++){
5657                     var n = next(ci);
5658                     if(n && is(n, ss)){
5659                         r[++ri] = ci;
5660                     }
5661                 }
5662                 return r;
5663             },
5664
5665             "prev" : function(c, ss){
5666                 var is = Roo.DomQuery.is;
5667                 var r = [], ri = -1;
5668                 for(var i = 0, ci; ci = c[i]; i++){
5669                     var n = prev(ci);
5670                     if(n && is(n, ss)){
5671                         r[++ri] = ci;
5672                     }
5673                 }
5674                 return r;
5675             }
5676         }
5677     };
5678 }();
5679
5680 /**
5681  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5682  * @param {String} path The selector/xpath query
5683  * @param {Node} root (optional) The start of the query (defaults to document).
5684  * @return {Array}
5685  * @member Roo
5686  * @method query
5687  */
5688 Roo.query = Roo.DomQuery.select;
5689 /*
5690  * Based on:
5691  * Ext JS Library 1.1.1
5692  * Copyright(c) 2006-2007, Ext JS, LLC.
5693  *
5694  * Originally Released Under LGPL - original licence link has changed is not relivant.
5695  *
5696  * Fork - LGPL
5697  * <script type="text/javascript">
5698  */
5699
5700 /**
5701  * @class Roo.util.Observable
5702  * Base class that provides a common interface for publishing events. Subclasses are expected to
5703  * to have a property "events" with all the events defined.<br>
5704  * For example:
5705  * <pre><code>
5706  Employee = function(name){
5707     this.name = name;
5708     this.addEvents({
5709         "fired" : true,
5710         "quit" : true
5711     });
5712  }
5713  Roo.extend(Employee, Roo.util.Observable);
5714 </code></pre>
5715  * @param {Object} config properties to use (incuding events / listeners)
5716  */
5717
5718 Roo.util.Observable = function(cfg){
5719     
5720     cfg = cfg|| {};
5721     this.addEvents(cfg.events || {});
5722     if (cfg.events) {
5723         delete cfg.events; // make sure
5724     }
5725      
5726     Roo.apply(this, cfg);
5727     
5728     if(this.listeners){
5729         this.on(this.listeners);
5730         delete this.listeners;
5731     }
5732 };
5733 Roo.util.Observable.prototype = {
5734     /** 
5735  * @cfg {Object} listeners  list of events and functions to call for this object, 
5736  * For example :
5737  * <pre><code>
5738     listeners :  { 
5739        'click' : function(e) {
5740            ..... 
5741         } ,
5742         .... 
5743     } 
5744   </code></pre>
5745  */
5746     
5747     
5748     /**
5749      * Fires the specified event with the passed parameters (minus the event name).
5750      * @param {String} eventName
5751      * @param {Object...} args Variable number of parameters are passed to handlers
5752      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5753      */
5754     fireEvent : function(){
5755         var ce = this.events[arguments[0].toLowerCase()];
5756         if(typeof ce == "object"){
5757             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5758         }else{
5759             return true;
5760         }
5761     },
5762
5763     // private
5764     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5765
5766     /**
5767      * Appends an event handler to this component
5768      * @param {String}   eventName The type of event to listen for
5769      * @param {Function} handler The method the event invokes
5770      * @param {Object}   scope (optional) The scope in which to execute the handler
5771      * function. The handler function's "this" context.
5772      * @param {Object}   options (optional) An object containing handler configuration
5773      * properties. This may contain any of the following properties:<ul>
5774      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5775      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5776      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5777      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5778      * by the specified number of milliseconds. If the event fires again within that time, the original
5779      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5780      * </ul><br>
5781      * <p>
5782      * <b>Combining Options</b><br>
5783      * Using the options argument, it is possible to combine different types of listeners:<br>
5784      * <br>
5785      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5786                 <pre><code>
5787                 el.on('click', this.onClick, this, {
5788                         single: true,
5789                 delay: 100,
5790                 forumId: 4
5791                 });
5792                 </code></pre>
5793      * <p>
5794      * <b>Attaching multiple handlers in 1 call</b><br>
5795      * The method also allows for a single argument to be passed which is a config object containing properties
5796      * which specify multiple handlers.
5797      * <pre><code>
5798                 el.on({
5799                         'click': {
5800                         fn: this.onClick,
5801                         scope: this,
5802                         delay: 100
5803                 }, 
5804                 'mouseover': {
5805                         fn: this.onMouseOver,
5806                         scope: this
5807                 },
5808                 'mouseout': {
5809                         fn: this.onMouseOut,
5810                         scope: this
5811                 }
5812                 });
5813                 </code></pre>
5814      * <p>
5815      * Or a shorthand syntax which passes the same scope object to all handlers:
5816         <pre><code>
5817                 el.on({
5818                         'click': this.onClick,
5819                 'mouseover': this.onMouseOver,
5820                 'mouseout': this.onMouseOut,
5821                 scope: this
5822                 });
5823                 </code></pre>
5824      */
5825     addListener : function(eventName, fn, scope, o){
5826         if(typeof eventName == "object"){
5827             o = eventName;
5828             for(var e in o){
5829                 if(this.filterOptRe.test(e)){
5830                     continue;
5831                 }
5832                 if(typeof o[e] == "function"){
5833                     // shared options
5834                     this.addListener(e, o[e], o.scope,  o);
5835                 }else{
5836                     // individual options
5837                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5838                 }
5839             }
5840             return;
5841         }
5842         o = (!o || typeof o == "boolean") ? {} : o;
5843         eventName = eventName.toLowerCase();
5844         var ce = this.events[eventName] || true;
5845         if(typeof ce == "boolean"){
5846             ce = new Roo.util.Event(this, eventName);
5847             this.events[eventName] = ce;
5848         }
5849         ce.addListener(fn, scope, o);
5850     },
5851
5852     /**
5853      * Removes a listener
5854      * @param {String}   eventName     The type of event to listen for
5855      * @param {Function} handler        The handler to remove
5856      * @param {Object}   scope  (optional) The scope (this object) for the handler
5857      */
5858     removeListener : function(eventName, fn, scope){
5859         var ce = this.events[eventName.toLowerCase()];
5860         if(typeof ce == "object"){
5861             ce.removeListener(fn, scope);
5862         }
5863     },
5864
5865     /**
5866      * Removes all listeners for this object
5867      */
5868     purgeListeners : function(){
5869         for(var evt in this.events){
5870             if(typeof this.events[evt] == "object"){
5871                  this.events[evt].clearListeners();
5872             }
5873         }
5874     },
5875
5876     relayEvents : function(o, events){
5877         var createHandler = function(ename){
5878             return function(){
5879                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5880             };
5881         };
5882         for(var i = 0, len = events.length; i < len; i++){
5883             var ename = events[i];
5884             if(!this.events[ename]){ this.events[ename] = true; };
5885             o.on(ename, createHandler(ename), this);
5886         }
5887     },
5888
5889     /**
5890      * Used to define events on this Observable
5891      * @param {Object} object The object with the events defined
5892      */
5893     addEvents : function(o){
5894         if(!this.events){
5895             this.events = {};
5896         }
5897         Roo.applyIf(this.events, o);
5898     },
5899
5900     /**
5901      * Checks to see if this object has any listeners for a specified event
5902      * @param {String} eventName The name of the event to check for
5903      * @return {Boolean} True if the event is being listened for, else false
5904      */
5905     hasListener : function(eventName){
5906         var e = this.events[eventName];
5907         return typeof e == "object" && e.listeners.length > 0;
5908     }
5909 };
5910 /**
5911  * Appends an event handler to this element (shorthand for addListener)
5912  * @param {String}   eventName     The type of event to listen for
5913  * @param {Function} handler        The method the event invokes
5914  * @param {Object}   scope (optional) The scope in which to execute the handler
5915  * function. The handler function's "this" context.
5916  * @param {Object}   options  (optional)
5917  * @method
5918  */
5919 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5920 /**
5921  * Removes a listener (shorthand for removeListener)
5922  * @param {String}   eventName     The type of event to listen for
5923  * @param {Function} handler        The handler to remove
5924  * @param {Object}   scope  (optional) The scope (this object) for the handler
5925  * @method
5926  */
5927 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5928
5929 /**
5930  * Starts capture on the specified Observable. All events will be passed
5931  * to the supplied function with the event name + standard signature of the event
5932  * <b>before</b> the event is fired. If the supplied function returns false,
5933  * the event will not fire.
5934  * @param {Observable} o The Observable to capture
5935  * @param {Function} fn The function to call
5936  * @param {Object} scope (optional) The scope (this object) for the fn
5937  * @static
5938  */
5939 Roo.util.Observable.capture = function(o, fn, scope){
5940     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5941 };
5942
5943 /**
5944  * Removes <b>all</b> added captures from the Observable.
5945  * @param {Observable} o The Observable to release
5946  * @static
5947  */
5948 Roo.util.Observable.releaseCapture = function(o){
5949     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5950 };
5951
5952 (function(){
5953
5954     var createBuffered = function(h, o, scope){
5955         var task = new Roo.util.DelayedTask();
5956         return function(){
5957             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5958         };
5959     };
5960
5961     var createSingle = function(h, e, fn, scope){
5962         return function(){
5963             e.removeListener(fn, scope);
5964             return h.apply(scope, arguments);
5965         };
5966     };
5967
5968     var createDelayed = function(h, o, scope){
5969         return function(){
5970             var args = Array.prototype.slice.call(arguments, 0);
5971             setTimeout(function(){
5972                 h.apply(scope, args);
5973             }, o.delay || 10);
5974         };
5975     };
5976
5977     Roo.util.Event = function(obj, name){
5978         this.name = name;
5979         this.obj = obj;
5980         this.listeners = [];
5981     };
5982
5983     Roo.util.Event.prototype = {
5984         addListener : function(fn, scope, options){
5985             var o = options || {};
5986             scope = scope || this.obj;
5987             if(!this.isListening(fn, scope)){
5988                 var l = {fn: fn, scope: scope, options: o};
5989                 var h = fn;
5990                 if(o.delay){
5991                     h = createDelayed(h, o, scope);
5992                 }
5993                 if(o.single){
5994                     h = createSingle(h, this, fn, scope);
5995                 }
5996                 if(o.buffer){
5997                     h = createBuffered(h, o, scope);
5998                 }
5999                 l.fireFn = h;
6000                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6001                     this.listeners.push(l);
6002                 }else{
6003                     this.listeners = this.listeners.slice(0);
6004                     this.listeners.push(l);
6005                 }
6006             }
6007         },
6008
6009         findListener : function(fn, scope){
6010             scope = scope || this.obj;
6011             var ls = this.listeners;
6012             for(var i = 0, len = ls.length; i < len; i++){
6013                 var l = ls[i];
6014                 if(l.fn == fn && l.scope == scope){
6015                     return i;
6016                 }
6017             }
6018             return -1;
6019         },
6020
6021         isListening : function(fn, scope){
6022             return this.findListener(fn, scope) != -1;
6023         },
6024
6025         removeListener : function(fn, scope){
6026             var index;
6027             if((index = this.findListener(fn, scope)) != -1){
6028                 if(!this.firing){
6029                     this.listeners.splice(index, 1);
6030                 }else{
6031                     this.listeners = this.listeners.slice(0);
6032                     this.listeners.splice(index, 1);
6033                 }
6034                 return true;
6035             }
6036             return false;
6037         },
6038
6039         clearListeners : function(){
6040             this.listeners = [];
6041         },
6042
6043         fire : function(){
6044             var ls = this.listeners, scope, len = ls.length;
6045             if(len > 0){
6046                 this.firing = true;
6047                 var args = Array.prototype.slice.call(arguments, 0);
6048                 for(var i = 0; i < len; i++){
6049                     var l = ls[i];
6050                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6051                         this.firing = false;
6052                         return false;
6053                     }
6054                 }
6055                 this.firing = false;
6056             }
6057             return true;
6058         }
6059     };
6060 })();/*
6061  * RooJS Library 
6062  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6063  *
6064  * Licence LGPL 
6065  *
6066  */
6067  
6068 /**
6069  * @class Roo.Document
6070  * @extends Roo.util.Observable
6071  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6072  * 
6073  * @param {Object} config the methods and properties of the 'base' class for the application.
6074  * 
6075  *  Generic Page handler - implement this to start your app..
6076  * 
6077  * eg.
6078  *  MyProject = new Roo.Document({
6079         events : {
6080             'load' : true // your events..
6081         },
6082         listeners : {
6083             'ready' : function() {
6084                 // fired on Roo.onReady()
6085             }
6086         }
6087  * 
6088  */
6089 Roo.Document = function(cfg) {
6090      
6091     this.addEvents({ 
6092         'ready' : true
6093     });
6094     Roo.util.Observable.call(this,cfg);
6095     
6096     var _this = this;
6097     
6098     Roo.onReady(function() {
6099         _this.fireEvent('ready');
6100     },null,false);
6101     
6102     
6103 }
6104
6105 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6106  * Based on:
6107  * Ext JS Library 1.1.1
6108  * Copyright(c) 2006-2007, Ext JS, LLC.
6109  *
6110  * Originally Released Under LGPL - original licence link has changed is not relivant.
6111  *
6112  * Fork - LGPL
6113  * <script type="text/javascript">
6114  */
6115
6116 /**
6117  * @class Roo.EventManager
6118  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6119  * several useful events directly.
6120  * See {@link Roo.EventObject} for more details on normalized event objects.
6121  * @singleton
6122  */
6123 Roo.EventManager = function(){
6124     var docReadyEvent, docReadyProcId, docReadyState = false;
6125     var resizeEvent, resizeTask, textEvent, textSize;
6126     var E = Roo.lib.Event;
6127     var D = Roo.lib.Dom;
6128
6129     
6130     
6131
6132     var fireDocReady = function(){
6133         if(!docReadyState){
6134             docReadyState = true;
6135             Roo.isReady = true;
6136             if(docReadyProcId){
6137                 clearInterval(docReadyProcId);
6138             }
6139             if(Roo.isGecko || Roo.isOpera) {
6140                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6141             }
6142             if(Roo.isIE){
6143                 var defer = document.getElementById("ie-deferred-loader");
6144                 if(defer){
6145                     defer.onreadystatechange = null;
6146                     defer.parentNode.removeChild(defer);
6147                 }
6148             }
6149             if(docReadyEvent){
6150                 docReadyEvent.fire();
6151                 docReadyEvent.clearListeners();
6152             }
6153         }
6154     };
6155     
6156     var initDocReady = function(){
6157         docReadyEvent = new Roo.util.Event();
6158         if(Roo.isGecko || Roo.isOpera) {
6159             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6160         }else if(Roo.isIE){
6161             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6162             var defer = document.getElementById("ie-deferred-loader");
6163             defer.onreadystatechange = function(){
6164                 if(this.readyState == "complete"){
6165                     fireDocReady();
6166                 }
6167             };
6168         }else if(Roo.isSafari){ 
6169             docReadyProcId = setInterval(function(){
6170                 var rs = document.readyState;
6171                 if(rs == "complete") {
6172                     fireDocReady();     
6173                  }
6174             }, 10);
6175         }
6176         // no matter what, make sure it fires on load
6177         E.on(window, "load", fireDocReady);
6178     };
6179
6180     var createBuffered = function(h, o){
6181         var task = new Roo.util.DelayedTask(h);
6182         return function(e){
6183             // create new event object impl so new events don't wipe out properties
6184             e = new Roo.EventObjectImpl(e);
6185             task.delay(o.buffer, h, null, [e]);
6186         };
6187     };
6188
6189     var createSingle = function(h, el, ename, fn){
6190         return function(e){
6191             Roo.EventManager.removeListener(el, ename, fn);
6192             h(e);
6193         };
6194     };
6195
6196     var createDelayed = function(h, o){
6197         return function(e){
6198             // create new event object impl so new events don't wipe out properties
6199             e = new Roo.EventObjectImpl(e);
6200             setTimeout(function(){
6201                 h(e);
6202             }, o.delay || 10);
6203         };
6204     };
6205     var transitionEndVal = false;
6206     
6207     var transitionEnd = function()
6208     {
6209         if (transitionEndVal) {
6210             return transitionEndVal;
6211         }
6212         var el = document.createElement('div');
6213
6214         var transEndEventNames = {
6215             WebkitTransition : 'webkitTransitionEnd',
6216             MozTransition    : 'transitionend',
6217             OTransition      : 'oTransitionEnd otransitionend',
6218             transition       : 'transitionend'
6219         };
6220     
6221         for (var name in transEndEventNames) {
6222             if (el.style[name] !== undefined) {
6223                 transitionEndVal = transEndEventNames[name];
6224                 return  transitionEndVal ;
6225             }
6226         }
6227     }
6228     
6229
6230     var listen = function(element, ename, opt, fn, scope){
6231         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6232         fn = fn || o.fn; scope = scope || o.scope;
6233         var el = Roo.getDom(element);
6234         
6235         
6236         if(!el){
6237             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6238         }
6239         
6240         if (ename == 'transitionend') {
6241             ename = transitionEnd();
6242         }
6243         var h = function(e){
6244             e = Roo.EventObject.setEvent(e);
6245             var t;
6246             if(o.delegate){
6247                 t = e.getTarget(o.delegate, el);
6248                 if(!t){
6249                     return;
6250                 }
6251             }else{
6252                 t = e.target;
6253             }
6254             if(o.stopEvent === true){
6255                 e.stopEvent();
6256             }
6257             if(o.preventDefault === true){
6258                e.preventDefault();
6259             }
6260             if(o.stopPropagation === true){
6261                 e.stopPropagation();
6262             }
6263
6264             if(o.normalized === false){
6265                 e = e.browserEvent;
6266             }
6267
6268             fn.call(scope || el, e, t, o);
6269         };
6270         if(o.delay){
6271             h = createDelayed(h, o);
6272         }
6273         if(o.single){
6274             h = createSingle(h, el, ename, fn);
6275         }
6276         if(o.buffer){
6277             h = createBuffered(h, o);
6278         }
6279         fn._handlers = fn._handlers || [];
6280         
6281         
6282         fn._handlers.push([Roo.id(el), ename, h]);
6283         
6284         
6285          
6286         E.on(el, ename, h);
6287         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6288             el.addEventListener("DOMMouseScroll", h, false);
6289             E.on(window, 'unload', function(){
6290                 el.removeEventListener("DOMMouseScroll", h, false);
6291             });
6292         }
6293         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6294             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6295         }
6296         return h;
6297     };
6298
6299     var stopListening = function(el, ename, fn){
6300         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6301         if(hds){
6302             for(var i = 0, len = hds.length; i < len; i++){
6303                 var h = hds[i];
6304                 if(h[0] == id && h[1] == ename){
6305                     hd = h[2];
6306                     hds.splice(i, 1);
6307                     break;
6308                 }
6309             }
6310         }
6311         E.un(el, ename, hd);
6312         el = Roo.getDom(el);
6313         if(ename == "mousewheel" && el.addEventListener){
6314             el.removeEventListener("DOMMouseScroll", hd, false);
6315         }
6316         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6317             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6318         }
6319     };
6320
6321     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6322     
6323     var pub = {
6324         
6325         
6326         /** 
6327          * Fix for doc tools
6328          * @scope Roo.EventManager
6329          */
6330         
6331         
6332         /** 
6333          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6334          * object with a Roo.EventObject
6335          * @param {Function} fn        The method the event invokes
6336          * @param {Object}   scope    An object that becomes the scope of the handler
6337          * @param {boolean}  override If true, the obj passed in becomes
6338          *                             the execution scope of the listener
6339          * @return {Function} The wrapped function
6340          * @deprecated
6341          */
6342         wrap : function(fn, scope, override){
6343             return function(e){
6344                 Roo.EventObject.setEvent(e);
6345                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6346             };
6347         },
6348         
6349         /**
6350      * Appends an event handler to an element (shorthand for addListener)
6351      * @param {String/HTMLElement}   element        The html element or id to assign the
6352      * @param {String}   eventName The type of event to listen for
6353      * @param {Function} handler The method the event invokes
6354      * @param {Object}   scope (optional) The scope in which to execute the handler
6355      * function. The handler function's "this" context.
6356      * @param {Object}   options (optional) An object containing handler configuration
6357      * properties. This may contain any of the following properties:<ul>
6358      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6359      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6360      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6361      * <li>preventDefault {Boolean} True to prevent the default action</li>
6362      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6363      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6364      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6365      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6366      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6367      * by the specified number of milliseconds. If the event fires again within that time, the original
6368      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6369      * </ul><br>
6370      * <p>
6371      * <b>Combining Options</b><br>
6372      * Using the options argument, it is possible to combine different types of listeners:<br>
6373      * <br>
6374      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6375      * Code:<pre><code>
6376 el.on('click', this.onClick, this, {
6377     single: true,
6378     delay: 100,
6379     stopEvent : true,
6380     forumId: 4
6381 });</code></pre>
6382      * <p>
6383      * <b>Attaching multiple handlers in 1 call</b><br>
6384       * The method also allows for a single argument to be passed which is a config object containing properties
6385      * which specify multiple handlers.
6386      * <p>
6387      * Code:<pre><code>
6388 el.on({
6389     'click' : {
6390         fn: this.onClick
6391         scope: this,
6392         delay: 100
6393     },
6394     'mouseover' : {
6395         fn: this.onMouseOver
6396         scope: this
6397     },
6398     'mouseout' : {
6399         fn: this.onMouseOut
6400         scope: this
6401     }
6402 });</code></pre>
6403      * <p>
6404      * Or a shorthand syntax:<br>
6405      * Code:<pre><code>
6406 el.on({
6407     'click' : this.onClick,
6408     'mouseover' : this.onMouseOver,
6409     'mouseout' : this.onMouseOut
6410     scope: this
6411 });</code></pre>
6412      */
6413         addListener : function(element, eventName, fn, scope, options){
6414             if(typeof eventName == "object"){
6415                 var o = eventName;
6416                 for(var e in o){
6417                     if(propRe.test(e)){
6418                         continue;
6419                     }
6420                     if(typeof o[e] == "function"){
6421                         // shared options
6422                         listen(element, e, o, o[e], o.scope);
6423                     }else{
6424                         // individual options
6425                         listen(element, e, o[e]);
6426                     }
6427                 }
6428                 return;
6429             }
6430             return listen(element, eventName, options, fn, scope);
6431         },
6432         
6433         /**
6434          * Removes an event handler
6435          *
6436          * @param {String/HTMLElement}   element        The id or html element to remove the 
6437          *                             event from
6438          * @param {String}   eventName     The type of event
6439          * @param {Function} fn
6440          * @return {Boolean} True if a listener was actually removed
6441          */
6442         removeListener : function(element, eventName, fn){
6443             return stopListening(element, eventName, fn);
6444         },
6445         
6446         /**
6447          * Fires when the document is ready (before onload and before images are loaded). Can be 
6448          * accessed shorthanded Roo.onReady().
6449          * @param {Function} fn        The method the event invokes
6450          * @param {Object}   scope    An  object that becomes the scope of the handler
6451          * @param {boolean}  options
6452          */
6453         onDocumentReady : function(fn, scope, options){
6454             if(docReadyState){ // if it already fired
6455                 docReadyEvent.addListener(fn, scope, options);
6456                 docReadyEvent.fire();
6457                 docReadyEvent.clearListeners();
6458                 return;
6459             }
6460             if(!docReadyEvent){
6461                 initDocReady();
6462             }
6463             docReadyEvent.addListener(fn, scope, options);
6464         },
6465         
6466         /**
6467          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6468          * @param {Function} fn        The method the event invokes
6469          * @param {Object}   scope    An object that becomes the scope of the handler
6470          * @param {boolean}  options
6471          */
6472         onWindowResize : function(fn, scope, options){
6473             if(!resizeEvent){
6474                 resizeEvent = new Roo.util.Event();
6475                 resizeTask = new Roo.util.DelayedTask(function(){
6476                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6477                 });
6478                 E.on(window, "resize", function(){
6479                     if(Roo.isIE){
6480                         resizeTask.delay(50);
6481                     }else{
6482                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6483                     }
6484                 });
6485             }
6486             resizeEvent.addListener(fn, scope, options);
6487         },
6488
6489         /**
6490          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6491          * @param {Function} fn        The method the event invokes
6492          * @param {Object}   scope    An object that becomes the scope of the handler
6493          * @param {boolean}  options
6494          */
6495         onTextResize : function(fn, scope, options){
6496             if(!textEvent){
6497                 textEvent = new Roo.util.Event();
6498                 var textEl = new Roo.Element(document.createElement('div'));
6499                 textEl.dom.className = 'x-text-resize';
6500                 textEl.dom.innerHTML = 'X';
6501                 textEl.appendTo(document.body);
6502                 textSize = textEl.dom.offsetHeight;
6503                 setInterval(function(){
6504                     if(textEl.dom.offsetHeight != textSize){
6505                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6506                     }
6507                 }, this.textResizeInterval);
6508             }
6509             textEvent.addListener(fn, scope, options);
6510         },
6511
6512         /**
6513          * Removes the passed window resize listener.
6514          * @param {Function} fn        The method the event invokes
6515          * @param {Object}   scope    The scope of handler
6516          */
6517         removeResizeListener : function(fn, scope){
6518             if(resizeEvent){
6519                 resizeEvent.removeListener(fn, scope);
6520             }
6521         },
6522
6523         // private
6524         fireResize : function(){
6525             if(resizeEvent){
6526                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6527             }   
6528         },
6529         /**
6530          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6531          */
6532         ieDeferSrc : false,
6533         /**
6534          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6535          */
6536         textResizeInterval : 50
6537     };
6538     
6539     /**
6540      * Fix for doc tools
6541      * @scopeAlias pub=Roo.EventManager
6542      */
6543     
6544      /**
6545      * Appends an event handler to an element (shorthand for addListener)
6546      * @param {String/HTMLElement}   element        The html element or id to assign the
6547      * @param {String}   eventName The type of event to listen for
6548      * @param {Function} handler The method the event invokes
6549      * @param {Object}   scope (optional) The scope in which to execute the handler
6550      * function. The handler function's "this" context.
6551      * @param {Object}   options (optional) An object containing handler configuration
6552      * properties. This may contain any of the following properties:<ul>
6553      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6554      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6555      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6556      * <li>preventDefault {Boolean} True to prevent the default action</li>
6557      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6558      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6559      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6560      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6561      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6562      * by the specified number of milliseconds. If the event fires again within that time, the original
6563      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6564      * </ul><br>
6565      * <p>
6566      * <b>Combining Options</b><br>
6567      * Using the options argument, it is possible to combine different types of listeners:<br>
6568      * <br>
6569      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6570      * Code:<pre><code>
6571 el.on('click', this.onClick, this, {
6572     single: true,
6573     delay: 100,
6574     stopEvent : true,
6575     forumId: 4
6576 });</code></pre>
6577      * <p>
6578      * <b>Attaching multiple handlers in 1 call</b><br>
6579       * The method also allows for a single argument to be passed which is a config object containing properties
6580      * which specify multiple handlers.
6581      * <p>
6582      * Code:<pre><code>
6583 el.on({
6584     'click' : {
6585         fn: this.onClick
6586         scope: this,
6587         delay: 100
6588     },
6589     'mouseover' : {
6590         fn: this.onMouseOver
6591         scope: this
6592     },
6593     'mouseout' : {
6594         fn: this.onMouseOut
6595         scope: this
6596     }
6597 });</code></pre>
6598      * <p>
6599      * Or a shorthand syntax:<br>
6600      * Code:<pre><code>
6601 el.on({
6602     'click' : this.onClick,
6603     'mouseover' : this.onMouseOver,
6604     'mouseout' : this.onMouseOut
6605     scope: this
6606 });</code></pre>
6607      */
6608     pub.on = pub.addListener;
6609     pub.un = pub.removeListener;
6610
6611     pub.stoppedMouseDownEvent = new Roo.util.Event();
6612     return pub;
6613 }();
6614 /**
6615   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6616   * @param {Function} fn        The method the event invokes
6617   * @param {Object}   scope    An  object that becomes the scope of the handler
6618   * @param {boolean}  override If true, the obj passed in becomes
6619   *                             the execution scope of the listener
6620   * @member Roo
6621   * @method onReady
6622  */
6623 Roo.onReady = Roo.EventManager.onDocumentReady;
6624
6625 Roo.onReady(function(){
6626     var bd = Roo.get(document.body);
6627     if(!bd){ return; }
6628
6629     var cls = [
6630             Roo.isIE ? "roo-ie"
6631             : Roo.isGecko ? "roo-gecko"
6632             : Roo.isOpera ? "roo-opera"
6633             : Roo.isSafari ? "roo-safari" : ""];
6634
6635     if(Roo.isMac){
6636         cls.push("roo-mac");
6637     }
6638     if(Roo.isLinux){
6639         cls.push("roo-linux");
6640     }
6641     if(Roo.isIOS){
6642         cls.push("roo-ios");
6643     }
6644     if(Roo.isTouch){
6645         cls.push("roo-touch");
6646     }
6647     if(Roo.isBorderBox){
6648         cls.push('roo-border-box');
6649     }
6650     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6651         var p = bd.dom.parentNode;
6652         if(p){
6653             p.className += ' roo-strict';
6654         }
6655     }
6656     bd.addClass(cls.join(' '));
6657 });
6658
6659 /**
6660  * @class Roo.EventObject
6661  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6662  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6663  * Example:
6664  * <pre><code>
6665  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6666     e.preventDefault();
6667     var target = e.getTarget();
6668     ...
6669  }
6670  var myDiv = Roo.get("myDiv");
6671  myDiv.on("click", handleClick);
6672  //or
6673  Roo.EventManager.on("myDiv", 'click', handleClick);
6674  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6675  </code></pre>
6676  * @singleton
6677  */
6678 Roo.EventObject = function(){
6679     
6680     var E = Roo.lib.Event;
6681     
6682     // safari keypress events for special keys return bad keycodes
6683     var safariKeys = {
6684         63234 : 37, // left
6685         63235 : 39, // right
6686         63232 : 38, // up
6687         63233 : 40, // down
6688         63276 : 33, // page up
6689         63277 : 34, // page down
6690         63272 : 46, // delete
6691         63273 : 36, // home
6692         63275 : 35  // end
6693     };
6694
6695     // normalize button clicks
6696     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6697                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6698
6699     Roo.EventObjectImpl = function(e){
6700         if(e){
6701             this.setEvent(e.browserEvent || e);
6702         }
6703     };
6704     Roo.EventObjectImpl.prototype = {
6705         /**
6706          * Used to fix doc tools.
6707          * @scope Roo.EventObject.prototype
6708          */
6709             
6710
6711         
6712         
6713         /** The normal browser event */
6714         browserEvent : null,
6715         /** The button pressed in a mouse event */
6716         button : -1,
6717         /** True if the shift key was down during the event */
6718         shiftKey : false,
6719         /** True if the control key was down during the event */
6720         ctrlKey : false,
6721         /** True if the alt key was down during the event */
6722         altKey : false,
6723
6724         /** Key constant 
6725         * @type Number */
6726         BACKSPACE : 8,
6727         /** Key constant 
6728         * @type Number */
6729         TAB : 9,
6730         /** Key constant 
6731         * @type Number */
6732         RETURN : 13,
6733         /** Key constant 
6734         * @type Number */
6735         ENTER : 13,
6736         /** Key constant 
6737         * @type Number */
6738         SHIFT : 16,
6739         /** Key constant 
6740         * @type Number */
6741         CONTROL : 17,
6742         /** Key constant 
6743         * @type Number */
6744         ESC : 27,
6745         /** Key constant 
6746         * @type Number */
6747         SPACE : 32,
6748         /** Key constant 
6749         * @type Number */
6750         PAGEUP : 33,
6751         /** Key constant 
6752         * @type Number */
6753         PAGEDOWN : 34,
6754         /** Key constant 
6755         * @type Number */
6756         END : 35,
6757         /** Key constant 
6758         * @type Number */
6759         HOME : 36,
6760         /** Key constant 
6761         * @type Number */
6762         LEFT : 37,
6763         /** Key constant 
6764         * @type Number */
6765         UP : 38,
6766         /** Key constant 
6767         * @type Number */
6768         RIGHT : 39,
6769         /** Key constant 
6770         * @type Number */
6771         DOWN : 40,
6772         /** Key constant 
6773         * @type Number */
6774         DELETE : 46,
6775         /** Key constant 
6776         * @type Number */
6777         F5 : 116,
6778
6779            /** @private */
6780         setEvent : function(e){
6781             if(e == this || (e && e.browserEvent)){ // already wrapped
6782                 return e;
6783             }
6784             this.browserEvent = e;
6785             if(e){
6786                 // normalize buttons
6787                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6788                 if(e.type == 'click' && this.button == -1){
6789                     this.button = 0;
6790                 }
6791                 this.type = e.type;
6792                 this.shiftKey = e.shiftKey;
6793                 // mac metaKey behaves like ctrlKey
6794                 this.ctrlKey = e.ctrlKey || e.metaKey;
6795                 this.altKey = e.altKey;
6796                 // in getKey these will be normalized for the mac
6797                 this.keyCode = e.keyCode;
6798                 // keyup warnings on firefox.
6799                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6800                 // cache the target for the delayed and or buffered events
6801                 this.target = E.getTarget(e);
6802                 // same for XY
6803                 this.xy = E.getXY(e);
6804             }else{
6805                 this.button = -1;
6806                 this.shiftKey = false;
6807                 this.ctrlKey = false;
6808                 this.altKey = false;
6809                 this.keyCode = 0;
6810                 this.charCode =0;
6811                 this.target = null;
6812                 this.xy = [0, 0];
6813             }
6814             return this;
6815         },
6816
6817         /**
6818          * Stop the event (preventDefault and stopPropagation)
6819          */
6820         stopEvent : function(){
6821             if(this.browserEvent){
6822                 if(this.browserEvent.type == 'mousedown'){
6823                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6824                 }
6825                 E.stopEvent(this.browserEvent);
6826             }
6827         },
6828
6829         /**
6830          * Prevents the browsers default handling of the event.
6831          */
6832         preventDefault : function(){
6833             if(this.browserEvent){
6834                 E.preventDefault(this.browserEvent);
6835             }
6836         },
6837
6838         /** @private */
6839         isNavKeyPress : function(){
6840             var k = this.keyCode;
6841             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6842             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6843         },
6844
6845         isSpecialKey : function(){
6846             var k = this.keyCode;
6847             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6848             (k == 16) || (k == 17) ||
6849             (k >= 18 && k <= 20) ||
6850             (k >= 33 && k <= 35) ||
6851             (k >= 36 && k <= 39) ||
6852             (k >= 44 && k <= 45);
6853         },
6854         /**
6855          * Cancels bubbling of the event.
6856          */
6857         stopPropagation : function(){
6858             if(this.browserEvent){
6859                 if(this.type == 'mousedown'){
6860                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6861                 }
6862                 E.stopPropagation(this.browserEvent);
6863             }
6864         },
6865
6866         /**
6867          * Gets the key code for the event.
6868          * @return {Number}
6869          */
6870         getCharCode : function(){
6871             return this.charCode || this.keyCode;
6872         },
6873
6874         /**
6875          * Returns a normalized keyCode for the event.
6876          * @return {Number} The key code
6877          */
6878         getKey : function(){
6879             var k = this.keyCode || this.charCode;
6880             return Roo.isSafari ? (safariKeys[k] || k) : k;
6881         },
6882
6883         /**
6884          * Gets the x coordinate of the event.
6885          * @return {Number}
6886          */
6887         getPageX : function(){
6888             return this.xy[0];
6889         },
6890
6891         /**
6892          * Gets the y coordinate of the event.
6893          * @return {Number}
6894          */
6895         getPageY : function(){
6896             return this.xy[1];
6897         },
6898
6899         /**
6900          * Gets the time of the event.
6901          * @return {Number}
6902          */
6903         getTime : function(){
6904             if(this.browserEvent){
6905                 return E.getTime(this.browserEvent);
6906             }
6907             return null;
6908         },
6909
6910         /**
6911          * Gets the page coordinates of the event.
6912          * @return {Array} The xy values like [x, y]
6913          */
6914         getXY : function(){
6915             return this.xy;
6916         },
6917
6918         /**
6919          * Gets the target for the event.
6920          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6921          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6922                 search as a number or element (defaults to 10 || document.body)
6923          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6924          * @return {HTMLelement}
6925          */
6926         getTarget : function(selector, maxDepth, returnEl){
6927             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6928         },
6929         /**
6930          * Gets the related target.
6931          * @return {HTMLElement}
6932          */
6933         getRelatedTarget : function(){
6934             if(this.browserEvent){
6935                 return E.getRelatedTarget(this.browserEvent);
6936             }
6937             return null;
6938         },
6939
6940         /**
6941          * Normalizes mouse wheel delta across browsers
6942          * @return {Number} The delta
6943          */
6944         getWheelDelta : function(){
6945             var e = this.browserEvent;
6946             var delta = 0;
6947             if(e.wheelDelta){ /* IE/Opera. */
6948                 delta = e.wheelDelta/120;
6949             }else if(e.detail){ /* Mozilla case. */
6950                 delta = -e.detail/3;
6951             }
6952             return delta;
6953         },
6954
6955         /**
6956          * Returns true if the control, meta, shift or alt key was pressed during this event.
6957          * @return {Boolean}
6958          */
6959         hasModifier : function(){
6960             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6961         },
6962
6963         /**
6964          * Returns true if the target of this event equals el or is a child of el
6965          * @param {String/HTMLElement/Element} el
6966          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6967          * @return {Boolean}
6968          */
6969         within : function(el, related){
6970             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6971             return t && Roo.fly(el).contains(t);
6972         },
6973
6974         getPoint : function(){
6975             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6976         }
6977     };
6978
6979     return new Roo.EventObjectImpl();
6980 }();
6981             
6982     /*
6983  * Based on:
6984  * Ext JS Library 1.1.1
6985  * Copyright(c) 2006-2007, Ext JS, LLC.
6986  *
6987  * Originally Released Under LGPL - original licence link has changed is not relivant.
6988  *
6989  * Fork - LGPL
6990  * <script type="text/javascript">
6991  */
6992
6993  
6994 // was in Composite Element!??!?!
6995  
6996 (function(){
6997     var D = Roo.lib.Dom;
6998     var E = Roo.lib.Event;
6999     var A = Roo.lib.Anim;
7000
7001     // local style camelizing for speed
7002     var propCache = {};
7003     var camelRe = /(-[a-z])/gi;
7004     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7005     var view = document.defaultView;
7006
7007 /**
7008  * @class Roo.Element
7009  * Represents an Element in the DOM.<br><br>
7010  * Usage:<br>
7011 <pre><code>
7012 var el = Roo.get("my-div");
7013
7014 // or with getEl
7015 var el = getEl("my-div");
7016
7017 // or with a DOM element
7018 var el = Roo.get(myDivElement);
7019 </code></pre>
7020  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7021  * each call instead of constructing a new one.<br><br>
7022  * <b>Animations</b><br />
7023  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7024  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7025 <pre>
7026 Option    Default   Description
7027 --------- --------  ---------------------------------------------
7028 duration  .35       The duration of the animation in seconds
7029 easing    easeOut   The YUI easing method
7030 callback  none      A function to execute when the anim completes
7031 scope     this      The scope (this) of the callback function
7032 </pre>
7033 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7034 * manipulate the animation. Here's an example:
7035 <pre><code>
7036 var el = Roo.get("my-div");
7037
7038 // no animation
7039 el.setWidth(100);
7040
7041 // default animation
7042 el.setWidth(100, true);
7043
7044 // animation with some options set
7045 el.setWidth(100, {
7046     duration: 1,
7047     callback: this.foo,
7048     scope: this
7049 });
7050
7051 // using the "anim" property to get the Anim object
7052 var opt = {
7053     duration: 1,
7054     callback: this.foo,
7055     scope: this
7056 };
7057 el.setWidth(100, opt);
7058 ...
7059 if(opt.anim.isAnimated()){
7060     opt.anim.stop();
7061 }
7062 </code></pre>
7063 * <b> Composite (Collections of) Elements</b><br />
7064  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7065  * @constructor Create a new Element directly.
7066  * @param {String/HTMLElement} element
7067  * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
7068  */
7069     Roo.Element = function(element, forceNew){
7070         var dom = typeof element == "string" ?
7071                 document.getElementById(element) : element;
7072         if(!dom){ // invalid id/element
7073             return null;
7074         }
7075         var id = dom.id;
7076         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7077             return Roo.Element.cache[id];
7078         }
7079
7080         /**
7081          * The DOM element
7082          * @type HTMLElement
7083          */
7084         this.dom = dom;
7085
7086         /**
7087          * The DOM element ID
7088          * @type String
7089          */
7090         this.id = id || Roo.id(dom);
7091     };
7092
7093     var El = Roo.Element;
7094
7095     El.prototype = {
7096         /**
7097          * The element's default display mode  (defaults to "")
7098          * @type String
7099          */
7100         originalDisplay : "",
7101
7102         visibilityMode : 1,
7103         /**
7104          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7105          * @type String
7106          */
7107         defaultUnit : "px",
7108         
7109         /**
7110          * Sets the element's visibility mode. When setVisible() is called it
7111          * will use this to determine whether to set the visibility or the display property.
7112          * @param visMode Element.VISIBILITY or Element.DISPLAY
7113          * @return {Roo.Element} this
7114          */
7115         setVisibilityMode : function(visMode){
7116             this.visibilityMode = visMode;
7117             return this;
7118         },
7119         /**
7120          * Convenience method for setVisibilityMode(Element.DISPLAY)
7121          * @param {String} display (optional) What to set display to when visible
7122          * @return {Roo.Element} this
7123          */
7124         enableDisplayMode : function(display){
7125             this.setVisibilityMode(El.DISPLAY);
7126             if(typeof display != "undefined") { this.originalDisplay = display; }
7127             return this;
7128         },
7129
7130         /**
7131          * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7132          * @param {String} selector The simple selector to test
7133          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7134                 search as a number or element (defaults to 10 || document.body)
7135          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7136          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7137          */
7138         findParent : function(simpleSelector, maxDepth, returnEl){
7139             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7140             maxDepth = maxDepth || 50;
7141             if(typeof maxDepth != "number"){
7142                 stopEl = Roo.getDom(maxDepth);
7143                 maxDepth = 10;
7144             }
7145             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7146                 if(dq.is(p, simpleSelector)){
7147                     return returnEl ? Roo.get(p) : p;
7148                 }
7149                 depth++;
7150                 p = p.parentNode;
7151             }
7152             return null;
7153         },
7154
7155
7156         /**
7157          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7158          * @param {String} selector The simple selector to test
7159          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7160                 search as a number or element (defaults to 10 || document.body)
7161          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7162          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7163          */
7164         findParentNode : function(simpleSelector, maxDepth, returnEl){
7165             var p = Roo.fly(this.dom.parentNode, '_internal');
7166             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7167         },
7168         
7169         /**
7170          * Looks at  the scrollable parent element
7171          */
7172         findScrollableParent : function()
7173         {
7174             var overflowRegex = /(auto|scroll)/;
7175             
7176             if(this.getStyle('position') === 'fixed'){
7177                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7178             }
7179             
7180             var excludeStaticParent = this.getStyle('position') === "absolute";
7181             
7182             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7183                 
7184                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7185                     continue;
7186                 }
7187                 
7188                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7189                     return parent;
7190                 }
7191                 
7192                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7193                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7194                 }
7195             }
7196             
7197             alert('is android : ' + Roo.isAndroid);
7198             alert('is ios : ' + Roo.isIOS);
7199             
7200             if(Roo.isAndroid){
7201                 alert('Is Android');
7202                 return Roo.get(document.documentElement);
7203             }
7204             
7205             if(!Roo.isAndroid){
7206                 alert('not android');
7207             }
7208             
7209             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7210         },
7211
7212         /**
7213          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7214          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7215          * @param {String} selector The simple selector to test
7216          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7217                 search as a number or element (defaults to 10 || document.body)
7218          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7219          */
7220         up : function(simpleSelector, maxDepth){
7221             return this.findParentNode(simpleSelector, maxDepth, true);
7222         },
7223
7224
7225
7226         /**
7227          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7228          * @param {String} selector The simple selector to test
7229          * @return {Boolean} True if this element matches the selector, else false
7230          */
7231         is : function(simpleSelector){
7232             return Roo.DomQuery.is(this.dom, simpleSelector);
7233         },
7234
7235         /**
7236          * Perform animation on this element.
7237          * @param {Object} args The YUI animation control args
7238          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7239          * @param {Function} onComplete (optional) Function to call when animation completes
7240          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7241          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7242          * @return {Roo.Element} this
7243          */
7244         animate : function(args, duration, onComplete, easing, animType){
7245             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7246             return this;
7247         },
7248
7249         /*
7250          * @private Internal animation call
7251          */
7252         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7253             animType = animType || 'run';
7254             opt = opt || {};
7255             var anim = Roo.lib.Anim[animType](
7256                 this.dom, args,
7257                 (opt.duration || defaultDur) || .35,
7258                 (opt.easing || defaultEase) || 'easeOut',
7259                 function(){
7260                     Roo.callback(cb, this);
7261                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7262                 },
7263                 this
7264             );
7265             opt.anim = anim;
7266             return anim;
7267         },
7268
7269         // private legacy anim prep
7270         preanim : function(a, i){
7271             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7272         },
7273
7274         /**
7275          * Removes worthless text nodes
7276          * @param {Boolean} forceReclean (optional) By default the element
7277          * keeps track if it has been cleaned already so
7278          * you can call this over and over. However, if you update the element and
7279          * need to force a reclean, you can pass true.
7280          */
7281         clean : function(forceReclean){
7282             if(this.isCleaned && forceReclean !== true){
7283                 return this;
7284             }
7285             var ns = /\S/;
7286             var d = this.dom, n = d.firstChild, ni = -1;
7287             while(n){
7288                 var nx = n.nextSibling;
7289                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7290                     d.removeChild(n);
7291                 }else{
7292                     n.nodeIndex = ++ni;
7293                 }
7294                 n = nx;
7295             }
7296             this.isCleaned = true;
7297             return this;
7298         },
7299
7300         // private
7301         calcOffsetsTo : function(el){
7302             el = Roo.get(el);
7303             var d = el.dom;
7304             var restorePos = false;
7305             if(el.getStyle('position') == 'static'){
7306                 el.position('relative');
7307                 restorePos = true;
7308             }
7309             var x = 0, y =0;
7310             var op = this.dom;
7311             while(op && op != d && op.tagName != 'HTML'){
7312                 x+= op.offsetLeft;
7313                 y+= op.offsetTop;
7314                 op = op.offsetParent;
7315             }
7316             if(restorePos){
7317                 el.position('static');
7318             }
7319             return [x, y];
7320         },
7321
7322         /**
7323          * Scrolls this element into view within the passed container.
7324          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7325          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7326          * @return {Roo.Element} this
7327          */
7328         scrollIntoView : function(container, hscroll){
7329             var c = Roo.getDom(container) || document.body;
7330             var el = this.dom;
7331
7332             var o = this.calcOffsetsTo(c),
7333                 l = o[0],
7334                 t = o[1],
7335                 b = t+el.offsetHeight,
7336                 r = l+el.offsetWidth;
7337
7338             var ch = c.clientHeight;
7339             var ct = parseInt(c.scrollTop, 10);
7340             var cl = parseInt(c.scrollLeft, 10);
7341             var cb = ct + ch;
7342             var cr = cl + c.clientWidth;
7343
7344             if(t < ct){
7345                 c.scrollTop = t;
7346             }else if(b > cb){
7347                 c.scrollTop = b-ch;
7348             }
7349
7350             if(hscroll !== false){
7351                 if(l < cl){
7352                     c.scrollLeft = l;
7353                 }else if(r > cr){
7354                     c.scrollLeft = r-c.clientWidth;
7355                 }
7356             }
7357             return this;
7358         },
7359
7360         // private
7361         scrollChildIntoView : function(child, hscroll){
7362             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7363         },
7364
7365         /**
7366          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7367          * the new height may not be available immediately.
7368          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7369          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7370          * @param {Function} onComplete (optional) Function to call when animation completes
7371          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7372          * @return {Roo.Element} this
7373          */
7374         autoHeight : function(animate, duration, onComplete, easing){
7375             var oldHeight = this.getHeight();
7376             this.clip();
7377             this.setHeight(1); // force clipping
7378             setTimeout(function(){
7379                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7380                 if(!animate){
7381                     this.setHeight(height);
7382                     this.unclip();
7383                     if(typeof onComplete == "function"){
7384                         onComplete();
7385                     }
7386                 }else{
7387                     this.setHeight(oldHeight); // restore original height
7388                     this.setHeight(height, animate, duration, function(){
7389                         this.unclip();
7390                         if(typeof onComplete == "function") { onComplete(); }
7391                     }.createDelegate(this), easing);
7392                 }
7393             }.createDelegate(this), 0);
7394             return this;
7395         },
7396
7397         /**
7398          * Returns true if this element is an ancestor of the passed element
7399          * @param {HTMLElement/String} el The element to check
7400          * @return {Boolean} True if this element is an ancestor of el, else false
7401          */
7402         contains : function(el){
7403             if(!el){return false;}
7404             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7405         },
7406
7407         /**
7408          * Checks whether the element is currently visible using both visibility and display properties.
7409          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7410          * @return {Boolean} True if the element is currently visible, else false
7411          */
7412         isVisible : function(deep) {
7413             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7414             if(deep !== true || !vis){
7415                 return vis;
7416             }
7417             var p = this.dom.parentNode;
7418             while(p && p.tagName.toLowerCase() != "body"){
7419                 if(!Roo.fly(p, '_isVisible').isVisible()){
7420                     return false;
7421                 }
7422                 p = p.parentNode;
7423             }
7424             return true;
7425         },
7426
7427         /**
7428          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7429          * @param {String} selector The CSS selector
7430          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7431          * @return {CompositeElement/CompositeElementLite} The composite element
7432          */
7433         select : function(selector, unique){
7434             return El.select(selector, unique, this.dom);
7435         },
7436
7437         /**
7438          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7439          * @param {String} selector The CSS selector
7440          * @return {Array} An array of the matched nodes
7441          */
7442         query : function(selector, unique){
7443             return Roo.DomQuery.select(selector, this.dom);
7444         },
7445
7446         /**
7447          * Selects a single child at any depth below this element 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         child : function(selector, returnDom){
7453             var n = Roo.DomQuery.selectNode(selector, this.dom);
7454             return returnDom ? n : Roo.get(n);
7455         },
7456
7457         /**
7458          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7459          * @param {String} selector The CSS selector
7460          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7461          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7462          */
7463         down : function(selector, returnDom){
7464             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7465             return returnDom ? n : Roo.get(n);
7466         },
7467
7468         /**
7469          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7470          * @param {String} group The group the DD object is member of
7471          * @param {Object} config The DD config object
7472          * @param {Object} overrides An object containing methods to override/implement on the DD object
7473          * @return {Roo.dd.DD} The DD object
7474          */
7475         initDD : function(group, config, overrides){
7476             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7477             return Roo.apply(dd, overrides);
7478         },
7479
7480         /**
7481          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7482          * @param {String} group The group the DDProxy object is member of
7483          * @param {Object} config The DDProxy config object
7484          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7485          * @return {Roo.dd.DDProxy} The DDProxy object
7486          */
7487         initDDProxy : function(group, config, overrides){
7488             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7489             return Roo.apply(dd, overrides);
7490         },
7491
7492         /**
7493          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7494          * @param {String} group The group the DDTarget object is member of
7495          * @param {Object} config The DDTarget config object
7496          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7497          * @return {Roo.dd.DDTarget} The DDTarget object
7498          */
7499         initDDTarget : function(group, config, overrides){
7500             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7501             return Roo.apply(dd, overrides);
7502         },
7503
7504         /**
7505          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7506          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7507          * @param {Boolean} visible Whether the element is visible
7508          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7509          * @return {Roo.Element} this
7510          */
7511          setVisible : function(visible, animate){
7512             if(!animate || !A){
7513                 if(this.visibilityMode == El.DISPLAY){
7514                     this.setDisplayed(visible);
7515                 }else{
7516                     this.fixDisplay();
7517                     this.dom.style.visibility = visible ? "visible" : "hidden";
7518                 }
7519             }else{
7520                 // closure for composites
7521                 var dom = this.dom;
7522                 var visMode = this.visibilityMode;
7523                 if(visible){
7524                     this.setOpacity(.01);
7525                     this.setVisible(true);
7526                 }
7527                 this.anim({opacity: { to: (visible?1:0) }},
7528                       this.preanim(arguments, 1),
7529                       null, .35, 'easeIn', function(){
7530                          if(!visible){
7531                              if(visMode == El.DISPLAY){
7532                                  dom.style.display = "none";
7533                              }else{
7534                                  dom.style.visibility = "hidden";
7535                              }
7536                              Roo.get(dom).setOpacity(1);
7537                          }
7538                      });
7539             }
7540             return this;
7541         },
7542
7543         /**
7544          * Returns true if display is not "none"
7545          * @return {Boolean}
7546          */
7547         isDisplayed : function() {
7548             return this.getStyle("display") != "none";
7549         },
7550
7551         /**
7552          * Toggles the element's visibility or display, depending on visibility mode.
7553          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7554          * @return {Roo.Element} this
7555          */
7556         toggle : function(animate){
7557             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7558             return this;
7559         },
7560
7561         /**
7562          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7563          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7564          * @return {Roo.Element} this
7565          */
7566         setDisplayed : function(value) {
7567             if(typeof value == "boolean"){
7568                value = value ? this.originalDisplay : "none";
7569             }
7570             this.setStyle("display", value);
7571             return this;
7572         },
7573
7574         /**
7575          * Tries to focus the element. Any exceptions are caught and ignored.
7576          * @return {Roo.Element} this
7577          */
7578         focus : function() {
7579             try{
7580                 this.dom.focus();
7581             }catch(e){}
7582             return this;
7583         },
7584
7585         /**
7586          * Tries to blur the element. Any exceptions are caught and ignored.
7587          * @return {Roo.Element} this
7588          */
7589         blur : function() {
7590             try{
7591                 this.dom.blur();
7592             }catch(e){}
7593             return this;
7594         },
7595
7596         /**
7597          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7598          * @param {String/Array} className The CSS class to add, or an array of classes
7599          * @return {Roo.Element} this
7600          */
7601         addClass : function(className){
7602             if(className instanceof Array){
7603                 for(var i = 0, len = className.length; i < len; i++) {
7604                     this.addClass(className[i]);
7605                 }
7606             }else{
7607                 if(className && !this.hasClass(className)){
7608                     this.dom.className = this.dom.className + " " + className;
7609                 }
7610             }
7611             return this;
7612         },
7613
7614         /**
7615          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7616          * @param {String/Array} className The CSS class to add, or an array of classes
7617          * @return {Roo.Element} this
7618          */
7619         radioClass : function(className){
7620             var siblings = this.dom.parentNode.childNodes;
7621             for(var i = 0; i < siblings.length; i++) {
7622                 var s = siblings[i];
7623                 if(s.nodeType == 1){
7624                     Roo.get(s).removeClass(className);
7625                 }
7626             }
7627             this.addClass(className);
7628             return this;
7629         },
7630
7631         /**
7632          * Removes one or more CSS classes from the element.
7633          * @param {String/Array} className The CSS class to remove, or an array of classes
7634          * @return {Roo.Element} this
7635          */
7636         removeClass : function(className){
7637             if(!className || !this.dom.className){
7638                 return this;
7639             }
7640             if(className instanceof Array){
7641                 for(var i = 0, len = className.length; i < len; i++) {
7642                     this.removeClass(className[i]);
7643                 }
7644             }else{
7645                 if(this.hasClass(className)){
7646                     var re = this.classReCache[className];
7647                     if (!re) {
7648                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7649                        this.classReCache[className] = re;
7650                     }
7651                     this.dom.className =
7652                         this.dom.className.replace(re, " ");
7653                 }
7654             }
7655             return this;
7656         },
7657
7658         // private
7659         classReCache: {},
7660
7661         /**
7662          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7663          * @param {String} className The CSS class to toggle
7664          * @return {Roo.Element} this
7665          */
7666         toggleClass : function(className){
7667             if(this.hasClass(className)){
7668                 this.removeClass(className);
7669             }else{
7670                 this.addClass(className);
7671             }
7672             return this;
7673         },
7674
7675         /**
7676          * Checks if the specified CSS class exists on this element's DOM node.
7677          * @param {String} className The CSS class to check for
7678          * @return {Boolean} True if the class exists, else false
7679          */
7680         hasClass : function(className){
7681             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7682         },
7683
7684         /**
7685          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7686          * @param {String} oldClassName The CSS class to replace
7687          * @param {String} newClassName The replacement CSS class
7688          * @return {Roo.Element} this
7689          */
7690         replaceClass : function(oldClassName, newClassName){
7691             this.removeClass(oldClassName);
7692             this.addClass(newClassName);
7693             return this;
7694         },
7695
7696         /**
7697          * Returns an object with properties matching the styles requested.
7698          * For example, el.getStyles('color', 'font-size', 'width') might return
7699          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7700          * @param {String} style1 A style name
7701          * @param {String} style2 A style name
7702          * @param {String} etc.
7703          * @return {Object} The style object
7704          */
7705         getStyles : function(){
7706             var a = arguments, len = a.length, r = {};
7707             for(var i = 0; i < len; i++){
7708                 r[a[i]] = this.getStyle(a[i]);
7709             }
7710             return r;
7711         },
7712
7713         /**
7714          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7715          * @param {String} property The style property whose value is returned.
7716          * @return {String} The current value of the style property for this element.
7717          */
7718         getStyle : function(){
7719             return view && view.getComputedStyle ?
7720                 function(prop){
7721                     var el = this.dom, v, cs, camel;
7722                     if(prop == 'float'){
7723                         prop = "cssFloat";
7724                     }
7725                     if(el.style && (v = el.style[prop])){
7726                         return v;
7727                     }
7728                     if(cs = view.getComputedStyle(el, "")){
7729                         if(!(camel = propCache[prop])){
7730                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7731                         }
7732                         return cs[camel];
7733                     }
7734                     return null;
7735                 } :
7736                 function(prop){
7737                     var el = this.dom, v, cs, camel;
7738                     if(prop == 'opacity'){
7739                         if(typeof el.style.filter == 'string'){
7740                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7741                             if(m){
7742                                 var fv = parseFloat(m[1]);
7743                                 if(!isNaN(fv)){
7744                                     return fv ? fv / 100 : 0;
7745                                 }
7746                             }
7747                         }
7748                         return 1;
7749                     }else if(prop == 'float'){
7750                         prop = "styleFloat";
7751                     }
7752                     if(!(camel = propCache[prop])){
7753                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7754                     }
7755                     if(v = el.style[camel]){
7756                         return v;
7757                     }
7758                     if(cs = el.currentStyle){
7759                         return cs[camel];
7760                     }
7761                     return null;
7762                 };
7763         }(),
7764
7765         /**
7766          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7767          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7768          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7769          * @return {Roo.Element} this
7770          */
7771         setStyle : function(prop, value){
7772             if(typeof prop == "string"){
7773                 
7774                 if (prop == 'float') {
7775                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7776                     return this;
7777                 }
7778                 
7779                 var camel;
7780                 if(!(camel = propCache[prop])){
7781                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7782                 }
7783                 
7784                 if(camel == 'opacity') {
7785                     this.setOpacity(value);
7786                 }else{
7787                     this.dom.style[camel] = value;
7788                 }
7789             }else{
7790                 for(var style in prop){
7791                     if(typeof prop[style] != "function"){
7792                        this.setStyle(style, prop[style]);
7793                     }
7794                 }
7795             }
7796             return this;
7797         },
7798
7799         /**
7800          * More flexible version of {@link #setStyle} for setting style properties.
7801          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7802          * a function which returns such a specification.
7803          * @return {Roo.Element} this
7804          */
7805         applyStyles : function(style){
7806             Roo.DomHelper.applyStyles(this.dom, style);
7807             return this;
7808         },
7809
7810         /**
7811           * 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).
7812           * @return {Number} The X position of the element
7813           */
7814         getX : function(){
7815             return D.getX(this.dom);
7816         },
7817
7818         /**
7819           * 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).
7820           * @return {Number} The Y position of the element
7821           */
7822         getY : function(){
7823             return D.getY(this.dom);
7824         },
7825
7826         /**
7827           * 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).
7828           * @return {Array} The XY position of the element
7829           */
7830         getXY : function(){
7831             return D.getXY(this.dom);
7832         },
7833
7834         /**
7835          * 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).
7836          * @param {Number} The X position of the element
7837          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7838          * @return {Roo.Element} this
7839          */
7840         setX : function(x, animate){
7841             if(!animate || !A){
7842                 D.setX(this.dom, x);
7843             }else{
7844                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7845             }
7846             return this;
7847         },
7848
7849         /**
7850          * 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).
7851          * @param {Number} The Y position of the element
7852          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7853          * @return {Roo.Element} this
7854          */
7855         setY : function(y, animate){
7856             if(!animate || !A){
7857                 D.setY(this.dom, y);
7858             }else{
7859                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7860             }
7861             return this;
7862         },
7863
7864         /**
7865          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7866          * @param {String} left The left CSS property value
7867          * @return {Roo.Element} this
7868          */
7869         setLeft : function(left){
7870             this.setStyle("left", this.addUnits(left));
7871             return this;
7872         },
7873
7874         /**
7875          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7876          * @param {String} top The top CSS property value
7877          * @return {Roo.Element} this
7878          */
7879         setTop : function(top){
7880             this.setStyle("top", this.addUnits(top));
7881             return this;
7882         },
7883
7884         /**
7885          * Sets the element's CSS right style.
7886          * @param {String} right The right CSS property value
7887          * @return {Roo.Element} this
7888          */
7889         setRight : function(right){
7890             this.setStyle("right", this.addUnits(right));
7891             return this;
7892         },
7893
7894         /**
7895          * Sets the element's CSS bottom style.
7896          * @param {String} bottom The bottom CSS property value
7897          * @return {Roo.Element} this
7898          */
7899         setBottom : function(bottom){
7900             this.setStyle("bottom", this.addUnits(bottom));
7901             return this;
7902         },
7903
7904         /**
7905          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7906          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7907          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7908          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7909          * @return {Roo.Element} this
7910          */
7911         setXY : function(pos, animate){
7912             if(!animate || !A){
7913                 D.setXY(this.dom, pos);
7914             }else{
7915                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7916             }
7917             return this;
7918         },
7919
7920         /**
7921          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7922          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7923          * @param {Number} x X value for new position (coordinates are page-based)
7924          * @param {Number} y Y value for new position (coordinates are page-based)
7925          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7926          * @return {Roo.Element} this
7927          */
7928         setLocation : function(x, y, animate){
7929             this.setXY([x, y], this.preanim(arguments, 2));
7930             return this;
7931         },
7932
7933         /**
7934          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7935          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7936          * @param {Number} x X value for new position (coordinates are page-based)
7937          * @param {Number} y Y value for new position (coordinates are page-based)
7938          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7939          * @return {Roo.Element} this
7940          */
7941         moveTo : function(x, y, animate){
7942             this.setXY([x, y], this.preanim(arguments, 2));
7943             return this;
7944         },
7945
7946         /**
7947          * Returns the region of the given element.
7948          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7949          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7950          */
7951         getRegion : function(){
7952             return D.getRegion(this.dom);
7953         },
7954
7955         /**
7956          * Returns the offset height of the element
7957          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7958          * @return {Number} The element's height
7959          */
7960         getHeight : function(contentHeight){
7961             var h = this.dom.offsetHeight || 0;
7962             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7963         },
7964
7965         /**
7966          * Returns the offset width of the element
7967          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7968          * @return {Number} The element's width
7969          */
7970         getWidth : function(contentWidth){
7971             var w = this.dom.offsetWidth || 0;
7972             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7973         },
7974
7975         /**
7976          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7977          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7978          * if a height has not been set using CSS.
7979          * @return {Number}
7980          */
7981         getComputedHeight : function(){
7982             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7983             if(!h){
7984                 h = parseInt(this.getStyle('height'), 10) || 0;
7985                 if(!this.isBorderBox()){
7986                     h += this.getFrameWidth('tb');
7987                 }
7988             }
7989             return h;
7990         },
7991
7992         /**
7993          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7994          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7995          * if a width has not been set using CSS.
7996          * @return {Number}
7997          */
7998         getComputedWidth : function(){
7999             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8000             if(!w){
8001                 w = parseInt(this.getStyle('width'), 10) || 0;
8002                 if(!this.isBorderBox()){
8003                     w += this.getFrameWidth('lr');
8004                 }
8005             }
8006             return w;
8007         },
8008
8009         /**
8010          * Returns the size of the element.
8011          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8012          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8013          */
8014         getSize : function(contentSize){
8015             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8016         },
8017
8018         /**
8019          * Returns the width and height of the viewport.
8020          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8021          */
8022         getViewSize : function(){
8023             var d = this.dom, doc = document, aw = 0, ah = 0;
8024             if(d == doc || d == doc.body){
8025                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8026             }else{
8027                 return {
8028                     width : d.clientWidth,
8029                     height: d.clientHeight
8030                 };
8031             }
8032         },
8033
8034         /**
8035          * Returns the value of the "value" attribute
8036          * @param {Boolean} asNumber true to parse the value as a number
8037          * @return {String/Number}
8038          */
8039         getValue : function(asNumber){
8040             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8041         },
8042
8043         // private
8044         adjustWidth : function(width){
8045             if(typeof width == "number"){
8046                 if(this.autoBoxAdjust && !this.isBorderBox()){
8047                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8048                 }
8049                 if(width < 0){
8050                     width = 0;
8051                 }
8052             }
8053             return width;
8054         },
8055
8056         // private
8057         adjustHeight : function(height){
8058             if(typeof height == "number"){
8059                if(this.autoBoxAdjust && !this.isBorderBox()){
8060                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8061                }
8062                if(height < 0){
8063                    height = 0;
8064                }
8065             }
8066             return height;
8067         },
8068
8069         /**
8070          * Set the width of the element
8071          * @param {Number} width The new width
8072          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8073          * @return {Roo.Element} this
8074          */
8075         setWidth : function(width, animate){
8076             width = this.adjustWidth(width);
8077             if(!animate || !A){
8078                 this.dom.style.width = this.addUnits(width);
8079             }else{
8080                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8081             }
8082             return this;
8083         },
8084
8085         /**
8086          * Set the height of the element
8087          * @param {Number} height The new height
8088          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8089          * @return {Roo.Element} this
8090          */
8091          setHeight : function(height, animate){
8092             height = this.adjustHeight(height);
8093             if(!animate || !A){
8094                 this.dom.style.height = this.addUnits(height);
8095             }else{
8096                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8097             }
8098             return this;
8099         },
8100
8101         /**
8102          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8103          * @param {Number} width The new width
8104          * @param {Number} height The new height
8105          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8106          * @return {Roo.Element} this
8107          */
8108          setSize : function(width, height, animate){
8109             if(typeof width == "object"){ // in case of object from getSize()
8110                 height = width.height; width = width.width;
8111             }
8112             width = this.adjustWidth(width); height = this.adjustHeight(height);
8113             if(!animate || !A){
8114                 this.dom.style.width = this.addUnits(width);
8115                 this.dom.style.height = this.addUnits(height);
8116             }else{
8117                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8118             }
8119             return this;
8120         },
8121
8122         /**
8123          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8124          * @param {Number} x X value for new position (coordinates are page-based)
8125          * @param {Number} y Y value for new position (coordinates are page-based)
8126          * @param {Number} width The new width
8127          * @param {Number} height The new height
8128          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8129          * @return {Roo.Element} this
8130          */
8131         setBounds : function(x, y, width, height, animate){
8132             if(!animate || !A){
8133                 this.setSize(width, height);
8134                 this.setLocation(x, y);
8135             }else{
8136                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8137                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8138                               this.preanim(arguments, 4), 'motion');
8139             }
8140             return this;
8141         },
8142
8143         /**
8144          * 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.
8145          * @param {Roo.lib.Region} region The region to fill
8146          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8147          * @return {Roo.Element} this
8148          */
8149         setRegion : function(region, animate){
8150             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8151             return this;
8152         },
8153
8154         /**
8155          * Appends an event handler
8156          *
8157          * @param {String}   eventName     The type of event to append
8158          * @param {Function} fn        The method the event invokes
8159          * @param {Object} scope       (optional) The scope (this object) of the fn
8160          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8161          */
8162         addListener : function(eventName, fn, scope, options){
8163             if (this.dom) {
8164                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8165             }
8166         },
8167
8168         /**
8169          * Removes an event handler from this element
8170          * @param {String} eventName the type of event to remove
8171          * @param {Function} fn the method the event invokes
8172          * @return {Roo.Element} this
8173          */
8174         removeListener : function(eventName, fn){
8175             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8176             return this;
8177         },
8178
8179         /**
8180          * Removes all previous added listeners from this element
8181          * @return {Roo.Element} this
8182          */
8183         removeAllListeners : function(){
8184             E.purgeElement(this.dom);
8185             return this;
8186         },
8187
8188         relayEvent : function(eventName, observable){
8189             this.on(eventName, function(e){
8190                 observable.fireEvent(eventName, e);
8191             });
8192         },
8193
8194         /**
8195          * Set the opacity of the element
8196          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8197          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8198          * @return {Roo.Element} this
8199          */
8200          setOpacity : function(opacity, animate){
8201             if(!animate || !A){
8202                 var s = this.dom.style;
8203                 if(Roo.isIE){
8204                     s.zoom = 1;
8205                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8206                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8207                 }else{
8208                     s.opacity = opacity;
8209                 }
8210             }else{
8211                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8212             }
8213             return this;
8214         },
8215
8216         /**
8217          * Gets the left X coordinate
8218          * @param {Boolean} local True to get the local css position instead of page coordinate
8219          * @return {Number}
8220          */
8221         getLeft : function(local){
8222             if(!local){
8223                 return this.getX();
8224             }else{
8225                 return parseInt(this.getStyle("left"), 10) || 0;
8226             }
8227         },
8228
8229         /**
8230          * Gets the right X coordinate of the element (element X position + element width)
8231          * @param {Boolean} local True to get the local css position instead of page coordinate
8232          * @return {Number}
8233          */
8234         getRight : function(local){
8235             if(!local){
8236                 return this.getX() + this.getWidth();
8237             }else{
8238                 return (this.getLeft(true) + this.getWidth()) || 0;
8239             }
8240         },
8241
8242         /**
8243          * Gets the top Y coordinate
8244          * @param {Boolean} local True to get the local css position instead of page coordinate
8245          * @return {Number}
8246          */
8247         getTop : function(local) {
8248             if(!local){
8249                 return this.getY();
8250             }else{
8251                 return parseInt(this.getStyle("top"), 10) || 0;
8252             }
8253         },
8254
8255         /**
8256          * Gets the bottom Y coordinate of the element (element Y position + element height)
8257          * @param {Boolean} local True to get the local css position instead of page coordinate
8258          * @return {Number}
8259          */
8260         getBottom : function(local){
8261             if(!local){
8262                 return this.getY() + this.getHeight();
8263             }else{
8264                 return (this.getTop(true) + this.getHeight()) || 0;
8265             }
8266         },
8267
8268         /**
8269         * Initializes positioning on this element. If a desired position is not passed, it will make the
8270         * the element positioned relative IF it is not already positioned.
8271         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8272         * @param {Number} zIndex (optional) The zIndex to apply
8273         * @param {Number} x (optional) Set the page X position
8274         * @param {Number} y (optional) Set the page Y position
8275         */
8276         position : function(pos, zIndex, x, y){
8277             if(!pos){
8278                if(this.getStyle('position') == 'static'){
8279                    this.setStyle('position', 'relative');
8280                }
8281             }else{
8282                 this.setStyle("position", pos);
8283             }
8284             if(zIndex){
8285                 this.setStyle("z-index", zIndex);
8286             }
8287             if(x !== undefined && y !== undefined){
8288                 this.setXY([x, y]);
8289             }else if(x !== undefined){
8290                 this.setX(x);
8291             }else if(y !== undefined){
8292                 this.setY(y);
8293             }
8294         },
8295
8296         /**
8297         * Clear positioning back to the default when the document was loaded
8298         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8299         * @return {Roo.Element} this
8300          */
8301         clearPositioning : function(value){
8302             value = value ||'';
8303             this.setStyle({
8304                 "left": value,
8305                 "right": value,
8306                 "top": value,
8307                 "bottom": value,
8308                 "z-index": "",
8309                 "position" : "static"
8310             });
8311             return this;
8312         },
8313
8314         /**
8315         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8316         * snapshot before performing an update and then restoring the element.
8317         * @return {Object}
8318         */
8319         getPositioning : function(){
8320             var l = this.getStyle("left");
8321             var t = this.getStyle("top");
8322             return {
8323                 "position" : this.getStyle("position"),
8324                 "left" : l,
8325                 "right" : l ? "" : this.getStyle("right"),
8326                 "top" : t,
8327                 "bottom" : t ? "" : this.getStyle("bottom"),
8328                 "z-index" : this.getStyle("z-index")
8329             };
8330         },
8331
8332         /**
8333          * Gets the width of the border(s) for the specified side(s)
8334          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8335          * passing lr would get the border (l)eft width + the border (r)ight width.
8336          * @return {Number} The width of the sides passed added together
8337          */
8338         getBorderWidth : function(side){
8339             return this.addStyles(side, El.borders);
8340         },
8341
8342         /**
8343          * Gets the width of the padding(s) for the specified side(s)
8344          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8345          * passing lr would get the padding (l)eft + the padding (r)ight.
8346          * @return {Number} The padding of the sides passed added together
8347          */
8348         getPadding : function(side){
8349             return this.addStyles(side, El.paddings);
8350         },
8351
8352         /**
8353         * Set positioning with an object returned by getPositioning().
8354         * @param {Object} posCfg
8355         * @return {Roo.Element} this
8356          */
8357         setPositioning : function(pc){
8358             this.applyStyles(pc);
8359             if(pc.right == "auto"){
8360                 this.dom.style.right = "";
8361             }
8362             if(pc.bottom == "auto"){
8363                 this.dom.style.bottom = "";
8364             }
8365             return this;
8366         },
8367
8368         // private
8369         fixDisplay : function(){
8370             if(this.getStyle("display") == "none"){
8371                 this.setStyle("visibility", "hidden");
8372                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8373                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8374                     this.setStyle("display", "block");
8375                 }
8376             }
8377         },
8378
8379         /**
8380          * Quick set left and top adding default units
8381          * @param {String} left The left CSS property value
8382          * @param {String} top The top CSS property value
8383          * @return {Roo.Element} this
8384          */
8385          setLeftTop : function(left, top){
8386             this.dom.style.left = this.addUnits(left);
8387             this.dom.style.top = this.addUnits(top);
8388             return this;
8389         },
8390
8391         /**
8392          * Move this element relative to its current position.
8393          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8394          * @param {Number} distance How far to move the element in pixels
8395          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8396          * @return {Roo.Element} this
8397          */
8398          move : function(direction, distance, animate){
8399             var xy = this.getXY();
8400             direction = direction.toLowerCase();
8401             switch(direction){
8402                 case "l":
8403                 case "left":
8404                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8405                     break;
8406                case "r":
8407                case "right":
8408                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8409                     break;
8410                case "t":
8411                case "top":
8412                case "up":
8413                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8414                     break;
8415                case "b":
8416                case "bottom":
8417                case "down":
8418                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8419                     break;
8420             }
8421             return this;
8422         },
8423
8424         /**
8425          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8426          * @return {Roo.Element} this
8427          */
8428         clip : function(){
8429             if(!this.isClipped){
8430                this.isClipped = true;
8431                this.originalClip = {
8432                    "o": this.getStyle("overflow"),
8433                    "x": this.getStyle("overflow-x"),
8434                    "y": this.getStyle("overflow-y")
8435                };
8436                this.setStyle("overflow", "hidden");
8437                this.setStyle("overflow-x", "hidden");
8438                this.setStyle("overflow-y", "hidden");
8439             }
8440             return this;
8441         },
8442
8443         /**
8444          *  Return clipping (overflow) to original clipping before clip() was called
8445          * @return {Roo.Element} this
8446          */
8447         unclip : function(){
8448             if(this.isClipped){
8449                 this.isClipped = false;
8450                 var o = this.originalClip;
8451                 if(o.o){this.setStyle("overflow", o.o);}
8452                 if(o.x){this.setStyle("overflow-x", o.x);}
8453                 if(o.y){this.setStyle("overflow-y", o.y);}
8454             }
8455             return this;
8456         },
8457
8458
8459         /**
8460          * Gets the x,y coordinates specified by the anchor position on the element.
8461          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8462          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8463          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8464          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8465          * @return {Array} [x, y] An array containing the element's x and y coordinates
8466          */
8467         getAnchorXY : function(anchor, local, s){
8468             //Passing a different size is useful for pre-calculating anchors,
8469             //especially for anchored animations that change the el size.
8470
8471             var w, h, vp = false;
8472             if(!s){
8473                 var d = this.dom;
8474                 if(d == document.body || d == document){
8475                     vp = true;
8476                     w = D.getViewWidth(); h = D.getViewHeight();
8477                 }else{
8478                     w = this.getWidth(); h = this.getHeight();
8479                 }
8480             }else{
8481                 w = s.width;  h = s.height;
8482             }
8483             var x = 0, y = 0, r = Math.round;
8484             switch((anchor || "tl").toLowerCase()){
8485                 case "c":
8486                     x = r(w*.5);
8487                     y = r(h*.5);
8488                 break;
8489                 case "t":
8490                     x = r(w*.5);
8491                     y = 0;
8492                 break;
8493                 case "l":
8494                     x = 0;
8495                     y = r(h*.5);
8496                 break;
8497                 case "r":
8498                     x = w;
8499                     y = r(h*.5);
8500                 break;
8501                 case "b":
8502                     x = r(w*.5);
8503                     y = h;
8504                 break;
8505                 case "tl":
8506                     x = 0;
8507                     y = 0;
8508                 break;
8509                 case "bl":
8510                     x = 0;
8511                     y = h;
8512                 break;
8513                 case "br":
8514                     x = w;
8515                     y = h;
8516                 break;
8517                 case "tr":
8518                     x = w;
8519                     y = 0;
8520                 break;
8521             }
8522             if(local === true){
8523                 return [x, y];
8524             }
8525             if(vp){
8526                 var sc = this.getScroll();
8527                 return [x + sc.left, y + sc.top];
8528             }
8529             //Add the element's offset xy
8530             var o = this.getXY();
8531             return [x+o[0], y+o[1]];
8532         },
8533
8534         /**
8535          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8536          * supported position values.
8537          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8538          * @param {String} position The position to align to.
8539          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8540          * @return {Array} [x, y]
8541          */
8542         getAlignToXY : function(el, p, o){
8543             el = Roo.get(el);
8544             var d = this.dom;
8545             if(!el.dom){
8546                 throw "Element.alignTo with an element that doesn't exist";
8547             }
8548             var c = false; //constrain to viewport
8549             var p1 = "", p2 = "";
8550             o = o || [0,0];
8551
8552             if(!p){
8553                 p = "tl-bl";
8554             }else if(p == "?"){
8555                 p = "tl-bl?";
8556             }else if(p.indexOf("-") == -1){
8557                 p = "tl-" + p;
8558             }
8559             p = p.toLowerCase();
8560             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8561             if(!m){
8562                throw "Element.alignTo with an invalid alignment " + p;
8563             }
8564             p1 = m[1]; p2 = m[2]; c = !!m[3];
8565
8566             //Subtract the aligned el's internal xy from the target's offset xy
8567             //plus custom offset to get the aligned el's new offset xy
8568             var a1 = this.getAnchorXY(p1, true);
8569             var a2 = el.getAnchorXY(p2, false);
8570             var x = a2[0] - a1[0] + o[0];
8571             var y = a2[1] - a1[1] + o[1];
8572             if(c){
8573                 //constrain the aligned el to viewport if necessary
8574                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8575                 // 5px of margin for ie
8576                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8577
8578                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8579                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8580                 //otherwise swap the aligned el to the opposite border of the target.
8581                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8582                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8583                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8584                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8585
8586                var doc = document;
8587                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8588                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8589
8590                if((x+w) > dw + scrollX){
8591                     x = swapX ? r.left-w : dw+scrollX-w;
8592                 }
8593                if(x < scrollX){
8594                    x = swapX ? r.right : scrollX;
8595                }
8596                if((y+h) > dh + scrollY){
8597                     y = swapY ? r.top-h : dh+scrollY-h;
8598                 }
8599                if (y < scrollY){
8600                    y = swapY ? r.bottom : scrollY;
8601                }
8602             }
8603             return [x,y];
8604         },
8605
8606         // private
8607         getConstrainToXY : function(){
8608             var os = {top:0, left:0, bottom:0, right: 0};
8609
8610             return function(el, local, offsets, proposedXY){
8611                 el = Roo.get(el);
8612                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8613
8614                 var vw, vh, vx = 0, vy = 0;
8615                 if(el.dom == document.body || el.dom == document){
8616                     vw = Roo.lib.Dom.getViewWidth();
8617                     vh = Roo.lib.Dom.getViewHeight();
8618                 }else{
8619                     vw = el.dom.clientWidth;
8620                     vh = el.dom.clientHeight;
8621                     if(!local){
8622                         var vxy = el.getXY();
8623                         vx = vxy[0];
8624                         vy = vxy[1];
8625                     }
8626                 }
8627
8628                 var s = el.getScroll();
8629
8630                 vx += offsets.left + s.left;
8631                 vy += offsets.top + s.top;
8632
8633                 vw -= offsets.right;
8634                 vh -= offsets.bottom;
8635
8636                 var vr = vx+vw;
8637                 var vb = vy+vh;
8638
8639                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8640                 var x = xy[0], y = xy[1];
8641                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8642
8643                 // only move it if it needs it
8644                 var moved = false;
8645
8646                 // first validate right/bottom
8647                 if((x + w) > vr){
8648                     x = vr - w;
8649                     moved = true;
8650                 }
8651                 if((y + h) > vb){
8652                     y = vb - h;
8653                     moved = true;
8654                 }
8655                 // then make sure top/left isn't negative
8656                 if(x < vx){
8657                     x = vx;
8658                     moved = true;
8659                 }
8660                 if(y < vy){
8661                     y = vy;
8662                     moved = true;
8663                 }
8664                 return moved ? [x, y] : false;
8665             };
8666         }(),
8667
8668         // private
8669         adjustForConstraints : function(xy, parent, offsets){
8670             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8671         },
8672
8673         /**
8674          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8675          * document it aligns it to the viewport.
8676          * The position parameter is optional, and can be specified in any one of the following formats:
8677          * <ul>
8678          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8679          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8680          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8681          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8682          *   <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
8683          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8684          * </ul>
8685          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8686          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8687          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8688          * that specified in order to enforce the viewport constraints.
8689          * Following are all of the supported anchor positions:
8690     <pre>
8691     Value  Description
8692     -----  -----------------------------
8693     tl     The top left corner (default)
8694     t      The center of the top edge
8695     tr     The top right corner
8696     l      The center of the left edge
8697     c      In the center of the element
8698     r      The center of the right edge
8699     bl     The bottom left corner
8700     b      The center of the bottom edge
8701     br     The bottom right corner
8702     </pre>
8703     Example Usage:
8704     <pre><code>
8705     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8706     el.alignTo("other-el");
8707
8708     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8709     el.alignTo("other-el", "tr?");
8710
8711     // align the bottom right corner of el with the center left edge of other-el
8712     el.alignTo("other-el", "br-l?");
8713
8714     // align the center of el with the bottom left corner of other-el and
8715     // adjust the x position by -6 pixels (and the y position by 0)
8716     el.alignTo("other-el", "c-bl", [-6, 0]);
8717     </code></pre>
8718          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8719          * @param {String} position The position to align to.
8720          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8721          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8722          * @return {Roo.Element} this
8723          */
8724         alignTo : function(element, position, offsets, animate){
8725             var xy = this.getAlignToXY(element, position, offsets);
8726             this.setXY(xy, this.preanim(arguments, 3));
8727             return this;
8728         },
8729
8730         /**
8731          * Anchors an element to another element and realigns it when the window is resized.
8732          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8733          * @param {String} position The position to align to.
8734          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8735          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8736          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8737          * is a number, it is used as the buffer delay (defaults to 50ms).
8738          * @param {Function} callback The function to call after the animation finishes
8739          * @return {Roo.Element} this
8740          */
8741         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8742             var action = function(){
8743                 this.alignTo(el, alignment, offsets, animate);
8744                 Roo.callback(callback, this);
8745             };
8746             Roo.EventManager.onWindowResize(action, this);
8747             var tm = typeof monitorScroll;
8748             if(tm != 'undefined'){
8749                 Roo.EventManager.on(window, 'scroll', action, this,
8750                     {buffer: tm == 'number' ? monitorScroll : 50});
8751             }
8752             action.call(this); // align immediately
8753             return this;
8754         },
8755         /**
8756          * Clears any opacity settings from this element. Required in some cases for IE.
8757          * @return {Roo.Element} this
8758          */
8759         clearOpacity : function(){
8760             if (window.ActiveXObject) {
8761                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8762                     this.dom.style.filter = "";
8763                 }
8764             } else {
8765                 this.dom.style.opacity = "";
8766                 this.dom.style["-moz-opacity"] = "";
8767                 this.dom.style["-khtml-opacity"] = "";
8768             }
8769             return this;
8770         },
8771
8772         /**
8773          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8774          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8775          * @return {Roo.Element} this
8776          */
8777         hide : function(animate){
8778             this.setVisible(false, this.preanim(arguments, 0));
8779             return this;
8780         },
8781
8782         /**
8783         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8784         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8785          * @return {Roo.Element} this
8786          */
8787         show : function(animate){
8788             this.setVisible(true, this.preanim(arguments, 0));
8789             return this;
8790         },
8791
8792         /**
8793          * @private Test if size has a unit, otherwise appends the default
8794          */
8795         addUnits : function(size){
8796             return Roo.Element.addUnits(size, this.defaultUnit);
8797         },
8798
8799         /**
8800          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8801          * @return {Roo.Element} this
8802          */
8803         beginMeasure : function(){
8804             var el = this.dom;
8805             if(el.offsetWidth || el.offsetHeight){
8806                 return this; // offsets work already
8807             }
8808             var changed = [];
8809             var p = this.dom, b = document.body; // start with this element
8810             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8811                 var pe = Roo.get(p);
8812                 if(pe.getStyle('display') == 'none'){
8813                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8814                     p.style.visibility = "hidden";
8815                     p.style.display = "block";
8816                 }
8817                 p = p.parentNode;
8818             }
8819             this._measureChanged = changed;
8820             return this;
8821
8822         },
8823
8824         /**
8825          * Restores displays to before beginMeasure was called
8826          * @return {Roo.Element} this
8827          */
8828         endMeasure : function(){
8829             var changed = this._measureChanged;
8830             if(changed){
8831                 for(var i = 0, len = changed.length; i < len; i++) {
8832                     var r = changed[i];
8833                     r.el.style.visibility = r.visibility;
8834                     r.el.style.display = "none";
8835                 }
8836                 this._measureChanged = null;
8837             }
8838             return this;
8839         },
8840
8841         /**
8842         * Update the innerHTML of this element, optionally searching for and processing scripts
8843         * @param {String} html The new HTML
8844         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8845         * @param {Function} callback For async script loading you can be noticed when the update completes
8846         * @return {Roo.Element} this
8847          */
8848         update : function(html, loadScripts, callback){
8849             if(typeof html == "undefined"){
8850                 html = "";
8851             }
8852             if(loadScripts !== true){
8853                 this.dom.innerHTML = html;
8854                 if(typeof callback == "function"){
8855                     callback();
8856                 }
8857                 return this;
8858             }
8859             var id = Roo.id();
8860             var dom = this.dom;
8861
8862             html += '<span id="' + id + '"></span>';
8863
8864             E.onAvailable(id, function(){
8865                 var hd = document.getElementsByTagName("head")[0];
8866                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8867                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8868                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8869
8870                 var match;
8871                 while(match = re.exec(html)){
8872                     var attrs = match[1];
8873                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8874                     if(srcMatch && srcMatch[2]){
8875                        var s = document.createElement("script");
8876                        s.src = srcMatch[2];
8877                        var typeMatch = attrs.match(typeRe);
8878                        if(typeMatch && typeMatch[2]){
8879                            s.type = typeMatch[2];
8880                        }
8881                        hd.appendChild(s);
8882                     }else if(match[2] && match[2].length > 0){
8883                         if(window.execScript) {
8884                            window.execScript(match[2]);
8885                         } else {
8886                             /**
8887                              * eval:var:id
8888                              * eval:var:dom
8889                              * eval:var:html
8890                              * 
8891                              */
8892                            window.eval(match[2]);
8893                         }
8894                     }
8895                 }
8896                 var el = document.getElementById(id);
8897                 if(el){el.parentNode.removeChild(el);}
8898                 if(typeof callback == "function"){
8899                     callback();
8900                 }
8901             });
8902             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8903             return this;
8904         },
8905
8906         /**
8907          * Direct access to the UpdateManager update() method (takes the same parameters).
8908          * @param {String/Function} url The url for this request or a function to call to get the url
8909          * @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}
8910          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8911          * @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.
8912          * @return {Roo.Element} this
8913          */
8914         load : function(){
8915             var um = this.getUpdateManager();
8916             um.update.apply(um, arguments);
8917             return this;
8918         },
8919
8920         /**
8921         * Gets this element's UpdateManager
8922         * @return {Roo.UpdateManager} The UpdateManager
8923         */
8924         getUpdateManager : function(){
8925             if(!this.updateManager){
8926                 this.updateManager = new Roo.UpdateManager(this);
8927             }
8928             return this.updateManager;
8929         },
8930
8931         /**
8932          * Disables text selection for this element (normalized across browsers)
8933          * @return {Roo.Element} this
8934          */
8935         unselectable : function(){
8936             this.dom.unselectable = "on";
8937             this.swallowEvent("selectstart", true);
8938             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8939             this.addClass("x-unselectable");
8940             return this;
8941         },
8942
8943         /**
8944         * Calculates the x, y to center this element on the screen
8945         * @return {Array} The x, y values [x, y]
8946         */
8947         getCenterXY : function(){
8948             return this.getAlignToXY(document, 'c-c');
8949         },
8950
8951         /**
8952         * Centers the Element in either the viewport, or another Element.
8953         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8954         */
8955         center : function(centerIn){
8956             this.alignTo(centerIn || document, 'c-c');
8957             return this;
8958         },
8959
8960         /**
8961          * Tests various css rules/browsers to determine if this element uses a border box
8962          * @return {Boolean}
8963          */
8964         isBorderBox : function(){
8965             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8966         },
8967
8968         /**
8969          * Return a box {x, y, width, height} that can be used to set another elements
8970          * size/location to match this element.
8971          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8972          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8973          * @return {Object} box An object in the format {x, y, width, height}
8974          */
8975         getBox : function(contentBox, local){
8976             var xy;
8977             if(!local){
8978                 xy = this.getXY();
8979             }else{
8980                 var left = parseInt(this.getStyle("left"), 10) || 0;
8981                 var top = parseInt(this.getStyle("top"), 10) || 0;
8982                 xy = [left, top];
8983             }
8984             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8985             if(!contentBox){
8986                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8987             }else{
8988                 var l = this.getBorderWidth("l")+this.getPadding("l");
8989                 var r = this.getBorderWidth("r")+this.getPadding("r");
8990                 var t = this.getBorderWidth("t")+this.getPadding("t");
8991                 var b = this.getBorderWidth("b")+this.getPadding("b");
8992                 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)};
8993             }
8994             bx.right = bx.x + bx.width;
8995             bx.bottom = bx.y + bx.height;
8996             return bx;
8997         },
8998
8999         /**
9000          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9001          for more information about the sides.
9002          * @param {String} sides
9003          * @return {Number}
9004          */
9005         getFrameWidth : function(sides, onlyContentBox){
9006             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9007         },
9008
9009         /**
9010          * 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.
9011          * @param {Object} box The box to fill {x, y, width, height}
9012          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9013          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9014          * @return {Roo.Element} this
9015          */
9016         setBox : function(box, adjust, animate){
9017             var w = box.width, h = box.height;
9018             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9019                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9020                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9021             }
9022             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9023             return this;
9024         },
9025
9026         /**
9027          * Forces the browser to repaint this element
9028          * @return {Roo.Element} this
9029          */
9030          repaint : function(){
9031             var dom = this.dom;
9032             this.addClass("x-repaint");
9033             setTimeout(function(){
9034                 Roo.get(dom).removeClass("x-repaint");
9035             }, 1);
9036             return this;
9037         },
9038
9039         /**
9040          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9041          * then it returns the calculated width of the sides (see getPadding)
9042          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9043          * @return {Object/Number}
9044          */
9045         getMargins : function(side){
9046             if(!side){
9047                 return {
9048                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9049                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9050                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9051                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9052                 };
9053             }else{
9054                 return this.addStyles(side, El.margins);
9055              }
9056         },
9057
9058         // private
9059         addStyles : function(sides, styles){
9060             var val = 0, v, w;
9061             for(var i = 0, len = sides.length; i < len; i++){
9062                 v = this.getStyle(styles[sides.charAt(i)]);
9063                 if(v){
9064                      w = parseInt(v, 10);
9065                      if(w){ val += w; }
9066                 }
9067             }
9068             return val;
9069         },
9070
9071         /**
9072          * Creates a proxy element of this element
9073          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9074          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9075          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9076          * @return {Roo.Element} The new proxy element
9077          */
9078         createProxy : function(config, renderTo, matchBox){
9079             if(renderTo){
9080                 renderTo = Roo.getDom(renderTo);
9081             }else{
9082                 renderTo = document.body;
9083             }
9084             config = typeof config == "object" ?
9085                 config : {tag : "div", cls: config};
9086             var proxy = Roo.DomHelper.append(renderTo, config, true);
9087             if(matchBox){
9088                proxy.setBox(this.getBox());
9089             }
9090             return proxy;
9091         },
9092
9093         /**
9094          * Puts a mask over this element to disable user interaction. Requires core.css.
9095          * This method can only be applied to elements which accept child nodes.
9096          * @param {String} msg (optional) A message to display in the mask
9097          * @param {String} msgCls (optional) A css class to apply to the msg element
9098          * @return {Element} The mask  element
9099          */
9100         mask : function(msg, msgCls)
9101         {
9102             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9103                 this.setStyle("position", "relative");
9104             }
9105             if(!this._mask){
9106                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9107             }
9108             this.addClass("x-masked");
9109             this._mask.setDisplayed(true);
9110             
9111             // we wander
9112             var z = 0;
9113             var dom = this.dom;
9114             while (dom && dom.style) {
9115                 if (!isNaN(parseInt(dom.style.zIndex))) {
9116                     z = Math.max(z, parseInt(dom.style.zIndex));
9117                 }
9118                 dom = dom.parentNode;
9119             }
9120             // if we are masking the body - then it hides everything..
9121             if (this.dom == document.body) {
9122                 z = 1000000;
9123                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9124                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9125             }
9126            
9127             if(typeof msg == 'string'){
9128                 if(!this._maskMsg){
9129                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9130                 }
9131                 var mm = this._maskMsg;
9132                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9133                 if (mm.dom.firstChild) { // weird IE issue?
9134                     mm.dom.firstChild.innerHTML = msg;
9135                 }
9136                 mm.setDisplayed(true);
9137                 mm.center(this);
9138                 mm.setStyle('z-index', z + 102);
9139             }
9140             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9141                 this._mask.setHeight(this.getHeight());
9142             }
9143             this._mask.setStyle('z-index', z + 100);
9144             
9145             return this._mask;
9146         },
9147
9148         /**
9149          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9150          * it is cached for reuse.
9151          */
9152         unmask : function(removeEl){
9153             if(this._mask){
9154                 if(removeEl === true){
9155                     this._mask.remove();
9156                     delete this._mask;
9157                     if(this._maskMsg){
9158                         this._maskMsg.remove();
9159                         delete this._maskMsg;
9160                     }
9161                 }else{
9162                     this._mask.setDisplayed(false);
9163                     if(this._maskMsg){
9164                         this._maskMsg.setDisplayed(false);
9165                     }
9166                 }
9167             }
9168             this.removeClass("x-masked");
9169         },
9170
9171         /**
9172          * Returns true if this element is masked
9173          * @return {Boolean}
9174          */
9175         isMasked : function(){
9176             return this._mask && this._mask.isVisible();
9177         },
9178
9179         /**
9180          * Creates an iframe shim for this element to keep selects and other windowed objects from
9181          * showing through.
9182          * @return {Roo.Element} The new shim element
9183          */
9184         createShim : function(){
9185             var el = document.createElement('iframe');
9186             el.frameBorder = 'no';
9187             el.className = 'roo-shim';
9188             if(Roo.isIE && Roo.isSecure){
9189                 el.src = Roo.SSL_SECURE_URL;
9190             }
9191             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9192             shim.autoBoxAdjust = false;
9193             return shim;
9194         },
9195
9196         /**
9197          * Removes this element from the DOM and deletes it from the cache
9198          */
9199         remove : function(){
9200             if(this.dom.parentNode){
9201                 this.dom.parentNode.removeChild(this.dom);
9202             }
9203             delete El.cache[this.dom.id];
9204         },
9205
9206         /**
9207          * Sets up event handlers to add and remove a css class when the mouse is over this element
9208          * @param {String} className
9209          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9210          * mouseout events for children elements
9211          * @return {Roo.Element} this
9212          */
9213         addClassOnOver : function(className, preventFlicker){
9214             this.on("mouseover", function(){
9215                 Roo.fly(this, '_internal').addClass(className);
9216             }, this.dom);
9217             var removeFn = function(e){
9218                 if(preventFlicker !== true || !e.within(this, true)){
9219                     Roo.fly(this, '_internal').removeClass(className);
9220                 }
9221             };
9222             this.on("mouseout", removeFn, this.dom);
9223             return this;
9224         },
9225
9226         /**
9227          * Sets up event handlers to add and remove a css class when this element has the focus
9228          * @param {String} className
9229          * @return {Roo.Element} this
9230          */
9231         addClassOnFocus : function(className){
9232             this.on("focus", function(){
9233                 Roo.fly(this, '_internal').addClass(className);
9234             }, this.dom);
9235             this.on("blur", function(){
9236                 Roo.fly(this, '_internal').removeClass(className);
9237             }, this.dom);
9238             return this;
9239         },
9240         /**
9241          * 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)
9242          * @param {String} className
9243          * @return {Roo.Element} this
9244          */
9245         addClassOnClick : function(className){
9246             var dom = this.dom;
9247             this.on("mousedown", function(){
9248                 Roo.fly(dom, '_internal').addClass(className);
9249                 var d = Roo.get(document);
9250                 var fn = function(){
9251                     Roo.fly(dom, '_internal').removeClass(className);
9252                     d.removeListener("mouseup", fn);
9253                 };
9254                 d.on("mouseup", fn);
9255             });
9256             return this;
9257         },
9258
9259         /**
9260          * Stops the specified event from bubbling and optionally prevents the default action
9261          * @param {String} eventName
9262          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9263          * @return {Roo.Element} this
9264          */
9265         swallowEvent : function(eventName, preventDefault){
9266             var fn = function(e){
9267                 e.stopPropagation();
9268                 if(preventDefault){
9269                     e.preventDefault();
9270                 }
9271             };
9272             if(eventName instanceof Array){
9273                 for(var i = 0, len = eventName.length; i < len; i++){
9274                      this.on(eventName[i], fn);
9275                 }
9276                 return this;
9277             }
9278             this.on(eventName, fn);
9279             return this;
9280         },
9281
9282         /**
9283          * @private
9284          */
9285       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9286
9287         /**
9288          * Sizes this element to its parent element's dimensions performing
9289          * neccessary box adjustments.
9290          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9291          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9292          * @return {Roo.Element} this
9293          */
9294         fitToParent : function(monitorResize, targetParent) {
9295           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9296           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9297           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9298             return;
9299           }
9300           var p = Roo.get(targetParent || this.dom.parentNode);
9301           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9302           if (monitorResize === true) {
9303             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9304             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9305           }
9306           return this;
9307         },
9308
9309         /**
9310          * Gets the next sibling, skipping text nodes
9311          * @return {HTMLElement} The next sibling or null
9312          */
9313         getNextSibling : function(){
9314             var n = this.dom.nextSibling;
9315             while(n && n.nodeType != 1){
9316                 n = n.nextSibling;
9317             }
9318             return n;
9319         },
9320
9321         /**
9322          * Gets the previous sibling, skipping text nodes
9323          * @return {HTMLElement} The previous sibling or null
9324          */
9325         getPrevSibling : function(){
9326             var n = this.dom.previousSibling;
9327             while(n && n.nodeType != 1){
9328                 n = n.previousSibling;
9329             }
9330             return n;
9331         },
9332
9333
9334         /**
9335          * Appends the passed element(s) to this element
9336          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9337          * @return {Roo.Element} this
9338          */
9339         appendChild: function(el){
9340             el = Roo.get(el);
9341             el.appendTo(this);
9342             return this;
9343         },
9344
9345         /**
9346          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9347          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9348          * automatically generated with the specified attributes.
9349          * @param {HTMLElement} insertBefore (optional) a child element of this element
9350          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9351          * @return {Roo.Element} The new child element
9352          */
9353         createChild: function(config, insertBefore, returnDom){
9354             config = config || {tag:'div'};
9355             if(insertBefore){
9356                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9357             }
9358             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9359         },
9360
9361         /**
9362          * Appends this element to the passed element
9363          * @param {String/HTMLElement/Element} el The new parent element
9364          * @return {Roo.Element} this
9365          */
9366         appendTo: function(el){
9367             el = Roo.getDom(el);
9368             el.appendChild(this.dom);
9369             return this;
9370         },
9371
9372         /**
9373          * Inserts this element before the passed element in the DOM
9374          * @param {String/HTMLElement/Element} el The element to insert before
9375          * @return {Roo.Element} this
9376          */
9377         insertBefore: function(el){
9378             el = Roo.getDom(el);
9379             el.parentNode.insertBefore(this.dom, el);
9380             return this;
9381         },
9382
9383         /**
9384          * Inserts this element after the passed element in the DOM
9385          * @param {String/HTMLElement/Element} el The element to insert after
9386          * @return {Roo.Element} this
9387          */
9388         insertAfter: function(el){
9389             el = Roo.getDom(el);
9390             el.parentNode.insertBefore(this.dom, el.nextSibling);
9391             return this;
9392         },
9393
9394         /**
9395          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9396          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9397          * @return {Roo.Element} The new child
9398          */
9399         insertFirst: function(el, returnDom){
9400             el = el || {};
9401             if(typeof el == 'object' && !el.nodeType){ // dh config
9402                 return this.createChild(el, this.dom.firstChild, returnDom);
9403             }else{
9404                 el = Roo.getDom(el);
9405                 this.dom.insertBefore(el, this.dom.firstChild);
9406                 return !returnDom ? Roo.get(el) : el;
9407             }
9408         },
9409
9410         /**
9411          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9412          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9413          * @param {String} where (optional) 'before' or 'after' defaults to before
9414          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9415          * @return {Roo.Element} the inserted Element
9416          */
9417         insertSibling: function(el, where, returnDom){
9418             where = where ? where.toLowerCase() : 'before';
9419             el = el || {};
9420             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9421
9422             if(typeof el == 'object' && !el.nodeType){ // dh config
9423                 if(where == 'after' && !this.dom.nextSibling){
9424                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9425                 }else{
9426                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9427                 }
9428
9429             }else{
9430                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9431                             where == 'before' ? this.dom : this.dom.nextSibling);
9432                 if(!returnDom){
9433                     rt = Roo.get(rt);
9434                 }
9435             }
9436             return rt;
9437         },
9438
9439         /**
9440          * Creates and wraps this element with another element
9441          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9442          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9443          * @return {HTMLElement/Element} The newly created wrapper element
9444          */
9445         wrap: function(config, returnDom){
9446             if(!config){
9447                 config = {tag: "div"};
9448             }
9449             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9450             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9451             return newEl;
9452         },
9453
9454         /**
9455          * Replaces the passed element with this element
9456          * @param {String/HTMLElement/Element} el The element to replace
9457          * @return {Roo.Element} this
9458          */
9459         replace: function(el){
9460             el = Roo.get(el);
9461             this.insertBefore(el);
9462             el.remove();
9463             return this;
9464         },
9465
9466         /**
9467          * Inserts an html fragment into this element
9468          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9469          * @param {String} html The HTML fragment
9470          * @param {Boolean} returnEl True to return an Roo.Element
9471          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9472          */
9473         insertHtml : function(where, html, returnEl){
9474             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9475             return returnEl ? Roo.get(el) : el;
9476         },
9477
9478         /**
9479          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9480          * @param {Object} o The object with the attributes
9481          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9482          * @return {Roo.Element} this
9483          */
9484         set : function(o, useSet){
9485             var el = this.dom;
9486             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9487             for(var attr in o){
9488                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9489                 if(attr=="cls"){
9490                     el.className = o["cls"];
9491                 }else{
9492                     if(useSet) {
9493                         el.setAttribute(attr, o[attr]);
9494                     } else {
9495                         el[attr] = o[attr];
9496                     }
9497                 }
9498             }
9499             if(o.style){
9500                 Roo.DomHelper.applyStyles(el, o.style);
9501             }
9502             return this;
9503         },
9504
9505         /**
9506          * Convenience method for constructing a KeyMap
9507          * @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:
9508          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9509          * @param {Function} fn The function to call
9510          * @param {Object} scope (optional) The scope of the function
9511          * @return {Roo.KeyMap} The KeyMap created
9512          */
9513         addKeyListener : function(key, fn, scope){
9514             var config;
9515             if(typeof key != "object" || key instanceof Array){
9516                 config = {
9517                     key: key,
9518                     fn: fn,
9519                     scope: scope
9520                 };
9521             }else{
9522                 config = {
9523                     key : key.key,
9524                     shift : key.shift,
9525                     ctrl : key.ctrl,
9526                     alt : key.alt,
9527                     fn: fn,
9528                     scope: scope
9529                 };
9530             }
9531             return new Roo.KeyMap(this, config);
9532         },
9533
9534         /**
9535          * Creates a KeyMap for this element
9536          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9537          * @return {Roo.KeyMap} The KeyMap created
9538          */
9539         addKeyMap : function(config){
9540             return new Roo.KeyMap(this, config);
9541         },
9542
9543         /**
9544          * Returns true if this element is scrollable.
9545          * @return {Boolean}
9546          */
9547          isScrollable : function(){
9548             var dom = this.dom;
9549             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9550         },
9551
9552         /**
9553          * 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().
9554          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9555          * @param {Number} value The new scroll value
9556          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9557          * @return {Element} this
9558          */
9559
9560         scrollTo : function(side, value, animate){
9561             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9562             if(!animate || !A){
9563                 this.dom[prop] = value;
9564             }else{
9565                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9566                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9567             }
9568             return this;
9569         },
9570
9571         /**
9572          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9573          * within this element's scrollable range.
9574          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9575          * @param {Number} distance How far to scroll the element in pixels
9576          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9577          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9578          * was scrolled as far as it could go.
9579          */
9580          scroll : function(direction, distance, animate){
9581              if(!this.isScrollable()){
9582                  return;
9583              }
9584              var el = this.dom;
9585              var l = el.scrollLeft, t = el.scrollTop;
9586              var w = el.scrollWidth, h = el.scrollHeight;
9587              var cw = el.clientWidth, ch = el.clientHeight;
9588              direction = direction.toLowerCase();
9589              var scrolled = false;
9590              var a = this.preanim(arguments, 2);
9591              switch(direction){
9592                  case "l":
9593                  case "left":
9594                      if(w - l > cw){
9595                          var v = Math.min(l + distance, w-cw);
9596                          this.scrollTo("left", v, a);
9597                          scrolled = true;
9598                      }
9599                      break;
9600                 case "r":
9601                 case "right":
9602                      if(l > 0){
9603                          var v = Math.max(l - distance, 0);
9604                          this.scrollTo("left", v, a);
9605                          scrolled = true;
9606                      }
9607                      break;
9608                 case "t":
9609                 case "top":
9610                 case "up":
9611                      if(t > 0){
9612                          var v = Math.max(t - distance, 0);
9613                          this.scrollTo("top", v, a);
9614                          scrolled = true;
9615                      }
9616                      break;
9617                 case "b":
9618                 case "bottom":
9619                 case "down":
9620                      if(h - t > ch){
9621                          var v = Math.min(t + distance, h-ch);
9622                          this.scrollTo("top", v, a);
9623                          scrolled = true;
9624                      }
9625                      break;
9626              }
9627              return scrolled;
9628         },
9629
9630         /**
9631          * Translates the passed page coordinates into left/top css values for this element
9632          * @param {Number/Array} x The page x or an array containing [x, y]
9633          * @param {Number} y The page y
9634          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9635          */
9636         translatePoints : function(x, y){
9637             if(typeof x == 'object' || x instanceof Array){
9638                 y = x[1]; x = x[0];
9639             }
9640             var p = this.getStyle('position');
9641             var o = this.getXY();
9642
9643             var l = parseInt(this.getStyle('left'), 10);
9644             var t = parseInt(this.getStyle('top'), 10);
9645
9646             if(isNaN(l)){
9647                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9648             }
9649             if(isNaN(t)){
9650                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9651             }
9652
9653             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9654         },
9655
9656         /**
9657          * Returns the current scroll position of the element.
9658          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9659          */
9660         getScroll : function(){
9661             var d = this.dom, doc = document;
9662             if(d == doc || d == doc.body){
9663                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9664                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9665                 return {left: l, top: t};
9666             }else{
9667                 return {left: d.scrollLeft, top: d.scrollTop};
9668             }
9669         },
9670
9671         /**
9672          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9673          * are convert to standard 6 digit hex color.
9674          * @param {String} attr The css attribute
9675          * @param {String} defaultValue The default value to use when a valid color isn't found
9676          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9677          * YUI color anims.
9678          */
9679         getColor : function(attr, defaultValue, prefix){
9680             var v = this.getStyle(attr);
9681             if(!v || v == "transparent" || v == "inherit") {
9682                 return defaultValue;
9683             }
9684             var color = typeof prefix == "undefined" ? "#" : prefix;
9685             if(v.substr(0, 4) == "rgb("){
9686                 var rvs = v.slice(4, v.length -1).split(",");
9687                 for(var i = 0; i < 3; i++){
9688                     var h = parseInt(rvs[i]).toString(16);
9689                     if(h < 16){
9690                         h = "0" + h;
9691                     }
9692                     color += h;
9693                 }
9694             } else {
9695                 if(v.substr(0, 1) == "#"){
9696                     if(v.length == 4) {
9697                         for(var i = 1; i < 4; i++){
9698                             var c = v.charAt(i);
9699                             color +=  c + c;
9700                         }
9701                     }else if(v.length == 7){
9702                         color += v.substr(1);
9703                     }
9704                 }
9705             }
9706             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9707         },
9708
9709         /**
9710          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9711          * gradient background, rounded corners and a 4-way shadow.
9712          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9713          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9714          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9715          * @return {Roo.Element} this
9716          */
9717         boxWrap : function(cls){
9718             cls = cls || 'x-box';
9719             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9720             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9721             return el;
9722         },
9723
9724         /**
9725          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9726          * @param {String} namespace The namespace in which to look for the attribute
9727          * @param {String} name The attribute name
9728          * @return {String} The attribute value
9729          */
9730         getAttributeNS : Roo.isIE ? function(ns, name){
9731             var d = this.dom;
9732             var type = typeof d[ns+":"+name];
9733             if(type != 'undefined' && type != 'unknown'){
9734                 return d[ns+":"+name];
9735             }
9736             return d[name];
9737         } : function(ns, name){
9738             var d = this.dom;
9739             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9740         },
9741         
9742         
9743         /**
9744          * Sets or Returns the value the dom attribute value
9745          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9746          * @param {String} value (optional) The value to set the attribute to
9747          * @return {String} The attribute value
9748          */
9749         attr : function(name){
9750             if (arguments.length > 1) {
9751                 this.dom.setAttribute(name, arguments[1]);
9752                 return arguments[1];
9753             }
9754             if (typeof(name) == 'object') {
9755                 for(var i in name) {
9756                     this.attr(i, name[i]);
9757                 }
9758                 return name;
9759             }
9760             
9761             
9762             if (!this.dom.hasAttribute(name)) {
9763                 return undefined;
9764             }
9765             return this.dom.getAttribute(name);
9766         }
9767         
9768         
9769         
9770     };
9771
9772     var ep = El.prototype;
9773
9774     /**
9775      * Appends an event handler (Shorthand for addListener)
9776      * @param {String}   eventName     The type of event to append
9777      * @param {Function} fn        The method the event invokes
9778      * @param {Object} scope       (optional) The scope (this object) of the fn
9779      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9780      * @method
9781      */
9782     ep.on = ep.addListener;
9783         // backwards compat
9784     ep.mon = ep.addListener;
9785
9786     /**
9787      * Removes an event handler from this element (shorthand for removeListener)
9788      * @param {String} eventName the type of event to remove
9789      * @param {Function} fn the method the event invokes
9790      * @return {Roo.Element} this
9791      * @method
9792      */
9793     ep.un = ep.removeListener;
9794
9795     /**
9796      * true to automatically adjust width and height settings for box-model issues (default to true)
9797      */
9798     ep.autoBoxAdjust = true;
9799
9800     // private
9801     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9802
9803     // private
9804     El.addUnits = function(v, defaultUnit){
9805         if(v === "" || v == "auto"){
9806             return v;
9807         }
9808         if(v === undefined){
9809             return '';
9810         }
9811         if(typeof v == "number" || !El.unitPattern.test(v)){
9812             return v + (defaultUnit || 'px');
9813         }
9814         return v;
9815     };
9816
9817     // special markup used throughout Roo when box wrapping elements
9818     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>';
9819     /**
9820      * Visibility mode constant - Use visibility to hide element
9821      * @static
9822      * @type Number
9823      */
9824     El.VISIBILITY = 1;
9825     /**
9826      * Visibility mode constant - Use display to hide element
9827      * @static
9828      * @type Number
9829      */
9830     El.DISPLAY = 2;
9831
9832     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9833     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9834     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9835
9836
9837
9838     /**
9839      * @private
9840      */
9841     El.cache = {};
9842
9843     var docEl;
9844
9845     /**
9846      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9847      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9848      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9849      * @return {Element} The Element object
9850      * @static
9851      */
9852     El.get = function(el){
9853         var ex, elm, id;
9854         if(!el){ return null; }
9855         if(typeof el == "string"){ // element id
9856             if(!(elm = document.getElementById(el))){
9857                 return null;
9858             }
9859             if(ex = El.cache[el]){
9860                 ex.dom = elm;
9861             }else{
9862                 ex = El.cache[el] = new El(elm);
9863             }
9864             return ex;
9865         }else if(el.tagName){ // dom element
9866             if(!(id = el.id)){
9867                 id = Roo.id(el);
9868             }
9869             if(ex = El.cache[id]){
9870                 ex.dom = el;
9871             }else{
9872                 ex = El.cache[id] = new El(el);
9873             }
9874             return ex;
9875         }else if(el instanceof El){
9876             if(el != docEl){
9877                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9878                                                               // catch case where it hasn't been appended
9879                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9880             }
9881             return el;
9882         }else if(el.isComposite){
9883             return el;
9884         }else if(el instanceof Array){
9885             return El.select(el);
9886         }else if(el == document){
9887             // create a bogus element object representing the document object
9888             if(!docEl){
9889                 var f = function(){};
9890                 f.prototype = El.prototype;
9891                 docEl = new f();
9892                 docEl.dom = document;
9893             }
9894             return docEl;
9895         }
9896         return null;
9897     };
9898
9899     // private
9900     El.uncache = function(el){
9901         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9902             if(a[i]){
9903                 delete El.cache[a[i].id || a[i]];
9904             }
9905         }
9906     };
9907
9908     // private
9909     // Garbage collection - uncache elements/purge listeners on orphaned elements
9910     // so we don't hold a reference and cause the browser to retain them
9911     El.garbageCollect = function(){
9912         if(!Roo.enableGarbageCollector){
9913             clearInterval(El.collectorThread);
9914             return;
9915         }
9916         for(var eid in El.cache){
9917             var el = El.cache[eid], d = el.dom;
9918             // -------------------------------------------------------
9919             // Determining what is garbage:
9920             // -------------------------------------------------------
9921             // !d
9922             // dom node is null, definitely garbage
9923             // -------------------------------------------------------
9924             // !d.parentNode
9925             // no parentNode == direct orphan, definitely garbage
9926             // -------------------------------------------------------
9927             // !d.offsetParent && !document.getElementById(eid)
9928             // display none elements have no offsetParent so we will
9929             // also try to look it up by it's id. However, check
9930             // offsetParent first so we don't do unneeded lookups.
9931             // This enables collection of elements that are not orphans
9932             // directly, but somewhere up the line they have an orphan
9933             // parent.
9934             // -------------------------------------------------------
9935             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9936                 delete El.cache[eid];
9937                 if(d && Roo.enableListenerCollection){
9938                     E.purgeElement(d);
9939                 }
9940             }
9941         }
9942     }
9943     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9944
9945
9946     // dom is optional
9947     El.Flyweight = function(dom){
9948         this.dom = dom;
9949     };
9950     El.Flyweight.prototype = El.prototype;
9951
9952     El._flyweights = {};
9953     /**
9954      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9955      * the dom node can be overwritten by other code.
9956      * @param {String/HTMLElement} el The dom node or id
9957      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9958      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9959      * @static
9960      * @return {Element} The shared Element object
9961      */
9962     El.fly = function(el, named){
9963         named = named || '_global';
9964         el = Roo.getDom(el);
9965         if(!el){
9966             return null;
9967         }
9968         if(!El._flyweights[named]){
9969             El._flyweights[named] = new El.Flyweight();
9970         }
9971         El._flyweights[named].dom = el;
9972         return El._flyweights[named];
9973     };
9974
9975     /**
9976      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9977      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9978      * Shorthand of {@link Roo.Element#get}
9979      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9980      * @return {Element} The Element object
9981      * @member Roo
9982      * @method get
9983      */
9984     Roo.get = El.get;
9985     /**
9986      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9987      * the dom node can be overwritten by other code.
9988      * Shorthand of {@link Roo.Element#fly}
9989      * @param {String/HTMLElement} el The dom node or id
9990      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9991      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9992      * @static
9993      * @return {Element} The shared Element object
9994      * @member Roo
9995      * @method fly
9996      */
9997     Roo.fly = El.fly;
9998
9999     // speedy lookup for elements never to box adjust
10000     var noBoxAdjust = Roo.isStrict ? {
10001         select:1
10002     } : {
10003         input:1, select:1, textarea:1
10004     };
10005     if(Roo.isIE || Roo.isGecko){
10006         noBoxAdjust['button'] = 1;
10007     }
10008
10009
10010     Roo.EventManager.on(window, 'unload', function(){
10011         delete El.cache;
10012         delete El._flyweights;
10013     });
10014 })();
10015
10016
10017
10018
10019 if(Roo.DomQuery){
10020     Roo.Element.selectorFunction = Roo.DomQuery.select;
10021 }
10022
10023 Roo.Element.select = function(selector, unique, root){
10024     var els;
10025     if(typeof selector == "string"){
10026         els = Roo.Element.selectorFunction(selector, root);
10027     }else if(selector.length !== undefined){
10028         els = selector;
10029     }else{
10030         throw "Invalid selector";
10031     }
10032     if(unique === true){
10033         return new Roo.CompositeElement(els);
10034     }else{
10035         return new Roo.CompositeElementLite(els);
10036     }
10037 };
10038 /**
10039  * Selects elements based on the passed CSS selector to enable working on them as 1.
10040  * @param {String/Array} selector The CSS selector or an array of elements
10041  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10042  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10043  * @return {CompositeElementLite/CompositeElement}
10044  * @member Roo
10045  * @method select
10046  */
10047 Roo.select = Roo.Element.select;
10048
10049
10050
10051
10052
10053
10054
10055
10056
10057
10058
10059
10060
10061
10062 /*
10063  * Based on:
10064  * Ext JS Library 1.1.1
10065  * Copyright(c) 2006-2007, Ext JS, LLC.
10066  *
10067  * Originally Released Under LGPL - original licence link has changed is not relivant.
10068  *
10069  * Fork - LGPL
10070  * <script type="text/javascript">
10071  */
10072
10073
10074
10075 //Notifies Element that fx methods are available
10076 Roo.enableFx = true;
10077
10078 /**
10079  * @class Roo.Fx
10080  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10081  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10082  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10083  * Element effects to work.</p><br/>
10084  *
10085  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10086  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10087  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10088  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10089  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10090  * expected results and should be done with care.</p><br/>
10091  *
10092  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10093  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10094 <pre>
10095 Value  Description
10096 -----  -----------------------------
10097 tl     The top left corner
10098 t      The center of the top edge
10099 tr     The top right corner
10100 l      The center of the left edge
10101 r      The center of the right edge
10102 bl     The bottom left corner
10103 b      The center of the bottom edge
10104 br     The bottom right corner
10105 </pre>
10106  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10107  * below are common options that can be passed to any Fx method.</b>
10108  * @cfg {Function} callback A function called when the effect is finished
10109  * @cfg {Object} scope The scope of the effect function
10110  * @cfg {String} easing A valid Easing value for the effect
10111  * @cfg {String} afterCls A css class to apply after the effect
10112  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10113  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10114  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10115  * effects that end with the element being visually hidden, ignored otherwise)
10116  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10117  * a function which returns such a specification that will be applied to the Element after the effect finishes
10118  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10119  * @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
10120  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10121  */
10122 Roo.Fx = {
10123         /**
10124          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10125          * origin for the slide effect.  This function automatically handles wrapping the element with
10126          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10127          * Usage:
10128          *<pre><code>
10129 // default: slide the element in from the top
10130 el.slideIn();
10131
10132 // custom: slide the element in from the right with a 2-second duration
10133 el.slideIn('r', { duration: 2 });
10134
10135 // common config options shown with default values
10136 el.slideIn('t', {
10137     easing: 'easeOut',
10138     duration: .5
10139 });
10140 </code></pre>
10141          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10142          * @param {Object} options (optional) Object literal with any of the Fx config options
10143          * @return {Roo.Element} The Element
10144          */
10145     slideIn : function(anchor, o){
10146         var el = this.getFxEl();
10147         o = o || {};
10148
10149         el.queueFx(o, function(){
10150
10151             anchor = anchor || "t";
10152
10153             // fix display to visibility
10154             this.fixDisplay();
10155
10156             // restore values after effect
10157             var r = this.getFxRestore();
10158             var b = this.getBox();
10159             // fixed size for slide
10160             this.setSize(b);
10161
10162             // wrap if needed
10163             var wrap = this.fxWrap(r.pos, o, "hidden");
10164
10165             var st = this.dom.style;
10166             st.visibility = "visible";
10167             st.position = "absolute";
10168
10169             // clear out temp styles after slide and unwrap
10170             var after = function(){
10171                 el.fxUnwrap(wrap, r.pos, o);
10172                 st.width = r.width;
10173                 st.height = r.height;
10174                 el.afterFx(o);
10175             };
10176             // time to calc the positions
10177             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10178
10179             switch(anchor.toLowerCase()){
10180                 case "t":
10181                     wrap.setSize(b.width, 0);
10182                     st.left = st.bottom = "0";
10183                     a = {height: bh};
10184                 break;
10185                 case "l":
10186                     wrap.setSize(0, b.height);
10187                     st.right = st.top = "0";
10188                     a = {width: bw};
10189                 break;
10190                 case "r":
10191                     wrap.setSize(0, b.height);
10192                     wrap.setX(b.right);
10193                     st.left = st.top = "0";
10194                     a = {width: bw, points: pt};
10195                 break;
10196                 case "b":
10197                     wrap.setSize(b.width, 0);
10198                     wrap.setY(b.bottom);
10199                     st.left = st.top = "0";
10200                     a = {height: bh, points: pt};
10201                 break;
10202                 case "tl":
10203                     wrap.setSize(0, 0);
10204                     st.right = st.bottom = "0";
10205                     a = {width: bw, height: bh};
10206                 break;
10207                 case "bl":
10208                     wrap.setSize(0, 0);
10209                     wrap.setY(b.y+b.height);
10210                     st.right = st.top = "0";
10211                     a = {width: bw, height: bh, points: pt};
10212                 break;
10213                 case "br":
10214                     wrap.setSize(0, 0);
10215                     wrap.setXY([b.right, b.bottom]);
10216                     st.left = st.top = "0";
10217                     a = {width: bw, height: bh, points: pt};
10218                 break;
10219                 case "tr":
10220                     wrap.setSize(0, 0);
10221                     wrap.setX(b.x+b.width);
10222                     st.left = st.bottom = "0";
10223                     a = {width: bw, height: bh, points: pt};
10224                 break;
10225             }
10226             this.dom.style.visibility = "visible";
10227             wrap.show();
10228
10229             arguments.callee.anim = wrap.fxanim(a,
10230                 o,
10231                 'motion',
10232                 .5,
10233                 'easeOut', after);
10234         });
10235         return this;
10236     },
10237     
10238         /**
10239          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10240          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10241          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10242          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10243          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10244          * Usage:
10245          *<pre><code>
10246 // default: slide the element out to the top
10247 el.slideOut();
10248
10249 // custom: slide the element out to the right with a 2-second duration
10250 el.slideOut('r', { duration: 2 });
10251
10252 // common config options shown with default values
10253 el.slideOut('t', {
10254     easing: 'easeOut',
10255     duration: .5,
10256     remove: false,
10257     useDisplay: false
10258 });
10259 </code></pre>
10260          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10261          * @param {Object} options (optional) Object literal with any of the Fx config options
10262          * @return {Roo.Element} The Element
10263          */
10264     slideOut : function(anchor, o){
10265         var el = this.getFxEl();
10266         o = o || {};
10267
10268         el.queueFx(o, function(){
10269
10270             anchor = anchor || "t";
10271
10272             // restore values after effect
10273             var r = this.getFxRestore();
10274             
10275             var b = this.getBox();
10276             // fixed size for slide
10277             this.setSize(b);
10278
10279             // wrap if needed
10280             var wrap = this.fxWrap(r.pos, o, "visible");
10281
10282             var st = this.dom.style;
10283             st.visibility = "visible";
10284             st.position = "absolute";
10285
10286             wrap.setSize(b);
10287
10288             var after = function(){
10289                 if(o.useDisplay){
10290                     el.setDisplayed(false);
10291                 }else{
10292                     el.hide();
10293                 }
10294
10295                 el.fxUnwrap(wrap, r.pos, o);
10296
10297                 st.width = r.width;
10298                 st.height = r.height;
10299
10300                 el.afterFx(o);
10301             };
10302
10303             var a, zero = {to: 0};
10304             switch(anchor.toLowerCase()){
10305                 case "t":
10306                     st.left = st.bottom = "0";
10307                     a = {height: zero};
10308                 break;
10309                 case "l":
10310                     st.right = st.top = "0";
10311                     a = {width: zero};
10312                 break;
10313                 case "r":
10314                     st.left = st.top = "0";
10315                     a = {width: zero, points: {to:[b.right, b.y]}};
10316                 break;
10317                 case "b":
10318                     st.left = st.top = "0";
10319                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10320                 break;
10321                 case "tl":
10322                     st.right = st.bottom = "0";
10323                     a = {width: zero, height: zero};
10324                 break;
10325                 case "bl":
10326                     st.right = st.top = "0";
10327                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10328                 break;
10329                 case "br":
10330                     st.left = st.top = "0";
10331                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10332                 break;
10333                 case "tr":
10334                     st.left = st.bottom = "0";
10335                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10336                 break;
10337             }
10338
10339             arguments.callee.anim = wrap.fxanim(a,
10340                 o,
10341                 'motion',
10342                 .5,
10343                 "easeOut", after);
10344         });
10345         return this;
10346     },
10347
10348         /**
10349          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10350          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10351          * The element must be removed from the DOM using the 'remove' config option if desired.
10352          * Usage:
10353          *<pre><code>
10354 // default
10355 el.puff();
10356
10357 // common config options shown with default values
10358 el.puff({
10359     easing: 'easeOut',
10360     duration: .5,
10361     remove: false,
10362     useDisplay: false
10363 });
10364 </code></pre>
10365          * @param {Object} options (optional) Object literal with any of the Fx config options
10366          * @return {Roo.Element} The Element
10367          */
10368     puff : function(o){
10369         var el = this.getFxEl();
10370         o = o || {};
10371
10372         el.queueFx(o, function(){
10373             this.clearOpacity();
10374             this.show();
10375
10376             // restore values after effect
10377             var r = this.getFxRestore();
10378             var st = this.dom.style;
10379
10380             var after = function(){
10381                 if(o.useDisplay){
10382                     el.setDisplayed(false);
10383                 }else{
10384                     el.hide();
10385                 }
10386
10387                 el.clearOpacity();
10388
10389                 el.setPositioning(r.pos);
10390                 st.width = r.width;
10391                 st.height = r.height;
10392                 st.fontSize = '';
10393                 el.afterFx(o);
10394             };
10395
10396             var width = this.getWidth();
10397             var height = this.getHeight();
10398
10399             arguments.callee.anim = this.fxanim({
10400                     width : {to: this.adjustWidth(width * 2)},
10401                     height : {to: this.adjustHeight(height * 2)},
10402                     points : {by: [-(width * .5), -(height * .5)]},
10403                     opacity : {to: 0},
10404                     fontSize: {to:200, unit: "%"}
10405                 },
10406                 o,
10407                 'motion',
10408                 .5,
10409                 "easeOut", after);
10410         });
10411         return this;
10412     },
10413
10414         /**
10415          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10416          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10417          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10418          * Usage:
10419          *<pre><code>
10420 // default
10421 el.switchOff();
10422
10423 // all config options shown with default values
10424 el.switchOff({
10425     easing: 'easeIn',
10426     duration: .3,
10427     remove: false,
10428     useDisplay: false
10429 });
10430 </code></pre>
10431          * @param {Object} options (optional) Object literal with any of the Fx config options
10432          * @return {Roo.Element} The Element
10433          */
10434     switchOff : function(o){
10435         var el = this.getFxEl();
10436         o = o || {};
10437
10438         el.queueFx(o, function(){
10439             this.clearOpacity();
10440             this.clip();
10441
10442             // restore values after effect
10443             var r = this.getFxRestore();
10444             var st = this.dom.style;
10445
10446             var after = function(){
10447                 if(o.useDisplay){
10448                     el.setDisplayed(false);
10449                 }else{
10450                     el.hide();
10451                 }
10452
10453                 el.clearOpacity();
10454                 el.setPositioning(r.pos);
10455                 st.width = r.width;
10456                 st.height = r.height;
10457
10458                 el.afterFx(o);
10459             };
10460
10461             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10462                 this.clearOpacity();
10463                 (function(){
10464                     this.fxanim({
10465                         height:{to:1},
10466                         points:{by:[0, this.getHeight() * .5]}
10467                     }, o, 'motion', 0.3, 'easeIn', after);
10468                 }).defer(100, this);
10469             });
10470         });
10471         return this;
10472     },
10473
10474     /**
10475      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10476      * changed using the "attr" config option) and then fading back to the original color. If no original
10477      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10478      * Usage:
10479 <pre><code>
10480 // default: highlight background to yellow
10481 el.highlight();
10482
10483 // custom: highlight foreground text to blue for 2 seconds
10484 el.highlight("0000ff", { attr: 'color', duration: 2 });
10485
10486 // common config options shown with default values
10487 el.highlight("ffff9c", {
10488     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10489     endColor: (current color) or "ffffff",
10490     easing: 'easeIn',
10491     duration: 1
10492 });
10493 </code></pre>
10494      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10495      * @param {Object} options (optional) Object literal with any of the Fx config options
10496      * @return {Roo.Element} The Element
10497      */ 
10498     highlight : function(color, o){
10499         var el = this.getFxEl();
10500         o = o || {};
10501
10502         el.queueFx(o, function(){
10503             color = color || "ffff9c";
10504             attr = o.attr || "backgroundColor";
10505
10506             this.clearOpacity();
10507             this.show();
10508
10509             var origColor = this.getColor(attr);
10510             var restoreColor = this.dom.style[attr];
10511             endColor = (o.endColor || origColor) || "ffffff";
10512
10513             var after = function(){
10514                 el.dom.style[attr] = restoreColor;
10515                 el.afterFx(o);
10516             };
10517
10518             var a = {};
10519             a[attr] = {from: color, to: endColor};
10520             arguments.callee.anim = this.fxanim(a,
10521                 o,
10522                 'color',
10523                 1,
10524                 'easeIn', after);
10525         });
10526         return this;
10527     },
10528
10529    /**
10530     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10531     * Usage:
10532 <pre><code>
10533 // default: a single light blue ripple
10534 el.frame();
10535
10536 // custom: 3 red ripples lasting 3 seconds total
10537 el.frame("ff0000", 3, { duration: 3 });
10538
10539 // common config options shown with default values
10540 el.frame("C3DAF9", 1, {
10541     duration: 1 //duration of entire animation (not each individual ripple)
10542     // Note: Easing is not configurable and will be ignored if included
10543 });
10544 </code></pre>
10545     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10546     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10547     * @param {Object} options (optional) Object literal with any of the Fx config options
10548     * @return {Roo.Element} The Element
10549     */
10550     frame : function(color, count, o){
10551         var el = this.getFxEl();
10552         o = o || {};
10553
10554         el.queueFx(o, function(){
10555             color = color || "#C3DAF9";
10556             if(color.length == 6){
10557                 color = "#" + color;
10558             }
10559             count = count || 1;
10560             duration = o.duration || 1;
10561             this.show();
10562
10563             var b = this.getBox();
10564             var animFn = function(){
10565                 var proxy = this.createProxy({
10566
10567                      style:{
10568                         visbility:"hidden",
10569                         position:"absolute",
10570                         "z-index":"35000", // yee haw
10571                         border:"0px solid " + color
10572                      }
10573                   });
10574                 var scale = Roo.isBorderBox ? 2 : 1;
10575                 proxy.animate({
10576                     top:{from:b.y, to:b.y - 20},
10577                     left:{from:b.x, to:b.x - 20},
10578                     borderWidth:{from:0, to:10},
10579                     opacity:{from:1, to:0},
10580                     height:{from:b.height, to:(b.height + (20*scale))},
10581                     width:{from:b.width, to:(b.width + (20*scale))}
10582                 }, duration, function(){
10583                     proxy.remove();
10584                 });
10585                 if(--count > 0){
10586                      animFn.defer((duration/2)*1000, this);
10587                 }else{
10588                     el.afterFx(o);
10589                 }
10590             };
10591             animFn.call(this);
10592         });
10593         return this;
10594     },
10595
10596    /**
10597     * Creates a pause before any subsequent queued effects begin.  If there are
10598     * no effects queued after the pause it will have no effect.
10599     * Usage:
10600 <pre><code>
10601 el.pause(1);
10602 </code></pre>
10603     * @param {Number} seconds The length of time to pause (in seconds)
10604     * @return {Roo.Element} The Element
10605     */
10606     pause : function(seconds){
10607         var el = this.getFxEl();
10608         var o = {};
10609
10610         el.queueFx(o, function(){
10611             setTimeout(function(){
10612                 el.afterFx(o);
10613             }, seconds * 1000);
10614         });
10615         return this;
10616     },
10617
10618    /**
10619     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10620     * using the "endOpacity" config option.
10621     * Usage:
10622 <pre><code>
10623 // default: fade in from opacity 0 to 100%
10624 el.fadeIn();
10625
10626 // custom: fade in from opacity 0 to 75% over 2 seconds
10627 el.fadeIn({ endOpacity: .75, duration: 2});
10628
10629 // common config options shown with default values
10630 el.fadeIn({
10631     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10632     easing: 'easeOut',
10633     duration: .5
10634 });
10635 </code></pre>
10636     * @param {Object} options (optional) Object literal with any of the Fx config options
10637     * @return {Roo.Element} The Element
10638     */
10639     fadeIn : function(o){
10640         var el = this.getFxEl();
10641         o = o || {};
10642         el.queueFx(o, function(){
10643             this.setOpacity(0);
10644             this.fixDisplay();
10645             this.dom.style.visibility = 'visible';
10646             var to = o.endOpacity || 1;
10647             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10648                 o, null, .5, "easeOut", function(){
10649                 if(to == 1){
10650                     this.clearOpacity();
10651                 }
10652                 el.afterFx(o);
10653             });
10654         });
10655         return this;
10656     },
10657
10658    /**
10659     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10660     * using the "endOpacity" config option.
10661     * Usage:
10662 <pre><code>
10663 // default: fade out from the element's current opacity to 0
10664 el.fadeOut();
10665
10666 // custom: fade out from the element's current opacity to 25% over 2 seconds
10667 el.fadeOut({ endOpacity: .25, duration: 2});
10668
10669 // common config options shown with default values
10670 el.fadeOut({
10671     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10672     easing: 'easeOut',
10673     duration: .5
10674     remove: false,
10675     useDisplay: false
10676 });
10677 </code></pre>
10678     * @param {Object} options (optional) Object literal with any of the Fx config options
10679     * @return {Roo.Element} The Element
10680     */
10681     fadeOut : function(o){
10682         var el = this.getFxEl();
10683         o = o || {};
10684         el.queueFx(o, function(){
10685             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10686                 o, null, .5, "easeOut", function(){
10687                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10688                      this.dom.style.display = "none";
10689                 }else{
10690                      this.dom.style.visibility = "hidden";
10691                 }
10692                 this.clearOpacity();
10693                 el.afterFx(o);
10694             });
10695         });
10696         return this;
10697     },
10698
10699    /**
10700     * Animates the transition of an element's dimensions from a starting height/width
10701     * to an ending height/width.
10702     * Usage:
10703 <pre><code>
10704 // change height and width to 100x100 pixels
10705 el.scale(100, 100);
10706
10707 // common config options shown with default values.  The height and width will default to
10708 // the element's existing values if passed as null.
10709 el.scale(
10710     [element's width],
10711     [element's height], {
10712     easing: 'easeOut',
10713     duration: .35
10714 });
10715 </code></pre>
10716     * @param {Number} width  The new width (pass undefined to keep the original width)
10717     * @param {Number} height  The new height (pass undefined to keep the original height)
10718     * @param {Object} options (optional) Object literal with any of the Fx config options
10719     * @return {Roo.Element} The Element
10720     */
10721     scale : function(w, h, o){
10722         this.shift(Roo.apply({}, o, {
10723             width: w,
10724             height: h
10725         }));
10726         return this;
10727     },
10728
10729    /**
10730     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10731     * Any of these properties not specified in the config object will not be changed.  This effect 
10732     * requires that at least one new dimension, position or opacity setting must be passed in on
10733     * the config object in order for the function to have any effect.
10734     * Usage:
10735 <pre><code>
10736 // slide the element horizontally to x position 200 while changing the height and opacity
10737 el.shift({ x: 200, height: 50, opacity: .8 });
10738
10739 // common config options shown with default values.
10740 el.shift({
10741     width: [element's width],
10742     height: [element's height],
10743     x: [element's x position],
10744     y: [element's y position],
10745     opacity: [element's opacity],
10746     easing: 'easeOut',
10747     duration: .35
10748 });
10749 </code></pre>
10750     * @param {Object} options  Object literal with any of the Fx config options
10751     * @return {Roo.Element} The Element
10752     */
10753     shift : function(o){
10754         var el = this.getFxEl();
10755         o = o || {};
10756         el.queueFx(o, function(){
10757             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10758             if(w !== undefined){
10759                 a.width = {to: this.adjustWidth(w)};
10760             }
10761             if(h !== undefined){
10762                 a.height = {to: this.adjustHeight(h)};
10763             }
10764             if(x !== undefined || y !== undefined){
10765                 a.points = {to: [
10766                     x !== undefined ? x : this.getX(),
10767                     y !== undefined ? y : this.getY()
10768                 ]};
10769             }
10770             if(op !== undefined){
10771                 a.opacity = {to: op};
10772             }
10773             if(o.xy !== undefined){
10774                 a.points = {to: o.xy};
10775             }
10776             arguments.callee.anim = this.fxanim(a,
10777                 o, 'motion', .35, "easeOut", function(){
10778                 el.afterFx(o);
10779             });
10780         });
10781         return this;
10782     },
10783
10784         /**
10785          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10786          * ending point of the effect.
10787          * Usage:
10788          *<pre><code>
10789 // default: slide the element downward while fading out
10790 el.ghost();
10791
10792 // custom: slide the element out to the right with a 2-second duration
10793 el.ghost('r', { duration: 2 });
10794
10795 // common config options shown with default values
10796 el.ghost('b', {
10797     easing: 'easeOut',
10798     duration: .5
10799     remove: false,
10800     useDisplay: false
10801 });
10802 </code></pre>
10803          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10804          * @param {Object} options (optional) Object literal with any of the Fx config options
10805          * @return {Roo.Element} The Element
10806          */
10807     ghost : function(anchor, o){
10808         var el = this.getFxEl();
10809         o = o || {};
10810
10811         el.queueFx(o, function(){
10812             anchor = anchor || "b";
10813
10814             // restore values after effect
10815             var r = this.getFxRestore();
10816             var w = this.getWidth(),
10817                 h = this.getHeight();
10818
10819             var st = this.dom.style;
10820
10821             var after = function(){
10822                 if(o.useDisplay){
10823                     el.setDisplayed(false);
10824                 }else{
10825                     el.hide();
10826                 }
10827
10828                 el.clearOpacity();
10829                 el.setPositioning(r.pos);
10830                 st.width = r.width;
10831                 st.height = r.height;
10832
10833                 el.afterFx(o);
10834             };
10835
10836             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10837             switch(anchor.toLowerCase()){
10838                 case "t":
10839                     pt.by = [0, -h];
10840                 break;
10841                 case "l":
10842                     pt.by = [-w, 0];
10843                 break;
10844                 case "r":
10845                     pt.by = [w, 0];
10846                 break;
10847                 case "b":
10848                     pt.by = [0, h];
10849                 break;
10850                 case "tl":
10851                     pt.by = [-w, -h];
10852                 break;
10853                 case "bl":
10854                     pt.by = [-w, h];
10855                 break;
10856                 case "br":
10857                     pt.by = [w, h];
10858                 break;
10859                 case "tr":
10860                     pt.by = [w, -h];
10861                 break;
10862             }
10863
10864             arguments.callee.anim = this.fxanim(a,
10865                 o,
10866                 'motion',
10867                 .5,
10868                 "easeOut", after);
10869         });
10870         return this;
10871     },
10872
10873         /**
10874          * Ensures that all effects queued after syncFx is called on the element are
10875          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10876          * @return {Roo.Element} The Element
10877          */
10878     syncFx : function(){
10879         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10880             block : false,
10881             concurrent : true,
10882             stopFx : false
10883         });
10884         return this;
10885     },
10886
10887         /**
10888          * Ensures that all effects queued after sequenceFx is called on the element are
10889          * run in sequence.  This is the opposite of {@link #syncFx}.
10890          * @return {Roo.Element} The Element
10891          */
10892     sequenceFx : function(){
10893         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10894             block : false,
10895             concurrent : false,
10896             stopFx : false
10897         });
10898         return this;
10899     },
10900
10901         /* @private */
10902     nextFx : function(){
10903         var ef = this.fxQueue[0];
10904         if(ef){
10905             ef.call(this);
10906         }
10907     },
10908
10909         /**
10910          * Returns true if the element has any effects actively running or queued, else returns false.
10911          * @return {Boolean} True if element has active effects, else false
10912          */
10913     hasActiveFx : function(){
10914         return this.fxQueue && this.fxQueue[0];
10915     },
10916
10917         /**
10918          * Stops any running effects and clears the element's internal effects queue if it contains
10919          * any additional effects that haven't started yet.
10920          * @return {Roo.Element} The Element
10921          */
10922     stopFx : function(){
10923         if(this.hasActiveFx()){
10924             var cur = this.fxQueue[0];
10925             if(cur && cur.anim && cur.anim.isAnimated()){
10926                 this.fxQueue = [cur]; // clear out others
10927                 cur.anim.stop(true);
10928             }
10929         }
10930         return this;
10931     },
10932
10933         /* @private */
10934     beforeFx : function(o){
10935         if(this.hasActiveFx() && !o.concurrent){
10936            if(o.stopFx){
10937                this.stopFx();
10938                return true;
10939            }
10940            return false;
10941         }
10942         return true;
10943     },
10944
10945         /**
10946          * Returns true if the element is currently blocking so that no other effect can be queued
10947          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10948          * used to ensure that an effect initiated by a user action runs to completion prior to the
10949          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10950          * @return {Boolean} True if blocking, else false
10951          */
10952     hasFxBlock : function(){
10953         var q = this.fxQueue;
10954         return q && q[0] && q[0].block;
10955     },
10956
10957         /* @private */
10958     queueFx : function(o, fn){
10959         if(!this.fxQueue){
10960             this.fxQueue = [];
10961         }
10962         if(!this.hasFxBlock()){
10963             Roo.applyIf(o, this.fxDefaults);
10964             if(!o.concurrent){
10965                 var run = this.beforeFx(o);
10966                 fn.block = o.block;
10967                 this.fxQueue.push(fn);
10968                 if(run){
10969                     this.nextFx();
10970                 }
10971             }else{
10972                 fn.call(this);
10973             }
10974         }
10975         return this;
10976     },
10977
10978         /* @private */
10979     fxWrap : function(pos, o, vis){
10980         var wrap;
10981         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10982             var wrapXY;
10983             if(o.fixPosition){
10984                 wrapXY = this.getXY();
10985             }
10986             var div = document.createElement("div");
10987             div.style.visibility = vis;
10988             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10989             wrap.setPositioning(pos);
10990             if(wrap.getStyle("position") == "static"){
10991                 wrap.position("relative");
10992             }
10993             this.clearPositioning('auto');
10994             wrap.clip();
10995             wrap.dom.appendChild(this.dom);
10996             if(wrapXY){
10997                 wrap.setXY(wrapXY);
10998             }
10999         }
11000         return wrap;
11001     },
11002
11003         /* @private */
11004     fxUnwrap : function(wrap, pos, o){
11005         this.clearPositioning();
11006         this.setPositioning(pos);
11007         if(!o.wrap){
11008             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11009             wrap.remove();
11010         }
11011     },
11012
11013         /* @private */
11014     getFxRestore : function(){
11015         var st = this.dom.style;
11016         return {pos: this.getPositioning(), width: st.width, height : st.height};
11017     },
11018
11019         /* @private */
11020     afterFx : function(o){
11021         if(o.afterStyle){
11022             this.applyStyles(o.afterStyle);
11023         }
11024         if(o.afterCls){
11025             this.addClass(o.afterCls);
11026         }
11027         if(o.remove === true){
11028             this.remove();
11029         }
11030         Roo.callback(o.callback, o.scope, [this]);
11031         if(!o.concurrent){
11032             this.fxQueue.shift();
11033             this.nextFx();
11034         }
11035     },
11036
11037         /* @private */
11038     getFxEl : function(){ // support for composite element fx
11039         return Roo.get(this.dom);
11040     },
11041
11042         /* @private */
11043     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11044         animType = animType || 'run';
11045         opt = opt || {};
11046         var anim = Roo.lib.Anim[animType](
11047             this.dom, args,
11048             (opt.duration || defaultDur) || .35,
11049             (opt.easing || defaultEase) || 'easeOut',
11050             function(){
11051                 Roo.callback(cb, this);
11052             },
11053             this
11054         );
11055         opt.anim = anim;
11056         return anim;
11057     }
11058 };
11059
11060 // backwords compat
11061 Roo.Fx.resize = Roo.Fx.scale;
11062
11063 //When included, Roo.Fx is automatically applied to Element so that all basic
11064 //effects are available directly via the Element API
11065 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11066  * Based on:
11067  * Ext JS Library 1.1.1
11068  * Copyright(c) 2006-2007, Ext JS, LLC.
11069  *
11070  * Originally Released Under LGPL - original licence link has changed is not relivant.
11071  *
11072  * Fork - LGPL
11073  * <script type="text/javascript">
11074  */
11075
11076
11077 /**
11078  * @class Roo.CompositeElement
11079  * Standard composite class. Creates a Roo.Element for every element in the collection.
11080  * <br><br>
11081  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11082  * actions will be performed on all the elements in this collection.</b>
11083  * <br><br>
11084  * All methods return <i>this</i> and can be chained.
11085  <pre><code>
11086  var els = Roo.select("#some-el div.some-class", true);
11087  // or select directly from an existing element
11088  var el = Roo.get('some-el');
11089  el.select('div.some-class', true);
11090
11091  els.setWidth(100); // all elements become 100 width
11092  els.hide(true); // all elements fade out and hide
11093  // or
11094  els.setWidth(100).hide(true);
11095  </code></pre>
11096  */
11097 Roo.CompositeElement = function(els){
11098     this.elements = [];
11099     this.addElements(els);
11100 };
11101 Roo.CompositeElement.prototype = {
11102     isComposite: true,
11103     addElements : function(els){
11104         if(!els) {
11105             return this;
11106         }
11107         if(typeof els == "string"){
11108             els = Roo.Element.selectorFunction(els);
11109         }
11110         var yels = this.elements;
11111         var index = yels.length-1;
11112         for(var i = 0, len = els.length; i < len; i++) {
11113                 yels[++index] = Roo.get(els[i]);
11114         }
11115         return this;
11116     },
11117
11118     /**
11119     * Clears this composite and adds the elements returned by the passed selector.
11120     * @param {String/Array} els A string CSS selector, an array of elements or an element
11121     * @return {CompositeElement} this
11122     */
11123     fill : function(els){
11124         this.elements = [];
11125         this.add(els);
11126         return this;
11127     },
11128
11129     /**
11130     * Filters this composite to only elements that match the passed selector.
11131     * @param {String} selector A string CSS selector
11132     * @param {Boolean} inverse return inverse filter (not matches)
11133     * @return {CompositeElement} this
11134     */
11135     filter : function(selector, inverse){
11136         var els = [];
11137         inverse = inverse || false;
11138         this.each(function(el){
11139             var match = inverse ? !el.is(selector) : el.is(selector);
11140             if(match){
11141                 els[els.length] = el.dom;
11142             }
11143         });
11144         this.fill(els);
11145         return this;
11146     },
11147
11148     invoke : function(fn, args){
11149         var els = this.elements;
11150         for(var i = 0, len = els.length; i < len; i++) {
11151                 Roo.Element.prototype[fn].apply(els[i], args);
11152         }
11153         return this;
11154     },
11155     /**
11156     * Adds elements to this composite.
11157     * @param {String/Array} els A string CSS selector, an array of elements or an element
11158     * @return {CompositeElement} this
11159     */
11160     add : function(els){
11161         if(typeof els == "string"){
11162             this.addElements(Roo.Element.selectorFunction(els));
11163         }else if(els.length !== undefined){
11164             this.addElements(els);
11165         }else{
11166             this.addElements([els]);
11167         }
11168         return this;
11169     },
11170     /**
11171     * Calls the passed function passing (el, this, index) for each element in this composite.
11172     * @param {Function} fn The function to call
11173     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11174     * @return {CompositeElement} this
11175     */
11176     each : function(fn, scope){
11177         var els = this.elements;
11178         for(var i = 0, len = els.length; i < len; i++){
11179             if(fn.call(scope || els[i], els[i], this, i) === false) {
11180                 break;
11181             }
11182         }
11183         return this;
11184     },
11185
11186     /**
11187      * Returns the Element object at the specified index
11188      * @param {Number} index
11189      * @return {Roo.Element}
11190      */
11191     item : function(index){
11192         return this.elements[index] || null;
11193     },
11194
11195     /**
11196      * Returns the first Element
11197      * @return {Roo.Element}
11198      */
11199     first : function(){
11200         return this.item(0);
11201     },
11202
11203     /**
11204      * Returns the last Element
11205      * @return {Roo.Element}
11206      */
11207     last : function(){
11208         return this.item(this.elements.length-1);
11209     },
11210
11211     /**
11212      * Returns the number of elements in this composite
11213      * @return Number
11214      */
11215     getCount : function(){
11216         return this.elements.length;
11217     },
11218
11219     /**
11220      * Returns true if this composite contains the passed element
11221      * @return Boolean
11222      */
11223     contains : function(el){
11224         return this.indexOf(el) !== -1;
11225     },
11226
11227     /**
11228      * Returns true if this composite contains the passed element
11229      * @return Boolean
11230      */
11231     indexOf : function(el){
11232         return this.elements.indexOf(Roo.get(el));
11233     },
11234
11235
11236     /**
11237     * Removes the specified element(s).
11238     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11239     * or an array of any of those.
11240     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11241     * @return {CompositeElement} this
11242     */
11243     removeElement : function(el, removeDom){
11244         if(el instanceof Array){
11245             for(var i = 0, len = el.length; i < len; i++){
11246                 this.removeElement(el[i]);
11247             }
11248             return this;
11249         }
11250         var index = typeof el == 'number' ? el : this.indexOf(el);
11251         if(index !== -1){
11252             if(removeDom){
11253                 var d = this.elements[index];
11254                 if(d.dom){
11255                     d.remove();
11256                 }else{
11257                     d.parentNode.removeChild(d);
11258                 }
11259             }
11260             this.elements.splice(index, 1);
11261         }
11262         return this;
11263     },
11264
11265     /**
11266     * Replaces the specified element with the passed element.
11267     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11268     * to replace.
11269     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11270     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11271     * @return {CompositeElement} this
11272     */
11273     replaceElement : function(el, replacement, domReplace){
11274         var index = typeof el == 'number' ? el : this.indexOf(el);
11275         if(index !== -1){
11276             if(domReplace){
11277                 this.elements[index].replaceWith(replacement);
11278             }else{
11279                 this.elements.splice(index, 1, Roo.get(replacement))
11280             }
11281         }
11282         return this;
11283     },
11284
11285     /**
11286      * Removes all elements.
11287      */
11288     clear : function(){
11289         this.elements = [];
11290     }
11291 };
11292 (function(){
11293     Roo.CompositeElement.createCall = function(proto, fnName){
11294         if(!proto[fnName]){
11295             proto[fnName] = function(){
11296                 return this.invoke(fnName, arguments);
11297             };
11298         }
11299     };
11300     for(var fnName in Roo.Element.prototype){
11301         if(typeof Roo.Element.prototype[fnName] == "function"){
11302             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11303         }
11304     };
11305 })();
11306 /*
11307  * Based on:
11308  * Ext JS Library 1.1.1
11309  * Copyright(c) 2006-2007, Ext JS, LLC.
11310  *
11311  * Originally Released Under LGPL - original licence link has changed is not relivant.
11312  *
11313  * Fork - LGPL
11314  * <script type="text/javascript">
11315  */
11316
11317 /**
11318  * @class Roo.CompositeElementLite
11319  * @extends Roo.CompositeElement
11320  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11321  <pre><code>
11322  var els = Roo.select("#some-el div.some-class");
11323  // or select directly from an existing element
11324  var el = Roo.get('some-el');
11325  el.select('div.some-class');
11326
11327  els.setWidth(100); // all elements become 100 width
11328  els.hide(true); // all elements fade out and hide
11329  // or
11330  els.setWidth(100).hide(true);
11331  </code></pre><br><br>
11332  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11333  * actions will be performed on all the elements in this collection.</b>
11334  */
11335 Roo.CompositeElementLite = function(els){
11336     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11337     this.el = new Roo.Element.Flyweight();
11338 };
11339 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11340     addElements : function(els){
11341         if(els){
11342             if(els instanceof Array){
11343                 this.elements = this.elements.concat(els);
11344             }else{
11345                 var yels = this.elements;
11346                 var index = yels.length-1;
11347                 for(var i = 0, len = els.length; i < len; i++) {
11348                     yels[++index] = els[i];
11349                 }
11350             }
11351         }
11352         return this;
11353     },
11354     invoke : function(fn, args){
11355         var els = this.elements;
11356         var el = this.el;
11357         for(var i = 0, len = els.length; i < len; i++) {
11358             el.dom = els[i];
11359                 Roo.Element.prototype[fn].apply(el, args);
11360         }
11361         return this;
11362     },
11363     /**
11364      * Returns a flyweight Element of the dom element object at the specified index
11365      * @param {Number} index
11366      * @return {Roo.Element}
11367      */
11368     item : function(index){
11369         if(!this.elements[index]){
11370             return null;
11371         }
11372         this.el.dom = this.elements[index];
11373         return this.el;
11374     },
11375
11376     // fixes scope with flyweight
11377     addListener : function(eventName, handler, scope, opt){
11378         var els = this.elements;
11379         for(var i = 0, len = els.length; i < len; i++) {
11380             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11381         }
11382         return this;
11383     },
11384
11385     /**
11386     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11387     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11388     * a reference to the dom node, use el.dom.</b>
11389     * @param {Function} fn The function to call
11390     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11391     * @return {CompositeElement} this
11392     */
11393     each : function(fn, scope){
11394         var els = this.elements;
11395         var el = this.el;
11396         for(var i = 0, len = els.length; i < len; i++){
11397             el.dom = els[i];
11398                 if(fn.call(scope || el, el, this, i) === false){
11399                 break;
11400             }
11401         }
11402         return this;
11403     },
11404
11405     indexOf : function(el){
11406         return this.elements.indexOf(Roo.getDom(el));
11407     },
11408
11409     replaceElement : function(el, replacement, domReplace){
11410         var index = typeof el == 'number' ? el : this.indexOf(el);
11411         if(index !== -1){
11412             replacement = Roo.getDom(replacement);
11413             if(domReplace){
11414                 var d = this.elements[index];
11415                 d.parentNode.insertBefore(replacement, d);
11416                 d.parentNode.removeChild(d);
11417             }
11418             this.elements.splice(index, 1, replacement);
11419         }
11420         return this;
11421     }
11422 });
11423 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11424
11425 /*
11426  * Based on:
11427  * Ext JS Library 1.1.1
11428  * Copyright(c) 2006-2007, Ext JS, LLC.
11429  *
11430  * Originally Released Under LGPL - original licence link has changed is not relivant.
11431  *
11432  * Fork - LGPL
11433  * <script type="text/javascript">
11434  */
11435
11436  
11437
11438 /**
11439  * @class Roo.data.Connection
11440  * @extends Roo.util.Observable
11441  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11442  * either to a configured URL, or to a URL specified at request time.<br><br>
11443  * <p>
11444  * Requests made by this class are asynchronous, and will return immediately. No data from
11445  * the server will be available to the statement immediately following the {@link #request} call.
11446  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11447  * <p>
11448  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11449  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11450  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11451  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11452  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11453  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11454  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11455  * standard DOM methods.
11456  * @constructor
11457  * @param {Object} config a configuration object.
11458  */
11459 Roo.data.Connection = function(config){
11460     Roo.apply(this, config);
11461     this.addEvents({
11462         /**
11463          * @event beforerequest
11464          * Fires before a network request is made to retrieve a data object.
11465          * @param {Connection} conn This Connection object.
11466          * @param {Object} options The options config object passed to the {@link #request} method.
11467          */
11468         "beforerequest" : true,
11469         /**
11470          * @event requestcomplete
11471          * Fires if the request was successfully completed.
11472          * @param {Connection} conn This Connection object.
11473          * @param {Object} response The XHR object containing the response data.
11474          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11475          * @param {Object} options The options config object passed to the {@link #request} method.
11476          */
11477         "requestcomplete" : true,
11478         /**
11479          * @event requestexception
11480          * Fires if an error HTTP status was returned from the server.
11481          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11482          * @param {Connection} conn This Connection object.
11483          * @param {Object} response The XHR object containing the response data.
11484          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11485          * @param {Object} options The options config object passed to the {@link #request} method.
11486          */
11487         "requestexception" : true
11488     });
11489     Roo.data.Connection.superclass.constructor.call(this);
11490 };
11491
11492 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11493     /**
11494      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11495      */
11496     /**
11497      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11498      * extra parameters to each request made by this object. (defaults to undefined)
11499      */
11500     /**
11501      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11502      *  to each request made by this object. (defaults to undefined)
11503      */
11504     /**
11505      * @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)
11506      */
11507     /**
11508      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11509      */
11510     timeout : 30000,
11511     /**
11512      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11513      * @type Boolean
11514      */
11515     autoAbort:false,
11516
11517     /**
11518      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11519      * @type Boolean
11520      */
11521     disableCaching: true,
11522
11523     /**
11524      * Sends an HTTP request to a remote server.
11525      * @param {Object} options An object which may contain the following properties:<ul>
11526      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11527      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11528      * request, a url encoded string or a function to call to get either.</li>
11529      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11530      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11531      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11532      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11533      * <li>options {Object} The parameter to the request call.</li>
11534      * <li>success {Boolean} True if the request succeeded.</li>
11535      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11536      * </ul></li>
11537      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11538      * The callback is passed the following parameters:<ul>
11539      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11540      * <li>options {Object} The parameter to the request call.</li>
11541      * </ul></li>
11542      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11543      * The callback is passed the following parameters:<ul>
11544      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11545      * <li>options {Object} The parameter to the request call.</li>
11546      * </ul></li>
11547      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11548      * for the callback function. Defaults to the browser window.</li>
11549      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11550      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11551      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11552      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11553      * params for the post data. Any params will be appended to the URL.</li>
11554      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11555      * </ul>
11556      * @return {Number} transactionId
11557      */
11558     request : function(o){
11559         if(this.fireEvent("beforerequest", this, o) !== false){
11560             var p = o.params;
11561
11562             if(typeof p == "function"){
11563                 p = p.call(o.scope||window, o);
11564             }
11565             if(typeof p == "object"){
11566                 p = Roo.urlEncode(o.params);
11567             }
11568             if(this.extraParams){
11569                 var extras = Roo.urlEncode(this.extraParams);
11570                 p = p ? (p + '&' + extras) : extras;
11571             }
11572
11573             var url = o.url || this.url;
11574             if(typeof url == 'function'){
11575                 url = url.call(o.scope||window, o);
11576             }
11577
11578             if(o.form){
11579                 var form = Roo.getDom(o.form);
11580                 url = url || form.action;
11581
11582                 var enctype = form.getAttribute("enctype");
11583                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11584                     return this.doFormUpload(o, p, url);
11585                 }
11586                 var f = Roo.lib.Ajax.serializeForm(form);
11587                 p = p ? (p + '&' + f) : f;
11588             }
11589
11590             var hs = o.headers;
11591             if(this.defaultHeaders){
11592                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11593                 if(!o.headers){
11594                     o.headers = hs;
11595                 }
11596             }
11597
11598             var cb = {
11599                 success: this.handleResponse,
11600                 failure: this.handleFailure,
11601                 scope: this,
11602                 argument: {options: o},
11603                 timeout : o.timeout || this.timeout
11604             };
11605
11606             var method = o.method||this.method||(p ? "POST" : "GET");
11607
11608             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11609                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11610             }
11611
11612             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11613                 if(o.autoAbort){
11614                     this.abort();
11615                 }
11616             }else if(this.autoAbort !== false){
11617                 this.abort();
11618             }
11619
11620             if((method == 'GET' && p) || o.xmlData){
11621                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11622                 p = '';
11623             }
11624             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11625             return this.transId;
11626         }else{
11627             Roo.callback(o.callback, o.scope, [o, null, null]);
11628             return null;
11629         }
11630     },
11631
11632     /**
11633      * Determine whether this object has a request outstanding.
11634      * @param {Number} transactionId (Optional) defaults to the last transaction
11635      * @return {Boolean} True if there is an outstanding request.
11636      */
11637     isLoading : function(transId){
11638         if(transId){
11639             return Roo.lib.Ajax.isCallInProgress(transId);
11640         }else{
11641             return this.transId ? true : false;
11642         }
11643     },
11644
11645     /**
11646      * Aborts any outstanding request.
11647      * @param {Number} transactionId (Optional) defaults to the last transaction
11648      */
11649     abort : function(transId){
11650         if(transId || this.isLoading()){
11651             Roo.lib.Ajax.abort(transId || this.transId);
11652         }
11653     },
11654
11655     // private
11656     handleResponse : function(response){
11657         this.transId = false;
11658         var options = response.argument.options;
11659         response.argument = options ? options.argument : null;
11660         this.fireEvent("requestcomplete", this, response, options);
11661         Roo.callback(options.success, options.scope, [response, options]);
11662         Roo.callback(options.callback, options.scope, [options, true, response]);
11663     },
11664
11665     // private
11666     handleFailure : function(response, e){
11667         this.transId = false;
11668         var options = response.argument.options;
11669         response.argument = options ? options.argument : null;
11670         this.fireEvent("requestexception", this, response, options, e);
11671         Roo.callback(options.failure, options.scope, [response, options]);
11672         Roo.callback(options.callback, options.scope, [options, false, response]);
11673     },
11674
11675     // private
11676     doFormUpload : function(o, ps, url){
11677         var id = Roo.id();
11678         var frame = document.createElement('iframe');
11679         frame.id = id;
11680         frame.name = id;
11681         frame.className = 'x-hidden';
11682         if(Roo.isIE){
11683             frame.src = Roo.SSL_SECURE_URL;
11684         }
11685         document.body.appendChild(frame);
11686
11687         if(Roo.isIE){
11688            document.frames[id].name = id;
11689         }
11690
11691         var form = Roo.getDom(o.form);
11692         form.target = id;
11693         form.method = 'POST';
11694         form.enctype = form.encoding = 'multipart/form-data';
11695         if(url){
11696             form.action = url;
11697         }
11698
11699         var hiddens, hd;
11700         if(ps){ // add dynamic params
11701             hiddens = [];
11702             ps = Roo.urlDecode(ps, false);
11703             for(var k in ps){
11704                 if(ps.hasOwnProperty(k)){
11705                     hd = document.createElement('input');
11706                     hd.type = 'hidden';
11707                     hd.name = k;
11708                     hd.value = ps[k];
11709                     form.appendChild(hd);
11710                     hiddens.push(hd);
11711                 }
11712             }
11713         }
11714
11715         function cb(){
11716             var r = {  // bogus response object
11717                 responseText : '',
11718                 responseXML : null
11719             };
11720
11721             r.argument = o ? o.argument : null;
11722
11723             try { //
11724                 var doc;
11725                 if(Roo.isIE){
11726                     doc = frame.contentWindow.document;
11727                 }else {
11728                     doc = (frame.contentDocument || window.frames[id].document);
11729                 }
11730                 if(doc && doc.body){
11731                     r.responseText = doc.body.innerHTML;
11732                 }
11733                 if(doc && doc.XMLDocument){
11734                     r.responseXML = doc.XMLDocument;
11735                 }else {
11736                     r.responseXML = doc;
11737                 }
11738             }
11739             catch(e) {
11740                 // ignore
11741             }
11742
11743             Roo.EventManager.removeListener(frame, 'load', cb, this);
11744
11745             this.fireEvent("requestcomplete", this, r, o);
11746             Roo.callback(o.success, o.scope, [r, o]);
11747             Roo.callback(o.callback, o.scope, [o, true, r]);
11748
11749             setTimeout(function(){document.body.removeChild(frame);}, 100);
11750         }
11751
11752         Roo.EventManager.on(frame, 'load', cb, this);
11753         form.submit();
11754
11755         if(hiddens){ // remove dynamic params
11756             for(var i = 0, len = hiddens.length; i < len; i++){
11757                 form.removeChild(hiddens[i]);
11758             }
11759         }
11760     }
11761 });
11762 /*
11763  * Based on:
11764  * Ext JS Library 1.1.1
11765  * Copyright(c) 2006-2007, Ext JS, LLC.
11766  *
11767  * Originally Released Under LGPL - original licence link has changed is not relivant.
11768  *
11769  * Fork - LGPL
11770  * <script type="text/javascript">
11771  */
11772  
11773 /**
11774  * Global Ajax request class.
11775  * 
11776  * @class Roo.Ajax
11777  * @extends Roo.data.Connection
11778  * @static
11779  * 
11780  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11781  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11782  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11783  * @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)
11784  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11785  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11786  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11787  */
11788 Roo.Ajax = new Roo.data.Connection({
11789     // fix up the docs
11790     /**
11791      * @scope Roo.Ajax
11792      * @type {Boolear} 
11793      */
11794     autoAbort : false,
11795
11796     /**
11797      * Serialize the passed form into a url encoded string
11798      * @scope Roo.Ajax
11799      * @param {String/HTMLElement} form
11800      * @return {String}
11801      */
11802     serializeForm : function(form){
11803         return Roo.lib.Ajax.serializeForm(form);
11804     }
11805 });/*
11806  * Based on:
11807  * Ext JS Library 1.1.1
11808  * Copyright(c) 2006-2007, Ext JS, LLC.
11809  *
11810  * Originally Released Under LGPL - original licence link has changed is not relivant.
11811  *
11812  * Fork - LGPL
11813  * <script type="text/javascript">
11814  */
11815
11816  
11817 /**
11818  * @class Roo.UpdateManager
11819  * @extends Roo.util.Observable
11820  * Provides AJAX-style update for Element object.<br><br>
11821  * Usage:<br>
11822  * <pre><code>
11823  * // Get it from a Roo.Element object
11824  * var el = Roo.get("foo");
11825  * var mgr = el.getUpdateManager();
11826  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11827  * ...
11828  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11829  * <br>
11830  * // or directly (returns the same UpdateManager instance)
11831  * var mgr = new Roo.UpdateManager("myElementId");
11832  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11833  * mgr.on("update", myFcnNeedsToKnow);
11834  * <br>
11835    // short handed call directly from the element object
11836    Roo.get("foo").load({
11837         url: "bar.php",
11838         scripts:true,
11839         params: "for=bar",
11840         text: "Loading Foo..."
11841    });
11842  * </code></pre>
11843  * @constructor
11844  * Create new UpdateManager directly.
11845  * @param {String/HTMLElement/Roo.Element} el The element to update
11846  * @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).
11847  */
11848 Roo.UpdateManager = function(el, forceNew){
11849     el = Roo.get(el);
11850     if(!forceNew && el.updateManager){
11851         return el.updateManager;
11852     }
11853     /**
11854      * The Element object
11855      * @type Roo.Element
11856      */
11857     this.el = el;
11858     /**
11859      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11860      * @type String
11861      */
11862     this.defaultUrl = null;
11863
11864     this.addEvents({
11865         /**
11866          * @event beforeupdate
11867          * Fired before an update is made, return false from your handler and the update is cancelled.
11868          * @param {Roo.Element} el
11869          * @param {String/Object/Function} url
11870          * @param {String/Object} params
11871          */
11872         "beforeupdate": true,
11873         /**
11874          * @event update
11875          * Fired after successful update is made.
11876          * @param {Roo.Element} el
11877          * @param {Object} oResponseObject The response Object
11878          */
11879         "update": true,
11880         /**
11881          * @event failure
11882          * Fired on update failure.
11883          * @param {Roo.Element} el
11884          * @param {Object} oResponseObject The response Object
11885          */
11886         "failure": true
11887     });
11888     var d = Roo.UpdateManager.defaults;
11889     /**
11890      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11891      * @type String
11892      */
11893     this.sslBlankUrl = d.sslBlankUrl;
11894     /**
11895      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11896      * @type Boolean
11897      */
11898     this.disableCaching = d.disableCaching;
11899     /**
11900      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11901      * @type String
11902      */
11903     this.indicatorText = d.indicatorText;
11904     /**
11905      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11906      * @type String
11907      */
11908     this.showLoadIndicator = d.showLoadIndicator;
11909     /**
11910      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11911      * @type Number
11912      */
11913     this.timeout = d.timeout;
11914
11915     /**
11916      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11917      * @type Boolean
11918      */
11919     this.loadScripts = d.loadScripts;
11920
11921     /**
11922      * Transaction object of current executing transaction
11923      */
11924     this.transaction = null;
11925
11926     /**
11927      * @private
11928      */
11929     this.autoRefreshProcId = null;
11930     /**
11931      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11932      * @type Function
11933      */
11934     this.refreshDelegate = this.refresh.createDelegate(this);
11935     /**
11936      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11937      * @type Function
11938      */
11939     this.updateDelegate = this.update.createDelegate(this);
11940     /**
11941      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11942      * @type Function
11943      */
11944     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11945     /**
11946      * @private
11947      */
11948     this.successDelegate = this.processSuccess.createDelegate(this);
11949     /**
11950      * @private
11951      */
11952     this.failureDelegate = this.processFailure.createDelegate(this);
11953
11954     if(!this.renderer){
11955      /**
11956       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11957       */
11958     this.renderer = new Roo.UpdateManager.BasicRenderer();
11959     }
11960     
11961     Roo.UpdateManager.superclass.constructor.call(this);
11962 };
11963
11964 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11965     /**
11966      * Get the Element this UpdateManager is bound to
11967      * @return {Roo.Element} The element
11968      */
11969     getEl : function(){
11970         return this.el;
11971     },
11972     /**
11973      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11974      * @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:
11975 <pre><code>
11976 um.update({<br/>
11977     url: "your-url.php",<br/>
11978     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11979     callback: yourFunction,<br/>
11980     scope: yourObject, //(optional scope)  <br/>
11981     discardUrl: false, <br/>
11982     nocache: false,<br/>
11983     text: "Loading...",<br/>
11984     timeout: 30,<br/>
11985     scripts: false<br/>
11986 });
11987 </code></pre>
11988      * The only required property is url. The optional properties nocache, text and scripts
11989      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11990      * @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}
11991      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11992      * @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.
11993      */
11994     update : function(url, params, callback, discardUrl){
11995         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11996             var method = this.method,
11997                 cfg;
11998             if(typeof url == "object"){ // must be config object
11999                 cfg = url;
12000                 url = cfg.url;
12001                 params = params || cfg.params;
12002                 callback = callback || cfg.callback;
12003                 discardUrl = discardUrl || cfg.discardUrl;
12004                 if(callback && cfg.scope){
12005                     callback = callback.createDelegate(cfg.scope);
12006                 }
12007                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12008                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12009                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12010                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12011                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12012             }
12013             this.showLoading();
12014             if(!discardUrl){
12015                 this.defaultUrl = url;
12016             }
12017             if(typeof url == "function"){
12018                 url = url.call(this);
12019             }
12020
12021             method = method || (params ? "POST" : "GET");
12022             if(method == "GET"){
12023                 url = this.prepareUrl(url);
12024             }
12025
12026             var o = Roo.apply(cfg ||{}, {
12027                 url : url,
12028                 params: params,
12029                 success: this.successDelegate,
12030                 failure: this.failureDelegate,
12031                 callback: undefined,
12032                 timeout: (this.timeout*1000),
12033                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12034             });
12035             Roo.log("updated manager called with timeout of " + o.timeout);
12036             this.transaction = Roo.Ajax.request(o);
12037         }
12038     },
12039
12040     /**
12041      * 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.
12042      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12043      * @param {String/HTMLElement} form The form Id or form element
12044      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12045      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12046      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12047      */
12048     formUpdate : function(form, url, reset, callback){
12049         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12050             if(typeof url == "function"){
12051                 url = url.call(this);
12052             }
12053             form = Roo.getDom(form);
12054             this.transaction = Roo.Ajax.request({
12055                 form: form,
12056                 url:url,
12057                 success: this.successDelegate,
12058                 failure: this.failureDelegate,
12059                 timeout: (this.timeout*1000),
12060                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12061             });
12062             this.showLoading.defer(1, this);
12063         }
12064     },
12065
12066     /**
12067      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12068      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12069      */
12070     refresh : function(callback){
12071         if(this.defaultUrl == null){
12072             return;
12073         }
12074         this.update(this.defaultUrl, null, callback, true);
12075     },
12076
12077     /**
12078      * Set this element to auto refresh.
12079      * @param {Number} interval How often to update (in seconds).
12080      * @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)
12081      * @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}
12082      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12083      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12084      */
12085     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12086         if(refreshNow){
12087             this.update(url || this.defaultUrl, params, callback, true);
12088         }
12089         if(this.autoRefreshProcId){
12090             clearInterval(this.autoRefreshProcId);
12091         }
12092         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12093     },
12094
12095     /**
12096      * Stop auto refresh on this element.
12097      */
12098      stopAutoRefresh : function(){
12099         if(this.autoRefreshProcId){
12100             clearInterval(this.autoRefreshProcId);
12101             delete this.autoRefreshProcId;
12102         }
12103     },
12104
12105     isAutoRefreshing : function(){
12106        return this.autoRefreshProcId ? true : false;
12107     },
12108     /**
12109      * Called to update the element to "Loading" state. Override to perform custom action.
12110      */
12111     showLoading : function(){
12112         if(this.showLoadIndicator){
12113             this.el.update(this.indicatorText);
12114         }
12115     },
12116
12117     /**
12118      * Adds unique parameter to query string if disableCaching = true
12119      * @private
12120      */
12121     prepareUrl : function(url){
12122         if(this.disableCaching){
12123             var append = "_dc=" + (new Date().getTime());
12124             if(url.indexOf("?") !== -1){
12125                 url += "&" + append;
12126             }else{
12127                 url += "?" + append;
12128             }
12129         }
12130         return url;
12131     },
12132
12133     /**
12134      * @private
12135      */
12136     processSuccess : function(response){
12137         this.transaction = null;
12138         if(response.argument.form && response.argument.reset){
12139             try{ // put in try/catch since some older FF releases had problems with this
12140                 response.argument.form.reset();
12141             }catch(e){}
12142         }
12143         if(this.loadScripts){
12144             this.renderer.render(this.el, response, this,
12145                 this.updateComplete.createDelegate(this, [response]));
12146         }else{
12147             this.renderer.render(this.el, response, this);
12148             this.updateComplete(response);
12149         }
12150     },
12151
12152     updateComplete : function(response){
12153         this.fireEvent("update", this.el, response);
12154         if(typeof response.argument.callback == "function"){
12155             response.argument.callback(this.el, true, response);
12156         }
12157     },
12158
12159     /**
12160      * @private
12161      */
12162     processFailure : function(response){
12163         this.transaction = null;
12164         this.fireEvent("failure", this.el, response);
12165         if(typeof response.argument.callback == "function"){
12166             response.argument.callback(this.el, false, response);
12167         }
12168     },
12169
12170     /**
12171      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12172      * @param {Object} renderer The object implementing the render() method
12173      */
12174     setRenderer : function(renderer){
12175         this.renderer = renderer;
12176     },
12177
12178     getRenderer : function(){
12179        return this.renderer;
12180     },
12181
12182     /**
12183      * Set the defaultUrl used for updates
12184      * @param {String/Function} defaultUrl The url or a function to call to get the url
12185      */
12186     setDefaultUrl : function(defaultUrl){
12187         this.defaultUrl = defaultUrl;
12188     },
12189
12190     /**
12191      * Aborts the executing transaction
12192      */
12193     abort : function(){
12194         if(this.transaction){
12195             Roo.Ajax.abort(this.transaction);
12196         }
12197     },
12198
12199     /**
12200      * Returns true if an update is in progress
12201      * @return {Boolean}
12202      */
12203     isUpdating : function(){
12204         if(this.transaction){
12205             return Roo.Ajax.isLoading(this.transaction);
12206         }
12207         return false;
12208     }
12209 });
12210
12211 /**
12212  * @class Roo.UpdateManager.defaults
12213  * @static (not really - but it helps the doc tool)
12214  * The defaults collection enables customizing the default properties of UpdateManager
12215  */
12216    Roo.UpdateManager.defaults = {
12217        /**
12218          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12219          * @type Number
12220          */
12221          timeout : 30,
12222
12223          /**
12224          * True to process scripts by default (Defaults to false).
12225          * @type Boolean
12226          */
12227         loadScripts : false,
12228
12229         /**
12230         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12231         * @type String
12232         */
12233         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12234         /**
12235          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12236          * @type Boolean
12237          */
12238         disableCaching : false,
12239         /**
12240          * Whether to show indicatorText when loading (Defaults to true).
12241          * @type Boolean
12242          */
12243         showLoadIndicator : true,
12244         /**
12245          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12246          * @type String
12247          */
12248         indicatorText : '<div class="loading-indicator">Loading...</div>'
12249    };
12250
12251 /**
12252  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12253  *Usage:
12254  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12255  * @param {String/HTMLElement/Roo.Element} el The element to update
12256  * @param {String} url The url
12257  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12258  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12259  * @static
12260  * @deprecated
12261  * @member Roo.UpdateManager
12262  */
12263 Roo.UpdateManager.updateElement = function(el, url, params, options){
12264     var um = Roo.get(el, true).getUpdateManager();
12265     Roo.apply(um, options);
12266     um.update(url, params, options ? options.callback : null);
12267 };
12268 // alias for backwards compat
12269 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12270 /**
12271  * @class Roo.UpdateManager.BasicRenderer
12272  * Default Content renderer. Updates the elements innerHTML with the responseText.
12273  */
12274 Roo.UpdateManager.BasicRenderer = function(){};
12275
12276 Roo.UpdateManager.BasicRenderer.prototype = {
12277     /**
12278      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12279      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12280      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12281      * @param {Roo.Element} el The element being rendered
12282      * @param {Object} response The YUI Connect response object
12283      * @param {UpdateManager} updateManager The calling update manager
12284      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12285      */
12286      render : function(el, response, updateManager, callback){
12287         el.update(response.responseText, updateManager.loadScripts, callback);
12288     }
12289 };
12290 /*
12291  * Based on:
12292  * Roo JS
12293  * (c)) Alan Knowles
12294  * Licence : LGPL
12295  */
12296
12297
12298 /**
12299  * @class Roo.DomTemplate
12300  * @extends Roo.Template
12301  * An effort at a dom based template engine..
12302  *
12303  * Similar to XTemplate, except it uses dom parsing to create the template..
12304  *
12305  * Supported features:
12306  *
12307  *  Tags:
12308
12309 <pre><code>
12310       {a_variable} - output encoded.
12311       {a_variable.format:("Y-m-d")} - call a method on the variable
12312       {a_variable:raw} - unencoded output
12313       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12314       {a_variable:this.method_on_template(...)} - call a method on the template object.
12315  
12316 </code></pre>
12317  *  The tpl tag:
12318 <pre><code>
12319         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12320         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12321         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12322         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12323   
12324 </code></pre>
12325  *      
12326  */
12327 Roo.DomTemplate = function()
12328 {
12329      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12330      if (this.html) {
12331         this.compile();
12332      }
12333 };
12334
12335
12336 Roo.extend(Roo.DomTemplate, Roo.Template, {
12337     /**
12338      * id counter for sub templates.
12339      */
12340     id : 0,
12341     /**
12342      * flag to indicate if dom parser is inside a pre,
12343      * it will strip whitespace if not.
12344      */
12345     inPre : false,
12346     
12347     /**
12348      * The various sub templates
12349      */
12350     tpls : false,
12351     
12352     
12353     
12354     /**
12355      *
12356      * basic tag replacing syntax
12357      * WORD:WORD()
12358      *
12359      * // you can fake an object call by doing this
12360      *  x.t:(test,tesT) 
12361      * 
12362      */
12363     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12364     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12365     
12366     iterChild : function (node, method) {
12367         
12368         var oldPre = this.inPre;
12369         if (node.tagName == 'PRE') {
12370             this.inPre = true;
12371         }
12372         for( var i = 0; i < node.childNodes.length; i++) {
12373             method.call(this, node.childNodes[i]);
12374         }
12375         this.inPre = oldPre;
12376     },
12377     
12378     
12379     
12380     /**
12381      * compile the template
12382      *
12383      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12384      *
12385      */
12386     compile: function()
12387     {
12388         var s = this.html;
12389         
12390         // covert the html into DOM...
12391         var doc = false;
12392         var div =false;
12393         try {
12394             doc = document.implementation.createHTMLDocument("");
12395             doc.documentElement.innerHTML =   this.html  ;
12396             div = doc.documentElement;
12397         } catch (e) {
12398             // old IE... - nasty -- it causes all sorts of issues.. with
12399             // images getting pulled from server..
12400             div = document.createElement('div');
12401             div.innerHTML = this.html;
12402         }
12403         //doc.documentElement.innerHTML = htmlBody
12404          
12405         
12406         
12407         this.tpls = [];
12408         var _t = this;
12409         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12410         
12411         var tpls = this.tpls;
12412         
12413         // create a top level template from the snippet..
12414         
12415         //Roo.log(div.innerHTML);
12416         
12417         var tpl = {
12418             uid : 'master',
12419             id : this.id++,
12420             attr : false,
12421             value : false,
12422             body : div.innerHTML,
12423             
12424             forCall : false,
12425             execCall : false,
12426             dom : div,
12427             isTop : true
12428             
12429         };
12430         tpls.unshift(tpl);
12431         
12432         
12433         // compile them...
12434         this.tpls = [];
12435         Roo.each(tpls, function(tp){
12436             this.compileTpl(tp);
12437             this.tpls[tp.id] = tp;
12438         }, this);
12439         
12440         this.master = tpls[0];
12441         return this;
12442         
12443         
12444     },
12445     
12446     compileNode : function(node, istop) {
12447         // test for
12448         //Roo.log(node);
12449         
12450         
12451         // skip anything not a tag..
12452         if (node.nodeType != 1) {
12453             if (node.nodeType == 3 && !this.inPre) {
12454                 // reduce white space..
12455                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12456                 
12457             }
12458             return;
12459         }
12460         
12461         var tpl = {
12462             uid : false,
12463             id : false,
12464             attr : false,
12465             value : false,
12466             body : '',
12467             
12468             forCall : false,
12469             execCall : false,
12470             dom : false,
12471             isTop : istop
12472             
12473             
12474         };
12475         
12476         
12477         switch(true) {
12478             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12479             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12480             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12481             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12482             // no default..
12483         }
12484         
12485         
12486         if (!tpl.attr) {
12487             // just itterate children..
12488             this.iterChild(node,this.compileNode);
12489             return;
12490         }
12491         tpl.uid = this.id++;
12492         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12493         node.removeAttribute('roo-'+ tpl.attr);
12494         if (tpl.attr != 'name') {
12495             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12496             node.parentNode.replaceChild(placeholder,  node);
12497         } else {
12498             
12499             var placeholder =  document.createElement('span');
12500             placeholder.className = 'roo-tpl-' + tpl.value;
12501             node.parentNode.replaceChild(placeholder,  node);
12502         }
12503         
12504         // parent now sees '{domtplXXXX}
12505         this.iterChild(node,this.compileNode);
12506         
12507         // we should now have node body...
12508         var div = document.createElement('div');
12509         div.appendChild(node);
12510         tpl.dom = node;
12511         // this has the unfortunate side effect of converting tagged attributes
12512         // eg. href="{...}" into %7C...%7D
12513         // this has been fixed by searching for those combo's although it's a bit hacky..
12514         
12515         
12516         tpl.body = div.innerHTML;
12517         
12518         
12519          
12520         tpl.id = tpl.uid;
12521         switch(tpl.attr) {
12522             case 'for' :
12523                 switch (tpl.value) {
12524                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12525                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12526                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12527                 }
12528                 break;
12529             
12530             case 'exec':
12531                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12532                 break;
12533             
12534             case 'if':     
12535                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12536                 break;
12537             
12538             case 'name':
12539                 tpl.id  = tpl.value; // replace non characters???
12540                 break;
12541             
12542         }
12543         
12544         
12545         this.tpls.push(tpl);
12546         
12547         
12548         
12549     },
12550     
12551     
12552     
12553     
12554     /**
12555      * Compile a segment of the template into a 'sub-template'
12556      *
12557      * 
12558      * 
12559      *
12560      */
12561     compileTpl : function(tpl)
12562     {
12563         var fm = Roo.util.Format;
12564         var useF = this.disableFormats !== true;
12565         
12566         var sep = Roo.isGecko ? "+\n" : ",\n";
12567         
12568         var undef = function(str) {
12569             Roo.debug && Roo.log("Property not found :"  + str);
12570             return '';
12571         };
12572           
12573         //Roo.log(tpl.body);
12574         
12575         
12576         
12577         var fn = function(m, lbrace, name, format, args)
12578         {
12579             //Roo.log("ARGS");
12580             //Roo.log(arguments);
12581             args = args ? args.replace(/\\'/g,"'") : args;
12582             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12583             if (typeof(format) == 'undefined') {
12584                 format =  'htmlEncode'; 
12585             }
12586             if (format == 'raw' ) {
12587                 format = false;
12588             }
12589             
12590             if(name.substr(0, 6) == 'domtpl'){
12591                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12592             }
12593             
12594             // build an array of options to determine if value is undefined..
12595             
12596             // basically get 'xxxx.yyyy' then do
12597             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12598             //    (function () { Roo.log("Property not found"); return ''; })() :
12599             //    ......
12600             
12601             var udef_ar = [];
12602             var lookfor = '';
12603             Roo.each(name.split('.'), function(st) {
12604                 lookfor += (lookfor.length ? '.': '') + st;
12605                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12606             });
12607             
12608             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12609             
12610             
12611             if(format && useF){
12612                 
12613                 args = args ? ',' + args : "";
12614                  
12615                 if(format.substr(0, 5) != "this."){
12616                     format = "fm." + format + '(';
12617                 }else{
12618                     format = 'this.call("'+ format.substr(5) + '", ';
12619                     args = ", values";
12620                 }
12621                 
12622                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12623             }
12624              
12625             if (args && args.length) {
12626                 // called with xxyx.yuu:(test,test)
12627                 // change to ()
12628                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12629             }
12630             // raw.. - :raw modifier..
12631             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12632             
12633         };
12634         var body;
12635         // branched to use + in gecko and [].join() in others
12636         if(Roo.isGecko){
12637             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12638                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12639                     "';};};";
12640         }else{
12641             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12642             body.push(tpl.body.replace(/(\r\n|\n)/g,
12643                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12644             body.push("'].join('');};};");
12645             body = body.join('');
12646         }
12647         
12648         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12649        
12650         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12651         eval(body);
12652         
12653         return this;
12654     },
12655      
12656     /**
12657      * same as applyTemplate, except it's done to one of the subTemplates
12658      * when using named templates, you can do:
12659      *
12660      * var str = pl.applySubTemplate('your-name', values);
12661      *
12662      * 
12663      * @param {Number} id of the template
12664      * @param {Object} values to apply to template
12665      * @param {Object} parent (normaly the instance of this object)
12666      */
12667     applySubTemplate : function(id, values, parent)
12668     {
12669         
12670         
12671         var t = this.tpls[id];
12672         
12673         
12674         try { 
12675             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12676                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12677                 return '';
12678             }
12679         } catch(e) {
12680             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12681             Roo.log(values);
12682           
12683             return '';
12684         }
12685         try { 
12686             
12687             if(t.execCall && t.execCall.call(this, values, parent)){
12688                 return '';
12689             }
12690         } catch(e) {
12691             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12692             Roo.log(values);
12693             return '';
12694         }
12695         
12696         try {
12697             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12698             parent = t.target ? values : parent;
12699             if(t.forCall && vs instanceof Array){
12700                 var buf = [];
12701                 for(var i = 0, len = vs.length; i < len; i++){
12702                     try {
12703                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12704                     } catch (e) {
12705                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12706                         Roo.log(e.body);
12707                         //Roo.log(t.compiled);
12708                         Roo.log(vs[i]);
12709                     }   
12710                 }
12711                 return buf.join('');
12712             }
12713         } catch (e) {
12714             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12715             Roo.log(values);
12716             return '';
12717         }
12718         try {
12719             return t.compiled.call(this, vs, parent);
12720         } catch (e) {
12721             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12722             Roo.log(e.body);
12723             //Roo.log(t.compiled);
12724             Roo.log(values);
12725             return '';
12726         }
12727     },
12728
12729    
12730
12731     applyTemplate : function(values){
12732         return this.master.compiled.call(this, values, {});
12733         //var s = this.subs;
12734     },
12735
12736     apply : function(){
12737         return this.applyTemplate.apply(this, arguments);
12738     }
12739
12740  });
12741
12742 Roo.DomTemplate.from = function(el){
12743     el = Roo.getDom(el);
12744     return new Roo.Domtemplate(el.value || el.innerHTML);
12745 };/*
12746  * Based on:
12747  * Ext JS Library 1.1.1
12748  * Copyright(c) 2006-2007, Ext JS, LLC.
12749  *
12750  * Originally Released Under LGPL - original licence link has changed is not relivant.
12751  *
12752  * Fork - LGPL
12753  * <script type="text/javascript">
12754  */
12755
12756 /**
12757  * @class Roo.util.DelayedTask
12758  * Provides a convenient method of performing setTimeout where a new
12759  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12760  * You can use this class to buffer
12761  * the keypress events for a certain number of milliseconds, and perform only if they stop
12762  * for that amount of time.
12763  * @constructor The parameters to this constructor serve as defaults and are not required.
12764  * @param {Function} fn (optional) The default function to timeout
12765  * @param {Object} scope (optional) The default scope of that timeout
12766  * @param {Array} args (optional) The default Array of arguments
12767  */
12768 Roo.util.DelayedTask = function(fn, scope, args){
12769     var id = null, d, t;
12770
12771     var call = function(){
12772         var now = new Date().getTime();
12773         if(now - t >= d){
12774             clearInterval(id);
12775             id = null;
12776             fn.apply(scope, args || []);
12777         }
12778     };
12779     /**
12780      * Cancels any pending timeout and queues a new one
12781      * @param {Number} delay The milliseconds to delay
12782      * @param {Function} newFn (optional) Overrides function passed to constructor
12783      * @param {Object} newScope (optional) Overrides scope passed to constructor
12784      * @param {Array} newArgs (optional) Overrides args passed to constructor
12785      */
12786     this.delay = function(delay, newFn, newScope, newArgs){
12787         if(id && delay != d){
12788             this.cancel();
12789         }
12790         d = delay;
12791         t = new Date().getTime();
12792         fn = newFn || fn;
12793         scope = newScope || scope;
12794         args = newArgs || args;
12795         if(!id){
12796             id = setInterval(call, d);
12797         }
12798     };
12799
12800     /**
12801      * Cancel the last queued timeout
12802      */
12803     this.cancel = function(){
12804         if(id){
12805             clearInterval(id);
12806             id = null;
12807         }
12808     };
12809 };/*
12810  * Based on:
12811  * Ext JS Library 1.1.1
12812  * Copyright(c) 2006-2007, Ext JS, LLC.
12813  *
12814  * Originally Released Under LGPL - original licence link has changed is not relivant.
12815  *
12816  * Fork - LGPL
12817  * <script type="text/javascript">
12818  */
12819  
12820  
12821 Roo.util.TaskRunner = function(interval){
12822     interval = interval || 10;
12823     var tasks = [], removeQueue = [];
12824     var id = 0;
12825     var running = false;
12826
12827     var stopThread = function(){
12828         running = false;
12829         clearInterval(id);
12830         id = 0;
12831     };
12832
12833     var startThread = function(){
12834         if(!running){
12835             running = true;
12836             id = setInterval(runTasks, interval);
12837         }
12838     };
12839
12840     var removeTask = function(task){
12841         removeQueue.push(task);
12842         if(task.onStop){
12843             task.onStop();
12844         }
12845     };
12846
12847     var runTasks = function(){
12848         if(removeQueue.length > 0){
12849             for(var i = 0, len = removeQueue.length; i < len; i++){
12850                 tasks.remove(removeQueue[i]);
12851             }
12852             removeQueue = [];
12853             if(tasks.length < 1){
12854                 stopThread();
12855                 return;
12856             }
12857         }
12858         var now = new Date().getTime();
12859         for(var i = 0, len = tasks.length; i < len; ++i){
12860             var t = tasks[i];
12861             var itime = now - t.taskRunTime;
12862             if(t.interval <= itime){
12863                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12864                 t.taskRunTime = now;
12865                 if(rt === false || t.taskRunCount === t.repeat){
12866                     removeTask(t);
12867                     return;
12868                 }
12869             }
12870             if(t.duration && t.duration <= (now - t.taskStartTime)){
12871                 removeTask(t);
12872             }
12873         }
12874     };
12875
12876     /**
12877      * Queues a new task.
12878      * @param {Object} task
12879      */
12880     this.start = function(task){
12881         tasks.push(task);
12882         task.taskStartTime = new Date().getTime();
12883         task.taskRunTime = 0;
12884         task.taskRunCount = 0;
12885         startThread();
12886         return task;
12887     };
12888
12889     this.stop = function(task){
12890         removeTask(task);
12891         return task;
12892     };
12893
12894     this.stopAll = function(){
12895         stopThread();
12896         for(var i = 0, len = tasks.length; i < len; i++){
12897             if(tasks[i].onStop){
12898                 tasks[i].onStop();
12899             }
12900         }
12901         tasks = [];
12902         removeQueue = [];
12903     };
12904 };
12905
12906 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12907  * Based on:
12908  * Ext JS Library 1.1.1
12909  * Copyright(c) 2006-2007, Ext JS, LLC.
12910  *
12911  * Originally Released Under LGPL - original licence link has changed is not relivant.
12912  *
12913  * Fork - LGPL
12914  * <script type="text/javascript">
12915  */
12916
12917  
12918 /**
12919  * @class Roo.util.MixedCollection
12920  * @extends Roo.util.Observable
12921  * A Collection class that maintains both numeric indexes and keys and exposes events.
12922  * @constructor
12923  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12924  * collection (defaults to false)
12925  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12926  * and return the key value for that item.  This is used when available to look up the key on items that
12927  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12928  * equivalent to providing an implementation for the {@link #getKey} method.
12929  */
12930 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12931     this.items = [];
12932     this.map = {};
12933     this.keys = [];
12934     this.length = 0;
12935     this.addEvents({
12936         /**
12937          * @event clear
12938          * Fires when the collection is cleared.
12939          */
12940         "clear" : true,
12941         /**
12942          * @event add
12943          * Fires when an item is added to the collection.
12944          * @param {Number} index The index at which the item was added.
12945          * @param {Object} o The item added.
12946          * @param {String} key The key associated with the added item.
12947          */
12948         "add" : true,
12949         /**
12950          * @event replace
12951          * Fires when an item is replaced in the collection.
12952          * @param {String} key he key associated with the new added.
12953          * @param {Object} old The item being replaced.
12954          * @param {Object} new The new item.
12955          */
12956         "replace" : true,
12957         /**
12958          * @event remove
12959          * Fires when an item is removed from the collection.
12960          * @param {Object} o The item being removed.
12961          * @param {String} key (optional) The key associated with the removed item.
12962          */
12963         "remove" : true,
12964         "sort" : true
12965     });
12966     this.allowFunctions = allowFunctions === true;
12967     if(keyFn){
12968         this.getKey = keyFn;
12969     }
12970     Roo.util.MixedCollection.superclass.constructor.call(this);
12971 };
12972
12973 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12974     allowFunctions : false,
12975     
12976 /**
12977  * Adds an item to the collection.
12978  * @param {String} key The key to associate with the item
12979  * @param {Object} o The item to add.
12980  * @return {Object} The item added.
12981  */
12982     add : function(key, o){
12983         if(arguments.length == 1){
12984             o = arguments[0];
12985             key = this.getKey(o);
12986         }
12987         if(typeof key == "undefined" || key === null){
12988             this.length++;
12989             this.items.push(o);
12990             this.keys.push(null);
12991         }else{
12992             var old = this.map[key];
12993             if(old){
12994                 return this.replace(key, o);
12995             }
12996             this.length++;
12997             this.items.push(o);
12998             this.map[key] = o;
12999             this.keys.push(key);
13000         }
13001         this.fireEvent("add", this.length-1, o, key);
13002         return o;
13003     },
13004        
13005 /**
13006   * MixedCollection has a generic way to fetch keys if you implement getKey.
13007 <pre><code>
13008 // normal way
13009 var mc = new Roo.util.MixedCollection();
13010 mc.add(someEl.dom.id, someEl);
13011 mc.add(otherEl.dom.id, otherEl);
13012 //and so on
13013
13014 // using getKey
13015 var mc = new Roo.util.MixedCollection();
13016 mc.getKey = function(el){
13017    return el.dom.id;
13018 };
13019 mc.add(someEl);
13020 mc.add(otherEl);
13021
13022 // or via the constructor
13023 var mc = new Roo.util.MixedCollection(false, function(el){
13024    return el.dom.id;
13025 });
13026 mc.add(someEl);
13027 mc.add(otherEl);
13028 </code></pre>
13029  * @param o {Object} The item for which to find the key.
13030  * @return {Object} The key for the passed item.
13031  */
13032     getKey : function(o){
13033          return o.id; 
13034     },
13035    
13036 /**
13037  * Replaces an item in the collection.
13038  * @param {String} key The key associated with the item to replace, or the item to replace.
13039  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13040  * @return {Object}  The new item.
13041  */
13042     replace : function(key, o){
13043         if(arguments.length == 1){
13044             o = arguments[0];
13045             key = this.getKey(o);
13046         }
13047         var old = this.item(key);
13048         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13049              return this.add(key, o);
13050         }
13051         var index = this.indexOfKey(key);
13052         this.items[index] = o;
13053         this.map[key] = o;
13054         this.fireEvent("replace", key, old, o);
13055         return o;
13056     },
13057    
13058 /**
13059  * Adds all elements of an Array or an Object to the collection.
13060  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13061  * an Array of values, each of which are added to the collection.
13062  */
13063     addAll : function(objs){
13064         if(arguments.length > 1 || objs instanceof Array){
13065             var args = arguments.length > 1 ? arguments : objs;
13066             for(var i = 0, len = args.length; i < len; i++){
13067                 this.add(args[i]);
13068             }
13069         }else{
13070             for(var key in objs){
13071                 if(this.allowFunctions || typeof objs[key] != "function"){
13072                     this.add(key, objs[key]);
13073                 }
13074             }
13075         }
13076     },
13077    
13078 /**
13079  * Executes the specified function once for every item in the collection, passing each
13080  * item as the first and only parameter. returning false from the function will stop the iteration.
13081  * @param {Function} fn The function to execute for each item.
13082  * @param {Object} scope (optional) The scope in which to execute the function.
13083  */
13084     each : function(fn, scope){
13085         var items = [].concat(this.items); // each safe for removal
13086         for(var i = 0, len = items.length; i < len; i++){
13087             if(fn.call(scope || items[i], items[i], i, len) === false){
13088                 break;
13089             }
13090         }
13091     },
13092    
13093 /**
13094  * Executes the specified function once for every key in the collection, passing each
13095  * key, and its associated item as the first two parameters.
13096  * @param {Function} fn The function to execute for each item.
13097  * @param {Object} scope (optional) The scope in which to execute the function.
13098  */
13099     eachKey : function(fn, scope){
13100         for(var i = 0, len = this.keys.length; i < len; i++){
13101             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13102         }
13103     },
13104    
13105 /**
13106  * Returns the first item in the collection which elicits a true return value from the
13107  * passed selection function.
13108  * @param {Function} fn The selection function to execute for each item.
13109  * @param {Object} scope (optional) The scope in which to execute the function.
13110  * @return {Object} The first item in the collection which returned true from the selection function.
13111  */
13112     find : function(fn, scope){
13113         for(var i = 0, len = this.items.length; i < len; i++){
13114             if(fn.call(scope || window, this.items[i], this.keys[i])){
13115                 return this.items[i];
13116             }
13117         }
13118         return null;
13119     },
13120    
13121 /**
13122  * Inserts an item at the specified index in the collection.
13123  * @param {Number} index The index to insert the item at.
13124  * @param {String} key The key to associate with the new item, or the item itself.
13125  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13126  * @return {Object} The item inserted.
13127  */
13128     insert : function(index, key, o){
13129         if(arguments.length == 2){
13130             o = arguments[1];
13131             key = this.getKey(o);
13132         }
13133         if(index >= this.length){
13134             return this.add(key, o);
13135         }
13136         this.length++;
13137         this.items.splice(index, 0, o);
13138         if(typeof key != "undefined" && key != null){
13139             this.map[key] = o;
13140         }
13141         this.keys.splice(index, 0, key);
13142         this.fireEvent("add", index, o, key);
13143         return o;
13144     },
13145    
13146 /**
13147  * Removed an item from the collection.
13148  * @param {Object} o The item to remove.
13149  * @return {Object} The item removed.
13150  */
13151     remove : function(o){
13152         return this.removeAt(this.indexOf(o));
13153     },
13154    
13155 /**
13156  * Remove an item from a specified index in the collection.
13157  * @param {Number} index The index within the collection of the item to remove.
13158  */
13159     removeAt : function(index){
13160         if(index < this.length && index >= 0){
13161             this.length--;
13162             var o = this.items[index];
13163             this.items.splice(index, 1);
13164             var key = this.keys[index];
13165             if(typeof key != "undefined"){
13166                 delete this.map[key];
13167             }
13168             this.keys.splice(index, 1);
13169             this.fireEvent("remove", o, key);
13170         }
13171     },
13172    
13173 /**
13174  * Removed an item associated with the passed key fom the collection.
13175  * @param {String} key The key of the item to remove.
13176  */
13177     removeKey : function(key){
13178         return this.removeAt(this.indexOfKey(key));
13179     },
13180    
13181 /**
13182  * Returns the number of items in the collection.
13183  * @return {Number} the number of items in the collection.
13184  */
13185     getCount : function(){
13186         return this.length; 
13187     },
13188    
13189 /**
13190  * Returns index within the collection of the passed Object.
13191  * @param {Object} o The item to find the index of.
13192  * @return {Number} index of the item.
13193  */
13194     indexOf : function(o){
13195         if(!this.items.indexOf){
13196             for(var i = 0, len = this.items.length; i < len; i++){
13197                 if(this.items[i] == o) {
13198                     return i;
13199                 }
13200             }
13201             return -1;
13202         }else{
13203             return this.items.indexOf(o);
13204         }
13205     },
13206    
13207 /**
13208  * Returns index within the collection of the passed key.
13209  * @param {String} key The key to find the index of.
13210  * @return {Number} index of the key.
13211  */
13212     indexOfKey : function(key){
13213         if(!this.keys.indexOf){
13214             for(var i = 0, len = this.keys.length; i < len; i++){
13215                 if(this.keys[i] == key) {
13216                     return i;
13217                 }
13218             }
13219             return -1;
13220         }else{
13221             return this.keys.indexOf(key);
13222         }
13223     },
13224    
13225 /**
13226  * Returns the item associated with the passed key OR index. Key has priority over index.
13227  * @param {String/Number} key The key or index of the item.
13228  * @return {Object} The item associated with the passed key.
13229  */
13230     item : function(key){
13231         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13232         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13233     },
13234     
13235 /**
13236  * Returns the item at the specified index.
13237  * @param {Number} index The index of the item.
13238  * @return {Object}
13239  */
13240     itemAt : function(index){
13241         return this.items[index];
13242     },
13243     
13244 /**
13245  * Returns the item associated with the passed key.
13246  * @param {String/Number} key The key of the item.
13247  * @return {Object} The item associated with the passed key.
13248  */
13249     key : function(key){
13250         return this.map[key];
13251     },
13252    
13253 /**
13254  * Returns true if the collection contains the passed Object as an item.
13255  * @param {Object} o  The Object to look for in the collection.
13256  * @return {Boolean} True if the collection contains the Object as an item.
13257  */
13258     contains : function(o){
13259         return this.indexOf(o) != -1;
13260     },
13261    
13262 /**
13263  * Returns true if the collection contains the passed Object as a key.
13264  * @param {String} key The key to look for in the collection.
13265  * @return {Boolean} True if the collection contains the Object as a key.
13266  */
13267     containsKey : function(key){
13268         return typeof this.map[key] != "undefined";
13269     },
13270    
13271 /**
13272  * Removes all items from the collection.
13273  */
13274     clear : function(){
13275         this.length = 0;
13276         this.items = [];
13277         this.keys = [];
13278         this.map = {};
13279         this.fireEvent("clear");
13280     },
13281    
13282 /**
13283  * Returns the first item in the collection.
13284  * @return {Object} the first item in the collection..
13285  */
13286     first : function(){
13287         return this.items[0]; 
13288     },
13289    
13290 /**
13291  * Returns the last item in the collection.
13292  * @return {Object} the last item in the collection..
13293  */
13294     last : function(){
13295         return this.items[this.length-1];   
13296     },
13297     
13298     _sort : function(property, dir, fn){
13299         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13300         fn = fn || function(a, b){
13301             return a-b;
13302         };
13303         var c = [], k = this.keys, items = this.items;
13304         for(var i = 0, len = items.length; i < len; i++){
13305             c[c.length] = {key: k[i], value: items[i], index: i};
13306         }
13307         c.sort(function(a, b){
13308             var v = fn(a[property], b[property]) * dsc;
13309             if(v == 0){
13310                 v = (a.index < b.index ? -1 : 1);
13311             }
13312             return v;
13313         });
13314         for(var i = 0, len = c.length; i < len; i++){
13315             items[i] = c[i].value;
13316             k[i] = c[i].key;
13317         }
13318         this.fireEvent("sort", this);
13319     },
13320     
13321     /**
13322      * Sorts this collection with the passed comparison function
13323      * @param {String} direction (optional) "ASC" or "DESC"
13324      * @param {Function} fn (optional) comparison function
13325      */
13326     sort : function(dir, fn){
13327         this._sort("value", dir, fn);
13328     },
13329     
13330     /**
13331      * Sorts this collection by keys
13332      * @param {String} direction (optional) "ASC" or "DESC"
13333      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13334      */
13335     keySort : function(dir, fn){
13336         this._sort("key", dir, fn || function(a, b){
13337             return String(a).toUpperCase()-String(b).toUpperCase();
13338         });
13339     },
13340     
13341     /**
13342      * Returns a range of items in this collection
13343      * @param {Number} startIndex (optional) defaults to 0
13344      * @param {Number} endIndex (optional) default to the last item
13345      * @return {Array} An array of items
13346      */
13347     getRange : function(start, end){
13348         var items = this.items;
13349         if(items.length < 1){
13350             return [];
13351         }
13352         start = start || 0;
13353         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13354         var r = [];
13355         if(start <= end){
13356             for(var i = start; i <= end; i++) {
13357                     r[r.length] = items[i];
13358             }
13359         }else{
13360             for(var i = start; i >= end; i--) {
13361                     r[r.length] = items[i];
13362             }
13363         }
13364         return r;
13365     },
13366         
13367     /**
13368      * Filter the <i>objects</i> in this collection by a specific property. 
13369      * Returns a new collection that has been filtered.
13370      * @param {String} property A property on your objects
13371      * @param {String/RegExp} value Either string that the property values 
13372      * should start with or a RegExp to test against the property
13373      * @return {MixedCollection} The new filtered collection
13374      */
13375     filter : function(property, value){
13376         if(!value.exec){ // not a regex
13377             value = String(value);
13378             if(value.length == 0){
13379                 return this.clone();
13380             }
13381             value = new RegExp("^" + Roo.escapeRe(value), "i");
13382         }
13383         return this.filterBy(function(o){
13384             return o && value.test(o[property]);
13385         });
13386         },
13387     
13388     /**
13389      * Filter by a function. * Returns a new collection that has been filtered.
13390      * The passed function will be called with each 
13391      * object in the collection. If the function returns true, the value is included 
13392      * otherwise it is filtered.
13393      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13394      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13395      * @return {MixedCollection} The new filtered collection
13396      */
13397     filterBy : function(fn, scope){
13398         var r = new Roo.util.MixedCollection();
13399         r.getKey = this.getKey;
13400         var k = this.keys, it = this.items;
13401         for(var i = 0, len = it.length; i < len; i++){
13402             if(fn.call(scope||this, it[i], k[i])){
13403                                 r.add(k[i], it[i]);
13404                         }
13405         }
13406         return r;
13407     },
13408     
13409     /**
13410      * Creates a duplicate of this collection
13411      * @return {MixedCollection}
13412      */
13413     clone : function(){
13414         var r = new Roo.util.MixedCollection();
13415         var k = this.keys, it = this.items;
13416         for(var i = 0, len = it.length; i < len; i++){
13417             r.add(k[i], it[i]);
13418         }
13419         r.getKey = this.getKey;
13420         return r;
13421     }
13422 });
13423 /**
13424  * Returns the item associated with the passed key or index.
13425  * @method
13426  * @param {String/Number} key The key or index of the item.
13427  * @return {Object} The item associated with the passed key.
13428  */
13429 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13430  * Based on:
13431  * Ext JS Library 1.1.1
13432  * Copyright(c) 2006-2007, Ext JS, LLC.
13433  *
13434  * Originally Released Under LGPL - original licence link has changed is not relivant.
13435  *
13436  * Fork - LGPL
13437  * <script type="text/javascript">
13438  */
13439 /**
13440  * @class Roo.util.JSON
13441  * Modified version of Douglas Crockford"s json.js that doesn"t
13442  * mess with the Object prototype 
13443  * http://www.json.org/js.html
13444  * @singleton
13445  */
13446 Roo.util.JSON = new (function(){
13447     var useHasOwn = {}.hasOwnProperty ? true : false;
13448     
13449     // crashes Safari in some instances
13450     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13451     
13452     var pad = function(n) {
13453         return n < 10 ? "0" + n : n;
13454     };
13455     
13456     var m = {
13457         "\b": '\\b',
13458         "\t": '\\t',
13459         "\n": '\\n',
13460         "\f": '\\f',
13461         "\r": '\\r',
13462         '"' : '\\"',
13463         "\\": '\\\\'
13464     };
13465
13466     var encodeString = function(s){
13467         if (/["\\\x00-\x1f]/.test(s)) {
13468             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13469                 var c = m[b];
13470                 if(c){
13471                     return c;
13472                 }
13473                 c = b.charCodeAt();
13474                 return "\\u00" +
13475                     Math.floor(c / 16).toString(16) +
13476                     (c % 16).toString(16);
13477             }) + '"';
13478         }
13479         return '"' + s + '"';
13480     };
13481     
13482     var encodeArray = function(o){
13483         var a = ["["], b, i, l = o.length, v;
13484             for (i = 0; i < l; i += 1) {
13485                 v = o[i];
13486                 switch (typeof v) {
13487                     case "undefined":
13488                     case "function":
13489                     case "unknown":
13490                         break;
13491                     default:
13492                         if (b) {
13493                             a.push(',');
13494                         }
13495                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13496                         b = true;
13497                 }
13498             }
13499             a.push("]");
13500             return a.join("");
13501     };
13502     
13503     var encodeDate = function(o){
13504         return '"' + o.getFullYear() + "-" +
13505                 pad(o.getMonth() + 1) + "-" +
13506                 pad(o.getDate()) + "T" +
13507                 pad(o.getHours()) + ":" +
13508                 pad(o.getMinutes()) + ":" +
13509                 pad(o.getSeconds()) + '"';
13510     };
13511     
13512     /**
13513      * Encodes an Object, Array or other value
13514      * @param {Mixed} o The variable to encode
13515      * @return {String} The JSON string
13516      */
13517     this.encode = function(o)
13518     {
13519         // should this be extended to fully wrap stringify..
13520         
13521         if(typeof o == "undefined" || o === null){
13522             return "null";
13523         }else if(o instanceof Array){
13524             return encodeArray(o);
13525         }else if(o instanceof Date){
13526             return encodeDate(o);
13527         }else if(typeof o == "string"){
13528             return encodeString(o);
13529         }else if(typeof o == "number"){
13530             return isFinite(o) ? String(o) : "null";
13531         }else if(typeof o == "boolean"){
13532             return String(o);
13533         }else {
13534             var a = ["{"], b, i, v;
13535             for (i in o) {
13536                 if(!useHasOwn || o.hasOwnProperty(i)) {
13537                     v = o[i];
13538                     switch (typeof v) {
13539                     case "undefined":
13540                     case "function":
13541                     case "unknown":
13542                         break;
13543                     default:
13544                         if(b){
13545                             a.push(',');
13546                         }
13547                         a.push(this.encode(i), ":",
13548                                 v === null ? "null" : this.encode(v));
13549                         b = true;
13550                     }
13551                 }
13552             }
13553             a.push("}");
13554             return a.join("");
13555         }
13556     };
13557     
13558     /**
13559      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13560      * @param {String} json The JSON string
13561      * @return {Object} The resulting object
13562      */
13563     this.decode = function(json){
13564         
13565         return  /** eval:var:json */ eval("(" + json + ')');
13566     };
13567 })();
13568 /** 
13569  * Shorthand for {@link Roo.util.JSON#encode}
13570  * @member Roo encode 
13571  * @method */
13572 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13573 /** 
13574  * Shorthand for {@link Roo.util.JSON#decode}
13575  * @member Roo decode 
13576  * @method */
13577 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13578 /*
13579  * Based on:
13580  * Ext JS Library 1.1.1
13581  * Copyright(c) 2006-2007, Ext JS, LLC.
13582  *
13583  * Originally Released Under LGPL - original licence link has changed is not relivant.
13584  *
13585  * Fork - LGPL
13586  * <script type="text/javascript">
13587  */
13588  
13589 /**
13590  * @class Roo.util.Format
13591  * Reusable data formatting functions
13592  * @singleton
13593  */
13594 Roo.util.Format = function(){
13595     var trimRe = /^\s+|\s+$/g;
13596     return {
13597         /**
13598          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13599          * @param {String} value The string to truncate
13600          * @param {Number} length The maximum length to allow before truncating
13601          * @return {String} The converted text
13602          */
13603         ellipsis : function(value, len){
13604             if(value && value.length > len){
13605                 return value.substr(0, len-3)+"...";
13606             }
13607             return value;
13608         },
13609
13610         /**
13611          * Checks a reference and converts it to empty string if it is undefined
13612          * @param {Mixed} value Reference to check
13613          * @return {Mixed} Empty string if converted, otherwise the original value
13614          */
13615         undef : function(value){
13616             return typeof value != "undefined" ? value : "";
13617         },
13618
13619         /**
13620          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13621          * @param {String} value The string to encode
13622          * @return {String} The encoded text
13623          */
13624         htmlEncode : function(value){
13625             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13626         },
13627
13628         /**
13629          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13630          * @param {String} value The string to decode
13631          * @return {String} The decoded text
13632          */
13633         htmlDecode : function(value){
13634             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13635         },
13636
13637         /**
13638          * Trims any whitespace from either side of a string
13639          * @param {String} value The text to trim
13640          * @return {String} The trimmed text
13641          */
13642         trim : function(value){
13643             return String(value).replace(trimRe, "");
13644         },
13645
13646         /**
13647          * Returns a substring from within an original string
13648          * @param {String} value The original text
13649          * @param {Number} start The start index of the substring
13650          * @param {Number} length The length of the substring
13651          * @return {String} The substring
13652          */
13653         substr : function(value, start, length){
13654             return String(value).substr(start, length);
13655         },
13656
13657         /**
13658          * Converts a string to all lower case letters
13659          * @param {String} value The text to convert
13660          * @return {String} The converted text
13661          */
13662         lowercase : function(value){
13663             return String(value).toLowerCase();
13664         },
13665
13666         /**
13667          * Converts a string to all upper case letters
13668          * @param {String} value The text to convert
13669          * @return {String} The converted text
13670          */
13671         uppercase : function(value){
13672             return String(value).toUpperCase();
13673         },
13674
13675         /**
13676          * Converts the first character only of a string to upper case
13677          * @param {String} value The text to convert
13678          * @return {String} The converted text
13679          */
13680         capitalize : function(value){
13681             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13682         },
13683
13684         // private
13685         call : function(value, fn){
13686             if(arguments.length > 2){
13687                 var args = Array.prototype.slice.call(arguments, 2);
13688                 args.unshift(value);
13689                  
13690                 return /** eval:var:value */  eval(fn).apply(window, args);
13691             }else{
13692                 /** eval:var:value */
13693                 return /** eval:var:value */ eval(fn).call(window, value);
13694             }
13695         },
13696
13697        
13698         /**
13699          * safer version of Math.toFixed..??/
13700          * @param {Number/String} value The numeric value to format
13701          * @param {Number/String} value Decimal places 
13702          * @return {String} The formatted currency string
13703          */
13704         toFixed : function(v, n)
13705         {
13706             // why not use to fixed - precision is buggered???
13707             if (!n) {
13708                 return Math.round(v-0);
13709             }
13710             var fact = Math.pow(10,n+1);
13711             v = (Math.round((v-0)*fact))/fact;
13712             var z = (''+fact).substring(2);
13713             if (v == Math.floor(v)) {
13714                 return Math.floor(v) + '.' + z;
13715             }
13716             
13717             // now just padd decimals..
13718             var ps = String(v).split('.');
13719             var fd = (ps[1] + z);
13720             var r = fd.substring(0,n); 
13721             var rm = fd.substring(n); 
13722             if (rm < 5) {
13723                 return ps[0] + '.' + r;
13724             }
13725             r*=1; // turn it into a number;
13726             r++;
13727             if (String(r).length != n) {
13728                 ps[0]*=1;
13729                 ps[0]++;
13730                 r = String(r).substring(1); // chop the end off.
13731             }
13732             
13733             return ps[0] + '.' + r;
13734              
13735         },
13736         
13737         /**
13738          * Format a number as US currency
13739          * @param {Number/String} value The numeric value to format
13740          * @return {String} The formatted currency string
13741          */
13742         usMoney : function(v){
13743             return '$' + Roo.util.Format.number(v);
13744         },
13745         
13746         /**
13747          * Format a number
13748          * eventually this should probably emulate php's number_format
13749          * @param {Number/String} value The numeric value to format
13750          * @param {Number} decimals number of decimal places
13751          * @return {String} The formatted currency string
13752          */
13753         number : function(v,decimals)
13754         {
13755             // multiply and round.
13756             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13757             var mul = Math.pow(10, decimals);
13758             var zero = String(mul).substring(1);
13759             v = (Math.round((v-0)*mul))/mul;
13760             
13761             // if it's '0' number.. then
13762             
13763             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13764             v = String(v);
13765             var ps = v.split('.');
13766             var whole = ps[0];
13767             
13768             
13769             var r = /(\d+)(\d{3})/;
13770             // add comma's
13771             while (r.test(whole)) {
13772                 whole = whole.replace(r, '$1' + ',' + '$2');
13773             }
13774             
13775             
13776             var sub = ps[1] ?
13777                     // has decimals..
13778                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13779                     // does not have decimals
13780                     (decimals ? ('.' + zero) : '');
13781             
13782             
13783             return whole + sub ;
13784         },
13785         
13786         /**
13787          * Parse a value into a formatted date using the specified format pattern.
13788          * @param {Mixed} value The value to format
13789          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13790          * @return {String} The formatted date string
13791          */
13792         date : function(v, format){
13793             if(!v){
13794                 return "";
13795             }
13796             if(!(v instanceof Date)){
13797                 v = new Date(Date.parse(v));
13798             }
13799             return v.dateFormat(format || Roo.util.Format.defaults.date);
13800         },
13801
13802         /**
13803          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13804          * @param {String} format Any valid date format string
13805          * @return {Function} The date formatting function
13806          */
13807         dateRenderer : function(format){
13808             return function(v){
13809                 return Roo.util.Format.date(v, format);  
13810             };
13811         },
13812
13813         // private
13814         stripTagsRE : /<\/?[^>]+>/gi,
13815         
13816         /**
13817          * Strips all HTML tags
13818          * @param {Mixed} value The text from which to strip tags
13819          * @return {String} The stripped text
13820          */
13821         stripTags : function(v){
13822             return !v ? v : String(v).replace(this.stripTagsRE, "");
13823         }
13824     };
13825 }();
13826 Roo.util.Format.defaults = {
13827     date : 'd/M/Y'
13828 };/*
13829  * Based on:
13830  * Ext JS Library 1.1.1
13831  * Copyright(c) 2006-2007, Ext JS, LLC.
13832  *
13833  * Originally Released Under LGPL - original licence link has changed is not relivant.
13834  *
13835  * Fork - LGPL
13836  * <script type="text/javascript">
13837  */
13838
13839
13840  
13841
13842 /**
13843  * @class Roo.MasterTemplate
13844  * @extends Roo.Template
13845  * Provides a template that can have child templates. The syntax is:
13846 <pre><code>
13847 var t = new Roo.MasterTemplate(
13848         '&lt;select name="{name}"&gt;',
13849                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13850         '&lt;/select&gt;'
13851 );
13852 t.add('options', {value: 'foo', text: 'bar'});
13853 // or you can add multiple child elements in one shot
13854 t.addAll('options', [
13855     {value: 'foo', text: 'bar'},
13856     {value: 'foo2', text: 'bar2'},
13857     {value: 'foo3', text: 'bar3'}
13858 ]);
13859 // then append, applying the master template values
13860 t.append('my-form', {name: 'my-select'});
13861 </code></pre>
13862 * A name attribute for the child template is not required if you have only one child
13863 * template or you want to refer to them by index.
13864  */
13865 Roo.MasterTemplate = function(){
13866     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13867     this.originalHtml = this.html;
13868     var st = {};
13869     var m, re = this.subTemplateRe;
13870     re.lastIndex = 0;
13871     var subIndex = 0;
13872     while(m = re.exec(this.html)){
13873         var name = m[1], content = m[2];
13874         st[subIndex] = {
13875             name: name,
13876             index: subIndex,
13877             buffer: [],
13878             tpl : new Roo.Template(content)
13879         };
13880         if(name){
13881             st[name] = st[subIndex];
13882         }
13883         st[subIndex].tpl.compile();
13884         st[subIndex].tpl.call = this.call.createDelegate(this);
13885         subIndex++;
13886     }
13887     this.subCount = subIndex;
13888     this.subs = st;
13889 };
13890 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13891     /**
13892     * The regular expression used to match sub templates
13893     * @type RegExp
13894     * @property
13895     */
13896     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13897
13898     /**
13899      * Applies the passed values to a child template.
13900      * @param {String/Number} name (optional) The name or index of the child template
13901      * @param {Array/Object} values The values to be applied to the template
13902      * @return {MasterTemplate} this
13903      */
13904      add : function(name, values){
13905         if(arguments.length == 1){
13906             values = arguments[0];
13907             name = 0;
13908         }
13909         var s = this.subs[name];
13910         s.buffer[s.buffer.length] = s.tpl.apply(values);
13911         return this;
13912     },
13913
13914     /**
13915      * Applies all the passed values to a child template.
13916      * @param {String/Number} name (optional) The name or index of the child template
13917      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13918      * @param {Boolean} reset (optional) True to reset the template first
13919      * @return {MasterTemplate} this
13920      */
13921     fill : function(name, values, reset){
13922         var a = arguments;
13923         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13924             values = a[0];
13925             name = 0;
13926             reset = a[1];
13927         }
13928         if(reset){
13929             this.reset();
13930         }
13931         for(var i = 0, len = values.length; i < len; i++){
13932             this.add(name, values[i]);
13933         }
13934         return this;
13935     },
13936
13937     /**
13938      * Resets the template for reuse
13939      * @return {MasterTemplate} this
13940      */
13941      reset : function(){
13942         var s = this.subs;
13943         for(var i = 0; i < this.subCount; i++){
13944             s[i].buffer = [];
13945         }
13946         return this;
13947     },
13948
13949     applyTemplate : function(values){
13950         var s = this.subs;
13951         var replaceIndex = -1;
13952         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13953             return s[++replaceIndex].buffer.join("");
13954         });
13955         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13956     },
13957
13958     apply : function(){
13959         return this.applyTemplate.apply(this, arguments);
13960     },
13961
13962     compile : function(){return this;}
13963 });
13964
13965 /**
13966  * Alias for fill().
13967  * @method
13968  */
13969 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13970  /**
13971  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13972  * var tpl = Roo.MasterTemplate.from('element-id');
13973  * @param {String/HTMLElement} el
13974  * @param {Object} config
13975  * @static
13976  */
13977 Roo.MasterTemplate.from = function(el, config){
13978     el = Roo.getDom(el);
13979     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13980 };/*
13981  * Based on:
13982  * Ext JS Library 1.1.1
13983  * Copyright(c) 2006-2007, Ext JS, LLC.
13984  *
13985  * Originally Released Under LGPL - original licence link has changed is not relivant.
13986  *
13987  * Fork - LGPL
13988  * <script type="text/javascript">
13989  */
13990
13991  
13992 /**
13993  * @class Roo.util.CSS
13994  * Utility class for manipulating CSS rules
13995  * @singleton
13996  */
13997 Roo.util.CSS = function(){
13998         var rules = null;
13999         var doc = document;
14000
14001     var camelRe = /(-[a-z])/gi;
14002     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14003
14004    return {
14005    /**
14006     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14007     * tag and appended to the HEAD of the document.
14008     * @param {String|Object} cssText The text containing the css rules
14009     * @param {String} id An id to add to the stylesheet for later removal
14010     * @return {StyleSheet}
14011     */
14012     createStyleSheet : function(cssText, id){
14013         var ss;
14014         var head = doc.getElementsByTagName("head")[0];
14015         var nrules = doc.createElement("style");
14016         nrules.setAttribute("type", "text/css");
14017         if(id){
14018             nrules.setAttribute("id", id);
14019         }
14020         if (typeof(cssText) != 'string') {
14021             // support object maps..
14022             // not sure if this a good idea.. 
14023             // perhaps it should be merged with the general css handling
14024             // and handle js style props.
14025             var cssTextNew = [];
14026             for(var n in cssText) {
14027                 var citems = [];
14028                 for(var k in cssText[n]) {
14029                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14030                 }
14031                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14032                 
14033             }
14034             cssText = cssTextNew.join("\n");
14035             
14036         }
14037        
14038        
14039        if(Roo.isIE){
14040            head.appendChild(nrules);
14041            ss = nrules.styleSheet;
14042            ss.cssText = cssText;
14043        }else{
14044            try{
14045                 nrules.appendChild(doc.createTextNode(cssText));
14046            }catch(e){
14047                nrules.cssText = cssText; 
14048            }
14049            head.appendChild(nrules);
14050            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14051        }
14052        this.cacheStyleSheet(ss);
14053        return ss;
14054    },
14055
14056    /**
14057     * Removes a style or link tag by id
14058     * @param {String} id The id of the tag
14059     */
14060    removeStyleSheet : function(id){
14061        var existing = doc.getElementById(id);
14062        if(existing){
14063            existing.parentNode.removeChild(existing);
14064        }
14065    },
14066
14067    /**
14068     * Dynamically swaps an existing stylesheet reference for a new one
14069     * @param {String} id The id of an existing link tag to remove
14070     * @param {String} url The href of the new stylesheet to include
14071     */
14072    swapStyleSheet : function(id, url){
14073        this.removeStyleSheet(id);
14074        var ss = doc.createElement("link");
14075        ss.setAttribute("rel", "stylesheet");
14076        ss.setAttribute("type", "text/css");
14077        ss.setAttribute("id", id);
14078        ss.setAttribute("href", url);
14079        doc.getElementsByTagName("head")[0].appendChild(ss);
14080    },
14081    
14082    /**
14083     * Refresh the rule cache if you have dynamically added stylesheets
14084     * @return {Object} An object (hash) of rules indexed by selector
14085     */
14086    refreshCache : function(){
14087        return this.getRules(true);
14088    },
14089
14090    // private
14091    cacheStyleSheet : function(stylesheet){
14092        if(!rules){
14093            rules = {};
14094        }
14095        try{// try catch for cross domain access issue
14096            var ssRules = stylesheet.cssRules || stylesheet.rules;
14097            for(var j = ssRules.length-1; j >= 0; --j){
14098                rules[ssRules[j].selectorText] = ssRules[j];
14099            }
14100        }catch(e){}
14101    },
14102    
14103    /**
14104     * Gets all css rules for the document
14105     * @param {Boolean} refreshCache true to refresh the internal cache
14106     * @return {Object} An object (hash) of rules indexed by selector
14107     */
14108    getRules : function(refreshCache){
14109                 if(rules == null || refreshCache){
14110                         rules = {};
14111                         var ds = doc.styleSheets;
14112                         for(var i =0, len = ds.length; i < len; i++){
14113                             try{
14114                         this.cacheStyleSheet(ds[i]);
14115                     }catch(e){} 
14116                 }
14117                 }
14118                 return rules;
14119         },
14120         
14121         /**
14122     * Gets an an individual CSS rule by selector(s)
14123     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14124     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14125     * @return {CSSRule} The CSS rule or null if one is not found
14126     */
14127    getRule : function(selector, refreshCache){
14128                 var rs = this.getRules(refreshCache);
14129                 if(!(selector instanceof Array)){
14130                     return rs[selector];
14131                 }
14132                 for(var i = 0; i < selector.length; i++){
14133                         if(rs[selector[i]]){
14134                                 return rs[selector[i]];
14135                         }
14136                 }
14137                 return null;
14138         },
14139         
14140         
14141         /**
14142     * Updates a rule property
14143     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14144     * @param {String} property The css property
14145     * @param {String} value The new value for the property
14146     * @return {Boolean} true If a rule was found and updated
14147     */
14148    updateRule : function(selector, property, value){
14149                 if(!(selector instanceof Array)){
14150                         var rule = this.getRule(selector);
14151                         if(rule){
14152                                 rule.style[property.replace(camelRe, camelFn)] = value;
14153                                 return true;
14154                         }
14155                 }else{
14156                         for(var i = 0; i < selector.length; i++){
14157                                 if(this.updateRule(selector[i], property, value)){
14158                                         return true;
14159                                 }
14160                         }
14161                 }
14162                 return false;
14163         }
14164    };   
14165 }();/*
14166  * Based on:
14167  * Ext JS Library 1.1.1
14168  * Copyright(c) 2006-2007, Ext JS, LLC.
14169  *
14170  * Originally Released Under LGPL - original licence link has changed is not relivant.
14171  *
14172  * Fork - LGPL
14173  * <script type="text/javascript">
14174  */
14175
14176  
14177
14178 /**
14179  * @class Roo.util.ClickRepeater
14180  * @extends Roo.util.Observable
14181  * 
14182  * A wrapper class which can be applied to any element. Fires a "click" event while the
14183  * mouse is pressed. The interval between firings may be specified in the config but
14184  * defaults to 10 milliseconds.
14185  * 
14186  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14187  * 
14188  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14189  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14190  * Similar to an autorepeat key delay.
14191  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14192  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14193  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14194  *           "interval" and "delay" are ignored. "immediate" is honored.
14195  * @cfg {Boolean} preventDefault True to prevent the default click event
14196  * @cfg {Boolean} stopDefault True to stop the default click event
14197  * 
14198  * @history
14199  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14200  *     2007-02-02 jvs Renamed to ClickRepeater
14201  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14202  *
14203  *  @constructor
14204  * @param {String/HTMLElement/Element} el The element to listen on
14205  * @param {Object} config
14206  **/
14207 Roo.util.ClickRepeater = function(el, config)
14208 {
14209     this.el = Roo.get(el);
14210     this.el.unselectable();
14211
14212     Roo.apply(this, config);
14213
14214     this.addEvents({
14215     /**
14216      * @event mousedown
14217      * Fires when the mouse button is depressed.
14218      * @param {Roo.util.ClickRepeater} this
14219      */
14220         "mousedown" : true,
14221     /**
14222      * @event click
14223      * Fires on a specified interval during the time the element is pressed.
14224      * @param {Roo.util.ClickRepeater} this
14225      */
14226         "click" : true,
14227     /**
14228      * @event mouseup
14229      * Fires when the mouse key is released.
14230      * @param {Roo.util.ClickRepeater} this
14231      */
14232         "mouseup" : true
14233     });
14234
14235     this.el.on("mousedown", this.handleMouseDown, this);
14236     if(this.preventDefault || this.stopDefault){
14237         this.el.on("click", function(e){
14238             if(this.preventDefault){
14239                 e.preventDefault();
14240             }
14241             if(this.stopDefault){
14242                 e.stopEvent();
14243             }
14244         }, this);
14245     }
14246
14247     // allow inline handler
14248     if(this.handler){
14249         this.on("click", this.handler,  this.scope || this);
14250     }
14251
14252     Roo.util.ClickRepeater.superclass.constructor.call(this);
14253 };
14254
14255 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14256     interval : 20,
14257     delay: 250,
14258     preventDefault : true,
14259     stopDefault : false,
14260     timer : 0,
14261
14262     // private
14263     handleMouseDown : function(){
14264         clearTimeout(this.timer);
14265         this.el.blur();
14266         if(this.pressClass){
14267             this.el.addClass(this.pressClass);
14268         }
14269         this.mousedownTime = new Date();
14270
14271         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14272         this.el.on("mouseout", this.handleMouseOut, this);
14273
14274         this.fireEvent("mousedown", this);
14275         this.fireEvent("click", this);
14276         
14277         this.timer = this.click.defer(this.delay || this.interval, this);
14278     },
14279
14280     // private
14281     click : function(){
14282         this.fireEvent("click", this);
14283         this.timer = this.click.defer(this.getInterval(), this);
14284     },
14285
14286     // private
14287     getInterval: function(){
14288         if(!this.accelerate){
14289             return this.interval;
14290         }
14291         var pressTime = this.mousedownTime.getElapsed();
14292         if(pressTime < 500){
14293             return 400;
14294         }else if(pressTime < 1700){
14295             return 320;
14296         }else if(pressTime < 2600){
14297             return 250;
14298         }else if(pressTime < 3500){
14299             return 180;
14300         }else if(pressTime < 4400){
14301             return 140;
14302         }else if(pressTime < 5300){
14303             return 80;
14304         }else if(pressTime < 6200){
14305             return 50;
14306         }else{
14307             return 10;
14308         }
14309     },
14310
14311     // private
14312     handleMouseOut : function(){
14313         clearTimeout(this.timer);
14314         if(this.pressClass){
14315             this.el.removeClass(this.pressClass);
14316         }
14317         this.el.on("mouseover", this.handleMouseReturn, this);
14318     },
14319
14320     // private
14321     handleMouseReturn : function(){
14322         this.el.un("mouseover", this.handleMouseReturn);
14323         if(this.pressClass){
14324             this.el.addClass(this.pressClass);
14325         }
14326         this.click();
14327     },
14328
14329     // private
14330     handleMouseUp : function(){
14331         clearTimeout(this.timer);
14332         this.el.un("mouseover", this.handleMouseReturn);
14333         this.el.un("mouseout", this.handleMouseOut);
14334         Roo.get(document).un("mouseup", this.handleMouseUp);
14335         this.el.removeClass(this.pressClass);
14336         this.fireEvent("mouseup", this);
14337     }
14338 });/*
14339  * Based on:
14340  * Ext JS Library 1.1.1
14341  * Copyright(c) 2006-2007, Ext JS, LLC.
14342  *
14343  * Originally Released Under LGPL - original licence link has changed is not relivant.
14344  *
14345  * Fork - LGPL
14346  * <script type="text/javascript">
14347  */
14348
14349  
14350 /**
14351  * @class Roo.KeyNav
14352  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14353  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14354  * way to implement custom navigation schemes for any UI component.</p>
14355  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14356  * pageUp, pageDown, del, home, end.  Usage:</p>
14357  <pre><code>
14358 var nav = new Roo.KeyNav("my-element", {
14359     "left" : function(e){
14360         this.moveLeft(e.ctrlKey);
14361     },
14362     "right" : function(e){
14363         this.moveRight(e.ctrlKey);
14364     },
14365     "enter" : function(e){
14366         this.save();
14367     },
14368     scope : this
14369 });
14370 </code></pre>
14371  * @constructor
14372  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14373  * @param {Object} config The config
14374  */
14375 Roo.KeyNav = function(el, config){
14376     this.el = Roo.get(el);
14377     Roo.apply(this, config);
14378     if(!this.disabled){
14379         this.disabled = true;
14380         this.enable();
14381     }
14382 };
14383
14384 Roo.KeyNav.prototype = {
14385     /**
14386      * @cfg {Boolean} disabled
14387      * True to disable this KeyNav instance (defaults to false)
14388      */
14389     disabled : false,
14390     /**
14391      * @cfg {String} defaultEventAction
14392      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14393      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14394      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14395      */
14396     defaultEventAction: "stopEvent",
14397     /**
14398      * @cfg {Boolean} forceKeyDown
14399      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14400      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14401      * handle keydown instead of keypress.
14402      */
14403     forceKeyDown : false,
14404
14405     // private
14406     prepareEvent : function(e){
14407         var k = e.getKey();
14408         var h = this.keyToHandler[k];
14409         //if(h && this[h]){
14410         //    e.stopPropagation();
14411         //}
14412         if(Roo.isSafari && h && k >= 37 && k <= 40){
14413             e.stopEvent();
14414         }
14415     },
14416
14417     // private
14418     relay : function(e){
14419         var k = e.getKey();
14420         var h = this.keyToHandler[k];
14421         if(h && this[h]){
14422             if(this.doRelay(e, this[h], h) !== true){
14423                 e[this.defaultEventAction]();
14424             }
14425         }
14426     },
14427
14428     // private
14429     doRelay : function(e, h, hname){
14430         return h.call(this.scope || this, e);
14431     },
14432
14433     // possible handlers
14434     enter : false,
14435     left : false,
14436     right : false,
14437     up : false,
14438     down : false,
14439     tab : false,
14440     esc : false,
14441     pageUp : false,
14442     pageDown : false,
14443     del : false,
14444     home : false,
14445     end : false,
14446
14447     // quick lookup hash
14448     keyToHandler : {
14449         37 : "left",
14450         39 : "right",
14451         38 : "up",
14452         40 : "down",
14453         33 : "pageUp",
14454         34 : "pageDown",
14455         46 : "del",
14456         36 : "home",
14457         35 : "end",
14458         13 : "enter",
14459         27 : "esc",
14460         9  : "tab"
14461     },
14462
14463         /**
14464          * Enable this KeyNav
14465          */
14466         enable: function(){
14467                 if(this.disabled){
14468             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14469             // the EventObject will normalize Safari automatically
14470             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14471                 this.el.on("keydown", this.relay,  this);
14472             }else{
14473                 this.el.on("keydown", this.prepareEvent,  this);
14474                 this.el.on("keypress", this.relay,  this);
14475             }
14476                     this.disabled = false;
14477                 }
14478         },
14479
14480         /**
14481          * Disable this KeyNav
14482          */
14483         disable: function(){
14484                 if(!this.disabled){
14485                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14486                 this.el.un("keydown", this.relay);
14487             }else{
14488                 this.el.un("keydown", this.prepareEvent);
14489                 this.el.un("keypress", this.relay);
14490             }
14491                     this.disabled = true;
14492                 }
14493         }
14494 };/*
14495  * Based on:
14496  * Ext JS Library 1.1.1
14497  * Copyright(c) 2006-2007, Ext JS, LLC.
14498  *
14499  * Originally Released Under LGPL - original licence link has changed is not relivant.
14500  *
14501  * Fork - LGPL
14502  * <script type="text/javascript">
14503  */
14504
14505  
14506 /**
14507  * @class Roo.KeyMap
14508  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14509  * The constructor accepts the same config object as defined by {@link #addBinding}.
14510  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14511  * combination it will call the function with this signature (if the match is a multi-key
14512  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14513  * A KeyMap can also handle a string representation of keys.<br />
14514  * Usage:
14515  <pre><code>
14516 // map one key by key code
14517 var map = new Roo.KeyMap("my-element", {
14518     key: 13, // or Roo.EventObject.ENTER
14519     fn: myHandler,
14520     scope: myObject
14521 });
14522
14523 // map multiple keys to one action by string
14524 var map = new Roo.KeyMap("my-element", {
14525     key: "a\r\n\t",
14526     fn: myHandler,
14527     scope: myObject
14528 });
14529
14530 // map multiple keys to multiple actions by strings and array of codes
14531 var map = new Roo.KeyMap("my-element", [
14532     {
14533         key: [10,13],
14534         fn: function(){ alert("Return was pressed"); }
14535     }, {
14536         key: "abc",
14537         fn: function(){ alert('a, b or c was pressed'); }
14538     }, {
14539         key: "\t",
14540         ctrl:true,
14541         shift:true,
14542         fn: function(){ alert('Control + shift + tab was pressed.'); }
14543     }
14544 ]);
14545 </code></pre>
14546  * <b>Note: A KeyMap starts enabled</b>
14547  * @constructor
14548  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14549  * @param {Object} config The config (see {@link #addBinding})
14550  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14551  */
14552 Roo.KeyMap = function(el, config, eventName){
14553     this.el  = Roo.get(el);
14554     this.eventName = eventName || "keydown";
14555     this.bindings = [];
14556     if(config){
14557         this.addBinding(config);
14558     }
14559     this.enable();
14560 };
14561
14562 Roo.KeyMap.prototype = {
14563     /**
14564      * True to stop the event from bubbling and prevent the default browser action if the
14565      * key was handled by the KeyMap (defaults to false)
14566      * @type Boolean
14567      */
14568     stopEvent : false,
14569
14570     /**
14571      * Add a new binding to this KeyMap. The following config object properties are supported:
14572      * <pre>
14573 Property    Type             Description
14574 ----------  ---------------  ----------------------------------------------------------------------
14575 key         String/Array     A single keycode or an array of keycodes to handle
14576 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14577 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14578 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14579 fn          Function         The function to call when KeyMap finds the expected key combination
14580 scope       Object           The scope of the callback function
14581 </pre>
14582      *
14583      * Usage:
14584      * <pre><code>
14585 // Create a KeyMap
14586 var map = new Roo.KeyMap(document, {
14587     key: Roo.EventObject.ENTER,
14588     fn: handleKey,
14589     scope: this
14590 });
14591
14592 //Add a new binding to the existing KeyMap later
14593 map.addBinding({
14594     key: 'abc',
14595     shift: true,
14596     fn: handleKey,
14597     scope: this
14598 });
14599 </code></pre>
14600      * @param {Object/Array} config A single KeyMap config or an array of configs
14601      */
14602         addBinding : function(config){
14603         if(config instanceof Array){
14604             for(var i = 0, len = config.length; i < len; i++){
14605                 this.addBinding(config[i]);
14606             }
14607             return;
14608         }
14609         var keyCode = config.key,
14610             shift = config.shift, 
14611             ctrl = config.ctrl, 
14612             alt = config.alt,
14613             fn = config.fn,
14614             scope = config.scope;
14615         if(typeof keyCode == "string"){
14616             var ks = [];
14617             var keyString = keyCode.toUpperCase();
14618             for(var j = 0, len = keyString.length; j < len; j++){
14619                 ks.push(keyString.charCodeAt(j));
14620             }
14621             keyCode = ks;
14622         }
14623         var keyArray = keyCode instanceof Array;
14624         var handler = function(e){
14625             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14626                 var k = e.getKey();
14627                 if(keyArray){
14628                     for(var i = 0, len = keyCode.length; i < len; i++){
14629                         if(keyCode[i] == k){
14630                           if(this.stopEvent){
14631                               e.stopEvent();
14632                           }
14633                           fn.call(scope || window, k, e);
14634                           return;
14635                         }
14636                     }
14637                 }else{
14638                     if(k == keyCode){
14639                         if(this.stopEvent){
14640                            e.stopEvent();
14641                         }
14642                         fn.call(scope || window, k, e);
14643                     }
14644                 }
14645             }
14646         };
14647         this.bindings.push(handler);  
14648         },
14649
14650     /**
14651      * Shorthand for adding a single key listener
14652      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14653      * following options:
14654      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14655      * @param {Function} fn The function to call
14656      * @param {Object} scope (optional) The scope of the function
14657      */
14658     on : function(key, fn, scope){
14659         var keyCode, shift, ctrl, alt;
14660         if(typeof key == "object" && !(key instanceof Array)){
14661             keyCode = key.key;
14662             shift = key.shift;
14663             ctrl = key.ctrl;
14664             alt = key.alt;
14665         }else{
14666             keyCode = key;
14667         }
14668         this.addBinding({
14669             key: keyCode,
14670             shift: shift,
14671             ctrl: ctrl,
14672             alt: alt,
14673             fn: fn,
14674             scope: scope
14675         })
14676     },
14677
14678     // private
14679     handleKeyDown : function(e){
14680             if(this.enabled){ //just in case
14681             var b = this.bindings;
14682             for(var i = 0, len = b.length; i < len; i++){
14683                 b[i].call(this, e);
14684             }
14685             }
14686         },
14687         
14688         /**
14689          * Returns true if this KeyMap is enabled
14690          * @return {Boolean} 
14691          */
14692         isEnabled : function(){
14693             return this.enabled;  
14694         },
14695         
14696         /**
14697          * Enables this KeyMap
14698          */
14699         enable: function(){
14700                 if(!this.enabled){
14701                     this.el.on(this.eventName, this.handleKeyDown, this);
14702                     this.enabled = true;
14703                 }
14704         },
14705
14706         /**
14707          * Disable this KeyMap
14708          */
14709         disable: function(){
14710                 if(this.enabled){
14711                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14712                     this.enabled = false;
14713                 }
14714         }
14715 };/*
14716  * Based on:
14717  * Ext JS Library 1.1.1
14718  * Copyright(c) 2006-2007, Ext JS, LLC.
14719  *
14720  * Originally Released Under LGPL - original licence link has changed is not relivant.
14721  *
14722  * Fork - LGPL
14723  * <script type="text/javascript">
14724  */
14725
14726  
14727 /**
14728  * @class Roo.util.TextMetrics
14729  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14730  * wide, in pixels, a given block of text will be.
14731  * @singleton
14732  */
14733 Roo.util.TextMetrics = function(){
14734     var shared;
14735     return {
14736         /**
14737          * Measures the size of the specified text
14738          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14739          * that can affect the size of the rendered text
14740          * @param {String} text The text to measure
14741          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14742          * in order to accurately measure the text height
14743          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14744          */
14745         measure : function(el, text, fixedWidth){
14746             if(!shared){
14747                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14748             }
14749             shared.bind(el);
14750             shared.setFixedWidth(fixedWidth || 'auto');
14751             return shared.getSize(text);
14752         },
14753
14754         /**
14755          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14756          * the overhead of multiple calls to initialize the style properties on each measurement.
14757          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14758          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14759          * in order to accurately measure the text height
14760          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14761          */
14762         createInstance : function(el, fixedWidth){
14763             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14764         }
14765     };
14766 }();
14767
14768  
14769
14770 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14771     var ml = new Roo.Element(document.createElement('div'));
14772     document.body.appendChild(ml.dom);
14773     ml.position('absolute');
14774     ml.setLeftTop(-1000, -1000);
14775     ml.hide();
14776
14777     if(fixedWidth){
14778         ml.setWidth(fixedWidth);
14779     }
14780      
14781     var instance = {
14782         /**
14783          * Returns the size of the specified text based on the internal element's style and width properties
14784          * @memberOf Roo.util.TextMetrics.Instance#
14785          * @param {String} text The text to measure
14786          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14787          */
14788         getSize : function(text){
14789             ml.update(text);
14790             var s = ml.getSize();
14791             ml.update('');
14792             return s;
14793         },
14794
14795         /**
14796          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14797          * that can affect the size of the rendered text
14798          * @memberOf Roo.util.TextMetrics.Instance#
14799          * @param {String/HTMLElement} el The element, dom node or id
14800          */
14801         bind : function(el){
14802             ml.setStyle(
14803                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14804             );
14805         },
14806
14807         /**
14808          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14809          * to set a fixed width in order to accurately measure the text height.
14810          * @memberOf Roo.util.TextMetrics.Instance#
14811          * @param {Number} width The width to set on the element
14812          */
14813         setFixedWidth : function(width){
14814             ml.setWidth(width);
14815         },
14816
14817         /**
14818          * Returns the measured width of the specified text
14819          * @memberOf Roo.util.TextMetrics.Instance#
14820          * @param {String} text The text to measure
14821          * @return {Number} width The width in pixels
14822          */
14823         getWidth : function(text){
14824             ml.dom.style.width = 'auto';
14825             return this.getSize(text).width;
14826         },
14827
14828         /**
14829          * Returns the measured height of the specified text.  For multiline text, be sure to call
14830          * {@link #setFixedWidth} if necessary.
14831          * @memberOf Roo.util.TextMetrics.Instance#
14832          * @param {String} text The text to measure
14833          * @return {Number} height The height in pixels
14834          */
14835         getHeight : function(text){
14836             return this.getSize(text).height;
14837         }
14838     };
14839
14840     instance.bind(bindTo);
14841
14842     return instance;
14843 };
14844
14845 // backwards compat
14846 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14847  * Based on:
14848  * Ext JS Library 1.1.1
14849  * Copyright(c) 2006-2007, Ext JS, LLC.
14850  *
14851  * Originally Released Under LGPL - original licence link has changed is not relivant.
14852  *
14853  * Fork - LGPL
14854  * <script type="text/javascript">
14855  */
14856
14857 /**
14858  * @class Roo.state.Provider
14859  * Abstract base class for state provider implementations. This class provides methods
14860  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14861  * Provider interface.
14862  */
14863 Roo.state.Provider = function(){
14864     /**
14865      * @event statechange
14866      * Fires when a state change occurs.
14867      * @param {Provider} this This state provider
14868      * @param {String} key The state key which was changed
14869      * @param {String} value The encoded value for the state
14870      */
14871     this.addEvents({
14872         "statechange": true
14873     });
14874     this.state = {};
14875     Roo.state.Provider.superclass.constructor.call(this);
14876 };
14877 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14878     /**
14879      * Returns the current value for a key
14880      * @param {String} name The key name
14881      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14882      * @return {Mixed} The state data
14883      */
14884     get : function(name, defaultValue){
14885         return typeof this.state[name] == "undefined" ?
14886             defaultValue : this.state[name];
14887     },
14888     
14889     /**
14890      * Clears a value from the state
14891      * @param {String} name The key name
14892      */
14893     clear : function(name){
14894         delete this.state[name];
14895         this.fireEvent("statechange", this, name, null);
14896     },
14897     
14898     /**
14899      * Sets the value for a key
14900      * @param {String} name The key name
14901      * @param {Mixed} value The value to set
14902      */
14903     set : function(name, value){
14904         this.state[name] = value;
14905         this.fireEvent("statechange", this, name, value);
14906     },
14907     
14908     /**
14909      * Decodes a string previously encoded with {@link #encodeValue}.
14910      * @param {String} value The value to decode
14911      * @return {Mixed} The decoded value
14912      */
14913     decodeValue : function(cookie){
14914         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14915         var matches = re.exec(unescape(cookie));
14916         if(!matches || !matches[1]) {
14917             return; // non state cookie
14918         }
14919         var type = matches[1];
14920         var v = matches[2];
14921         switch(type){
14922             case "n":
14923                 return parseFloat(v);
14924             case "d":
14925                 return new Date(Date.parse(v));
14926             case "b":
14927                 return (v == "1");
14928             case "a":
14929                 var all = [];
14930                 var values = v.split("^");
14931                 for(var i = 0, len = values.length; i < len; i++){
14932                     all.push(this.decodeValue(values[i]));
14933                 }
14934                 return all;
14935            case "o":
14936                 var all = {};
14937                 var values = v.split("^");
14938                 for(var i = 0, len = values.length; i < len; i++){
14939                     var kv = values[i].split("=");
14940                     all[kv[0]] = this.decodeValue(kv[1]);
14941                 }
14942                 return all;
14943            default:
14944                 return v;
14945         }
14946     },
14947     
14948     /**
14949      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14950      * @param {Mixed} value The value to encode
14951      * @return {String} The encoded value
14952      */
14953     encodeValue : function(v){
14954         var enc;
14955         if(typeof v == "number"){
14956             enc = "n:" + v;
14957         }else if(typeof v == "boolean"){
14958             enc = "b:" + (v ? "1" : "0");
14959         }else if(v instanceof Date){
14960             enc = "d:" + v.toGMTString();
14961         }else if(v instanceof Array){
14962             var flat = "";
14963             for(var i = 0, len = v.length; i < len; i++){
14964                 flat += this.encodeValue(v[i]);
14965                 if(i != len-1) {
14966                     flat += "^";
14967                 }
14968             }
14969             enc = "a:" + flat;
14970         }else if(typeof v == "object"){
14971             var flat = "";
14972             for(var key in v){
14973                 if(typeof v[key] != "function"){
14974                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14975                 }
14976             }
14977             enc = "o:" + flat.substring(0, flat.length-1);
14978         }else{
14979             enc = "s:" + v;
14980         }
14981         return escape(enc);        
14982     }
14983 });
14984
14985 /*
14986  * Based on:
14987  * Ext JS Library 1.1.1
14988  * Copyright(c) 2006-2007, Ext JS, LLC.
14989  *
14990  * Originally Released Under LGPL - original licence link has changed is not relivant.
14991  *
14992  * Fork - LGPL
14993  * <script type="text/javascript">
14994  */
14995 /**
14996  * @class Roo.state.Manager
14997  * This is the global state manager. By default all components that are "state aware" check this class
14998  * for state information if you don't pass them a custom state provider. In order for this class
14999  * to be useful, it must be initialized with a provider when your application initializes.
15000  <pre><code>
15001 // in your initialization function
15002 init : function(){
15003    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15004    ...
15005    // supposed you have a {@link Roo.BorderLayout}
15006    var layout = new Roo.BorderLayout(...);
15007    layout.restoreState();
15008    // or a {Roo.BasicDialog}
15009    var dialog = new Roo.BasicDialog(...);
15010    dialog.restoreState();
15011  </code></pre>
15012  * @singleton
15013  */
15014 Roo.state.Manager = function(){
15015     var provider = new Roo.state.Provider();
15016     
15017     return {
15018         /**
15019          * Configures the default state provider for your application
15020          * @param {Provider} stateProvider The state provider to set
15021          */
15022         setProvider : function(stateProvider){
15023             provider = stateProvider;
15024         },
15025         
15026         /**
15027          * Returns the current value for a key
15028          * @param {String} name The key name
15029          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15030          * @return {Mixed} The state data
15031          */
15032         get : function(key, defaultValue){
15033             return provider.get(key, defaultValue);
15034         },
15035         
15036         /**
15037          * Sets the value for a key
15038          * @param {String} name The key name
15039          * @param {Mixed} value The state data
15040          */
15041          set : function(key, value){
15042             provider.set(key, value);
15043         },
15044         
15045         /**
15046          * Clears a value from the state
15047          * @param {String} name The key name
15048          */
15049         clear : function(key){
15050             provider.clear(key);
15051         },
15052         
15053         /**
15054          * Gets the currently configured state provider
15055          * @return {Provider} The state provider
15056          */
15057         getProvider : function(){
15058             return provider;
15059         }
15060     };
15061 }();
15062 /*
15063  * Based on:
15064  * Ext JS Library 1.1.1
15065  * Copyright(c) 2006-2007, Ext JS, LLC.
15066  *
15067  * Originally Released Under LGPL - original licence link has changed is not relivant.
15068  *
15069  * Fork - LGPL
15070  * <script type="text/javascript">
15071  */
15072 /**
15073  * @class Roo.state.CookieProvider
15074  * @extends Roo.state.Provider
15075  * The default Provider implementation which saves state via cookies.
15076  * <br />Usage:
15077  <pre><code>
15078    var cp = new Roo.state.CookieProvider({
15079        path: "/cgi-bin/",
15080        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15081        domain: "roojs.com"
15082    })
15083    Roo.state.Manager.setProvider(cp);
15084  </code></pre>
15085  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15086  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15087  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15088  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15089  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15090  * domain the page is running on including the 'www' like 'www.roojs.com')
15091  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15092  * @constructor
15093  * Create a new CookieProvider
15094  * @param {Object} config The configuration object
15095  */
15096 Roo.state.CookieProvider = function(config){
15097     Roo.state.CookieProvider.superclass.constructor.call(this);
15098     this.path = "/";
15099     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15100     this.domain = null;
15101     this.secure = false;
15102     Roo.apply(this, config);
15103     this.state = this.readCookies();
15104 };
15105
15106 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15107     // private
15108     set : function(name, value){
15109         if(typeof value == "undefined" || value === null){
15110             this.clear(name);
15111             return;
15112         }
15113         this.setCookie(name, value);
15114         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15115     },
15116
15117     // private
15118     clear : function(name){
15119         this.clearCookie(name);
15120         Roo.state.CookieProvider.superclass.clear.call(this, name);
15121     },
15122
15123     // private
15124     readCookies : function(){
15125         var cookies = {};
15126         var c = document.cookie + ";";
15127         var re = /\s?(.*?)=(.*?);/g;
15128         var matches;
15129         while((matches = re.exec(c)) != null){
15130             var name = matches[1];
15131             var value = matches[2];
15132             if(name && name.substring(0,3) == "ys-"){
15133                 cookies[name.substr(3)] = this.decodeValue(value);
15134             }
15135         }
15136         return cookies;
15137     },
15138
15139     // private
15140     setCookie : function(name, value){
15141         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15142            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15143            ((this.path == null) ? "" : ("; path=" + this.path)) +
15144            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15145            ((this.secure == true) ? "; secure" : "");
15146     },
15147
15148     // private
15149     clearCookie : function(name){
15150         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15151            ((this.path == null) ? "" : ("; path=" + this.path)) +
15152            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15153            ((this.secure == true) ? "; secure" : "");
15154     }
15155 });/*
15156  * Based on:
15157  * Ext JS Library 1.1.1
15158  * Copyright(c) 2006-2007, Ext JS, LLC.
15159  *
15160  * Originally Released Under LGPL - original licence link has changed is not relivant.
15161  *
15162  * Fork - LGPL
15163  * <script type="text/javascript">
15164  */
15165  
15166
15167 /**
15168  * @class Roo.ComponentMgr
15169  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15170  * @singleton
15171  */
15172 Roo.ComponentMgr = function(){
15173     var all = new Roo.util.MixedCollection();
15174
15175     return {
15176         /**
15177          * Registers a component.
15178          * @param {Roo.Component} c The component
15179          */
15180         register : function(c){
15181             all.add(c);
15182         },
15183
15184         /**
15185          * Unregisters a component.
15186          * @param {Roo.Component} c The component
15187          */
15188         unregister : function(c){
15189             all.remove(c);
15190         },
15191
15192         /**
15193          * Returns a component by id
15194          * @param {String} id The component id
15195          */
15196         get : function(id){
15197             return all.get(id);
15198         },
15199
15200         /**
15201          * Registers a function that will be called when a specified component is added to ComponentMgr
15202          * @param {String} id The component id
15203          * @param {Funtction} fn The callback function
15204          * @param {Object} scope The scope of the callback
15205          */
15206         onAvailable : function(id, fn, scope){
15207             all.on("add", function(index, o){
15208                 if(o.id == id){
15209                     fn.call(scope || o, o);
15210                     all.un("add", fn, scope);
15211                 }
15212             });
15213         }
15214     };
15215 }();/*
15216  * Based on:
15217  * Ext JS Library 1.1.1
15218  * Copyright(c) 2006-2007, Ext JS, LLC.
15219  *
15220  * Originally Released Under LGPL - original licence link has changed is not relivant.
15221  *
15222  * Fork - LGPL
15223  * <script type="text/javascript">
15224  */
15225  
15226 /**
15227  * @class Roo.Component
15228  * @extends Roo.util.Observable
15229  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15230  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15231  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15232  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15233  * All visual components (widgets) that require rendering into a layout should subclass Component.
15234  * @constructor
15235  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15236  * 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
15237  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15238  */
15239 Roo.Component = function(config){
15240     config = config || {};
15241     if(config.tagName || config.dom || typeof config == "string"){ // element object
15242         config = {el: config, id: config.id || config};
15243     }
15244     this.initialConfig = config;
15245
15246     Roo.apply(this, config);
15247     this.addEvents({
15248         /**
15249          * @event disable
15250          * Fires after the component is disabled.
15251              * @param {Roo.Component} this
15252              */
15253         disable : true,
15254         /**
15255          * @event enable
15256          * Fires after the component is enabled.
15257              * @param {Roo.Component} this
15258              */
15259         enable : true,
15260         /**
15261          * @event beforeshow
15262          * Fires before the component is shown.  Return false to stop the show.
15263              * @param {Roo.Component} this
15264              */
15265         beforeshow : true,
15266         /**
15267          * @event show
15268          * Fires after the component is shown.
15269              * @param {Roo.Component} this
15270              */
15271         show : true,
15272         /**
15273          * @event beforehide
15274          * Fires before the component is hidden. Return false to stop the hide.
15275              * @param {Roo.Component} this
15276              */
15277         beforehide : true,
15278         /**
15279          * @event hide
15280          * Fires after the component is hidden.
15281              * @param {Roo.Component} this
15282              */
15283         hide : true,
15284         /**
15285          * @event beforerender
15286          * Fires before the component is rendered. Return false to stop the render.
15287              * @param {Roo.Component} this
15288              */
15289         beforerender : true,
15290         /**
15291          * @event render
15292          * Fires after the component is rendered.
15293              * @param {Roo.Component} this
15294              */
15295         render : true,
15296         /**
15297          * @event beforedestroy
15298          * Fires before the component is destroyed. Return false to stop the destroy.
15299              * @param {Roo.Component} this
15300              */
15301         beforedestroy : true,
15302         /**
15303          * @event destroy
15304          * Fires after the component is destroyed.
15305              * @param {Roo.Component} this
15306              */
15307         destroy : true
15308     });
15309     if(!this.id){
15310         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15311     }
15312     Roo.ComponentMgr.register(this);
15313     Roo.Component.superclass.constructor.call(this);
15314     this.initComponent();
15315     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15316         this.render(this.renderTo);
15317         delete this.renderTo;
15318     }
15319 };
15320
15321 /** @private */
15322 Roo.Component.AUTO_ID = 1000;
15323
15324 Roo.extend(Roo.Component, Roo.util.Observable, {
15325     /**
15326      * @scope Roo.Component.prototype
15327      * @type {Boolean}
15328      * true if this component is hidden. Read-only.
15329      */
15330     hidden : false,
15331     /**
15332      * @type {Boolean}
15333      * true if this component is disabled. Read-only.
15334      */
15335     disabled : false,
15336     /**
15337      * @type {Boolean}
15338      * true if this component has been rendered. Read-only.
15339      */
15340     rendered : false,
15341     
15342     /** @cfg {String} disableClass
15343      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15344      */
15345     disabledClass : "x-item-disabled",
15346         /** @cfg {Boolean} allowDomMove
15347          * Whether the component can move the Dom node when rendering (defaults to true).
15348          */
15349     allowDomMove : true,
15350     /** @cfg {String} hideMode (display|visibility)
15351      * How this component should hidden. Supported values are
15352      * "visibility" (css visibility), "offsets" (negative offset position) and
15353      * "display" (css display) - defaults to "display".
15354      */
15355     hideMode: 'display',
15356
15357     /** @private */
15358     ctype : "Roo.Component",
15359
15360     /**
15361      * @cfg {String} actionMode 
15362      * which property holds the element that used for  hide() / show() / disable() / enable()
15363      * default is 'el' 
15364      */
15365     actionMode : "el",
15366
15367     /** @private */
15368     getActionEl : function(){
15369         return this[this.actionMode];
15370     },
15371
15372     initComponent : Roo.emptyFn,
15373     /**
15374      * If this is a lazy rendering component, render it to its container element.
15375      * @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.
15376      */
15377     render : function(container, position){
15378         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15379             if(!container && this.el){
15380                 this.el = Roo.get(this.el);
15381                 container = this.el.dom.parentNode;
15382                 this.allowDomMove = false;
15383             }
15384             this.container = Roo.get(container);
15385             this.rendered = true;
15386             if(position !== undefined){
15387                 if(typeof position == 'number'){
15388                     position = this.container.dom.childNodes[position];
15389                 }else{
15390                     position = Roo.getDom(position);
15391                 }
15392             }
15393             this.onRender(this.container, position || null);
15394             if(this.cls){
15395                 this.el.addClass(this.cls);
15396                 delete this.cls;
15397             }
15398             if(this.style){
15399                 this.el.applyStyles(this.style);
15400                 delete this.style;
15401             }
15402             this.fireEvent("render", this);
15403             this.afterRender(this.container);
15404             if(this.hidden){
15405                 this.hide();
15406             }
15407             if(this.disabled){
15408                 this.disable();
15409             }
15410         }
15411         return this;
15412     },
15413
15414     /** @private */
15415     // default function is not really useful
15416     onRender : function(ct, position){
15417         if(this.el){
15418             this.el = Roo.get(this.el);
15419             if(this.allowDomMove !== false){
15420                 ct.dom.insertBefore(this.el.dom, position);
15421             }
15422         }
15423     },
15424
15425     /** @private */
15426     getAutoCreate : function(){
15427         var cfg = typeof this.autoCreate == "object" ?
15428                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15429         if(this.id && !cfg.id){
15430             cfg.id = this.id;
15431         }
15432         return cfg;
15433     },
15434
15435     /** @private */
15436     afterRender : Roo.emptyFn,
15437
15438     /**
15439      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15440      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15441      */
15442     destroy : function(){
15443         if(this.fireEvent("beforedestroy", this) !== false){
15444             this.purgeListeners();
15445             this.beforeDestroy();
15446             if(this.rendered){
15447                 this.el.removeAllListeners();
15448                 this.el.remove();
15449                 if(this.actionMode == "container"){
15450                     this.container.remove();
15451                 }
15452             }
15453             this.onDestroy();
15454             Roo.ComponentMgr.unregister(this);
15455             this.fireEvent("destroy", this);
15456         }
15457     },
15458
15459         /** @private */
15460     beforeDestroy : function(){
15461
15462     },
15463
15464         /** @private */
15465         onDestroy : function(){
15466
15467     },
15468
15469     /**
15470      * Returns the underlying {@link Roo.Element}.
15471      * @return {Roo.Element} The element
15472      */
15473     getEl : function(){
15474         return this.el;
15475     },
15476
15477     /**
15478      * Returns the id of this component.
15479      * @return {String}
15480      */
15481     getId : function(){
15482         return this.id;
15483     },
15484
15485     /**
15486      * Try to focus this component.
15487      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15488      * @return {Roo.Component} this
15489      */
15490     focus : function(selectText){
15491         if(this.rendered){
15492             this.el.focus();
15493             if(selectText === true){
15494                 this.el.dom.select();
15495             }
15496         }
15497         return this;
15498     },
15499
15500     /** @private */
15501     blur : function(){
15502         if(this.rendered){
15503             this.el.blur();
15504         }
15505         return this;
15506     },
15507
15508     /**
15509      * Disable this component.
15510      * @return {Roo.Component} this
15511      */
15512     disable : function(){
15513         if(this.rendered){
15514             this.onDisable();
15515         }
15516         this.disabled = true;
15517         this.fireEvent("disable", this);
15518         return this;
15519     },
15520
15521         // private
15522     onDisable : function(){
15523         this.getActionEl().addClass(this.disabledClass);
15524         this.el.dom.disabled = true;
15525     },
15526
15527     /**
15528      * Enable this component.
15529      * @return {Roo.Component} this
15530      */
15531     enable : function(){
15532         if(this.rendered){
15533             this.onEnable();
15534         }
15535         this.disabled = false;
15536         this.fireEvent("enable", this);
15537         return this;
15538     },
15539
15540         // private
15541     onEnable : function(){
15542         this.getActionEl().removeClass(this.disabledClass);
15543         this.el.dom.disabled = false;
15544     },
15545
15546     /**
15547      * Convenience function for setting disabled/enabled by boolean.
15548      * @param {Boolean} disabled
15549      */
15550     setDisabled : function(disabled){
15551         this[disabled ? "disable" : "enable"]();
15552     },
15553
15554     /**
15555      * Show this component.
15556      * @return {Roo.Component} this
15557      */
15558     show: function(){
15559         if(this.fireEvent("beforeshow", this) !== false){
15560             this.hidden = false;
15561             if(this.rendered){
15562                 this.onShow();
15563             }
15564             this.fireEvent("show", this);
15565         }
15566         return this;
15567     },
15568
15569     // private
15570     onShow : function(){
15571         var ae = this.getActionEl();
15572         if(this.hideMode == 'visibility'){
15573             ae.dom.style.visibility = "visible";
15574         }else if(this.hideMode == 'offsets'){
15575             ae.removeClass('x-hidden');
15576         }else{
15577             ae.dom.style.display = "";
15578         }
15579     },
15580
15581     /**
15582      * Hide this component.
15583      * @return {Roo.Component} this
15584      */
15585     hide: function(){
15586         if(this.fireEvent("beforehide", this) !== false){
15587             this.hidden = true;
15588             if(this.rendered){
15589                 this.onHide();
15590             }
15591             this.fireEvent("hide", this);
15592         }
15593         return this;
15594     },
15595
15596     // private
15597     onHide : function(){
15598         var ae = this.getActionEl();
15599         if(this.hideMode == 'visibility'){
15600             ae.dom.style.visibility = "hidden";
15601         }else if(this.hideMode == 'offsets'){
15602             ae.addClass('x-hidden');
15603         }else{
15604             ae.dom.style.display = "none";
15605         }
15606     },
15607
15608     /**
15609      * Convenience function to hide or show this component by boolean.
15610      * @param {Boolean} visible True to show, false to hide
15611      * @return {Roo.Component} this
15612      */
15613     setVisible: function(visible){
15614         if(visible) {
15615             this.show();
15616         }else{
15617             this.hide();
15618         }
15619         return this;
15620     },
15621
15622     /**
15623      * Returns true if this component is visible.
15624      */
15625     isVisible : function(){
15626         return this.getActionEl().isVisible();
15627     },
15628
15629     cloneConfig : function(overrides){
15630         overrides = overrides || {};
15631         var id = overrides.id || Roo.id();
15632         var cfg = Roo.applyIf(overrides, this.initialConfig);
15633         cfg.id = id; // prevent dup id
15634         return new this.constructor(cfg);
15635     }
15636 });/*
15637  * Based on:
15638  * Ext JS Library 1.1.1
15639  * Copyright(c) 2006-2007, Ext JS, LLC.
15640  *
15641  * Originally Released Under LGPL - original licence link has changed is not relivant.
15642  *
15643  * Fork - LGPL
15644  * <script type="text/javascript">
15645  */
15646
15647 /**
15648  * @class Roo.BoxComponent
15649  * @extends Roo.Component
15650  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15651  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15652  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15653  * layout containers.
15654  * @constructor
15655  * @param {Roo.Element/String/Object} config The configuration options.
15656  */
15657 Roo.BoxComponent = function(config){
15658     Roo.Component.call(this, config);
15659     this.addEvents({
15660         /**
15661          * @event resize
15662          * Fires after the component is resized.
15663              * @param {Roo.Component} this
15664              * @param {Number} adjWidth The box-adjusted width that was set
15665              * @param {Number} adjHeight The box-adjusted height that was set
15666              * @param {Number} rawWidth The width that was originally specified
15667              * @param {Number} rawHeight The height that was originally specified
15668              */
15669         resize : true,
15670         /**
15671          * @event move
15672          * Fires after the component is moved.
15673              * @param {Roo.Component} this
15674              * @param {Number} x The new x position
15675              * @param {Number} y The new y position
15676              */
15677         move : true
15678     });
15679 };
15680
15681 Roo.extend(Roo.BoxComponent, Roo.Component, {
15682     // private, set in afterRender to signify that the component has been rendered
15683     boxReady : false,
15684     // private, used to defer height settings to subclasses
15685     deferHeight: false,
15686     /** @cfg {Number} width
15687      * width (optional) size of component
15688      */
15689      /** @cfg {Number} height
15690      * height (optional) size of component
15691      */
15692      
15693     /**
15694      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15695      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15696      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15697      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15698      * @return {Roo.BoxComponent} this
15699      */
15700     setSize : function(w, h){
15701         // support for standard size objects
15702         if(typeof w == 'object'){
15703             h = w.height;
15704             w = w.width;
15705         }
15706         // not rendered
15707         if(!this.boxReady){
15708             this.width = w;
15709             this.height = h;
15710             return this;
15711         }
15712
15713         // prevent recalcs when not needed
15714         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15715             return this;
15716         }
15717         this.lastSize = {width: w, height: h};
15718
15719         var adj = this.adjustSize(w, h);
15720         var aw = adj.width, ah = adj.height;
15721         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15722             var rz = this.getResizeEl();
15723             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15724                 rz.setSize(aw, ah);
15725             }else if(!this.deferHeight && ah !== undefined){
15726                 rz.setHeight(ah);
15727             }else if(aw !== undefined){
15728                 rz.setWidth(aw);
15729             }
15730             this.onResize(aw, ah, w, h);
15731             this.fireEvent('resize', this, aw, ah, w, h);
15732         }
15733         return this;
15734     },
15735
15736     /**
15737      * Gets the current size of the component's underlying element.
15738      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15739      */
15740     getSize : function(){
15741         return this.el.getSize();
15742     },
15743
15744     /**
15745      * Gets the current XY position of the component's underlying element.
15746      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15747      * @return {Array} The XY position of the element (e.g., [100, 200])
15748      */
15749     getPosition : function(local){
15750         if(local === true){
15751             return [this.el.getLeft(true), this.el.getTop(true)];
15752         }
15753         return this.xy || this.el.getXY();
15754     },
15755
15756     /**
15757      * Gets the current box measurements of the component's underlying element.
15758      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15759      * @returns {Object} box An object in the format {x, y, width, height}
15760      */
15761     getBox : function(local){
15762         var s = this.el.getSize();
15763         if(local){
15764             s.x = this.el.getLeft(true);
15765             s.y = this.el.getTop(true);
15766         }else{
15767             var xy = this.xy || this.el.getXY();
15768             s.x = xy[0];
15769             s.y = xy[1];
15770         }
15771         return s;
15772     },
15773
15774     /**
15775      * Sets the current box measurements of the component's underlying element.
15776      * @param {Object} box An object in the format {x, y, width, height}
15777      * @returns {Roo.BoxComponent} this
15778      */
15779     updateBox : function(box){
15780         this.setSize(box.width, box.height);
15781         this.setPagePosition(box.x, box.y);
15782         return this;
15783     },
15784
15785     // protected
15786     getResizeEl : function(){
15787         return this.resizeEl || this.el;
15788     },
15789
15790     // protected
15791     getPositionEl : function(){
15792         return this.positionEl || this.el;
15793     },
15794
15795     /**
15796      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15797      * This method fires the move event.
15798      * @param {Number} left The new left
15799      * @param {Number} top The new top
15800      * @returns {Roo.BoxComponent} this
15801      */
15802     setPosition : function(x, y){
15803         this.x = x;
15804         this.y = y;
15805         if(!this.boxReady){
15806             return this;
15807         }
15808         var adj = this.adjustPosition(x, y);
15809         var ax = adj.x, ay = adj.y;
15810
15811         var el = this.getPositionEl();
15812         if(ax !== undefined || ay !== undefined){
15813             if(ax !== undefined && ay !== undefined){
15814                 el.setLeftTop(ax, ay);
15815             }else if(ax !== undefined){
15816                 el.setLeft(ax);
15817             }else if(ay !== undefined){
15818                 el.setTop(ay);
15819             }
15820             this.onPosition(ax, ay);
15821             this.fireEvent('move', this, ax, ay);
15822         }
15823         return this;
15824     },
15825
15826     /**
15827      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15828      * This method fires the move event.
15829      * @param {Number} x The new x position
15830      * @param {Number} y The new y position
15831      * @returns {Roo.BoxComponent} this
15832      */
15833     setPagePosition : function(x, y){
15834         this.pageX = x;
15835         this.pageY = y;
15836         if(!this.boxReady){
15837             return;
15838         }
15839         if(x === undefined || y === undefined){ // cannot translate undefined points
15840             return;
15841         }
15842         var p = this.el.translatePoints(x, y);
15843         this.setPosition(p.left, p.top);
15844         return this;
15845     },
15846
15847     // private
15848     onRender : function(ct, position){
15849         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15850         if(this.resizeEl){
15851             this.resizeEl = Roo.get(this.resizeEl);
15852         }
15853         if(this.positionEl){
15854             this.positionEl = Roo.get(this.positionEl);
15855         }
15856     },
15857
15858     // private
15859     afterRender : function(){
15860         Roo.BoxComponent.superclass.afterRender.call(this);
15861         this.boxReady = true;
15862         this.setSize(this.width, this.height);
15863         if(this.x || this.y){
15864             this.setPosition(this.x, this.y);
15865         }
15866         if(this.pageX || this.pageY){
15867             this.setPagePosition(this.pageX, this.pageY);
15868         }
15869     },
15870
15871     /**
15872      * Force the component's size to recalculate based on the underlying element's current height and width.
15873      * @returns {Roo.BoxComponent} this
15874      */
15875     syncSize : function(){
15876         delete this.lastSize;
15877         this.setSize(this.el.getWidth(), this.el.getHeight());
15878         return this;
15879     },
15880
15881     /**
15882      * Called after the component is resized, this method is empty by default but can be implemented by any
15883      * subclass that needs to perform custom logic after a resize occurs.
15884      * @param {Number} adjWidth The box-adjusted width that was set
15885      * @param {Number} adjHeight The box-adjusted height that was set
15886      * @param {Number} rawWidth The width that was originally specified
15887      * @param {Number} rawHeight The height that was originally specified
15888      */
15889     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15890
15891     },
15892
15893     /**
15894      * Called after the component is moved, this method is empty by default but can be implemented by any
15895      * subclass that needs to perform custom logic after a move occurs.
15896      * @param {Number} x The new x position
15897      * @param {Number} y The new y position
15898      */
15899     onPosition : function(x, y){
15900
15901     },
15902
15903     // private
15904     adjustSize : function(w, h){
15905         if(this.autoWidth){
15906             w = 'auto';
15907         }
15908         if(this.autoHeight){
15909             h = 'auto';
15910         }
15911         return {width : w, height: h};
15912     },
15913
15914     // private
15915     adjustPosition : function(x, y){
15916         return {x : x, y: y};
15917     }
15918 });/*
15919  * Original code for Roojs - LGPL
15920  * <script type="text/javascript">
15921  */
15922  
15923 /**
15924  * @class Roo.XComponent
15925  * A delayed Element creator...
15926  * Or a way to group chunks of interface together.
15927  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15928  *  used in conjunction with XComponent.build() it will create an instance of each element,
15929  *  then call addxtype() to build the User interface.
15930  * 
15931  * Mypart.xyx = new Roo.XComponent({
15932
15933     parent : 'Mypart.xyz', // empty == document.element.!!
15934     order : '001',
15935     name : 'xxxx'
15936     region : 'xxxx'
15937     disabled : function() {} 
15938      
15939     tree : function() { // return an tree of xtype declared components
15940         var MODULE = this;
15941         return 
15942         {
15943             xtype : 'NestedLayoutPanel',
15944             // technicall
15945         }
15946      ]
15947  *})
15948  *
15949  *
15950  * It can be used to build a big heiracy, with parent etc.
15951  * or you can just use this to render a single compoent to a dom element
15952  * MYPART.render(Roo.Element | String(id) | dom_element )
15953  *
15954  *
15955  * Usage patterns.
15956  *
15957  * Classic Roo
15958  *
15959  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15960  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15961  *
15962  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15963  *
15964  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15965  * - if mulitple topModules exist, the last one is defined as the top module.
15966  *
15967  * Embeded Roo
15968  * 
15969  * When the top level or multiple modules are to embedded into a existing HTML page,
15970  * the parent element can container '#id' of the element where the module will be drawn.
15971  *
15972  * Bootstrap Roo
15973  *
15974  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15975  * it relies more on a include mechanism, where sub modules are included into an outer page.
15976  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15977  * 
15978  * Bootstrap Roo Included elements
15979  *
15980  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15981  * hence confusing the component builder as it thinks there are multiple top level elements. 
15982  *
15983  * 
15984  * 
15985  * @extends Roo.util.Observable
15986  * @constructor
15987  * @param cfg {Object} configuration of component
15988  * 
15989  */
15990 Roo.XComponent = function(cfg) {
15991     Roo.apply(this, cfg);
15992     this.addEvents({ 
15993         /**
15994              * @event built
15995              * Fires when this the componnt is built
15996              * @param {Roo.XComponent} c the component
15997              */
15998         'built' : true
15999         
16000     });
16001     this.region = this.region || 'center'; // default..
16002     Roo.XComponent.register(this);
16003     this.modules = false;
16004     this.el = false; // where the layout goes..
16005     
16006     
16007 }
16008 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16009     /**
16010      * @property el
16011      * The created element (with Roo.factory())
16012      * @type {Roo.Layout}
16013      */
16014     el  : false,
16015     
16016     /**
16017      * @property el
16018      * for BC  - use el in new code
16019      * @type {Roo.Layout}
16020      */
16021     panel : false,
16022     
16023     /**
16024      * @property layout
16025      * for BC  - use el in new code
16026      * @type {Roo.Layout}
16027      */
16028     layout : false,
16029     
16030      /**
16031      * @cfg {Function|boolean} disabled
16032      * If this module is disabled by some rule, return true from the funtion
16033      */
16034     disabled : false,
16035     
16036     /**
16037      * @cfg {String} parent 
16038      * Name of parent element which it get xtype added to..
16039      */
16040     parent: false,
16041     
16042     /**
16043      * @cfg {String} order
16044      * Used to set the order in which elements are created (usefull for multiple tabs)
16045      */
16046     
16047     order : false,
16048     /**
16049      * @cfg {String} name
16050      * String to display while loading.
16051      */
16052     name : false,
16053     /**
16054      * @cfg {String} region
16055      * Region to render component to (defaults to center)
16056      */
16057     region : 'center',
16058     
16059     /**
16060      * @cfg {Array} items
16061      * A single item array - the first element is the root of the tree..
16062      * It's done this way to stay compatible with the Xtype system...
16063      */
16064     items : false,
16065     
16066     /**
16067      * @property _tree
16068      * The method that retuns the tree of parts that make up this compoennt 
16069      * @type {function}
16070      */
16071     _tree  : false,
16072     
16073      /**
16074      * render
16075      * render element to dom or tree
16076      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16077      */
16078     
16079     render : function(el)
16080     {
16081         
16082         el = el || false;
16083         var hp = this.parent ? 1 : 0;
16084         Roo.debug &&  Roo.log(this);
16085         
16086         var tree = this._tree ? this._tree() : this.tree();
16087
16088         
16089         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16090             // if parent is a '#.....' string, then let's use that..
16091             var ename = this.parent.substr(1);
16092             this.parent = false;
16093             Roo.debug && Roo.log(ename);
16094             switch (ename) {
16095                 case 'bootstrap-body':
16096                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16097                         // this is the BorderLayout standard?
16098                        this.parent = { el : true };
16099                        break;
16100                     }
16101                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16102                         // need to insert stuff...
16103                         this.parent =  {
16104                              el : new Roo.bootstrap.layout.Border({
16105                                  el : document.body, 
16106                      
16107                                  center: {
16108                                     titlebar: false,
16109                                     autoScroll:false,
16110                                     closeOnTab: true,
16111                                     tabPosition: 'top',
16112                                       //resizeTabs: true,
16113                                     alwaysShowTabs: true,
16114                                     hideTabs: false
16115                                      //minTabWidth: 140
16116                                  }
16117                              })
16118                         
16119                          };
16120                          break;
16121                     }
16122                          
16123                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16124                         this.parent = { el :  new  Roo.bootstrap.Body() };
16125                         Roo.debug && Roo.log("setting el to doc body");
16126                          
16127                     } else {
16128                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16129                     }
16130                     break;
16131                 case 'bootstrap':
16132                     this.parent = { el : true};
16133                     // fall through
16134                 default:
16135                     el = Roo.get(ename);
16136                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16137                         this.parent = { el : true};
16138                     }
16139                     
16140                     break;
16141             }
16142                 
16143             
16144             if (!el && !this.parent) {
16145                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16146                 return;
16147             }
16148         }
16149         
16150         Roo.debug && Roo.log("EL:");
16151         Roo.debug && Roo.log(el);
16152         Roo.debug && Roo.log("this.parent.el:");
16153         Roo.debug && Roo.log(this.parent.el);
16154         
16155
16156         // altertive root elements ??? - we need a better way to indicate these.
16157         var is_alt = Roo.XComponent.is_alt ||
16158                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16159                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16160                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16161         
16162         
16163         
16164         if (!this.parent && is_alt) {
16165             //el = Roo.get(document.body);
16166             this.parent = { el : true };
16167         }
16168             
16169             
16170         
16171         if (!this.parent) {
16172             
16173             Roo.debug && Roo.log("no parent - creating one");
16174             
16175             el = el ? Roo.get(el) : false;      
16176             
16177             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16178                 
16179                 this.parent =  {
16180                     el : new Roo.bootstrap.layout.Border({
16181                         el: el || document.body,
16182                     
16183                         center: {
16184                             titlebar: false,
16185                             autoScroll:false,
16186                             closeOnTab: true,
16187                             tabPosition: 'top',
16188                              //resizeTabs: true,
16189                             alwaysShowTabs: false,
16190                             hideTabs: true,
16191                             minTabWidth: 140,
16192                             overflow: 'visible'
16193                          }
16194                      })
16195                 };
16196             } else {
16197             
16198                 // it's a top level one..
16199                 this.parent =  {
16200                     el : new Roo.BorderLayout(el || document.body, {
16201                         center: {
16202                             titlebar: false,
16203                             autoScroll:false,
16204                             closeOnTab: true,
16205                             tabPosition: 'top',
16206                              //resizeTabs: true,
16207                             alwaysShowTabs: el && hp? false :  true,
16208                             hideTabs: el || !hp ? true :  false,
16209                             minTabWidth: 140
16210                          }
16211                     })
16212                 };
16213             }
16214         }
16215         
16216         if (!this.parent.el) {
16217                 // probably an old style ctor, which has been disabled.
16218                 return;
16219
16220         }
16221                 // The 'tree' method is  '_tree now' 
16222             
16223         tree.region = tree.region || this.region;
16224         var is_body = false;
16225         if (this.parent.el === true) {
16226             // bootstrap... - body..
16227             if (el) {
16228                 tree.el = el;
16229             }
16230             this.parent.el = Roo.factory(tree);
16231             is_body = true;
16232         }
16233         
16234         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16235         this.fireEvent('built', this);
16236         
16237         this.panel = this.el;
16238         this.layout = this.panel.layout;
16239         this.parentLayout = this.parent.layout  || false;  
16240          
16241     }
16242     
16243 });
16244
16245 Roo.apply(Roo.XComponent, {
16246     /**
16247      * @property  hideProgress
16248      * true to disable the building progress bar.. usefull on single page renders.
16249      * @type Boolean
16250      */
16251     hideProgress : false,
16252     /**
16253      * @property  buildCompleted
16254      * True when the builder has completed building the interface.
16255      * @type Boolean
16256      */
16257     buildCompleted : false,
16258      
16259     /**
16260      * @property  topModule
16261      * the upper most module - uses document.element as it's constructor.
16262      * @type Object
16263      */
16264      
16265     topModule  : false,
16266       
16267     /**
16268      * @property  modules
16269      * array of modules to be created by registration system.
16270      * @type {Array} of Roo.XComponent
16271      */
16272     
16273     modules : [],
16274     /**
16275      * @property  elmodules
16276      * array of modules to be created by which use #ID 
16277      * @type {Array} of Roo.XComponent
16278      */
16279      
16280     elmodules : [],
16281
16282      /**
16283      * @property  is_alt
16284      * Is an alternative Root - normally used by bootstrap or other systems,
16285      *    where the top element in the tree can wrap 'body' 
16286      * @type {boolean}  (default false)
16287      */
16288      
16289     is_alt : false,
16290     /**
16291      * @property  build_from_html
16292      * Build elements from html - used by bootstrap HTML stuff 
16293      *    - this is cleared after build is completed
16294      * @type {boolean}    (default false)
16295      */
16296      
16297     build_from_html : false,
16298     /**
16299      * Register components to be built later.
16300      *
16301      * This solves the following issues
16302      * - Building is not done on page load, but after an authentication process has occured.
16303      * - Interface elements are registered on page load
16304      * - Parent Interface elements may not be loaded before child, so this handles that..
16305      * 
16306      *
16307      * example:
16308      * 
16309      * MyApp.register({
16310           order : '000001',
16311           module : 'Pman.Tab.projectMgr',
16312           region : 'center',
16313           parent : 'Pman.layout',
16314           disabled : false,  // or use a function..
16315         })
16316      
16317      * * @param {Object} details about module
16318      */
16319     register : function(obj) {
16320                 
16321         Roo.XComponent.event.fireEvent('register', obj);
16322         switch(typeof(obj.disabled) ) {
16323                 
16324             case 'undefined':
16325                 break;
16326             
16327             case 'function':
16328                 if ( obj.disabled() ) {
16329                         return;
16330                 }
16331                 break;
16332             
16333             default:
16334                 if (obj.disabled) {
16335                         return;
16336                 }
16337                 break;
16338         }
16339                 
16340         this.modules.push(obj);
16341          
16342     },
16343     /**
16344      * convert a string to an object..
16345      * eg. 'AAA.BBB' -> finds AAA.BBB
16346
16347      */
16348     
16349     toObject : function(str)
16350     {
16351         if (!str || typeof(str) == 'object') {
16352             return str;
16353         }
16354         if (str.substring(0,1) == '#') {
16355             return str;
16356         }
16357
16358         var ar = str.split('.');
16359         var rt, o;
16360         rt = ar.shift();
16361             /** eval:var:o */
16362         try {
16363             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16364         } catch (e) {
16365             throw "Module not found : " + str;
16366         }
16367         
16368         if (o === false) {
16369             throw "Module not found : " + str;
16370         }
16371         Roo.each(ar, function(e) {
16372             if (typeof(o[e]) == 'undefined') {
16373                 throw "Module not found : " + str;
16374             }
16375             o = o[e];
16376         });
16377         
16378         return o;
16379         
16380     },
16381     
16382     
16383     /**
16384      * move modules into their correct place in the tree..
16385      * 
16386      */
16387     preBuild : function ()
16388     {
16389         var _t = this;
16390         Roo.each(this.modules , function (obj)
16391         {
16392             Roo.XComponent.event.fireEvent('beforebuild', obj);
16393             
16394             var opar = obj.parent;
16395             try { 
16396                 obj.parent = this.toObject(opar);
16397             } catch(e) {
16398                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16399                 return;
16400             }
16401             
16402             if (!obj.parent) {
16403                 Roo.debug && Roo.log("GOT top level module");
16404                 Roo.debug && Roo.log(obj);
16405                 obj.modules = new Roo.util.MixedCollection(false, 
16406                     function(o) { return o.order + '' }
16407                 );
16408                 this.topModule = obj;
16409                 return;
16410             }
16411                         // parent is a string (usually a dom element name..)
16412             if (typeof(obj.parent) == 'string') {
16413                 this.elmodules.push(obj);
16414                 return;
16415             }
16416             if (obj.parent.constructor != Roo.XComponent) {
16417                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16418             }
16419             if (!obj.parent.modules) {
16420                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16421                     function(o) { return o.order + '' }
16422                 );
16423             }
16424             if (obj.parent.disabled) {
16425                 obj.disabled = true;
16426             }
16427             obj.parent.modules.add(obj);
16428         }, this);
16429     },
16430     
16431      /**
16432      * make a list of modules to build.
16433      * @return {Array} list of modules. 
16434      */ 
16435     
16436     buildOrder : function()
16437     {
16438         var _this = this;
16439         var cmp = function(a,b) {   
16440             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16441         };
16442         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16443             throw "No top level modules to build";
16444         }
16445         
16446         // make a flat list in order of modules to build.
16447         var mods = this.topModule ? [ this.topModule ] : [];
16448                 
16449         
16450         // elmodules (is a list of DOM based modules )
16451         Roo.each(this.elmodules, function(e) {
16452             mods.push(e);
16453             if (!this.topModule &&
16454                 typeof(e.parent) == 'string' &&
16455                 e.parent.substring(0,1) == '#' &&
16456                 Roo.get(e.parent.substr(1))
16457                ) {
16458                 
16459                 _this.topModule = e;
16460             }
16461             
16462         });
16463
16464         
16465         // add modules to their parents..
16466         var addMod = function(m) {
16467             Roo.debug && Roo.log("build Order: add: " + m.name);
16468                 
16469             mods.push(m);
16470             if (m.modules && !m.disabled) {
16471                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16472                 m.modules.keySort('ASC',  cmp );
16473                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16474     
16475                 m.modules.each(addMod);
16476             } else {
16477                 Roo.debug && Roo.log("build Order: no child modules");
16478             }
16479             // not sure if this is used any more..
16480             if (m.finalize) {
16481                 m.finalize.name = m.name + " (clean up) ";
16482                 mods.push(m.finalize);
16483             }
16484             
16485         }
16486         if (this.topModule && this.topModule.modules) { 
16487             this.topModule.modules.keySort('ASC',  cmp );
16488             this.topModule.modules.each(addMod);
16489         } 
16490         return mods;
16491     },
16492     
16493      /**
16494      * Build the registered modules.
16495      * @param {Object} parent element.
16496      * @param {Function} optional method to call after module has been added.
16497      * 
16498      */ 
16499    
16500     build : function(opts) 
16501     {
16502         
16503         if (typeof(opts) != 'undefined') {
16504             Roo.apply(this,opts);
16505         }
16506         
16507         this.preBuild();
16508         var mods = this.buildOrder();
16509       
16510         //this.allmods = mods;
16511         //Roo.debug && Roo.log(mods);
16512         //return;
16513         if (!mods.length) { // should not happen
16514             throw "NO modules!!!";
16515         }
16516         
16517         
16518         var msg = "Building Interface...";
16519         // flash it up as modal - so we store the mask!?
16520         if (!this.hideProgress && Roo.MessageBox) {
16521             Roo.MessageBox.show({ title: 'loading' });
16522             Roo.MessageBox.show({
16523                title: "Please wait...",
16524                msg: msg,
16525                width:450,
16526                progress:true,
16527                closable:false,
16528                modal: false
16529               
16530             });
16531         }
16532         var total = mods.length;
16533         
16534         var _this = this;
16535         var progressRun = function() {
16536             if (!mods.length) {
16537                 Roo.debug && Roo.log('hide?');
16538                 if (!this.hideProgress && Roo.MessageBox) {
16539                     Roo.MessageBox.hide();
16540                 }
16541                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16542                 
16543                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16544                 
16545                 // THE END...
16546                 return false;   
16547             }
16548             
16549             var m = mods.shift();
16550             
16551             
16552             Roo.debug && Roo.log(m);
16553             // not sure if this is supported any more.. - modules that are are just function
16554             if (typeof(m) == 'function') { 
16555                 m.call(this);
16556                 return progressRun.defer(10, _this);
16557             } 
16558             
16559             
16560             msg = "Building Interface " + (total  - mods.length) + 
16561                     " of " + total + 
16562                     (m.name ? (' - ' + m.name) : '');
16563                         Roo.debug && Roo.log(msg);
16564             if (!_this.hideProgress &&  Roo.MessageBox) { 
16565                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16566             }
16567             
16568          
16569             // is the module disabled?
16570             var disabled = (typeof(m.disabled) == 'function') ?
16571                 m.disabled.call(m.module.disabled) : m.disabled;    
16572             
16573             
16574             if (disabled) {
16575                 return progressRun(); // we do not update the display!
16576             }
16577             
16578             // now build 
16579             
16580                         
16581                         
16582             m.render();
16583             // it's 10 on top level, and 1 on others??? why...
16584             return progressRun.defer(10, _this);
16585              
16586         }
16587         progressRun.defer(1, _this);
16588      
16589         
16590         
16591     },
16592         
16593         
16594         /**
16595          * Event Object.
16596          *
16597          *
16598          */
16599         event: false, 
16600     /**
16601          * wrapper for event.on - aliased later..  
16602          * Typically use to register a event handler for register:
16603          *
16604          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16605          *
16606          */
16607     on : false
16608    
16609     
16610     
16611 });
16612
16613 Roo.XComponent.event = new Roo.util.Observable({
16614                 events : { 
16615                         /**
16616                          * @event register
16617                          * Fires when an Component is registered,
16618                          * set the disable property on the Component to stop registration.
16619                          * @param {Roo.XComponent} c the component being registerd.
16620                          * 
16621                          */
16622                         'register' : true,
16623             /**
16624                          * @event beforebuild
16625                          * Fires before each Component is built
16626                          * can be used to apply permissions.
16627                          * @param {Roo.XComponent} c the component being registerd.
16628                          * 
16629                          */
16630                         'beforebuild' : true,
16631                         /**
16632                          * @event buildcomplete
16633                          * Fires on the top level element when all elements have been built
16634                          * @param {Roo.XComponent} the top level component.
16635                          */
16636                         'buildcomplete' : true
16637                         
16638                 }
16639 });
16640
16641 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16642  //
16643  /**
16644  * marked - a markdown parser
16645  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16646  * https://github.com/chjj/marked
16647  */
16648
16649
16650 /**
16651  *
16652  * Roo.Markdown - is a very crude wrapper around marked..
16653  *
16654  * usage:
16655  * 
16656  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16657  * 
16658  * Note: move the sample code to the bottom of this
16659  * file before uncommenting it.
16660  *
16661  */
16662
16663 Roo.Markdown = {};
16664 Roo.Markdown.toHtml = function(text) {
16665     
16666     var c = new Roo.Markdown.marked.setOptions({
16667             renderer: new Roo.Markdown.marked.Renderer(),
16668             gfm: true,
16669             tables: true,
16670             breaks: false,
16671             pedantic: false,
16672             sanitize: false,
16673             smartLists: true,
16674             smartypants: false
16675           });
16676     // A FEW HACKS!!?
16677     
16678     text = text.replace(/\\\n/g,' ');
16679     return Roo.Markdown.marked(text);
16680 };
16681 //
16682 // converter
16683 //
16684 // Wraps all "globals" so that the only thing
16685 // exposed is makeHtml().
16686 //
16687 (function() {
16688     
16689     /**
16690      * Block-Level Grammar
16691      */
16692     
16693     var block = {
16694       newline: /^\n+/,
16695       code: /^( {4}[^\n]+\n*)+/,
16696       fences: noop,
16697       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16698       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16699       nptable: noop,
16700       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16701       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16702       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16703       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16704       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16705       table: noop,
16706       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16707       text: /^[^\n]+/
16708     };
16709     
16710     block.bullet = /(?:[*+-]|\d+\.)/;
16711     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16712     block.item = replace(block.item, 'gm')
16713       (/bull/g, block.bullet)
16714       ();
16715     
16716     block.list = replace(block.list)
16717       (/bull/g, block.bullet)
16718       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16719       ('def', '\\n+(?=' + block.def.source + ')')
16720       ();
16721     
16722     block.blockquote = replace(block.blockquote)
16723       ('def', block.def)
16724       ();
16725     
16726     block._tag = '(?!(?:'
16727       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16728       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16729       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16730     
16731     block.html = replace(block.html)
16732       ('comment', /<!--[\s\S]*?-->/)
16733       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16734       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16735       (/tag/g, block._tag)
16736       ();
16737     
16738     block.paragraph = replace(block.paragraph)
16739       ('hr', block.hr)
16740       ('heading', block.heading)
16741       ('lheading', block.lheading)
16742       ('blockquote', block.blockquote)
16743       ('tag', '<' + block._tag)
16744       ('def', block.def)
16745       ();
16746     
16747     /**
16748      * Normal Block Grammar
16749      */
16750     
16751     block.normal = merge({}, block);
16752     
16753     /**
16754      * GFM Block Grammar
16755      */
16756     
16757     block.gfm = merge({}, block.normal, {
16758       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16759       paragraph: /^/,
16760       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16761     });
16762     
16763     block.gfm.paragraph = replace(block.paragraph)
16764       ('(?!', '(?!'
16765         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16766         + block.list.source.replace('\\1', '\\3') + '|')
16767       ();
16768     
16769     /**
16770      * GFM + Tables Block Grammar
16771      */
16772     
16773     block.tables = merge({}, block.gfm, {
16774       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16775       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16776     });
16777     
16778     /**
16779      * Block Lexer
16780      */
16781     
16782     function Lexer(options) {
16783       this.tokens = [];
16784       this.tokens.links = {};
16785       this.options = options || marked.defaults;
16786       this.rules = block.normal;
16787     
16788       if (this.options.gfm) {
16789         if (this.options.tables) {
16790           this.rules = block.tables;
16791         } else {
16792           this.rules = block.gfm;
16793         }
16794       }
16795     }
16796     
16797     /**
16798      * Expose Block Rules
16799      */
16800     
16801     Lexer.rules = block;
16802     
16803     /**
16804      * Static Lex Method
16805      */
16806     
16807     Lexer.lex = function(src, options) {
16808       var lexer = new Lexer(options);
16809       return lexer.lex(src);
16810     };
16811     
16812     /**
16813      * Preprocessing
16814      */
16815     
16816     Lexer.prototype.lex = function(src) {
16817       src = src
16818         .replace(/\r\n|\r/g, '\n')
16819         .replace(/\t/g, '    ')
16820         .replace(/\u00a0/g, ' ')
16821         .replace(/\u2424/g, '\n');
16822     
16823       return this.token(src, true);
16824     };
16825     
16826     /**
16827      * Lexing
16828      */
16829     
16830     Lexer.prototype.token = function(src, top, bq) {
16831       var src = src.replace(/^ +$/gm, '')
16832         , next
16833         , loose
16834         , cap
16835         , bull
16836         , b
16837         , item
16838         , space
16839         , i
16840         , l;
16841     
16842       while (src) {
16843         // newline
16844         if (cap = this.rules.newline.exec(src)) {
16845           src = src.substring(cap[0].length);
16846           if (cap[0].length > 1) {
16847             this.tokens.push({
16848               type: 'space'
16849             });
16850           }
16851         }
16852     
16853         // code
16854         if (cap = this.rules.code.exec(src)) {
16855           src = src.substring(cap[0].length);
16856           cap = cap[0].replace(/^ {4}/gm, '');
16857           this.tokens.push({
16858             type: 'code',
16859             text: !this.options.pedantic
16860               ? cap.replace(/\n+$/, '')
16861               : cap
16862           });
16863           continue;
16864         }
16865     
16866         // fences (gfm)
16867         if (cap = this.rules.fences.exec(src)) {
16868           src = src.substring(cap[0].length);
16869           this.tokens.push({
16870             type: 'code',
16871             lang: cap[2],
16872             text: cap[3] || ''
16873           });
16874           continue;
16875         }
16876     
16877         // heading
16878         if (cap = this.rules.heading.exec(src)) {
16879           src = src.substring(cap[0].length);
16880           this.tokens.push({
16881             type: 'heading',
16882             depth: cap[1].length,
16883             text: cap[2]
16884           });
16885           continue;
16886         }
16887     
16888         // table no leading pipe (gfm)
16889         if (top && (cap = this.rules.nptable.exec(src))) {
16890           src = src.substring(cap[0].length);
16891     
16892           item = {
16893             type: 'table',
16894             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16895             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16896             cells: cap[3].replace(/\n$/, '').split('\n')
16897           };
16898     
16899           for (i = 0; i < item.align.length; i++) {
16900             if (/^ *-+: *$/.test(item.align[i])) {
16901               item.align[i] = 'right';
16902             } else if (/^ *:-+: *$/.test(item.align[i])) {
16903               item.align[i] = 'center';
16904             } else if (/^ *:-+ *$/.test(item.align[i])) {
16905               item.align[i] = 'left';
16906             } else {
16907               item.align[i] = null;
16908             }
16909           }
16910     
16911           for (i = 0; i < item.cells.length; i++) {
16912             item.cells[i] = item.cells[i].split(/ *\| */);
16913           }
16914     
16915           this.tokens.push(item);
16916     
16917           continue;
16918         }
16919     
16920         // lheading
16921         if (cap = this.rules.lheading.exec(src)) {
16922           src = src.substring(cap[0].length);
16923           this.tokens.push({
16924             type: 'heading',
16925             depth: cap[2] === '=' ? 1 : 2,
16926             text: cap[1]
16927           });
16928           continue;
16929         }
16930     
16931         // hr
16932         if (cap = this.rules.hr.exec(src)) {
16933           src = src.substring(cap[0].length);
16934           this.tokens.push({
16935             type: 'hr'
16936           });
16937           continue;
16938         }
16939     
16940         // blockquote
16941         if (cap = this.rules.blockquote.exec(src)) {
16942           src = src.substring(cap[0].length);
16943     
16944           this.tokens.push({
16945             type: 'blockquote_start'
16946           });
16947     
16948           cap = cap[0].replace(/^ *> ?/gm, '');
16949     
16950           // Pass `top` to keep the current
16951           // "toplevel" state. This is exactly
16952           // how markdown.pl works.
16953           this.token(cap, top, true);
16954     
16955           this.tokens.push({
16956             type: 'blockquote_end'
16957           });
16958     
16959           continue;
16960         }
16961     
16962         // list
16963         if (cap = this.rules.list.exec(src)) {
16964           src = src.substring(cap[0].length);
16965           bull = cap[2];
16966     
16967           this.tokens.push({
16968             type: 'list_start',
16969             ordered: bull.length > 1
16970           });
16971     
16972           // Get each top-level item.
16973           cap = cap[0].match(this.rules.item);
16974     
16975           next = false;
16976           l = cap.length;
16977           i = 0;
16978     
16979           for (; i < l; i++) {
16980             item = cap[i];
16981     
16982             // Remove the list item's bullet
16983             // so it is seen as the next token.
16984             space = item.length;
16985             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16986     
16987             // Outdent whatever the
16988             // list item contains. Hacky.
16989             if (~item.indexOf('\n ')) {
16990               space -= item.length;
16991               item = !this.options.pedantic
16992                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16993                 : item.replace(/^ {1,4}/gm, '');
16994             }
16995     
16996             // Determine whether the next list item belongs here.
16997             // Backpedal if it does not belong in this list.
16998             if (this.options.smartLists && i !== l - 1) {
16999               b = block.bullet.exec(cap[i + 1])[0];
17000               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17001                 src = cap.slice(i + 1).join('\n') + src;
17002                 i = l - 1;
17003               }
17004             }
17005     
17006             // Determine whether item is loose or not.
17007             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17008             // for discount behavior.
17009             loose = next || /\n\n(?!\s*$)/.test(item);
17010             if (i !== l - 1) {
17011               next = item.charAt(item.length - 1) === '\n';
17012               if (!loose) { loose = next; }
17013             }
17014     
17015             this.tokens.push({
17016               type: loose
17017                 ? 'loose_item_start'
17018                 : 'list_item_start'
17019             });
17020     
17021             // Recurse.
17022             this.token(item, false, bq);
17023     
17024             this.tokens.push({
17025               type: 'list_item_end'
17026             });
17027           }
17028     
17029           this.tokens.push({
17030             type: 'list_end'
17031           });
17032     
17033           continue;
17034         }
17035     
17036         // html
17037         if (cap = this.rules.html.exec(src)) {
17038           src = src.substring(cap[0].length);
17039           this.tokens.push({
17040             type: this.options.sanitize
17041               ? 'paragraph'
17042               : 'html',
17043             pre: !this.options.sanitizer
17044               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17045             text: cap[0]
17046           });
17047           continue;
17048         }
17049     
17050         // def
17051         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17052           src = src.substring(cap[0].length);
17053           this.tokens.links[cap[1].toLowerCase()] = {
17054             href: cap[2],
17055             title: cap[3]
17056           };
17057           continue;
17058         }
17059     
17060         // table (gfm)
17061         if (top && (cap = this.rules.table.exec(src))) {
17062           src = src.substring(cap[0].length);
17063     
17064           item = {
17065             type: 'table',
17066             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17067             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17068             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17069           };
17070     
17071           for (i = 0; i < item.align.length; i++) {
17072             if (/^ *-+: *$/.test(item.align[i])) {
17073               item.align[i] = 'right';
17074             } else if (/^ *:-+: *$/.test(item.align[i])) {
17075               item.align[i] = 'center';
17076             } else if (/^ *:-+ *$/.test(item.align[i])) {
17077               item.align[i] = 'left';
17078             } else {
17079               item.align[i] = null;
17080             }
17081           }
17082     
17083           for (i = 0; i < item.cells.length; i++) {
17084             item.cells[i] = item.cells[i]
17085               .replace(/^ *\| *| *\| *$/g, '')
17086               .split(/ *\| */);
17087           }
17088     
17089           this.tokens.push(item);
17090     
17091           continue;
17092         }
17093     
17094         // top-level paragraph
17095         if (top && (cap = this.rules.paragraph.exec(src))) {
17096           src = src.substring(cap[0].length);
17097           this.tokens.push({
17098             type: 'paragraph',
17099             text: cap[1].charAt(cap[1].length - 1) === '\n'
17100               ? cap[1].slice(0, -1)
17101               : cap[1]
17102           });
17103           continue;
17104         }
17105     
17106         // text
17107         if (cap = this.rules.text.exec(src)) {
17108           // Top-level should never reach here.
17109           src = src.substring(cap[0].length);
17110           this.tokens.push({
17111             type: 'text',
17112             text: cap[0]
17113           });
17114           continue;
17115         }
17116     
17117         if (src) {
17118           throw new
17119             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17120         }
17121       }
17122     
17123       return this.tokens;
17124     };
17125     
17126     /**
17127      * Inline-Level Grammar
17128      */
17129     
17130     var inline = {
17131       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17132       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17133       url: noop,
17134       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17135       link: /^!?\[(inside)\]\(href\)/,
17136       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17137       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17138       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17139       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17140       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17141       br: /^ {2,}\n(?!\s*$)/,
17142       del: noop,
17143       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17144     };
17145     
17146     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17147     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17148     
17149     inline.link = replace(inline.link)
17150       ('inside', inline._inside)
17151       ('href', inline._href)
17152       ();
17153     
17154     inline.reflink = replace(inline.reflink)
17155       ('inside', inline._inside)
17156       ();
17157     
17158     /**
17159      * Normal Inline Grammar
17160      */
17161     
17162     inline.normal = merge({}, inline);
17163     
17164     /**
17165      * Pedantic Inline Grammar
17166      */
17167     
17168     inline.pedantic = merge({}, inline.normal, {
17169       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17170       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17171     });
17172     
17173     /**
17174      * GFM Inline Grammar
17175      */
17176     
17177     inline.gfm = merge({}, inline.normal, {
17178       escape: replace(inline.escape)('])', '~|])')(),
17179       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17180       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17181       text: replace(inline.text)
17182         (']|', '~]|')
17183         ('|', '|https?://|')
17184         ()
17185     });
17186     
17187     /**
17188      * GFM + Line Breaks Inline Grammar
17189      */
17190     
17191     inline.breaks = merge({}, inline.gfm, {
17192       br: replace(inline.br)('{2,}', '*')(),
17193       text: replace(inline.gfm.text)('{2,}', '*')()
17194     });
17195     
17196     /**
17197      * Inline Lexer & Compiler
17198      */
17199     
17200     function InlineLexer(links, options) {
17201       this.options = options || marked.defaults;
17202       this.links = links;
17203       this.rules = inline.normal;
17204       this.renderer = this.options.renderer || new Renderer;
17205       this.renderer.options = this.options;
17206     
17207       if (!this.links) {
17208         throw new
17209           Error('Tokens array requires a `links` property.');
17210       }
17211     
17212       if (this.options.gfm) {
17213         if (this.options.breaks) {
17214           this.rules = inline.breaks;
17215         } else {
17216           this.rules = inline.gfm;
17217         }
17218       } else if (this.options.pedantic) {
17219         this.rules = inline.pedantic;
17220       }
17221     }
17222     
17223     /**
17224      * Expose Inline Rules
17225      */
17226     
17227     InlineLexer.rules = inline;
17228     
17229     /**
17230      * Static Lexing/Compiling Method
17231      */
17232     
17233     InlineLexer.output = function(src, links, options) {
17234       var inline = new InlineLexer(links, options);
17235       return inline.output(src);
17236     };
17237     
17238     /**
17239      * Lexing/Compiling
17240      */
17241     
17242     InlineLexer.prototype.output = function(src) {
17243       var out = ''
17244         , link
17245         , text
17246         , href
17247         , cap;
17248     
17249       while (src) {
17250         // escape
17251         if (cap = this.rules.escape.exec(src)) {
17252           src = src.substring(cap[0].length);
17253           out += cap[1];
17254           continue;
17255         }
17256     
17257         // autolink
17258         if (cap = this.rules.autolink.exec(src)) {
17259           src = src.substring(cap[0].length);
17260           if (cap[2] === '@') {
17261             text = cap[1].charAt(6) === ':'
17262               ? this.mangle(cap[1].substring(7))
17263               : this.mangle(cap[1]);
17264             href = this.mangle('mailto:') + text;
17265           } else {
17266             text = escape(cap[1]);
17267             href = text;
17268           }
17269           out += this.renderer.link(href, null, text);
17270           continue;
17271         }
17272     
17273         // url (gfm)
17274         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17275           src = src.substring(cap[0].length);
17276           text = escape(cap[1]);
17277           href = text;
17278           out += this.renderer.link(href, null, text);
17279           continue;
17280         }
17281     
17282         // tag
17283         if (cap = this.rules.tag.exec(src)) {
17284           if (!this.inLink && /^<a /i.test(cap[0])) {
17285             this.inLink = true;
17286           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17287             this.inLink = false;
17288           }
17289           src = src.substring(cap[0].length);
17290           out += this.options.sanitize
17291             ? this.options.sanitizer
17292               ? this.options.sanitizer(cap[0])
17293               : escape(cap[0])
17294             : cap[0];
17295           continue;
17296         }
17297     
17298         // link
17299         if (cap = this.rules.link.exec(src)) {
17300           src = src.substring(cap[0].length);
17301           this.inLink = true;
17302           out += this.outputLink(cap, {
17303             href: cap[2],
17304             title: cap[3]
17305           });
17306           this.inLink = false;
17307           continue;
17308         }
17309     
17310         // reflink, nolink
17311         if ((cap = this.rules.reflink.exec(src))
17312             || (cap = this.rules.nolink.exec(src))) {
17313           src = src.substring(cap[0].length);
17314           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17315           link = this.links[link.toLowerCase()];
17316           if (!link || !link.href) {
17317             out += cap[0].charAt(0);
17318             src = cap[0].substring(1) + src;
17319             continue;
17320           }
17321           this.inLink = true;
17322           out += this.outputLink(cap, link);
17323           this.inLink = false;
17324           continue;
17325         }
17326     
17327         // strong
17328         if (cap = this.rules.strong.exec(src)) {
17329           src = src.substring(cap[0].length);
17330           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17331           continue;
17332         }
17333     
17334         // em
17335         if (cap = this.rules.em.exec(src)) {
17336           src = src.substring(cap[0].length);
17337           out += this.renderer.em(this.output(cap[2] || cap[1]));
17338           continue;
17339         }
17340     
17341         // code
17342         if (cap = this.rules.code.exec(src)) {
17343           src = src.substring(cap[0].length);
17344           out += this.renderer.codespan(escape(cap[2], true));
17345           continue;
17346         }
17347     
17348         // br
17349         if (cap = this.rules.br.exec(src)) {
17350           src = src.substring(cap[0].length);
17351           out += this.renderer.br();
17352           continue;
17353         }
17354     
17355         // del (gfm)
17356         if (cap = this.rules.del.exec(src)) {
17357           src = src.substring(cap[0].length);
17358           out += this.renderer.del(this.output(cap[1]));
17359           continue;
17360         }
17361     
17362         // text
17363         if (cap = this.rules.text.exec(src)) {
17364           src = src.substring(cap[0].length);
17365           out += this.renderer.text(escape(this.smartypants(cap[0])));
17366           continue;
17367         }
17368     
17369         if (src) {
17370           throw new
17371             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17372         }
17373       }
17374     
17375       return out;
17376     };
17377     
17378     /**
17379      * Compile Link
17380      */
17381     
17382     InlineLexer.prototype.outputLink = function(cap, link) {
17383       var href = escape(link.href)
17384         , title = link.title ? escape(link.title) : null;
17385     
17386       return cap[0].charAt(0) !== '!'
17387         ? this.renderer.link(href, title, this.output(cap[1]))
17388         : this.renderer.image(href, title, escape(cap[1]));
17389     };
17390     
17391     /**
17392      * Smartypants Transformations
17393      */
17394     
17395     InlineLexer.prototype.smartypants = function(text) {
17396       if (!this.options.smartypants)  { return text; }
17397       return text
17398         // em-dashes
17399         .replace(/---/g, '\u2014')
17400         // en-dashes
17401         .replace(/--/g, '\u2013')
17402         // opening singles
17403         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17404         // closing singles & apostrophes
17405         .replace(/'/g, '\u2019')
17406         // opening doubles
17407         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17408         // closing doubles
17409         .replace(/"/g, '\u201d')
17410         // ellipses
17411         .replace(/\.{3}/g, '\u2026');
17412     };
17413     
17414     /**
17415      * Mangle Links
17416      */
17417     
17418     InlineLexer.prototype.mangle = function(text) {
17419       if (!this.options.mangle) { return text; }
17420       var out = ''
17421         , l = text.length
17422         , i = 0
17423         , ch;
17424     
17425       for (; i < l; i++) {
17426         ch = text.charCodeAt(i);
17427         if (Math.random() > 0.5) {
17428           ch = 'x' + ch.toString(16);
17429         }
17430         out += '&#' + ch + ';';
17431       }
17432     
17433       return out;
17434     };
17435     
17436     /**
17437      * Renderer
17438      */
17439     
17440     function Renderer(options) {
17441       this.options = options || {};
17442     }
17443     
17444     Renderer.prototype.code = function(code, lang, escaped) {
17445       if (this.options.highlight) {
17446         var out = this.options.highlight(code, lang);
17447         if (out != null && out !== code) {
17448           escaped = true;
17449           code = out;
17450         }
17451       } else {
17452             // hack!!! - it's already escapeD?
17453             escaped = true;
17454       }
17455     
17456       if (!lang) {
17457         return '<pre><code>'
17458           + (escaped ? code : escape(code, true))
17459           + '\n</code></pre>';
17460       }
17461     
17462       return '<pre><code class="'
17463         + this.options.langPrefix
17464         + escape(lang, true)
17465         + '">'
17466         + (escaped ? code : escape(code, true))
17467         + '\n</code></pre>\n';
17468     };
17469     
17470     Renderer.prototype.blockquote = function(quote) {
17471       return '<blockquote>\n' + quote + '</blockquote>\n';
17472     };
17473     
17474     Renderer.prototype.html = function(html) {
17475       return html;
17476     };
17477     
17478     Renderer.prototype.heading = function(text, level, raw) {
17479       return '<h'
17480         + level
17481         + ' id="'
17482         + this.options.headerPrefix
17483         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17484         + '">'
17485         + text
17486         + '</h'
17487         + level
17488         + '>\n';
17489     };
17490     
17491     Renderer.prototype.hr = function() {
17492       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17493     };
17494     
17495     Renderer.prototype.list = function(body, ordered) {
17496       var type = ordered ? 'ol' : 'ul';
17497       return '<' + type + '>\n' + body + '</' + type + '>\n';
17498     };
17499     
17500     Renderer.prototype.listitem = function(text) {
17501       return '<li>' + text + '</li>\n';
17502     };
17503     
17504     Renderer.prototype.paragraph = function(text) {
17505       return '<p>' + text + '</p>\n';
17506     };
17507     
17508     Renderer.prototype.table = function(header, body) {
17509       return '<table class="table table-striped">\n'
17510         + '<thead>\n'
17511         + header
17512         + '</thead>\n'
17513         + '<tbody>\n'
17514         + body
17515         + '</tbody>\n'
17516         + '</table>\n';
17517     };
17518     
17519     Renderer.prototype.tablerow = function(content) {
17520       return '<tr>\n' + content + '</tr>\n';
17521     };
17522     
17523     Renderer.prototype.tablecell = function(content, flags) {
17524       var type = flags.header ? 'th' : 'td';
17525       var tag = flags.align
17526         ? '<' + type + ' style="text-align:' + flags.align + '">'
17527         : '<' + type + '>';
17528       return tag + content + '</' + type + '>\n';
17529     };
17530     
17531     // span level renderer
17532     Renderer.prototype.strong = function(text) {
17533       return '<strong>' + text + '</strong>';
17534     };
17535     
17536     Renderer.prototype.em = function(text) {
17537       return '<em>' + text + '</em>';
17538     };
17539     
17540     Renderer.prototype.codespan = function(text) {
17541       return '<code>' + text + '</code>';
17542     };
17543     
17544     Renderer.prototype.br = function() {
17545       return this.options.xhtml ? '<br/>' : '<br>';
17546     };
17547     
17548     Renderer.prototype.del = function(text) {
17549       return '<del>' + text + '</del>';
17550     };
17551     
17552     Renderer.prototype.link = function(href, title, text) {
17553       if (this.options.sanitize) {
17554         try {
17555           var prot = decodeURIComponent(unescape(href))
17556             .replace(/[^\w:]/g, '')
17557             .toLowerCase();
17558         } catch (e) {
17559           return '';
17560         }
17561         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17562           return '';
17563         }
17564       }
17565       var out = '<a href="' + href + '"';
17566       if (title) {
17567         out += ' title="' + title + '"';
17568       }
17569       out += '>' + text + '</a>';
17570       return out;
17571     };
17572     
17573     Renderer.prototype.image = function(href, title, text) {
17574       var out = '<img src="' + href + '" alt="' + text + '"';
17575       if (title) {
17576         out += ' title="' + title + '"';
17577       }
17578       out += this.options.xhtml ? '/>' : '>';
17579       return out;
17580     };
17581     
17582     Renderer.prototype.text = function(text) {
17583       return text;
17584     };
17585     
17586     /**
17587      * Parsing & Compiling
17588      */
17589     
17590     function Parser(options) {
17591       this.tokens = [];
17592       this.token = null;
17593       this.options = options || marked.defaults;
17594       this.options.renderer = this.options.renderer || new Renderer;
17595       this.renderer = this.options.renderer;
17596       this.renderer.options = this.options;
17597     }
17598     
17599     /**
17600      * Static Parse Method
17601      */
17602     
17603     Parser.parse = function(src, options, renderer) {
17604       var parser = new Parser(options, renderer);
17605       return parser.parse(src);
17606     };
17607     
17608     /**
17609      * Parse Loop
17610      */
17611     
17612     Parser.prototype.parse = function(src) {
17613       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17614       this.tokens = src.reverse();
17615     
17616       var out = '';
17617       while (this.next()) {
17618         out += this.tok();
17619       }
17620     
17621       return out;
17622     };
17623     
17624     /**
17625      * Next Token
17626      */
17627     
17628     Parser.prototype.next = function() {
17629       return this.token = this.tokens.pop();
17630     };
17631     
17632     /**
17633      * Preview Next Token
17634      */
17635     
17636     Parser.prototype.peek = function() {
17637       return this.tokens[this.tokens.length - 1] || 0;
17638     };
17639     
17640     /**
17641      * Parse Text Tokens
17642      */
17643     
17644     Parser.prototype.parseText = function() {
17645       var body = this.token.text;
17646     
17647       while (this.peek().type === 'text') {
17648         body += '\n' + this.next().text;
17649       }
17650     
17651       return this.inline.output(body);
17652     };
17653     
17654     /**
17655      * Parse Current Token
17656      */
17657     
17658     Parser.prototype.tok = function() {
17659       switch (this.token.type) {
17660         case 'space': {
17661           return '';
17662         }
17663         case 'hr': {
17664           return this.renderer.hr();
17665         }
17666         case 'heading': {
17667           return this.renderer.heading(
17668             this.inline.output(this.token.text),
17669             this.token.depth,
17670             this.token.text);
17671         }
17672         case 'code': {
17673           return this.renderer.code(this.token.text,
17674             this.token.lang,
17675             this.token.escaped);
17676         }
17677         case 'table': {
17678           var header = ''
17679             , body = ''
17680             , i
17681             , row
17682             , cell
17683             , flags
17684             , j;
17685     
17686           // header
17687           cell = '';
17688           for (i = 0; i < this.token.header.length; i++) {
17689             flags = { header: true, align: this.token.align[i] };
17690             cell += this.renderer.tablecell(
17691               this.inline.output(this.token.header[i]),
17692               { header: true, align: this.token.align[i] }
17693             );
17694           }
17695           header += this.renderer.tablerow(cell);
17696     
17697           for (i = 0; i < this.token.cells.length; i++) {
17698             row = this.token.cells[i];
17699     
17700             cell = '';
17701             for (j = 0; j < row.length; j++) {
17702               cell += this.renderer.tablecell(
17703                 this.inline.output(row[j]),
17704                 { header: false, align: this.token.align[j] }
17705               );
17706             }
17707     
17708             body += this.renderer.tablerow(cell);
17709           }
17710           return this.renderer.table(header, body);
17711         }
17712         case 'blockquote_start': {
17713           var body = '';
17714     
17715           while (this.next().type !== 'blockquote_end') {
17716             body += this.tok();
17717           }
17718     
17719           return this.renderer.blockquote(body);
17720         }
17721         case 'list_start': {
17722           var body = ''
17723             , ordered = this.token.ordered;
17724     
17725           while (this.next().type !== 'list_end') {
17726             body += this.tok();
17727           }
17728     
17729           return this.renderer.list(body, ordered);
17730         }
17731         case 'list_item_start': {
17732           var body = '';
17733     
17734           while (this.next().type !== 'list_item_end') {
17735             body += this.token.type === 'text'
17736               ? this.parseText()
17737               : this.tok();
17738           }
17739     
17740           return this.renderer.listitem(body);
17741         }
17742         case 'loose_item_start': {
17743           var body = '';
17744     
17745           while (this.next().type !== 'list_item_end') {
17746             body += this.tok();
17747           }
17748     
17749           return this.renderer.listitem(body);
17750         }
17751         case 'html': {
17752           var html = !this.token.pre && !this.options.pedantic
17753             ? this.inline.output(this.token.text)
17754             : this.token.text;
17755           return this.renderer.html(html);
17756         }
17757         case 'paragraph': {
17758           return this.renderer.paragraph(this.inline.output(this.token.text));
17759         }
17760         case 'text': {
17761           return this.renderer.paragraph(this.parseText());
17762         }
17763       }
17764     };
17765     
17766     /**
17767      * Helpers
17768      */
17769     
17770     function escape(html, encode) {
17771       return html
17772         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17773         .replace(/</g, '&lt;')
17774         .replace(/>/g, '&gt;')
17775         .replace(/"/g, '&quot;')
17776         .replace(/'/g, '&#39;');
17777     }
17778     
17779     function unescape(html) {
17780         // explicitly match decimal, hex, and named HTML entities 
17781       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17782         n = n.toLowerCase();
17783         if (n === 'colon') { return ':'; }
17784         if (n.charAt(0) === '#') {
17785           return n.charAt(1) === 'x'
17786             ? String.fromCharCode(parseInt(n.substring(2), 16))
17787             : String.fromCharCode(+n.substring(1));
17788         }
17789         return '';
17790       });
17791     }
17792     
17793     function replace(regex, opt) {
17794       regex = regex.source;
17795       opt = opt || '';
17796       return function self(name, val) {
17797         if (!name) { return new RegExp(regex, opt); }
17798         val = val.source || val;
17799         val = val.replace(/(^|[^\[])\^/g, '$1');
17800         regex = regex.replace(name, val);
17801         return self;
17802       };
17803     }
17804     
17805     function noop() {}
17806     noop.exec = noop;
17807     
17808     function merge(obj) {
17809       var i = 1
17810         , target
17811         , key;
17812     
17813       for (; i < arguments.length; i++) {
17814         target = arguments[i];
17815         for (key in target) {
17816           if (Object.prototype.hasOwnProperty.call(target, key)) {
17817             obj[key] = target[key];
17818           }
17819         }
17820       }
17821     
17822       return obj;
17823     }
17824     
17825     
17826     /**
17827      * Marked
17828      */
17829     
17830     function marked(src, opt, callback) {
17831       if (callback || typeof opt === 'function') {
17832         if (!callback) {
17833           callback = opt;
17834           opt = null;
17835         }
17836     
17837         opt = merge({}, marked.defaults, opt || {});
17838     
17839         var highlight = opt.highlight
17840           , tokens
17841           , pending
17842           , i = 0;
17843     
17844         try {
17845           tokens = Lexer.lex(src, opt)
17846         } catch (e) {
17847           return callback(e);
17848         }
17849     
17850         pending = tokens.length;
17851     
17852         var done = function(err) {
17853           if (err) {
17854             opt.highlight = highlight;
17855             return callback(err);
17856           }
17857     
17858           var out;
17859     
17860           try {
17861             out = Parser.parse(tokens, opt);
17862           } catch (e) {
17863             err = e;
17864           }
17865     
17866           opt.highlight = highlight;
17867     
17868           return err
17869             ? callback(err)
17870             : callback(null, out);
17871         };
17872     
17873         if (!highlight || highlight.length < 3) {
17874           return done();
17875         }
17876     
17877         delete opt.highlight;
17878     
17879         if (!pending) { return done(); }
17880     
17881         for (; i < tokens.length; i++) {
17882           (function(token) {
17883             if (token.type !== 'code') {
17884               return --pending || done();
17885             }
17886             return highlight(token.text, token.lang, function(err, code) {
17887               if (err) { return done(err); }
17888               if (code == null || code === token.text) {
17889                 return --pending || done();
17890               }
17891               token.text = code;
17892               token.escaped = true;
17893               --pending || done();
17894             });
17895           })(tokens[i]);
17896         }
17897     
17898         return;
17899       }
17900       try {
17901         if (opt) { opt = merge({}, marked.defaults, opt); }
17902         return Parser.parse(Lexer.lex(src, opt), opt);
17903       } catch (e) {
17904         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17905         if ((opt || marked.defaults).silent) {
17906           return '<p>An error occured:</p><pre>'
17907             + escape(e.message + '', true)
17908             + '</pre>';
17909         }
17910         throw e;
17911       }
17912     }
17913     
17914     /**
17915      * Options
17916      */
17917     
17918     marked.options =
17919     marked.setOptions = function(opt) {
17920       merge(marked.defaults, opt);
17921       return marked;
17922     };
17923     
17924     marked.defaults = {
17925       gfm: true,
17926       tables: true,
17927       breaks: false,
17928       pedantic: false,
17929       sanitize: false,
17930       sanitizer: null,
17931       mangle: true,
17932       smartLists: false,
17933       silent: false,
17934       highlight: null,
17935       langPrefix: 'lang-',
17936       smartypants: false,
17937       headerPrefix: '',
17938       renderer: new Renderer,
17939       xhtml: false
17940     };
17941     
17942     /**
17943      * Expose
17944      */
17945     
17946     marked.Parser = Parser;
17947     marked.parser = Parser.parse;
17948     
17949     marked.Renderer = Renderer;
17950     
17951     marked.Lexer = Lexer;
17952     marked.lexer = Lexer.lex;
17953     
17954     marked.InlineLexer = InlineLexer;
17955     marked.inlineLexer = InlineLexer.output;
17956     
17957     marked.parse = marked;
17958     
17959     Roo.Markdown.marked = marked;
17960
17961 })();/*
17962  * Based on:
17963  * Ext JS Library 1.1.1
17964  * Copyright(c) 2006-2007, Ext JS, LLC.
17965  *
17966  * Originally Released Under LGPL - original licence link has changed is not relivant.
17967  *
17968  * Fork - LGPL
17969  * <script type="text/javascript">
17970  */
17971
17972
17973
17974 /*
17975  * These classes are derivatives of the similarly named classes in the YUI Library.
17976  * The original license:
17977  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17978  * Code licensed under the BSD License:
17979  * http://developer.yahoo.net/yui/license.txt
17980  */
17981
17982 (function() {
17983
17984 var Event=Roo.EventManager;
17985 var Dom=Roo.lib.Dom;
17986
17987 /**
17988  * @class Roo.dd.DragDrop
17989  * @extends Roo.util.Observable
17990  * Defines the interface and base operation of items that that can be
17991  * dragged or can be drop targets.  It was designed to be extended, overriding
17992  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17993  * Up to three html elements can be associated with a DragDrop instance:
17994  * <ul>
17995  * <li>linked element: the element that is passed into the constructor.
17996  * This is the element which defines the boundaries for interaction with
17997  * other DragDrop objects.</li>
17998  * <li>handle element(s): The drag operation only occurs if the element that
17999  * was clicked matches a handle element.  By default this is the linked
18000  * element, but there are times that you will want only a portion of the
18001  * linked element to initiate the drag operation, and the setHandleElId()
18002  * method provides a way to define this.</li>
18003  * <li>drag element: this represents the element that would be moved along
18004  * with the cursor during a drag operation.  By default, this is the linked
18005  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
18006  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18007  * </li>
18008  * </ul>
18009  * This class should not be instantiated until the onload event to ensure that
18010  * the associated elements are available.
18011  * The following would define a DragDrop obj that would interact with any
18012  * other DragDrop obj in the "group1" group:
18013  * <pre>
18014  *  dd = new Roo.dd.DragDrop("div1", "group1");
18015  * </pre>
18016  * Since none of the event handlers have been implemented, nothing would
18017  * actually happen if you were to run the code above.  Normally you would
18018  * override this class or one of the default implementations, but you can
18019  * also override the methods you want on an instance of the class...
18020  * <pre>
18021  *  dd.onDragDrop = function(e, id) {
18022  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18023  *  }
18024  * </pre>
18025  * @constructor
18026  * @param {String} id of the element that is linked to this instance
18027  * @param {String} sGroup the group of related DragDrop objects
18028  * @param {object} config an object containing configurable attributes
18029  *                Valid properties for DragDrop:
18030  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18031  */
18032 Roo.dd.DragDrop = function(id, sGroup, config) {
18033     if (id) {
18034         this.init(id, sGroup, config);
18035     }
18036     
18037 };
18038
18039 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18040
18041     /**
18042      * The id of the element associated with this object.  This is what we
18043      * refer to as the "linked element" because the size and position of
18044      * this element is used to determine when the drag and drop objects have
18045      * interacted.
18046      * @property id
18047      * @type String
18048      */
18049     id: null,
18050
18051     /**
18052      * Configuration attributes passed into the constructor
18053      * @property config
18054      * @type object
18055      */
18056     config: null,
18057
18058     /**
18059      * The id of the element that will be dragged.  By default this is same
18060      * as the linked element , but could be changed to another element. Ex:
18061      * Roo.dd.DDProxy
18062      * @property dragElId
18063      * @type String
18064      * @private
18065      */
18066     dragElId: null,
18067
18068     /**
18069      * the id of the element that initiates the drag operation.  By default
18070      * this is the linked element, but could be changed to be a child of this
18071      * element.  This lets us do things like only starting the drag when the
18072      * header element within the linked html element is clicked.
18073      * @property handleElId
18074      * @type String
18075      * @private
18076      */
18077     handleElId: null,
18078
18079     /**
18080      * An associative array of HTML tags that will be ignored if clicked.
18081      * @property invalidHandleTypes
18082      * @type {string: string}
18083      */
18084     invalidHandleTypes: null,
18085
18086     /**
18087      * An associative array of ids for elements that will be ignored if clicked
18088      * @property invalidHandleIds
18089      * @type {string: string}
18090      */
18091     invalidHandleIds: null,
18092
18093     /**
18094      * An indexted array of css class names for elements that will be ignored
18095      * if clicked.
18096      * @property invalidHandleClasses
18097      * @type string[]
18098      */
18099     invalidHandleClasses: null,
18100
18101     /**
18102      * The linked element's absolute X position at the time the drag was
18103      * started
18104      * @property startPageX
18105      * @type int
18106      * @private
18107      */
18108     startPageX: 0,
18109
18110     /**
18111      * The linked element's absolute X position at the time the drag was
18112      * started
18113      * @property startPageY
18114      * @type int
18115      * @private
18116      */
18117     startPageY: 0,
18118
18119     /**
18120      * The group defines a logical collection of DragDrop objects that are
18121      * related.  Instances only get events when interacting with other
18122      * DragDrop object in the same group.  This lets us define multiple
18123      * groups using a single DragDrop subclass if we want.
18124      * @property groups
18125      * @type {string: string}
18126      */
18127     groups: null,
18128
18129     /**
18130      * Individual drag/drop instances can be locked.  This will prevent
18131      * onmousedown start drag.
18132      * @property locked
18133      * @type boolean
18134      * @private
18135      */
18136     locked: false,
18137
18138     /**
18139      * Lock this instance
18140      * @method lock
18141      */
18142     lock: function() { this.locked = true; },
18143
18144     /**
18145      * Unlock this instace
18146      * @method unlock
18147      */
18148     unlock: function() { this.locked = false; },
18149
18150     /**
18151      * By default, all insances can be a drop target.  This can be disabled by
18152      * setting isTarget to false.
18153      * @method isTarget
18154      * @type boolean
18155      */
18156     isTarget: true,
18157
18158     /**
18159      * The padding configured for this drag and drop object for calculating
18160      * the drop zone intersection with this object.
18161      * @method padding
18162      * @type int[]
18163      */
18164     padding: null,
18165
18166     /**
18167      * Cached reference to the linked element
18168      * @property _domRef
18169      * @private
18170      */
18171     _domRef: null,
18172
18173     /**
18174      * Internal typeof flag
18175      * @property __ygDragDrop
18176      * @private
18177      */
18178     __ygDragDrop: true,
18179
18180     /**
18181      * Set to true when horizontal contraints are applied
18182      * @property constrainX
18183      * @type boolean
18184      * @private
18185      */
18186     constrainX: false,
18187
18188     /**
18189      * Set to true when vertical contraints are applied
18190      * @property constrainY
18191      * @type boolean
18192      * @private
18193      */
18194     constrainY: false,
18195
18196     /**
18197      * The left constraint
18198      * @property minX
18199      * @type int
18200      * @private
18201      */
18202     minX: 0,
18203
18204     /**
18205      * The right constraint
18206      * @property maxX
18207      * @type int
18208      * @private
18209      */
18210     maxX: 0,
18211
18212     /**
18213      * The up constraint
18214      * @property minY
18215      * @type int
18216      * @type int
18217      * @private
18218      */
18219     minY: 0,
18220
18221     /**
18222      * The down constraint
18223      * @property maxY
18224      * @type int
18225      * @private
18226      */
18227     maxY: 0,
18228
18229     /**
18230      * Maintain offsets when we resetconstraints.  Set to true when you want
18231      * the position of the element relative to its parent to stay the same
18232      * when the page changes
18233      *
18234      * @property maintainOffset
18235      * @type boolean
18236      */
18237     maintainOffset: false,
18238
18239     /**
18240      * Array of pixel locations the element will snap to if we specified a
18241      * horizontal graduation/interval.  This array is generated automatically
18242      * when you define a tick interval.
18243      * @property xTicks
18244      * @type int[]
18245      */
18246     xTicks: null,
18247
18248     /**
18249      * Array of pixel locations the element will snap to if we specified a
18250      * vertical graduation/interval.  This array is generated automatically
18251      * when you define a tick interval.
18252      * @property yTicks
18253      * @type int[]
18254      */
18255     yTicks: null,
18256
18257     /**
18258      * By default the drag and drop instance will only respond to the primary
18259      * button click (left button for a right-handed mouse).  Set to true to
18260      * allow drag and drop to start with any mouse click that is propogated
18261      * by the browser
18262      * @property primaryButtonOnly
18263      * @type boolean
18264      */
18265     primaryButtonOnly: true,
18266
18267     /**
18268      * The availabe property is false until the linked dom element is accessible.
18269      * @property available
18270      * @type boolean
18271      */
18272     available: false,
18273
18274     /**
18275      * By default, drags can only be initiated if the mousedown occurs in the
18276      * region the linked element is.  This is done in part to work around a
18277      * bug in some browsers that mis-report the mousedown if the previous
18278      * mouseup happened outside of the window.  This property is set to true
18279      * if outer handles are defined.
18280      *
18281      * @property hasOuterHandles
18282      * @type boolean
18283      * @default false
18284      */
18285     hasOuterHandles: false,
18286
18287     /**
18288      * Code that executes immediately before the startDrag event
18289      * @method b4StartDrag
18290      * @private
18291      */
18292     b4StartDrag: function(x, y) { },
18293
18294     /**
18295      * Abstract method called after a drag/drop object is clicked
18296      * and the drag or mousedown time thresholds have beeen met.
18297      * @method startDrag
18298      * @param {int} X click location
18299      * @param {int} Y click location
18300      */
18301     startDrag: function(x, y) { /* override this */ },
18302
18303     /**
18304      * Code that executes immediately before the onDrag event
18305      * @method b4Drag
18306      * @private
18307      */
18308     b4Drag: function(e) { },
18309
18310     /**
18311      * Abstract method called during the onMouseMove event while dragging an
18312      * object.
18313      * @method onDrag
18314      * @param {Event} e the mousemove event
18315      */
18316     onDrag: function(e) { /* override this */ },
18317
18318     /**
18319      * Abstract method called when this element fist begins hovering over
18320      * another DragDrop obj
18321      * @method onDragEnter
18322      * @param {Event} e the mousemove event
18323      * @param {String|DragDrop[]} id In POINT mode, the element
18324      * id this is hovering over.  In INTERSECT mode, an array of one or more
18325      * dragdrop items being hovered over.
18326      */
18327     onDragEnter: function(e, id) { /* override this */ },
18328
18329     /**
18330      * Code that executes immediately before the onDragOver event
18331      * @method b4DragOver
18332      * @private
18333      */
18334     b4DragOver: function(e) { },
18335
18336     /**
18337      * Abstract method called when this element is hovering over another
18338      * DragDrop obj
18339      * @method onDragOver
18340      * @param {Event} e the mousemove event
18341      * @param {String|DragDrop[]} id In POINT mode, the element
18342      * id this is hovering over.  In INTERSECT mode, an array of dd items
18343      * being hovered over.
18344      */
18345     onDragOver: function(e, id) { /* override this */ },
18346
18347     /**
18348      * Code that executes immediately before the onDragOut event
18349      * @method b4DragOut
18350      * @private
18351      */
18352     b4DragOut: function(e) { },
18353
18354     /**
18355      * Abstract method called when we are no longer hovering over an element
18356      * @method onDragOut
18357      * @param {Event} e the mousemove event
18358      * @param {String|DragDrop[]} id In POINT mode, the element
18359      * id this was hovering over.  In INTERSECT mode, an array of dd items
18360      * that the mouse is no longer over.
18361      */
18362     onDragOut: function(e, id) { /* override this */ },
18363
18364     /**
18365      * Code that executes immediately before the onDragDrop event
18366      * @method b4DragDrop
18367      * @private
18368      */
18369     b4DragDrop: function(e) { },
18370
18371     /**
18372      * Abstract method called when this item is dropped on another DragDrop
18373      * obj
18374      * @method onDragDrop
18375      * @param {Event} e the mouseup event
18376      * @param {String|DragDrop[]} id In POINT mode, the element
18377      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18378      * was dropped on.
18379      */
18380     onDragDrop: function(e, id) { /* override this */ },
18381
18382     /**
18383      * Abstract method called when this item is dropped on an area with no
18384      * drop target
18385      * @method onInvalidDrop
18386      * @param {Event} e the mouseup event
18387      */
18388     onInvalidDrop: function(e) { /* override this */ },
18389
18390     /**
18391      * Code that executes immediately before the endDrag event
18392      * @method b4EndDrag
18393      * @private
18394      */
18395     b4EndDrag: function(e) { },
18396
18397     /**
18398      * Fired when we are done dragging the object
18399      * @method endDrag
18400      * @param {Event} e the mouseup event
18401      */
18402     endDrag: function(e) { /* override this */ },
18403
18404     /**
18405      * Code executed immediately before the onMouseDown event
18406      * @method b4MouseDown
18407      * @param {Event} e the mousedown event
18408      * @private
18409      */
18410     b4MouseDown: function(e) {  },
18411
18412     /**
18413      * Event handler that fires when a drag/drop obj gets a mousedown
18414      * @method onMouseDown
18415      * @param {Event} e the mousedown event
18416      */
18417     onMouseDown: function(e) { /* override this */ },
18418
18419     /**
18420      * Event handler that fires when a drag/drop obj gets a mouseup
18421      * @method onMouseUp
18422      * @param {Event} e the mouseup event
18423      */
18424     onMouseUp: function(e) { /* override this */ },
18425
18426     /**
18427      * Override the onAvailable method to do what is needed after the initial
18428      * position was determined.
18429      * @method onAvailable
18430      */
18431     onAvailable: function () {
18432     },
18433
18434     /*
18435      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18436      * @type Object
18437      */
18438     defaultPadding : {left:0, right:0, top:0, bottom:0},
18439
18440     /*
18441      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18442  *
18443  * Usage:
18444  <pre><code>
18445  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18446                 { dragElId: "existingProxyDiv" });
18447  dd.startDrag = function(){
18448      this.constrainTo("parent-id");
18449  };
18450  </code></pre>
18451  * Or you can initalize it using the {@link Roo.Element} object:
18452  <pre><code>
18453  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18454      startDrag : function(){
18455          this.constrainTo("parent-id");
18456      }
18457  });
18458  </code></pre>
18459      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18460      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18461      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18462      * an object containing the sides to pad. For example: {right:10, bottom:10}
18463      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18464      */
18465     constrainTo : function(constrainTo, pad, inContent){
18466         if(typeof pad == "number"){
18467             pad = {left: pad, right:pad, top:pad, bottom:pad};
18468         }
18469         pad = pad || this.defaultPadding;
18470         var b = Roo.get(this.getEl()).getBox();
18471         var ce = Roo.get(constrainTo);
18472         var s = ce.getScroll();
18473         var c, cd = ce.dom;
18474         if(cd == document.body){
18475             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18476         }else{
18477             xy = ce.getXY();
18478             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18479         }
18480
18481
18482         var topSpace = b.y - c.y;
18483         var leftSpace = b.x - c.x;
18484
18485         this.resetConstraints();
18486         this.setXConstraint(leftSpace - (pad.left||0), // left
18487                 c.width - leftSpace - b.width - (pad.right||0) //right
18488         );
18489         this.setYConstraint(topSpace - (pad.top||0), //top
18490                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18491         );
18492     },
18493
18494     /**
18495      * Returns a reference to the linked element
18496      * @method getEl
18497      * @return {HTMLElement} the html element
18498      */
18499     getEl: function() {
18500         if (!this._domRef) {
18501             this._domRef = Roo.getDom(this.id);
18502         }
18503
18504         return this._domRef;
18505     },
18506
18507     /**
18508      * Returns a reference to the actual element to drag.  By default this is
18509      * the same as the html element, but it can be assigned to another
18510      * element. An example of this can be found in Roo.dd.DDProxy
18511      * @method getDragEl
18512      * @return {HTMLElement} the html element
18513      */
18514     getDragEl: function() {
18515         return Roo.getDom(this.dragElId);
18516     },
18517
18518     /**
18519      * Sets up the DragDrop object.  Must be called in the constructor of any
18520      * Roo.dd.DragDrop subclass
18521      * @method init
18522      * @param id the id of the linked element
18523      * @param {String} sGroup the group of related items
18524      * @param {object} config configuration attributes
18525      */
18526     init: function(id, sGroup, config) {
18527         this.initTarget(id, sGroup, config);
18528         if (!Roo.isTouch) {
18529             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18530         }
18531         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18532         // Event.on(this.id, "selectstart", Event.preventDefault);
18533     },
18534
18535     /**
18536      * Initializes Targeting functionality only... the object does not
18537      * get a mousedown handler.
18538      * @method initTarget
18539      * @param id the id of the linked element
18540      * @param {String} sGroup the group of related items
18541      * @param {object} config configuration attributes
18542      */
18543     initTarget: function(id, sGroup, config) {
18544
18545         // configuration attributes
18546         this.config = config || {};
18547
18548         // create a local reference to the drag and drop manager
18549         this.DDM = Roo.dd.DDM;
18550         // initialize the groups array
18551         this.groups = {};
18552
18553         // assume that we have an element reference instead of an id if the
18554         // parameter is not a string
18555         if (typeof id !== "string") {
18556             id = Roo.id(id);
18557         }
18558
18559         // set the id
18560         this.id = id;
18561
18562         // add to an interaction group
18563         this.addToGroup((sGroup) ? sGroup : "default");
18564
18565         // We don't want to register this as the handle with the manager
18566         // so we just set the id rather than calling the setter.
18567         this.handleElId = id;
18568
18569         // the linked element is the element that gets dragged by default
18570         this.setDragElId(id);
18571
18572         // by default, clicked anchors will not start drag operations.
18573         this.invalidHandleTypes = { A: "A" };
18574         this.invalidHandleIds = {};
18575         this.invalidHandleClasses = [];
18576
18577         this.applyConfig();
18578
18579         this.handleOnAvailable();
18580     },
18581
18582     /**
18583      * Applies the configuration parameters that were passed into the constructor.
18584      * This is supposed to happen at each level through the inheritance chain.  So
18585      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18586      * DragDrop in order to get all of the parameters that are available in
18587      * each object.
18588      * @method applyConfig
18589      */
18590     applyConfig: function() {
18591
18592         // configurable properties:
18593         //    padding, isTarget, maintainOffset, primaryButtonOnly
18594         this.padding           = this.config.padding || [0, 0, 0, 0];
18595         this.isTarget          = (this.config.isTarget !== false);
18596         this.maintainOffset    = (this.config.maintainOffset);
18597         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18598
18599     },
18600
18601     /**
18602      * Executed when the linked element is available
18603      * @method handleOnAvailable
18604      * @private
18605      */
18606     handleOnAvailable: function() {
18607         this.available = true;
18608         this.resetConstraints();
18609         this.onAvailable();
18610     },
18611
18612      /**
18613      * Configures the padding for the target zone in px.  Effectively expands
18614      * (or reduces) the virtual object size for targeting calculations.
18615      * Supports css-style shorthand; if only one parameter is passed, all sides
18616      * will have that padding, and if only two are passed, the top and bottom
18617      * will have the first param, the left and right the second.
18618      * @method setPadding
18619      * @param {int} iTop    Top pad
18620      * @param {int} iRight  Right pad
18621      * @param {int} iBot    Bot pad
18622      * @param {int} iLeft   Left pad
18623      */
18624     setPadding: function(iTop, iRight, iBot, iLeft) {
18625         // this.padding = [iLeft, iRight, iTop, iBot];
18626         if (!iRight && 0 !== iRight) {
18627             this.padding = [iTop, iTop, iTop, iTop];
18628         } else if (!iBot && 0 !== iBot) {
18629             this.padding = [iTop, iRight, iTop, iRight];
18630         } else {
18631             this.padding = [iTop, iRight, iBot, iLeft];
18632         }
18633     },
18634
18635     /**
18636      * Stores the initial placement of the linked element.
18637      * @method setInitialPosition
18638      * @param {int} diffX   the X offset, default 0
18639      * @param {int} diffY   the Y offset, default 0
18640      */
18641     setInitPosition: function(diffX, diffY) {
18642         var el = this.getEl();
18643
18644         if (!this.DDM.verifyEl(el)) {
18645             return;
18646         }
18647
18648         var dx = diffX || 0;
18649         var dy = diffY || 0;
18650
18651         var p = Dom.getXY( el );
18652
18653         this.initPageX = p[0] - dx;
18654         this.initPageY = p[1] - dy;
18655
18656         this.lastPageX = p[0];
18657         this.lastPageY = p[1];
18658
18659
18660         this.setStartPosition(p);
18661     },
18662
18663     /**
18664      * Sets the start position of the element.  This is set when the obj
18665      * is initialized, the reset when a drag is started.
18666      * @method setStartPosition
18667      * @param pos current position (from previous lookup)
18668      * @private
18669      */
18670     setStartPosition: function(pos) {
18671         var p = pos || Dom.getXY( this.getEl() );
18672         this.deltaSetXY = null;
18673
18674         this.startPageX = p[0];
18675         this.startPageY = p[1];
18676     },
18677
18678     /**
18679      * Add this instance to a group of related drag/drop objects.  All
18680      * instances belong to at least one group, and can belong to as many
18681      * groups as needed.
18682      * @method addToGroup
18683      * @param sGroup {string} the name of the group
18684      */
18685     addToGroup: function(sGroup) {
18686         this.groups[sGroup] = true;
18687         this.DDM.regDragDrop(this, sGroup);
18688     },
18689
18690     /**
18691      * Remove's this instance from the supplied interaction group
18692      * @method removeFromGroup
18693      * @param {string}  sGroup  The group to drop
18694      */
18695     removeFromGroup: function(sGroup) {
18696         if (this.groups[sGroup]) {
18697             delete this.groups[sGroup];
18698         }
18699
18700         this.DDM.removeDDFromGroup(this, sGroup);
18701     },
18702
18703     /**
18704      * Allows you to specify that an element other than the linked element
18705      * will be moved with the cursor during a drag
18706      * @method setDragElId
18707      * @param id {string} the id of the element that will be used to initiate the drag
18708      */
18709     setDragElId: function(id) {
18710         this.dragElId = id;
18711     },
18712
18713     /**
18714      * Allows you to specify a child of the linked element that should be
18715      * used to initiate the drag operation.  An example of this would be if
18716      * you have a content div with text and links.  Clicking anywhere in the
18717      * content area would normally start the drag operation.  Use this method
18718      * to specify that an element inside of the content div is the element
18719      * that starts the drag operation.
18720      * @method setHandleElId
18721      * @param id {string} the id of the element that will be used to
18722      * initiate the drag.
18723      */
18724     setHandleElId: function(id) {
18725         if (typeof id !== "string") {
18726             id = Roo.id(id);
18727         }
18728         this.handleElId = id;
18729         this.DDM.regHandle(this.id, id);
18730     },
18731
18732     /**
18733      * Allows you to set an element outside of the linked element as a drag
18734      * handle
18735      * @method setOuterHandleElId
18736      * @param id the id of the element that will be used to initiate the drag
18737      */
18738     setOuterHandleElId: function(id) {
18739         if (typeof id !== "string") {
18740             id = Roo.id(id);
18741         }
18742         Event.on(id, "mousedown",
18743                 this.handleMouseDown, this);
18744         this.setHandleElId(id);
18745
18746         this.hasOuterHandles = true;
18747     },
18748
18749     /**
18750      * Remove all drag and drop hooks for this element
18751      * @method unreg
18752      */
18753     unreg: function() {
18754         Event.un(this.id, "mousedown",
18755                 this.handleMouseDown);
18756         Event.un(this.id, "touchstart",
18757                 this.handleMouseDown);
18758         this._domRef = null;
18759         this.DDM._remove(this);
18760     },
18761
18762     destroy : function(){
18763         this.unreg();
18764     },
18765
18766     /**
18767      * Returns true if this instance is locked, or the drag drop mgr is locked
18768      * (meaning that all drag/drop is disabled on the page.)
18769      * @method isLocked
18770      * @return {boolean} true if this obj or all drag/drop is locked, else
18771      * false
18772      */
18773     isLocked: function() {
18774         return (this.DDM.isLocked() || this.locked);
18775     },
18776
18777     /**
18778      * Fired when this object is clicked
18779      * @method handleMouseDown
18780      * @param {Event} e
18781      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18782      * @private
18783      */
18784     handleMouseDown: function(e, oDD){
18785      
18786         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18787             //Roo.log('not touch/ button !=0');
18788             return;
18789         }
18790         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18791             return; // double touch..
18792         }
18793         
18794
18795         if (this.isLocked()) {
18796             //Roo.log('locked');
18797             return;
18798         }
18799
18800         this.DDM.refreshCache(this.groups);
18801 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18802         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18803         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18804             //Roo.log('no outer handes or not over target');
18805                 // do nothing.
18806         } else {
18807 //            Roo.log('check validator');
18808             if (this.clickValidator(e)) {
18809 //                Roo.log('validate success');
18810                 // set the initial element position
18811                 this.setStartPosition();
18812
18813
18814                 this.b4MouseDown(e);
18815                 this.onMouseDown(e);
18816
18817                 this.DDM.handleMouseDown(e, this);
18818
18819                 this.DDM.stopEvent(e);
18820             } else {
18821
18822
18823             }
18824         }
18825     },
18826
18827     clickValidator: function(e) {
18828         var target = e.getTarget();
18829         return ( this.isValidHandleChild(target) &&
18830                     (this.id == this.handleElId ||
18831                         this.DDM.handleWasClicked(target, this.id)) );
18832     },
18833
18834     /**
18835      * Allows you to specify a tag name that should not start a drag operation
18836      * when clicked.  This is designed to facilitate embedding links within a
18837      * drag handle that do something other than start the drag.
18838      * @method addInvalidHandleType
18839      * @param {string} tagName the type of element to exclude
18840      */
18841     addInvalidHandleType: function(tagName) {
18842         var type = tagName.toUpperCase();
18843         this.invalidHandleTypes[type] = type;
18844     },
18845
18846     /**
18847      * Lets you to specify an element id for a child of a drag handle
18848      * that should not initiate a drag
18849      * @method addInvalidHandleId
18850      * @param {string} id the element id of the element you wish to ignore
18851      */
18852     addInvalidHandleId: function(id) {
18853         if (typeof id !== "string") {
18854             id = Roo.id(id);
18855         }
18856         this.invalidHandleIds[id] = id;
18857     },
18858
18859     /**
18860      * Lets you specify a css class of elements that will not initiate a drag
18861      * @method addInvalidHandleClass
18862      * @param {string} cssClass the class of the elements you wish to ignore
18863      */
18864     addInvalidHandleClass: function(cssClass) {
18865         this.invalidHandleClasses.push(cssClass);
18866     },
18867
18868     /**
18869      * Unsets an excluded tag name set by addInvalidHandleType
18870      * @method removeInvalidHandleType
18871      * @param {string} tagName the type of element to unexclude
18872      */
18873     removeInvalidHandleType: function(tagName) {
18874         var type = tagName.toUpperCase();
18875         // this.invalidHandleTypes[type] = null;
18876         delete this.invalidHandleTypes[type];
18877     },
18878
18879     /**
18880      * Unsets an invalid handle id
18881      * @method removeInvalidHandleId
18882      * @param {string} id the id of the element to re-enable
18883      */
18884     removeInvalidHandleId: function(id) {
18885         if (typeof id !== "string") {
18886             id = Roo.id(id);
18887         }
18888         delete this.invalidHandleIds[id];
18889     },
18890
18891     /**
18892      * Unsets an invalid css class
18893      * @method removeInvalidHandleClass
18894      * @param {string} cssClass the class of the element(s) you wish to
18895      * re-enable
18896      */
18897     removeInvalidHandleClass: function(cssClass) {
18898         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18899             if (this.invalidHandleClasses[i] == cssClass) {
18900                 delete this.invalidHandleClasses[i];
18901             }
18902         }
18903     },
18904
18905     /**
18906      * Checks the tag exclusion list to see if this click should be ignored
18907      * @method isValidHandleChild
18908      * @param {HTMLElement} node the HTMLElement to evaluate
18909      * @return {boolean} true if this is a valid tag type, false if not
18910      */
18911     isValidHandleChild: function(node) {
18912
18913         var valid = true;
18914         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18915         var nodeName;
18916         try {
18917             nodeName = node.nodeName.toUpperCase();
18918         } catch(e) {
18919             nodeName = node.nodeName;
18920         }
18921         valid = valid && !this.invalidHandleTypes[nodeName];
18922         valid = valid && !this.invalidHandleIds[node.id];
18923
18924         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18925             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18926         }
18927
18928
18929         return valid;
18930
18931     },
18932
18933     /**
18934      * Create the array of horizontal tick marks if an interval was specified
18935      * in setXConstraint().
18936      * @method setXTicks
18937      * @private
18938      */
18939     setXTicks: function(iStartX, iTickSize) {
18940         this.xTicks = [];
18941         this.xTickSize = iTickSize;
18942
18943         var tickMap = {};
18944
18945         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18946             if (!tickMap[i]) {
18947                 this.xTicks[this.xTicks.length] = i;
18948                 tickMap[i] = true;
18949             }
18950         }
18951
18952         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18953             if (!tickMap[i]) {
18954                 this.xTicks[this.xTicks.length] = i;
18955                 tickMap[i] = true;
18956             }
18957         }
18958
18959         this.xTicks.sort(this.DDM.numericSort) ;
18960     },
18961
18962     /**
18963      * Create the array of vertical tick marks if an interval was specified in
18964      * setYConstraint().
18965      * @method setYTicks
18966      * @private
18967      */
18968     setYTicks: function(iStartY, iTickSize) {
18969         this.yTicks = [];
18970         this.yTickSize = iTickSize;
18971
18972         var tickMap = {};
18973
18974         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18975             if (!tickMap[i]) {
18976                 this.yTicks[this.yTicks.length] = i;
18977                 tickMap[i] = true;
18978             }
18979         }
18980
18981         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18982             if (!tickMap[i]) {
18983                 this.yTicks[this.yTicks.length] = i;
18984                 tickMap[i] = true;
18985             }
18986         }
18987
18988         this.yTicks.sort(this.DDM.numericSort) ;
18989     },
18990
18991     /**
18992      * By default, the element can be dragged any place on the screen.  Use
18993      * this method to limit the horizontal travel of the element.  Pass in
18994      * 0,0 for the parameters if you want to lock the drag to the y axis.
18995      * @method setXConstraint
18996      * @param {int} iLeft the number of pixels the element can move to the left
18997      * @param {int} iRight the number of pixels the element can move to the
18998      * right
18999      * @param {int} iTickSize optional parameter for specifying that the
19000      * element
19001      * should move iTickSize pixels at a time.
19002      */
19003     setXConstraint: function(iLeft, iRight, iTickSize) {
19004         this.leftConstraint = iLeft;
19005         this.rightConstraint = iRight;
19006
19007         this.minX = this.initPageX - iLeft;
19008         this.maxX = this.initPageX + iRight;
19009         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19010
19011         this.constrainX = true;
19012     },
19013
19014     /**
19015      * Clears any constraints applied to this instance.  Also clears ticks
19016      * since they can't exist independent of a constraint at this time.
19017      * @method clearConstraints
19018      */
19019     clearConstraints: function() {
19020         this.constrainX = false;
19021         this.constrainY = false;
19022         this.clearTicks();
19023     },
19024
19025     /**
19026      * Clears any tick interval defined for this instance
19027      * @method clearTicks
19028      */
19029     clearTicks: function() {
19030         this.xTicks = null;
19031         this.yTicks = null;
19032         this.xTickSize = 0;
19033         this.yTickSize = 0;
19034     },
19035
19036     /**
19037      * By default, the element can be dragged any place on the screen.  Set
19038      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19039      * parameters if you want to lock the drag to the x axis.
19040      * @method setYConstraint
19041      * @param {int} iUp the number of pixels the element can move up
19042      * @param {int} iDown the number of pixels the element can move down
19043      * @param {int} iTickSize optional parameter for specifying that the
19044      * element should move iTickSize pixels at a time.
19045      */
19046     setYConstraint: function(iUp, iDown, iTickSize) {
19047         this.topConstraint = iUp;
19048         this.bottomConstraint = iDown;
19049
19050         this.minY = this.initPageY - iUp;
19051         this.maxY = this.initPageY + iDown;
19052         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19053
19054         this.constrainY = true;
19055
19056     },
19057
19058     /**
19059      * resetConstraints must be called if you manually reposition a dd element.
19060      * @method resetConstraints
19061      * @param {boolean} maintainOffset
19062      */
19063     resetConstraints: function() {
19064
19065
19066         // Maintain offsets if necessary
19067         if (this.initPageX || this.initPageX === 0) {
19068             // figure out how much this thing has moved
19069             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19070             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19071
19072             this.setInitPosition(dx, dy);
19073
19074         // This is the first time we have detected the element's position
19075         } else {
19076             this.setInitPosition();
19077         }
19078
19079         if (this.constrainX) {
19080             this.setXConstraint( this.leftConstraint,
19081                                  this.rightConstraint,
19082                                  this.xTickSize        );
19083         }
19084
19085         if (this.constrainY) {
19086             this.setYConstraint( this.topConstraint,
19087                                  this.bottomConstraint,
19088                                  this.yTickSize         );
19089         }
19090     },
19091
19092     /**
19093      * Normally the drag element is moved pixel by pixel, but we can specify
19094      * that it move a number of pixels at a time.  This method resolves the
19095      * location when we have it set up like this.
19096      * @method getTick
19097      * @param {int} val where we want to place the object
19098      * @param {int[]} tickArray sorted array of valid points
19099      * @return {int} the closest tick
19100      * @private
19101      */
19102     getTick: function(val, tickArray) {
19103
19104         if (!tickArray) {
19105             // If tick interval is not defined, it is effectively 1 pixel,
19106             // so we return the value passed to us.
19107             return val;
19108         } else if (tickArray[0] >= val) {
19109             // The value is lower than the first tick, so we return the first
19110             // tick.
19111             return tickArray[0];
19112         } else {
19113             for (var i=0, len=tickArray.length; i<len; ++i) {
19114                 var next = i + 1;
19115                 if (tickArray[next] && tickArray[next] >= val) {
19116                     var diff1 = val - tickArray[i];
19117                     var diff2 = tickArray[next] - val;
19118                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19119                 }
19120             }
19121
19122             // The value is larger than the last tick, so we return the last
19123             // tick.
19124             return tickArray[tickArray.length - 1];
19125         }
19126     },
19127
19128     /**
19129      * toString method
19130      * @method toString
19131      * @return {string} string representation of the dd obj
19132      */
19133     toString: function() {
19134         return ("DragDrop " + this.id);
19135     }
19136
19137 });
19138
19139 })();
19140 /*
19141  * Based on:
19142  * Ext JS Library 1.1.1
19143  * Copyright(c) 2006-2007, Ext JS, LLC.
19144  *
19145  * Originally Released Under LGPL - original licence link has changed is not relivant.
19146  *
19147  * Fork - LGPL
19148  * <script type="text/javascript">
19149  */
19150
19151
19152 /**
19153  * The drag and drop utility provides a framework for building drag and drop
19154  * applications.  In addition to enabling drag and drop for specific elements,
19155  * the drag and drop elements are tracked by the manager class, and the
19156  * interactions between the various elements are tracked during the drag and
19157  * the implementing code is notified about these important moments.
19158  */
19159
19160 // Only load the library once.  Rewriting the manager class would orphan
19161 // existing drag and drop instances.
19162 if (!Roo.dd.DragDropMgr) {
19163
19164 /**
19165  * @class Roo.dd.DragDropMgr
19166  * DragDropMgr is a singleton that tracks the element interaction for
19167  * all DragDrop items in the window.  Generally, you will not call
19168  * this class directly, but it does have helper methods that could
19169  * be useful in your DragDrop implementations.
19170  * @singleton
19171  */
19172 Roo.dd.DragDropMgr = function() {
19173
19174     var Event = Roo.EventManager;
19175
19176     return {
19177
19178         /**
19179          * Two dimensional Array of registered DragDrop objects.  The first
19180          * dimension is the DragDrop item group, the second the DragDrop
19181          * object.
19182          * @property ids
19183          * @type {string: string}
19184          * @private
19185          * @static
19186          */
19187         ids: {},
19188
19189         /**
19190          * Array of element ids defined as drag handles.  Used to determine
19191          * if the element that generated the mousedown event is actually the
19192          * handle and not the html element itself.
19193          * @property handleIds
19194          * @type {string: string}
19195          * @private
19196          * @static
19197          */
19198         handleIds: {},
19199
19200         /**
19201          * the DragDrop object that is currently being dragged
19202          * @property dragCurrent
19203          * @type DragDrop
19204          * @private
19205          * @static
19206          **/
19207         dragCurrent: null,
19208
19209         /**
19210          * the DragDrop object(s) that are being hovered over
19211          * @property dragOvers
19212          * @type Array
19213          * @private
19214          * @static
19215          */
19216         dragOvers: {},
19217
19218         /**
19219          * the X distance between the cursor and the object being dragged
19220          * @property deltaX
19221          * @type int
19222          * @private
19223          * @static
19224          */
19225         deltaX: 0,
19226
19227         /**
19228          * the Y distance between the cursor and the object being dragged
19229          * @property deltaY
19230          * @type int
19231          * @private
19232          * @static
19233          */
19234         deltaY: 0,
19235
19236         /**
19237          * Flag to determine if we should prevent the default behavior of the
19238          * events we define. By default this is true, but this can be set to
19239          * false if you need the default behavior (not recommended)
19240          * @property preventDefault
19241          * @type boolean
19242          * @static
19243          */
19244         preventDefault: true,
19245
19246         /**
19247          * Flag to determine if we should stop the propagation of the events
19248          * we generate. This is true by default but you may want to set it to
19249          * false if the html element contains other features that require the
19250          * mouse click.
19251          * @property stopPropagation
19252          * @type boolean
19253          * @static
19254          */
19255         stopPropagation: true,
19256
19257         /**
19258          * Internal flag that is set to true when drag and drop has been
19259          * intialized
19260          * @property initialized
19261          * @private
19262          * @static
19263          */
19264         initalized: false,
19265
19266         /**
19267          * All drag and drop can be disabled.
19268          * @property locked
19269          * @private
19270          * @static
19271          */
19272         locked: false,
19273
19274         /**
19275          * Called the first time an element is registered.
19276          * @method init
19277          * @private
19278          * @static
19279          */
19280         init: function() {
19281             this.initialized = true;
19282         },
19283
19284         /**
19285          * In point mode, drag and drop interaction is defined by the
19286          * location of the cursor during the drag/drop
19287          * @property POINT
19288          * @type int
19289          * @static
19290          */
19291         POINT: 0,
19292
19293         /**
19294          * In intersect mode, drag and drop interactio nis defined by the
19295          * overlap of two or more drag and drop objects.
19296          * @property INTERSECT
19297          * @type int
19298          * @static
19299          */
19300         INTERSECT: 1,
19301
19302         /**
19303          * The current drag and drop mode.  Default: POINT
19304          * @property mode
19305          * @type int
19306          * @static
19307          */
19308         mode: 0,
19309
19310         /**
19311          * Runs method on all drag and drop objects
19312          * @method _execOnAll
19313          * @private
19314          * @static
19315          */
19316         _execOnAll: function(sMethod, args) {
19317             for (var i in this.ids) {
19318                 for (var j in this.ids[i]) {
19319                     var oDD = this.ids[i][j];
19320                     if (! this.isTypeOfDD(oDD)) {
19321                         continue;
19322                     }
19323                     oDD[sMethod].apply(oDD, args);
19324                 }
19325             }
19326         },
19327
19328         /**
19329          * Drag and drop initialization.  Sets up the global event handlers
19330          * @method _onLoad
19331          * @private
19332          * @static
19333          */
19334         _onLoad: function() {
19335
19336             this.init();
19337
19338             if (!Roo.isTouch) {
19339                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19340                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19341             }
19342             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19343             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19344             
19345             Event.on(window,   "unload",    this._onUnload, this, true);
19346             Event.on(window,   "resize",    this._onResize, this, true);
19347             // Event.on(window,   "mouseout",    this._test);
19348
19349         },
19350
19351         /**
19352          * Reset constraints on all drag and drop objs
19353          * @method _onResize
19354          * @private
19355          * @static
19356          */
19357         _onResize: function(e) {
19358             this._execOnAll("resetConstraints", []);
19359         },
19360
19361         /**
19362          * Lock all drag and drop functionality
19363          * @method lock
19364          * @static
19365          */
19366         lock: function() { this.locked = true; },
19367
19368         /**
19369          * Unlock all drag and drop functionality
19370          * @method unlock
19371          * @static
19372          */
19373         unlock: function() { this.locked = false; },
19374
19375         /**
19376          * Is drag and drop locked?
19377          * @method isLocked
19378          * @return {boolean} True if drag and drop is locked, false otherwise.
19379          * @static
19380          */
19381         isLocked: function() { return this.locked; },
19382
19383         /**
19384          * Location cache that is set for all drag drop objects when a drag is
19385          * initiated, cleared when the drag is finished.
19386          * @property locationCache
19387          * @private
19388          * @static
19389          */
19390         locationCache: {},
19391
19392         /**
19393          * Set useCache to false if you want to force object the lookup of each
19394          * drag and drop linked element constantly during a drag.
19395          * @property useCache
19396          * @type boolean
19397          * @static
19398          */
19399         useCache: true,
19400
19401         /**
19402          * The number of pixels that the mouse needs to move after the
19403          * mousedown before the drag is initiated.  Default=3;
19404          * @property clickPixelThresh
19405          * @type int
19406          * @static
19407          */
19408         clickPixelThresh: 3,
19409
19410         /**
19411          * The number of milliseconds after the mousedown event to initiate the
19412          * drag if we don't get a mouseup event. Default=1000
19413          * @property clickTimeThresh
19414          * @type int
19415          * @static
19416          */
19417         clickTimeThresh: 350,
19418
19419         /**
19420          * Flag that indicates that either the drag pixel threshold or the
19421          * mousdown time threshold has been met
19422          * @property dragThreshMet
19423          * @type boolean
19424          * @private
19425          * @static
19426          */
19427         dragThreshMet: false,
19428
19429         /**
19430          * Timeout used for the click time threshold
19431          * @property clickTimeout
19432          * @type Object
19433          * @private
19434          * @static
19435          */
19436         clickTimeout: null,
19437
19438         /**
19439          * The X position of the mousedown event stored for later use when a
19440          * drag threshold is met.
19441          * @property startX
19442          * @type int
19443          * @private
19444          * @static
19445          */
19446         startX: 0,
19447
19448         /**
19449          * The Y position of the mousedown event stored for later use when a
19450          * drag threshold is met.
19451          * @property startY
19452          * @type int
19453          * @private
19454          * @static
19455          */
19456         startY: 0,
19457
19458         /**
19459          * Each DragDrop instance must be registered with the DragDropMgr.
19460          * This is executed in DragDrop.init()
19461          * @method regDragDrop
19462          * @param {DragDrop} oDD the DragDrop object to register
19463          * @param {String} sGroup the name of the group this element belongs to
19464          * @static
19465          */
19466         regDragDrop: function(oDD, sGroup) {
19467             if (!this.initialized) { this.init(); }
19468
19469             if (!this.ids[sGroup]) {
19470                 this.ids[sGroup] = {};
19471             }
19472             this.ids[sGroup][oDD.id] = oDD;
19473         },
19474
19475         /**
19476          * Removes the supplied dd instance from the supplied group. Executed
19477          * by DragDrop.removeFromGroup, so don't call this function directly.
19478          * @method removeDDFromGroup
19479          * @private
19480          * @static
19481          */
19482         removeDDFromGroup: function(oDD, sGroup) {
19483             if (!this.ids[sGroup]) {
19484                 this.ids[sGroup] = {};
19485             }
19486
19487             var obj = this.ids[sGroup];
19488             if (obj && obj[oDD.id]) {
19489                 delete obj[oDD.id];
19490             }
19491         },
19492
19493         /**
19494          * Unregisters a drag and drop item.  This is executed in
19495          * DragDrop.unreg, use that method instead of calling this directly.
19496          * @method _remove
19497          * @private
19498          * @static
19499          */
19500         _remove: function(oDD) {
19501             for (var g in oDD.groups) {
19502                 if (g && this.ids[g][oDD.id]) {
19503                     delete this.ids[g][oDD.id];
19504                 }
19505             }
19506             delete this.handleIds[oDD.id];
19507         },
19508
19509         /**
19510          * Each DragDrop handle element must be registered.  This is done
19511          * automatically when executing DragDrop.setHandleElId()
19512          * @method regHandle
19513          * @param {String} sDDId the DragDrop id this element is a handle for
19514          * @param {String} sHandleId the id of the element that is the drag
19515          * handle
19516          * @static
19517          */
19518         regHandle: function(sDDId, sHandleId) {
19519             if (!this.handleIds[sDDId]) {
19520                 this.handleIds[sDDId] = {};
19521             }
19522             this.handleIds[sDDId][sHandleId] = sHandleId;
19523         },
19524
19525         /**
19526          * Utility function to determine if a given element has been
19527          * registered as a drag drop item.
19528          * @method isDragDrop
19529          * @param {String} id the element id to check
19530          * @return {boolean} true if this element is a DragDrop item,
19531          * false otherwise
19532          * @static
19533          */
19534         isDragDrop: function(id) {
19535             return ( this.getDDById(id) ) ? true : false;
19536         },
19537
19538         /**
19539          * Returns the drag and drop instances that are in all groups the
19540          * passed in instance belongs to.
19541          * @method getRelated
19542          * @param {DragDrop} p_oDD the obj to get related data for
19543          * @param {boolean} bTargetsOnly if true, only return targetable objs
19544          * @return {DragDrop[]} the related instances
19545          * @static
19546          */
19547         getRelated: function(p_oDD, bTargetsOnly) {
19548             var oDDs = [];
19549             for (var i in p_oDD.groups) {
19550                 for (j in this.ids[i]) {
19551                     var dd = this.ids[i][j];
19552                     if (! this.isTypeOfDD(dd)) {
19553                         continue;
19554                     }
19555                     if (!bTargetsOnly || dd.isTarget) {
19556                         oDDs[oDDs.length] = dd;
19557                     }
19558                 }
19559             }
19560
19561             return oDDs;
19562         },
19563
19564         /**
19565          * Returns true if the specified dd target is a legal target for
19566          * the specifice drag obj
19567          * @method isLegalTarget
19568          * @param {DragDrop} the drag obj
19569          * @param {DragDrop} the target
19570          * @return {boolean} true if the target is a legal target for the
19571          * dd obj
19572          * @static
19573          */
19574         isLegalTarget: function (oDD, oTargetDD) {
19575             var targets = this.getRelated(oDD, true);
19576             for (var i=0, len=targets.length;i<len;++i) {
19577                 if (targets[i].id == oTargetDD.id) {
19578                     return true;
19579                 }
19580             }
19581
19582             return false;
19583         },
19584
19585         /**
19586          * My goal is to be able to transparently determine if an object is
19587          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19588          * returns "object", oDD.constructor.toString() always returns
19589          * "DragDrop" and not the name of the subclass.  So for now it just
19590          * evaluates a well-known variable in DragDrop.
19591          * @method isTypeOfDD
19592          * @param {Object} the object to evaluate
19593          * @return {boolean} true if typeof oDD = DragDrop
19594          * @static
19595          */
19596         isTypeOfDD: function (oDD) {
19597             return (oDD && oDD.__ygDragDrop);
19598         },
19599
19600         /**
19601          * Utility function to determine if a given element has been
19602          * registered as a drag drop handle for the given Drag Drop object.
19603          * @method isHandle
19604          * @param {String} id the element id to check
19605          * @return {boolean} true if this element is a DragDrop handle, false
19606          * otherwise
19607          * @static
19608          */
19609         isHandle: function(sDDId, sHandleId) {
19610             return ( this.handleIds[sDDId] &&
19611                             this.handleIds[sDDId][sHandleId] );
19612         },
19613
19614         /**
19615          * Returns the DragDrop instance for a given id
19616          * @method getDDById
19617          * @param {String} id the id of the DragDrop object
19618          * @return {DragDrop} the drag drop object, null if it is not found
19619          * @static
19620          */
19621         getDDById: function(id) {
19622             for (var i in this.ids) {
19623                 if (this.ids[i][id]) {
19624                     return this.ids[i][id];
19625                 }
19626             }
19627             return null;
19628         },
19629
19630         /**
19631          * Fired after a registered DragDrop object gets the mousedown event.
19632          * Sets up the events required to track the object being dragged
19633          * @method handleMouseDown
19634          * @param {Event} e the event
19635          * @param oDD the DragDrop object being dragged
19636          * @private
19637          * @static
19638          */
19639         handleMouseDown: function(e, oDD) {
19640             if(Roo.QuickTips){
19641                 Roo.QuickTips.disable();
19642             }
19643             this.currentTarget = e.getTarget();
19644
19645             this.dragCurrent = oDD;
19646
19647             var el = oDD.getEl();
19648
19649             // track start position
19650             this.startX = e.getPageX();
19651             this.startY = e.getPageY();
19652
19653             this.deltaX = this.startX - el.offsetLeft;
19654             this.deltaY = this.startY - el.offsetTop;
19655
19656             this.dragThreshMet = false;
19657
19658             this.clickTimeout = setTimeout(
19659                     function() {
19660                         var DDM = Roo.dd.DDM;
19661                         DDM.startDrag(DDM.startX, DDM.startY);
19662                     },
19663                     this.clickTimeThresh );
19664         },
19665
19666         /**
19667          * Fired when either the drag pixel threshol or the mousedown hold
19668          * time threshold has been met.
19669          * @method startDrag
19670          * @param x {int} the X position of the original mousedown
19671          * @param y {int} the Y position of the original mousedown
19672          * @static
19673          */
19674         startDrag: function(x, y) {
19675             clearTimeout(this.clickTimeout);
19676             if (this.dragCurrent) {
19677                 this.dragCurrent.b4StartDrag(x, y);
19678                 this.dragCurrent.startDrag(x, y);
19679             }
19680             this.dragThreshMet = true;
19681         },
19682
19683         /**
19684          * Internal function to handle the mouseup event.  Will be invoked
19685          * from the context of the document.
19686          * @method handleMouseUp
19687          * @param {Event} e the event
19688          * @private
19689          * @static
19690          */
19691         handleMouseUp: function(e) {
19692
19693             if(Roo.QuickTips){
19694                 Roo.QuickTips.enable();
19695             }
19696             if (! this.dragCurrent) {
19697                 return;
19698             }
19699
19700             clearTimeout(this.clickTimeout);
19701
19702             if (this.dragThreshMet) {
19703                 this.fireEvents(e, true);
19704             } else {
19705             }
19706
19707             this.stopDrag(e);
19708
19709             this.stopEvent(e);
19710         },
19711
19712         /**
19713          * Utility to stop event propagation and event default, if these
19714          * features are turned on.
19715          * @method stopEvent
19716          * @param {Event} e the event as returned by this.getEvent()
19717          * @static
19718          */
19719         stopEvent: function(e){
19720             if(this.stopPropagation) {
19721                 e.stopPropagation();
19722             }
19723
19724             if (this.preventDefault) {
19725                 e.preventDefault();
19726             }
19727         },
19728
19729         /**
19730          * Internal function to clean up event handlers after the drag
19731          * operation is complete
19732          * @method stopDrag
19733          * @param {Event} e the event
19734          * @private
19735          * @static
19736          */
19737         stopDrag: function(e) {
19738             // Fire the drag end event for the item that was dragged
19739             if (this.dragCurrent) {
19740                 if (this.dragThreshMet) {
19741                     this.dragCurrent.b4EndDrag(e);
19742                     this.dragCurrent.endDrag(e);
19743                 }
19744
19745                 this.dragCurrent.onMouseUp(e);
19746             }
19747
19748             this.dragCurrent = null;
19749             this.dragOvers = {};
19750         },
19751
19752         /**
19753          * Internal function to handle the mousemove event.  Will be invoked
19754          * from the context of the html element.
19755          *
19756          * @TODO figure out what we can do about mouse events lost when the
19757          * user drags objects beyond the window boundary.  Currently we can
19758          * detect this in internet explorer by verifying that the mouse is
19759          * down during the mousemove event.  Firefox doesn't give us the
19760          * button state on the mousemove event.
19761          * @method handleMouseMove
19762          * @param {Event} e the event
19763          * @private
19764          * @static
19765          */
19766         handleMouseMove: function(e) {
19767             if (! this.dragCurrent) {
19768                 return true;
19769             }
19770
19771             // var button = e.which || e.button;
19772
19773             // check for IE mouseup outside of page boundary
19774             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19775                 this.stopEvent(e);
19776                 return this.handleMouseUp(e);
19777             }
19778
19779             if (!this.dragThreshMet) {
19780                 var diffX = Math.abs(this.startX - e.getPageX());
19781                 var diffY = Math.abs(this.startY - e.getPageY());
19782                 if (diffX > this.clickPixelThresh ||
19783                             diffY > this.clickPixelThresh) {
19784                     this.startDrag(this.startX, this.startY);
19785                 }
19786             }
19787
19788             if (this.dragThreshMet) {
19789                 this.dragCurrent.b4Drag(e);
19790                 this.dragCurrent.onDrag(e);
19791                 if(!this.dragCurrent.moveOnly){
19792                     this.fireEvents(e, false);
19793                 }
19794             }
19795
19796             this.stopEvent(e);
19797
19798             return true;
19799         },
19800
19801         /**
19802          * Iterates over all of the DragDrop elements to find ones we are
19803          * hovering over or dropping on
19804          * @method fireEvents
19805          * @param {Event} e the event
19806          * @param {boolean} isDrop is this a drop op or a mouseover op?
19807          * @private
19808          * @static
19809          */
19810         fireEvents: function(e, isDrop) {
19811             var dc = this.dragCurrent;
19812
19813             // If the user did the mouse up outside of the window, we could
19814             // get here even though we have ended the drag.
19815             if (!dc || dc.isLocked()) {
19816                 return;
19817             }
19818
19819             var pt = e.getPoint();
19820
19821             // cache the previous dragOver array
19822             var oldOvers = [];
19823
19824             var outEvts   = [];
19825             var overEvts  = [];
19826             var dropEvts  = [];
19827             var enterEvts = [];
19828
19829             // Check to see if the object(s) we were hovering over is no longer
19830             // being hovered over so we can fire the onDragOut event
19831             for (var i in this.dragOvers) {
19832
19833                 var ddo = this.dragOvers[i];
19834
19835                 if (! this.isTypeOfDD(ddo)) {
19836                     continue;
19837                 }
19838
19839                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19840                     outEvts.push( ddo );
19841                 }
19842
19843                 oldOvers[i] = true;
19844                 delete this.dragOvers[i];
19845             }
19846
19847             for (var sGroup in dc.groups) {
19848
19849                 if ("string" != typeof sGroup) {
19850                     continue;
19851                 }
19852
19853                 for (i in this.ids[sGroup]) {
19854                     var oDD = this.ids[sGroup][i];
19855                     if (! this.isTypeOfDD(oDD)) {
19856                         continue;
19857                     }
19858
19859                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19860                         if (this.isOverTarget(pt, oDD, this.mode)) {
19861                             // look for drop interactions
19862                             if (isDrop) {
19863                                 dropEvts.push( oDD );
19864                             // look for drag enter and drag over interactions
19865                             } else {
19866
19867                                 // initial drag over: dragEnter fires
19868                                 if (!oldOvers[oDD.id]) {
19869                                     enterEvts.push( oDD );
19870                                 // subsequent drag overs: dragOver fires
19871                                 } else {
19872                                     overEvts.push( oDD );
19873                                 }
19874
19875                                 this.dragOvers[oDD.id] = oDD;
19876                             }
19877                         }
19878                     }
19879                 }
19880             }
19881
19882             if (this.mode) {
19883                 if (outEvts.length) {
19884                     dc.b4DragOut(e, outEvts);
19885                     dc.onDragOut(e, outEvts);
19886                 }
19887
19888                 if (enterEvts.length) {
19889                     dc.onDragEnter(e, enterEvts);
19890                 }
19891
19892                 if (overEvts.length) {
19893                     dc.b4DragOver(e, overEvts);
19894                     dc.onDragOver(e, overEvts);
19895                 }
19896
19897                 if (dropEvts.length) {
19898                     dc.b4DragDrop(e, dropEvts);
19899                     dc.onDragDrop(e, dropEvts);
19900                 }
19901
19902             } else {
19903                 // fire dragout events
19904                 var len = 0;
19905                 for (i=0, len=outEvts.length; i<len; ++i) {
19906                     dc.b4DragOut(e, outEvts[i].id);
19907                     dc.onDragOut(e, outEvts[i].id);
19908                 }
19909
19910                 // fire enter events
19911                 for (i=0,len=enterEvts.length; i<len; ++i) {
19912                     // dc.b4DragEnter(e, oDD.id);
19913                     dc.onDragEnter(e, enterEvts[i].id);
19914                 }
19915
19916                 // fire over events
19917                 for (i=0,len=overEvts.length; i<len; ++i) {
19918                     dc.b4DragOver(e, overEvts[i].id);
19919                     dc.onDragOver(e, overEvts[i].id);
19920                 }
19921
19922                 // fire drop events
19923                 for (i=0, len=dropEvts.length; i<len; ++i) {
19924                     dc.b4DragDrop(e, dropEvts[i].id);
19925                     dc.onDragDrop(e, dropEvts[i].id);
19926                 }
19927
19928             }
19929
19930             // notify about a drop that did not find a target
19931             if (isDrop && !dropEvts.length) {
19932                 dc.onInvalidDrop(e);
19933             }
19934
19935         },
19936
19937         /**
19938          * Helper function for getting the best match from the list of drag
19939          * and drop objects returned by the drag and drop events when we are
19940          * in INTERSECT mode.  It returns either the first object that the
19941          * cursor is over, or the object that has the greatest overlap with
19942          * the dragged element.
19943          * @method getBestMatch
19944          * @param  {DragDrop[]} dds The array of drag and drop objects
19945          * targeted
19946          * @return {DragDrop}       The best single match
19947          * @static
19948          */
19949         getBestMatch: function(dds) {
19950             var winner = null;
19951             // Return null if the input is not what we expect
19952             //if (!dds || !dds.length || dds.length == 0) {
19953                // winner = null;
19954             // If there is only one item, it wins
19955             //} else if (dds.length == 1) {
19956
19957             var len = dds.length;
19958
19959             if (len == 1) {
19960                 winner = dds[0];
19961             } else {
19962                 // Loop through the targeted items
19963                 for (var i=0; i<len; ++i) {
19964                     var dd = dds[i];
19965                     // If the cursor is over the object, it wins.  If the
19966                     // cursor is over multiple matches, the first one we come
19967                     // to wins.
19968                     if (dd.cursorIsOver) {
19969                         winner = dd;
19970                         break;
19971                     // Otherwise the object with the most overlap wins
19972                     } else {
19973                         if (!winner ||
19974                             winner.overlap.getArea() < dd.overlap.getArea()) {
19975                             winner = dd;
19976                         }
19977                     }
19978                 }
19979             }
19980
19981             return winner;
19982         },
19983
19984         /**
19985          * Refreshes the cache of the top-left and bottom-right points of the
19986          * drag and drop objects in the specified group(s).  This is in the
19987          * format that is stored in the drag and drop instance, so typical
19988          * usage is:
19989          * <code>
19990          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19991          * </code>
19992          * Alternatively:
19993          * <code>
19994          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19995          * </code>
19996          * @TODO this really should be an indexed array.  Alternatively this
19997          * method could accept both.
19998          * @method refreshCache
19999          * @param {Object} groups an associative array of groups to refresh
20000          * @static
20001          */
20002         refreshCache: function(groups) {
20003             for (var sGroup in groups) {
20004                 if ("string" != typeof sGroup) {
20005                     continue;
20006                 }
20007                 for (var i in this.ids[sGroup]) {
20008                     var oDD = this.ids[sGroup][i];
20009
20010                     if (this.isTypeOfDD(oDD)) {
20011                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20012                         var loc = this.getLocation(oDD);
20013                         if (loc) {
20014                             this.locationCache[oDD.id] = loc;
20015                         } else {
20016                             delete this.locationCache[oDD.id];
20017                             // this will unregister the drag and drop object if
20018                             // the element is not in a usable state
20019                             // oDD.unreg();
20020                         }
20021                     }
20022                 }
20023             }
20024         },
20025
20026         /**
20027          * This checks to make sure an element exists and is in the DOM.  The
20028          * main purpose is to handle cases where innerHTML is used to remove
20029          * drag and drop objects from the DOM.  IE provides an 'unspecified
20030          * error' when trying to access the offsetParent of such an element
20031          * @method verifyEl
20032          * @param {HTMLElement} el the element to check
20033          * @return {boolean} true if the element looks usable
20034          * @static
20035          */
20036         verifyEl: function(el) {
20037             if (el) {
20038                 var parent;
20039                 if(Roo.isIE){
20040                     try{
20041                         parent = el.offsetParent;
20042                     }catch(e){}
20043                 }else{
20044                     parent = el.offsetParent;
20045                 }
20046                 if (parent) {
20047                     return true;
20048                 }
20049             }
20050
20051             return false;
20052         },
20053
20054         /**
20055          * Returns a Region object containing the drag and drop element's position
20056          * and size, including the padding configured for it
20057          * @method getLocation
20058          * @param {DragDrop} oDD the drag and drop object to get the
20059          *                       location for
20060          * @return {Roo.lib.Region} a Region object representing the total area
20061          *                             the element occupies, including any padding
20062          *                             the instance is configured for.
20063          * @static
20064          */
20065         getLocation: function(oDD) {
20066             if (! this.isTypeOfDD(oDD)) {
20067                 return null;
20068             }
20069
20070             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20071
20072             try {
20073                 pos= Roo.lib.Dom.getXY(el);
20074             } catch (e) { }
20075
20076             if (!pos) {
20077                 return null;
20078             }
20079
20080             x1 = pos[0];
20081             x2 = x1 + el.offsetWidth;
20082             y1 = pos[1];
20083             y2 = y1 + el.offsetHeight;
20084
20085             t = y1 - oDD.padding[0];
20086             r = x2 + oDD.padding[1];
20087             b = y2 + oDD.padding[2];
20088             l = x1 - oDD.padding[3];
20089
20090             return new Roo.lib.Region( t, r, b, l );
20091         },
20092
20093         /**
20094          * Checks the cursor location to see if it over the target
20095          * @method isOverTarget
20096          * @param {Roo.lib.Point} pt The point to evaluate
20097          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20098          * @return {boolean} true if the mouse is over the target
20099          * @private
20100          * @static
20101          */
20102         isOverTarget: function(pt, oTarget, intersect) {
20103             // use cache if available
20104             var loc = this.locationCache[oTarget.id];
20105             if (!loc || !this.useCache) {
20106                 loc = this.getLocation(oTarget);
20107                 this.locationCache[oTarget.id] = loc;
20108
20109             }
20110
20111             if (!loc) {
20112                 return false;
20113             }
20114
20115             oTarget.cursorIsOver = loc.contains( pt );
20116
20117             // DragDrop is using this as a sanity check for the initial mousedown
20118             // in this case we are done.  In POINT mode, if the drag obj has no
20119             // contraints, we are also done. Otherwise we need to evaluate the
20120             // location of the target as related to the actual location of the
20121             // dragged element.
20122             var dc = this.dragCurrent;
20123             if (!dc || !dc.getTargetCoord ||
20124                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20125                 return oTarget.cursorIsOver;
20126             }
20127
20128             oTarget.overlap = null;
20129
20130             // Get the current location of the drag element, this is the
20131             // location of the mouse event less the delta that represents
20132             // where the original mousedown happened on the element.  We
20133             // need to consider constraints and ticks as well.
20134             var pos = dc.getTargetCoord(pt.x, pt.y);
20135
20136             var el = dc.getDragEl();
20137             var curRegion = new Roo.lib.Region( pos.y,
20138                                                    pos.x + el.offsetWidth,
20139                                                    pos.y + el.offsetHeight,
20140                                                    pos.x );
20141
20142             var overlap = curRegion.intersect(loc);
20143
20144             if (overlap) {
20145                 oTarget.overlap = overlap;
20146                 return (intersect) ? true : oTarget.cursorIsOver;
20147             } else {
20148                 return false;
20149             }
20150         },
20151
20152         /**
20153          * unload event handler
20154          * @method _onUnload
20155          * @private
20156          * @static
20157          */
20158         _onUnload: function(e, me) {
20159             Roo.dd.DragDropMgr.unregAll();
20160         },
20161
20162         /**
20163          * Cleans up the drag and drop events and objects.
20164          * @method unregAll
20165          * @private
20166          * @static
20167          */
20168         unregAll: function() {
20169
20170             if (this.dragCurrent) {
20171                 this.stopDrag();
20172                 this.dragCurrent = null;
20173             }
20174
20175             this._execOnAll("unreg", []);
20176
20177             for (i in this.elementCache) {
20178                 delete this.elementCache[i];
20179             }
20180
20181             this.elementCache = {};
20182             this.ids = {};
20183         },
20184
20185         /**
20186          * A cache of DOM elements
20187          * @property elementCache
20188          * @private
20189          * @static
20190          */
20191         elementCache: {},
20192
20193         /**
20194          * Get the wrapper for the DOM element specified
20195          * @method getElWrapper
20196          * @param {String} id the id of the element to get
20197          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20198          * @private
20199          * @deprecated This wrapper isn't that useful
20200          * @static
20201          */
20202         getElWrapper: function(id) {
20203             var oWrapper = this.elementCache[id];
20204             if (!oWrapper || !oWrapper.el) {
20205                 oWrapper = this.elementCache[id] =
20206                     new this.ElementWrapper(Roo.getDom(id));
20207             }
20208             return oWrapper;
20209         },
20210
20211         /**
20212          * Returns the actual DOM element
20213          * @method getElement
20214          * @param {String} id the id of the elment to get
20215          * @return {Object} The element
20216          * @deprecated use Roo.getDom instead
20217          * @static
20218          */
20219         getElement: function(id) {
20220             return Roo.getDom(id);
20221         },
20222
20223         /**
20224          * Returns the style property for the DOM element (i.e.,
20225          * document.getElById(id).style)
20226          * @method getCss
20227          * @param {String} id the id of the elment to get
20228          * @return {Object} The style property of the element
20229          * @deprecated use Roo.getDom instead
20230          * @static
20231          */
20232         getCss: function(id) {
20233             var el = Roo.getDom(id);
20234             return (el) ? el.style : null;
20235         },
20236
20237         /**
20238          * Inner class for cached elements
20239          * @class DragDropMgr.ElementWrapper
20240          * @for DragDropMgr
20241          * @private
20242          * @deprecated
20243          */
20244         ElementWrapper: function(el) {
20245                 /**
20246                  * The element
20247                  * @property el
20248                  */
20249                 this.el = el || null;
20250                 /**
20251                  * The element id
20252                  * @property id
20253                  */
20254                 this.id = this.el && el.id;
20255                 /**
20256                  * A reference to the style property
20257                  * @property css
20258                  */
20259                 this.css = this.el && el.style;
20260             },
20261
20262         /**
20263          * Returns the X position of an html element
20264          * @method getPosX
20265          * @param el the element for which to get the position
20266          * @return {int} the X coordinate
20267          * @for DragDropMgr
20268          * @deprecated use Roo.lib.Dom.getX instead
20269          * @static
20270          */
20271         getPosX: function(el) {
20272             return Roo.lib.Dom.getX(el);
20273         },
20274
20275         /**
20276          * Returns the Y position of an html element
20277          * @method getPosY
20278          * @param el the element for which to get the position
20279          * @return {int} the Y coordinate
20280          * @deprecated use Roo.lib.Dom.getY instead
20281          * @static
20282          */
20283         getPosY: function(el) {
20284             return Roo.lib.Dom.getY(el);
20285         },
20286
20287         /**
20288          * Swap two nodes.  In IE, we use the native method, for others we
20289          * emulate the IE behavior
20290          * @method swapNode
20291          * @param n1 the first node to swap
20292          * @param n2 the other node to swap
20293          * @static
20294          */
20295         swapNode: function(n1, n2) {
20296             if (n1.swapNode) {
20297                 n1.swapNode(n2);
20298             } else {
20299                 var p = n2.parentNode;
20300                 var s = n2.nextSibling;
20301
20302                 if (s == n1) {
20303                     p.insertBefore(n1, n2);
20304                 } else if (n2 == n1.nextSibling) {
20305                     p.insertBefore(n2, n1);
20306                 } else {
20307                     n1.parentNode.replaceChild(n2, n1);
20308                     p.insertBefore(n1, s);
20309                 }
20310             }
20311         },
20312
20313         /**
20314          * Returns the current scroll position
20315          * @method getScroll
20316          * @private
20317          * @static
20318          */
20319         getScroll: function () {
20320             var t, l, dde=document.documentElement, db=document.body;
20321             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20322                 t = dde.scrollTop;
20323                 l = dde.scrollLeft;
20324             } else if (db) {
20325                 t = db.scrollTop;
20326                 l = db.scrollLeft;
20327             } else {
20328
20329             }
20330             return { top: t, left: l };
20331         },
20332
20333         /**
20334          * Returns the specified element style property
20335          * @method getStyle
20336          * @param {HTMLElement} el          the element
20337          * @param {string}      styleProp   the style property
20338          * @return {string} The value of the style property
20339          * @deprecated use Roo.lib.Dom.getStyle
20340          * @static
20341          */
20342         getStyle: function(el, styleProp) {
20343             return Roo.fly(el).getStyle(styleProp);
20344         },
20345
20346         /**
20347          * Gets the scrollTop
20348          * @method getScrollTop
20349          * @return {int} the document's scrollTop
20350          * @static
20351          */
20352         getScrollTop: function () { return this.getScroll().top; },
20353
20354         /**
20355          * Gets the scrollLeft
20356          * @method getScrollLeft
20357          * @return {int} the document's scrollTop
20358          * @static
20359          */
20360         getScrollLeft: function () { return this.getScroll().left; },
20361
20362         /**
20363          * Sets the x/y position of an element to the location of the
20364          * target element.
20365          * @method moveToEl
20366          * @param {HTMLElement} moveEl      The element to move
20367          * @param {HTMLElement} targetEl    The position reference element
20368          * @static
20369          */
20370         moveToEl: function (moveEl, targetEl) {
20371             var aCoord = Roo.lib.Dom.getXY(targetEl);
20372             Roo.lib.Dom.setXY(moveEl, aCoord);
20373         },
20374
20375         /**
20376          * Numeric array sort function
20377          * @method numericSort
20378          * @static
20379          */
20380         numericSort: function(a, b) { return (a - b); },
20381
20382         /**
20383          * Internal counter
20384          * @property _timeoutCount
20385          * @private
20386          * @static
20387          */
20388         _timeoutCount: 0,
20389
20390         /**
20391          * Trying to make the load order less important.  Without this we get
20392          * an error if this file is loaded before the Event Utility.
20393          * @method _addListeners
20394          * @private
20395          * @static
20396          */
20397         _addListeners: function() {
20398             var DDM = Roo.dd.DDM;
20399             if ( Roo.lib.Event && document ) {
20400                 DDM._onLoad();
20401             } else {
20402                 if (DDM._timeoutCount > 2000) {
20403                 } else {
20404                     setTimeout(DDM._addListeners, 10);
20405                     if (document && document.body) {
20406                         DDM._timeoutCount += 1;
20407                     }
20408                 }
20409             }
20410         },
20411
20412         /**
20413          * Recursively searches the immediate parent and all child nodes for
20414          * the handle element in order to determine wheter or not it was
20415          * clicked.
20416          * @method handleWasClicked
20417          * @param node the html element to inspect
20418          * @static
20419          */
20420         handleWasClicked: function(node, id) {
20421             if (this.isHandle(id, node.id)) {
20422                 return true;
20423             } else {
20424                 // check to see if this is a text node child of the one we want
20425                 var p = node.parentNode;
20426
20427                 while (p) {
20428                     if (this.isHandle(id, p.id)) {
20429                         return true;
20430                     } else {
20431                         p = p.parentNode;
20432                     }
20433                 }
20434             }
20435
20436             return false;
20437         }
20438
20439     };
20440
20441 }();
20442
20443 // shorter alias, save a few bytes
20444 Roo.dd.DDM = Roo.dd.DragDropMgr;
20445 Roo.dd.DDM._addListeners();
20446
20447 }/*
20448  * Based on:
20449  * Ext JS Library 1.1.1
20450  * Copyright(c) 2006-2007, Ext JS, LLC.
20451  *
20452  * Originally Released Under LGPL - original licence link has changed is not relivant.
20453  *
20454  * Fork - LGPL
20455  * <script type="text/javascript">
20456  */
20457
20458 /**
20459  * @class Roo.dd.DD
20460  * A DragDrop implementation where the linked element follows the
20461  * mouse cursor during a drag.
20462  * @extends Roo.dd.DragDrop
20463  * @constructor
20464  * @param {String} id the id of the linked element
20465  * @param {String} sGroup the group of related DragDrop items
20466  * @param {object} config an object containing configurable attributes
20467  *                Valid properties for DD:
20468  *                    scroll
20469  */
20470 Roo.dd.DD = function(id, sGroup, config) {
20471     if (id) {
20472         this.init(id, sGroup, config);
20473     }
20474 };
20475
20476 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20477
20478     /**
20479      * When set to true, the utility automatically tries to scroll the browser
20480      * window wehn a drag and drop element is dragged near the viewport boundary.
20481      * Defaults to true.
20482      * @property scroll
20483      * @type boolean
20484      */
20485     scroll: true,
20486
20487     /**
20488      * Sets the pointer offset to the distance between the linked element's top
20489      * left corner and the location the element was clicked
20490      * @method autoOffset
20491      * @param {int} iPageX the X coordinate of the click
20492      * @param {int} iPageY the Y coordinate of the click
20493      */
20494     autoOffset: function(iPageX, iPageY) {
20495         var x = iPageX - this.startPageX;
20496         var y = iPageY - this.startPageY;
20497         this.setDelta(x, y);
20498     },
20499
20500     /**
20501      * Sets the pointer offset.  You can call this directly to force the
20502      * offset to be in a particular location (e.g., pass in 0,0 to set it
20503      * to the center of the object)
20504      * @method setDelta
20505      * @param {int} iDeltaX the distance from the left
20506      * @param {int} iDeltaY the distance from the top
20507      */
20508     setDelta: function(iDeltaX, iDeltaY) {
20509         this.deltaX = iDeltaX;
20510         this.deltaY = iDeltaY;
20511     },
20512
20513     /**
20514      * Sets the drag element to the location of the mousedown or click event,
20515      * maintaining the cursor location relative to the location on the element
20516      * that was clicked.  Override this if you want to place the element in a
20517      * location other than where the cursor is.
20518      * @method setDragElPos
20519      * @param {int} iPageX the X coordinate of the mousedown or drag event
20520      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20521      */
20522     setDragElPos: function(iPageX, iPageY) {
20523         // the first time we do this, we are going to check to make sure
20524         // the element has css positioning
20525
20526         var el = this.getDragEl();
20527         this.alignElWithMouse(el, iPageX, iPageY);
20528     },
20529
20530     /**
20531      * Sets the element to the location of the mousedown or click event,
20532      * maintaining the cursor location relative to the location on the element
20533      * that was clicked.  Override this if you want to place the element in a
20534      * location other than where the cursor is.
20535      * @method alignElWithMouse
20536      * @param {HTMLElement} el the element to move
20537      * @param {int} iPageX the X coordinate of the mousedown or drag event
20538      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20539      */
20540     alignElWithMouse: function(el, iPageX, iPageY) {
20541         var oCoord = this.getTargetCoord(iPageX, iPageY);
20542         var fly = el.dom ? el : Roo.fly(el);
20543         if (!this.deltaSetXY) {
20544             var aCoord = [oCoord.x, oCoord.y];
20545             fly.setXY(aCoord);
20546             var newLeft = fly.getLeft(true);
20547             var newTop  = fly.getTop(true);
20548             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20549         } else {
20550             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20551         }
20552
20553         this.cachePosition(oCoord.x, oCoord.y);
20554         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20555         return oCoord;
20556     },
20557
20558     /**
20559      * Saves the most recent position so that we can reset the constraints and
20560      * tick marks on-demand.  We need to know this so that we can calculate the
20561      * number of pixels the element is offset from its original position.
20562      * @method cachePosition
20563      * @param iPageX the current x position (optional, this just makes it so we
20564      * don't have to look it up again)
20565      * @param iPageY the current y position (optional, this just makes it so we
20566      * don't have to look it up again)
20567      */
20568     cachePosition: function(iPageX, iPageY) {
20569         if (iPageX) {
20570             this.lastPageX = iPageX;
20571             this.lastPageY = iPageY;
20572         } else {
20573             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20574             this.lastPageX = aCoord[0];
20575             this.lastPageY = aCoord[1];
20576         }
20577     },
20578
20579     /**
20580      * Auto-scroll the window if the dragged object has been moved beyond the
20581      * visible window boundary.
20582      * @method autoScroll
20583      * @param {int} x the drag element's x position
20584      * @param {int} y the drag element's y position
20585      * @param {int} h the height of the drag element
20586      * @param {int} w the width of the drag element
20587      * @private
20588      */
20589     autoScroll: function(x, y, h, w) {
20590
20591         if (this.scroll) {
20592             // The client height
20593             var clientH = Roo.lib.Dom.getViewWidth();
20594
20595             // The client width
20596             var clientW = Roo.lib.Dom.getViewHeight();
20597
20598             // The amt scrolled down
20599             var st = this.DDM.getScrollTop();
20600
20601             // The amt scrolled right
20602             var sl = this.DDM.getScrollLeft();
20603
20604             // Location of the bottom of the element
20605             var bot = h + y;
20606
20607             // Location of the right of the element
20608             var right = w + x;
20609
20610             // The distance from the cursor to the bottom of the visible area,
20611             // adjusted so that we don't scroll if the cursor is beyond the
20612             // element drag constraints
20613             var toBot = (clientH + st - y - this.deltaY);
20614
20615             // The distance from the cursor to the right of the visible area
20616             var toRight = (clientW + sl - x - this.deltaX);
20617
20618
20619             // How close to the edge the cursor must be before we scroll
20620             // var thresh = (document.all) ? 100 : 40;
20621             var thresh = 40;
20622
20623             // How many pixels to scroll per autoscroll op.  This helps to reduce
20624             // clunky scrolling. IE is more sensitive about this ... it needs this
20625             // value to be higher.
20626             var scrAmt = (document.all) ? 80 : 30;
20627
20628             // Scroll down if we are near the bottom of the visible page and the
20629             // obj extends below the crease
20630             if ( bot > clientH && toBot < thresh ) {
20631                 window.scrollTo(sl, st + scrAmt);
20632             }
20633
20634             // Scroll up if the window is scrolled down and the top of the object
20635             // goes above the top border
20636             if ( y < st && st > 0 && y - st < thresh ) {
20637                 window.scrollTo(sl, st - scrAmt);
20638             }
20639
20640             // Scroll right if the obj is beyond the right border and the cursor is
20641             // near the border.
20642             if ( right > clientW && toRight < thresh ) {
20643                 window.scrollTo(sl + scrAmt, st);
20644             }
20645
20646             // Scroll left if the window has been scrolled to the right and the obj
20647             // extends past the left border
20648             if ( x < sl && sl > 0 && x - sl < thresh ) {
20649                 window.scrollTo(sl - scrAmt, st);
20650             }
20651         }
20652     },
20653
20654     /**
20655      * Finds the location the element should be placed if we want to move
20656      * it to where the mouse location less the click offset would place us.
20657      * @method getTargetCoord
20658      * @param {int} iPageX the X coordinate of the click
20659      * @param {int} iPageY the Y coordinate of the click
20660      * @return an object that contains the coordinates (Object.x and Object.y)
20661      * @private
20662      */
20663     getTargetCoord: function(iPageX, iPageY) {
20664
20665
20666         var x = iPageX - this.deltaX;
20667         var y = iPageY - this.deltaY;
20668
20669         if (this.constrainX) {
20670             if (x < this.minX) { x = this.minX; }
20671             if (x > this.maxX) { x = this.maxX; }
20672         }
20673
20674         if (this.constrainY) {
20675             if (y < this.minY) { y = this.minY; }
20676             if (y > this.maxY) { y = this.maxY; }
20677         }
20678
20679         x = this.getTick(x, this.xTicks);
20680         y = this.getTick(y, this.yTicks);
20681
20682
20683         return {x:x, y:y};
20684     },
20685
20686     /*
20687      * Sets up config options specific to this class. Overrides
20688      * Roo.dd.DragDrop, but all versions of this method through the
20689      * inheritance chain are called
20690      */
20691     applyConfig: function() {
20692         Roo.dd.DD.superclass.applyConfig.call(this);
20693         this.scroll = (this.config.scroll !== false);
20694     },
20695
20696     /*
20697      * Event that fires prior to the onMouseDown event.  Overrides
20698      * Roo.dd.DragDrop.
20699      */
20700     b4MouseDown: function(e) {
20701         // this.resetConstraints();
20702         this.autoOffset(e.getPageX(),
20703                             e.getPageY());
20704     },
20705
20706     /*
20707      * Event that fires prior to the onDrag event.  Overrides
20708      * Roo.dd.DragDrop.
20709      */
20710     b4Drag: function(e) {
20711         this.setDragElPos(e.getPageX(),
20712                             e.getPageY());
20713     },
20714
20715     toString: function() {
20716         return ("DD " + this.id);
20717     }
20718
20719     //////////////////////////////////////////////////////////////////////////
20720     // Debugging ygDragDrop events that can be overridden
20721     //////////////////////////////////////////////////////////////////////////
20722     /*
20723     startDrag: function(x, y) {
20724     },
20725
20726     onDrag: function(e) {
20727     },
20728
20729     onDragEnter: function(e, id) {
20730     },
20731
20732     onDragOver: function(e, id) {
20733     },
20734
20735     onDragOut: function(e, id) {
20736     },
20737
20738     onDragDrop: function(e, id) {
20739     },
20740
20741     endDrag: function(e) {
20742     }
20743
20744     */
20745
20746 });/*
20747  * Based on:
20748  * Ext JS Library 1.1.1
20749  * Copyright(c) 2006-2007, Ext JS, LLC.
20750  *
20751  * Originally Released Under LGPL - original licence link has changed is not relivant.
20752  *
20753  * Fork - LGPL
20754  * <script type="text/javascript">
20755  */
20756
20757 /**
20758  * @class Roo.dd.DDProxy
20759  * A DragDrop implementation that inserts an empty, bordered div into
20760  * the document that follows the cursor during drag operations.  At the time of
20761  * the click, the frame div is resized to the dimensions of the linked html
20762  * element, and moved to the exact location of the linked element.
20763  *
20764  * References to the "frame" element refer to the single proxy element that
20765  * was created to be dragged in place of all DDProxy elements on the
20766  * page.
20767  *
20768  * @extends Roo.dd.DD
20769  * @constructor
20770  * @param {String} id the id of the linked html element
20771  * @param {String} sGroup the group of related DragDrop objects
20772  * @param {object} config an object containing configurable attributes
20773  *                Valid properties for DDProxy in addition to those in DragDrop:
20774  *                   resizeFrame, centerFrame, dragElId
20775  */
20776 Roo.dd.DDProxy = function(id, sGroup, config) {
20777     if (id) {
20778         this.init(id, sGroup, config);
20779         this.initFrame();
20780     }
20781 };
20782
20783 /**
20784  * The default drag frame div id
20785  * @property Roo.dd.DDProxy.dragElId
20786  * @type String
20787  * @static
20788  */
20789 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20790
20791 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20792
20793     /**
20794      * By default we resize the drag frame to be the same size as the element
20795      * we want to drag (this is to get the frame effect).  We can turn it off
20796      * if we want a different behavior.
20797      * @property resizeFrame
20798      * @type boolean
20799      */
20800     resizeFrame: true,
20801
20802     /**
20803      * By default the frame is positioned exactly where the drag element is, so
20804      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20805      * you do not have constraints on the obj is to have the drag frame centered
20806      * around the cursor.  Set centerFrame to true for this effect.
20807      * @property centerFrame
20808      * @type boolean
20809      */
20810     centerFrame: false,
20811
20812     /**
20813      * Creates the proxy element if it does not yet exist
20814      * @method createFrame
20815      */
20816     createFrame: function() {
20817         var self = this;
20818         var body = document.body;
20819
20820         if (!body || !body.firstChild) {
20821             setTimeout( function() { self.createFrame(); }, 50 );
20822             return;
20823         }
20824
20825         var div = this.getDragEl();
20826
20827         if (!div) {
20828             div    = document.createElement("div");
20829             div.id = this.dragElId;
20830             var s  = div.style;
20831
20832             s.position   = "absolute";
20833             s.visibility = "hidden";
20834             s.cursor     = "move";
20835             s.border     = "2px solid #aaa";
20836             s.zIndex     = 999;
20837
20838             // appendChild can blow up IE if invoked prior to the window load event
20839             // while rendering a table.  It is possible there are other scenarios
20840             // that would cause this to happen as well.
20841             body.insertBefore(div, body.firstChild);
20842         }
20843     },
20844
20845     /**
20846      * Initialization for the drag frame element.  Must be called in the
20847      * constructor of all subclasses
20848      * @method initFrame
20849      */
20850     initFrame: function() {
20851         this.createFrame();
20852     },
20853
20854     applyConfig: function() {
20855         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20856
20857         this.resizeFrame = (this.config.resizeFrame !== false);
20858         this.centerFrame = (this.config.centerFrame);
20859         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20860     },
20861
20862     /**
20863      * Resizes the drag frame to the dimensions of the clicked object, positions
20864      * it over the object, and finally displays it
20865      * @method showFrame
20866      * @param {int} iPageX X click position
20867      * @param {int} iPageY Y click position
20868      * @private
20869      */
20870     showFrame: function(iPageX, iPageY) {
20871         var el = this.getEl();
20872         var dragEl = this.getDragEl();
20873         var s = dragEl.style;
20874
20875         this._resizeProxy();
20876
20877         if (this.centerFrame) {
20878             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20879                            Math.round(parseInt(s.height, 10)/2) );
20880         }
20881
20882         this.setDragElPos(iPageX, iPageY);
20883
20884         Roo.fly(dragEl).show();
20885     },
20886
20887     /**
20888      * The proxy is automatically resized to the dimensions of the linked
20889      * element when a drag is initiated, unless resizeFrame is set to false
20890      * @method _resizeProxy
20891      * @private
20892      */
20893     _resizeProxy: function() {
20894         if (this.resizeFrame) {
20895             var el = this.getEl();
20896             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20897         }
20898     },
20899
20900     // overrides Roo.dd.DragDrop
20901     b4MouseDown: function(e) {
20902         var x = e.getPageX();
20903         var y = e.getPageY();
20904         this.autoOffset(x, y);
20905         this.setDragElPos(x, y);
20906     },
20907
20908     // overrides Roo.dd.DragDrop
20909     b4StartDrag: function(x, y) {
20910         // show the drag frame
20911         this.showFrame(x, y);
20912     },
20913
20914     // overrides Roo.dd.DragDrop
20915     b4EndDrag: function(e) {
20916         Roo.fly(this.getDragEl()).hide();
20917     },
20918
20919     // overrides Roo.dd.DragDrop
20920     // By default we try to move the element to the last location of the frame.
20921     // This is so that the default behavior mirrors that of Roo.dd.DD.
20922     endDrag: function(e) {
20923
20924         var lel = this.getEl();
20925         var del = this.getDragEl();
20926
20927         // Show the drag frame briefly so we can get its position
20928         del.style.visibility = "";
20929
20930         this.beforeMove();
20931         // Hide the linked element before the move to get around a Safari
20932         // rendering bug.
20933         lel.style.visibility = "hidden";
20934         Roo.dd.DDM.moveToEl(lel, del);
20935         del.style.visibility = "hidden";
20936         lel.style.visibility = "";
20937
20938         this.afterDrag();
20939     },
20940
20941     beforeMove : function(){
20942
20943     },
20944
20945     afterDrag : function(){
20946
20947     },
20948
20949     toString: function() {
20950         return ("DDProxy " + this.id);
20951     }
20952
20953 });
20954 /*
20955  * Based on:
20956  * Ext JS Library 1.1.1
20957  * Copyright(c) 2006-2007, Ext JS, LLC.
20958  *
20959  * Originally Released Under LGPL - original licence link has changed is not relivant.
20960  *
20961  * Fork - LGPL
20962  * <script type="text/javascript">
20963  */
20964
20965  /**
20966  * @class Roo.dd.DDTarget
20967  * A DragDrop implementation that does not move, but can be a drop
20968  * target.  You would get the same result by simply omitting implementation
20969  * for the event callbacks, but this way we reduce the processing cost of the
20970  * event listener and the callbacks.
20971  * @extends Roo.dd.DragDrop
20972  * @constructor
20973  * @param {String} id the id of the element that is a drop target
20974  * @param {String} sGroup the group of related DragDrop objects
20975  * @param {object} config an object containing configurable attributes
20976  *                 Valid properties for DDTarget in addition to those in
20977  *                 DragDrop:
20978  *                    none
20979  */
20980 Roo.dd.DDTarget = function(id, sGroup, config) {
20981     if (id) {
20982         this.initTarget(id, sGroup, config);
20983     }
20984     if (config.listeners || config.events) { 
20985        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20986             listeners : config.listeners || {}, 
20987             events : config.events || {} 
20988         });    
20989     }
20990 };
20991
20992 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20993 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20994     toString: function() {
20995         return ("DDTarget " + this.id);
20996     }
20997 });
20998 /*
20999  * Based on:
21000  * Ext JS Library 1.1.1
21001  * Copyright(c) 2006-2007, Ext JS, LLC.
21002  *
21003  * Originally Released Under LGPL - original licence link has changed is not relivant.
21004  *
21005  * Fork - LGPL
21006  * <script type="text/javascript">
21007  */
21008  
21009
21010 /**
21011  * @class Roo.dd.ScrollManager
21012  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21013  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21014  * @singleton
21015  */
21016 Roo.dd.ScrollManager = function(){
21017     var ddm = Roo.dd.DragDropMgr;
21018     var els = {};
21019     var dragEl = null;
21020     var proc = {};
21021     
21022     
21023     
21024     var onStop = function(e){
21025         dragEl = null;
21026         clearProc();
21027     };
21028     
21029     var triggerRefresh = function(){
21030         if(ddm.dragCurrent){
21031              ddm.refreshCache(ddm.dragCurrent.groups);
21032         }
21033     };
21034     
21035     var doScroll = function(){
21036         if(ddm.dragCurrent){
21037             var dds = Roo.dd.ScrollManager;
21038             if(!dds.animate){
21039                 if(proc.el.scroll(proc.dir, dds.increment)){
21040                     triggerRefresh();
21041                 }
21042             }else{
21043                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21044             }
21045         }
21046     };
21047     
21048     var clearProc = function(){
21049         if(proc.id){
21050             clearInterval(proc.id);
21051         }
21052         proc.id = 0;
21053         proc.el = null;
21054         proc.dir = "";
21055     };
21056     
21057     var startProc = function(el, dir){
21058          Roo.log('scroll startproc');
21059         clearProc();
21060         proc.el = el;
21061         proc.dir = dir;
21062         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21063     };
21064     
21065     var onFire = function(e, isDrop){
21066        
21067         if(isDrop || !ddm.dragCurrent){ return; }
21068         var dds = Roo.dd.ScrollManager;
21069         if(!dragEl || dragEl != ddm.dragCurrent){
21070             dragEl = ddm.dragCurrent;
21071             // refresh regions on drag start
21072             dds.refreshCache();
21073         }
21074         
21075         var xy = Roo.lib.Event.getXY(e);
21076         var pt = new Roo.lib.Point(xy[0], xy[1]);
21077         for(var id in els){
21078             var el = els[id], r = el._region;
21079             if(r && r.contains(pt) && el.isScrollable()){
21080                 if(r.bottom - pt.y <= dds.thresh){
21081                     if(proc.el != el){
21082                         startProc(el, "down");
21083                     }
21084                     return;
21085                 }else if(r.right - pt.x <= dds.thresh){
21086                     if(proc.el != el){
21087                         startProc(el, "left");
21088                     }
21089                     return;
21090                 }else if(pt.y - r.top <= dds.thresh){
21091                     if(proc.el != el){
21092                         startProc(el, "up");
21093                     }
21094                     return;
21095                 }else if(pt.x - r.left <= dds.thresh){
21096                     if(proc.el != el){
21097                         startProc(el, "right");
21098                     }
21099                     return;
21100                 }
21101             }
21102         }
21103         clearProc();
21104     };
21105     
21106     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21107     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21108     
21109     return {
21110         /**
21111          * Registers new overflow element(s) to auto scroll
21112          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21113          */
21114         register : function(el){
21115             if(el instanceof Array){
21116                 for(var i = 0, len = el.length; i < len; i++) {
21117                         this.register(el[i]);
21118                 }
21119             }else{
21120                 el = Roo.get(el);
21121                 els[el.id] = el;
21122             }
21123             Roo.dd.ScrollManager.els = els;
21124         },
21125         
21126         /**
21127          * Unregisters overflow element(s) so they are no longer scrolled
21128          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21129          */
21130         unregister : function(el){
21131             if(el instanceof Array){
21132                 for(var i = 0, len = el.length; i < len; i++) {
21133                         this.unregister(el[i]);
21134                 }
21135             }else{
21136                 el = Roo.get(el);
21137                 delete els[el.id];
21138             }
21139         },
21140         
21141         /**
21142          * The number of pixels from the edge of a container the pointer needs to be to 
21143          * trigger scrolling (defaults to 25)
21144          * @type Number
21145          */
21146         thresh : 25,
21147         
21148         /**
21149          * The number of pixels to scroll in each scroll increment (defaults to 50)
21150          * @type Number
21151          */
21152         increment : 100,
21153         
21154         /**
21155          * The frequency of scrolls in milliseconds (defaults to 500)
21156          * @type Number
21157          */
21158         frequency : 500,
21159         
21160         /**
21161          * True to animate the scroll (defaults to true)
21162          * @type Boolean
21163          */
21164         animate: true,
21165         
21166         /**
21167          * The animation duration in seconds - 
21168          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21169          * @type Number
21170          */
21171         animDuration: .4,
21172         
21173         /**
21174          * Manually trigger a cache refresh.
21175          */
21176         refreshCache : function(){
21177             for(var id in els){
21178                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21179                     els[id]._region = els[id].getRegion();
21180                 }
21181             }
21182         }
21183     };
21184 }();/*
21185  * Based on:
21186  * Ext JS Library 1.1.1
21187  * Copyright(c) 2006-2007, Ext JS, LLC.
21188  *
21189  * Originally Released Under LGPL - original licence link has changed is not relivant.
21190  *
21191  * Fork - LGPL
21192  * <script type="text/javascript">
21193  */
21194  
21195
21196 /**
21197  * @class Roo.dd.Registry
21198  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21199  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21200  * @singleton
21201  */
21202 Roo.dd.Registry = function(){
21203     var elements = {}; 
21204     var handles = {}; 
21205     var autoIdSeed = 0;
21206
21207     var getId = function(el, autogen){
21208         if(typeof el == "string"){
21209             return el;
21210         }
21211         var id = el.id;
21212         if(!id && autogen !== false){
21213             id = "roodd-" + (++autoIdSeed);
21214             el.id = id;
21215         }
21216         return id;
21217     };
21218     
21219     return {
21220     /**
21221      * Register a drag drop element
21222      * @param {String|HTMLElement} element The id or DOM node to register
21223      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21224      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21225      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21226      * populated in the data object (if applicable):
21227      * <pre>
21228 Value      Description<br />
21229 ---------  ------------------------------------------<br />
21230 handles    Array of DOM nodes that trigger dragging<br />
21231            for the element being registered<br />
21232 isHandle   True if the element passed in triggers<br />
21233            dragging itself, else false
21234 </pre>
21235      */
21236         register : function(el, data){
21237             data = data || {};
21238             if(typeof el == "string"){
21239                 el = document.getElementById(el);
21240             }
21241             data.ddel = el;
21242             elements[getId(el)] = data;
21243             if(data.isHandle !== false){
21244                 handles[data.ddel.id] = data;
21245             }
21246             if(data.handles){
21247                 var hs = data.handles;
21248                 for(var i = 0, len = hs.length; i < len; i++){
21249                         handles[getId(hs[i])] = data;
21250                 }
21251             }
21252         },
21253
21254     /**
21255      * Unregister a drag drop element
21256      * @param {String|HTMLElement}  element The id or DOM node to unregister
21257      */
21258         unregister : function(el){
21259             var id = getId(el, false);
21260             var data = elements[id];
21261             if(data){
21262                 delete elements[id];
21263                 if(data.handles){
21264                     var hs = data.handles;
21265                     for(var i = 0, len = hs.length; i < len; i++){
21266                         delete handles[getId(hs[i], false)];
21267                     }
21268                 }
21269             }
21270         },
21271
21272     /**
21273      * Returns the handle registered for a DOM Node by id
21274      * @param {String|HTMLElement} id The DOM node or id to look up
21275      * @return {Object} handle The custom handle data
21276      */
21277         getHandle : function(id){
21278             if(typeof id != "string"){ // must be element?
21279                 id = id.id;
21280             }
21281             return handles[id];
21282         },
21283
21284     /**
21285      * Returns the handle that is registered for the DOM node that is the target of the event
21286      * @param {Event} e The event
21287      * @return {Object} handle The custom handle data
21288      */
21289         getHandleFromEvent : function(e){
21290             var t = Roo.lib.Event.getTarget(e);
21291             return t ? handles[t.id] : null;
21292         },
21293
21294     /**
21295      * Returns a custom data object that is registered for a DOM node by id
21296      * @param {String|HTMLElement} id The DOM node or id to look up
21297      * @return {Object} data The custom data
21298      */
21299         getTarget : function(id){
21300             if(typeof id != "string"){ // must be element?
21301                 id = id.id;
21302             }
21303             return elements[id];
21304         },
21305
21306     /**
21307      * Returns a custom data object that is registered for the DOM node that is the target of the event
21308      * @param {Event} e The event
21309      * @return {Object} data The custom data
21310      */
21311         getTargetFromEvent : function(e){
21312             var t = Roo.lib.Event.getTarget(e);
21313             return t ? elements[t.id] || handles[t.id] : null;
21314         }
21315     };
21316 }();/*
21317  * Based on:
21318  * Ext JS Library 1.1.1
21319  * Copyright(c) 2006-2007, Ext JS, LLC.
21320  *
21321  * Originally Released Under LGPL - original licence link has changed is not relivant.
21322  *
21323  * Fork - LGPL
21324  * <script type="text/javascript">
21325  */
21326  
21327
21328 /**
21329  * @class Roo.dd.StatusProxy
21330  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21331  * default drag proxy used by all Roo.dd components.
21332  * @constructor
21333  * @param {Object} config
21334  */
21335 Roo.dd.StatusProxy = function(config){
21336     Roo.apply(this, config);
21337     this.id = this.id || Roo.id();
21338     this.el = new Roo.Layer({
21339         dh: {
21340             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21341                 {tag: "div", cls: "x-dd-drop-icon"},
21342                 {tag: "div", cls: "x-dd-drag-ghost"}
21343             ]
21344         }, 
21345         shadow: !config || config.shadow !== false
21346     });
21347     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21348     this.dropStatus = this.dropNotAllowed;
21349 };
21350
21351 Roo.dd.StatusProxy.prototype = {
21352     /**
21353      * @cfg {String} dropAllowed
21354      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21355      */
21356     dropAllowed : "x-dd-drop-ok",
21357     /**
21358      * @cfg {String} dropNotAllowed
21359      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21360      */
21361     dropNotAllowed : "x-dd-drop-nodrop",
21362
21363     /**
21364      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21365      * over the current target element.
21366      * @param {String} cssClass The css class for the new drop status indicator image
21367      */
21368     setStatus : function(cssClass){
21369         cssClass = cssClass || this.dropNotAllowed;
21370         if(this.dropStatus != cssClass){
21371             this.el.replaceClass(this.dropStatus, cssClass);
21372             this.dropStatus = cssClass;
21373         }
21374     },
21375
21376     /**
21377      * Resets the status indicator to the default dropNotAllowed value
21378      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21379      */
21380     reset : function(clearGhost){
21381         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21382         this.dropStatus = this.dropNotAllowed;
21383         if(clearGhost){
21384             this.ghost.update("");
21385         }
21386     },
21387
21388     /**
21389      * Updates the contents of the ghost element
21390      * @param {String} html The html that will replace the current innerHTML of the ghost element
21391      */
21392     update : function(html){
21393         if(typeof html == "string"){
21394             this.ghost.update(html);
21395         }else{
21396             this.ghost.update("");
21397             html.style.margin = "0";
21398             this.ghost.dom.appendChild(html);
21399         }
21400         // ensure float = none set?? cant remember why though.
21401         var el = this.ghost.dom.firstChild;
21402                 if(el){
21403                         Roo.fly(el).setStyle('float', 'none');
21404                 }
21405     },
21406     
21407     /**
21408      * Returns the underlying proxy {@link Roo.Layer}
21409      * @return {Roo.Layer} el
21410     */
21411     getEl : function(){
21412         return this.el;
21413     },
21414
21415     /**
21416      * Returns the ghost element
21417      * @return {Roo.Element} el
21418      */
21419     getGhost : function(){
21420         return this.ghost;
21421     },
21422
21423     /**
21424      * Hides the proxy
21425      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21426      */
21427     hide : function(clear){
21428         this.el.hide();
21429         if(clear){
21430             this.reset(true);
21431         }
21432     },
21433
21434     /**
21435      * Stops the repair animation if it's currently running
21436      */
21437     stop : function(){
21438         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21439             this.anim.stop();
21440         }
21441     },
21442
21443     /**
21444      * Displays this proxy
21445      */
21446     show : function(){
21447         this.el.show();
21448     },
21449
21450     /**
21451      * Force the Layer to sync its shadow and shim positions to the element
21452      */
21453     sync : function(){
21454         this.el.sync();
21455     },
21456
21457     /**
21458      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21459      * invalid drop operation by the item being dragged.
21460      * @param {Array} xy The XY position of the element ([x, y])
21461      * @param {Function} callback The function to call after the repair is complete
21462      * @param {Object} scope The scope in which to execute the callback
21463      */
21464     repair : function(xy, callback, scope){
21465         this.callback = callback;
21466         this.scope = scope;
21467         if(xy && this.animRepair !== false){
21468             this.el.addClass("x-dd-drag-repair");
21469             this.el.hideUnders(true);
21470             this.anim = this.el.shift({
21471                 duration: this.repairDuration || .5,
21472                 easing: 'easeOut',
21473                 xy: xy,
21474                 stopFx: true,
21475                 callback: this.afterRepair,
21476                 scope: this
21477             });
21478         }else{
21479             this.afterRepair();
21480         }
21481     },
21482
21483     // private
21484     afterRepair : function(){
21485         this.hide(true);
21486         if(typeof this.callback == "function"){
21487             this.callback.call(this.scope || this);
21488         }
21489         this.callback = null;
21490         this.scope = null;
21491     }
21492 };/*
21493  * Based on:
21494  * Ext JS Library 1.1.1
21495  * Copyright(c) 2006-2007, Ext JS, LLC.
21496  *
21497  * Originally Released Under LGPL - original licence link has changed is not relivant.
21498  *
21499  * Fork - LGPL
21500  * <script type="text/javascript">
21501  */
21502
21503 /**
21504  * @class Roo.dd.DragSource
21505  * @extends Roo.dd.DDProxy
21506  * A simple class that provides the basic implementation needed to make any element draggable.
21507  * @constructor
21508  * @param {String/HTMLElement/Element} el The container element
21509  * @param {Object} config
21510  */
21511 Roo.dd.DragSource = function(el, config){
21512     this.el = Roo.get(el);
21513     this.dragData = {};
21514     
21515     Roo.apply(this, config);
21516     
21517     if(!this.proxy){
21518         this.proxy = new Roo.dd.StatusProxy();
21519     }
21520
21521     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21522           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21523     
21524     this.dragging = false;
21525 };
21526
21527 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21528     /**
21529      * @cfg {String} dropAllowed
21530      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21531      */
21532     dropAllowed : "x-dd-drop-ok",
21533     /**
21534      * @cfg {String} dropNotAllowed
21535      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21536      */
21537     dropNotAllowed : "x-dd-drop-nodrop",
21538
21539     /**
21540      * Returns the data object associated with this drag source
21541      * @return {Object} data An object containing arbitrary data
21542      */
21543     getDragData : function(e){
21544         return this.dragData;
21545     },
21546
21547     // private
21548     onDragEnter : function(e, id){
21549         var target = Roo.dd.DragDropMgr.getDDById(id);
21550         this.cachedTarget = target;
21551         if(this.beforeDragEnter(target, e, id) !== false){
21552             if(target.isNotifyTarget){
21553                 var status = target.notifyEnter(this, e, this.dragData);
21554                 this.proxy.setStatus(status);
21555             }else{
21556                 this.proxy.setStatus(this.dropAllowed);
21557             }
21558             
21559             if(this.afterDragEnter){
21560                 /**
21561                  * An empty function by default, but provided so that you can perform a custom action
21562                  * when the dragged item enters the drop target by providing an implementation.
21563                  * @param {Roo.dd.DragDrop} target The drop target
21564                  * @param {Event} e The event object
21565                  * @param {String} id The id of the dragged element
21566                  * @method afterDragEnter
21567                  */
21568                 this.afterDragEnter(target, e, id);
21569             }
21570         }
21571     },
21572
21573     /**
21574      * An empty function by default, but provided so that you can perform a custom action
21575      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21576      * @param {Roo.dd.DragDrop} target The drop target
21577      * @param {Event} e The event object
21578      * @param {String} id The id of the dragged element
21579      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21580      */
21581     beforeDragEnter : function(target, e, id){
21582         return true;
21583     },
21584
21585     // private
21586     alignElWithMouse: function() {
21587         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21588         this.proxy.sync();
21589     },
21590
21591     // private
21592     onDragOver : function(e, id){
21593         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21594         if(this.beforeDragOver(target, e, id) !== false){
21595             if(target.isNotifyTarget){
21596                 var status = target.notifyOver(this, e, this.dragData);
21597                 this.proxy.setStatus(status);
21598             }
21599
21600             if(this.afterDragOver){
21601                 /**
21602                  * An empty function by default, but provided so that you can perform a custom action
21603                  * while the dragged item is over the drop target by providing an implementation.
21604                  * @param {Roo.dd.DragDrop} target The drop target
21605                  * @param {Event} e The event object
21606                  * @param {String} id The id of the dragged element
21607                  * @method afterDragOver
21608                  */
21609                 this.afterDragOver(target, e, id);
21610             }
21611         }
21612     },
21613
21614     /**
21615      * An empty function by default, but provided so that you can perform a custom action
21616      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21617      * @param {Roo.dd.DragDrop} target The drop target
21618      * @param {Event} e The event object
21619      * @param {String} id The id of the dragged element
21620      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21621      */
21622     beforeDragOver : function(target, e, id){
21623         return true;
21624     },
21625
21626     // private
21627     onDragOut : function(e, id){
21628         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21629         if(this.beforeDragOut(target, e, id) !== false){
21630             if(target.isNotifyTarget){
21631                 target.notifyOut(this, e, this.dragData);
21632             }
21633             this.proxy.reset();
21634             if(this.afterDragOut){
21635                 /**
21636                  * An empty function by default, but provided so that you can perform a custom action
21637                  * after the dragged item is dragged out of the target without dropping.
21638                  * @param {Roo.dd.DragDrop} target The drop target
21639                  * @param {Event} e The event object
21640                  * @param {String} id The id of the dragged element
21641                  * @method afterDragOut
21642                  */
21643                 this.afterDragOut(target, e, id);
21644             }
21645         }
21646         this.cachedTarget = null;
21647     },
21648
21649     /**
21650      * An empty function by default, but provided so that you can perform a custom action before the dragged
21651      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21652      * @param {Roo.dd.DragDrop} target The drop target
21653      * @param {Event} e The event object
21654      * @param {String} id The id of the dragged element
21655      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21656      */
21657     beforeDragOut : function(target, e, id){
21658         return true;
21659     },
21660     
21661     // private
21662     onDragDrop : function(e, id){
21663         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21664         if(this.beforeDragDrop(target, e, id) !== false){
21665             if(target.isNotifyTarget){
21666                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21667                     this.onValidDrop(target, e, id);
21668                 }else{
21669                     this.onInvalidDrop(target, e, id);
21670                 }
21671             }else{
21672                 this.onValidDrop(target, e, id);
21673             }
21674             
21675             if(this.afterDragDrop){
21676                 /**
21677                  * An empty function by default, but provided so that you can perform a custom action
21678                  * after a valid drag drop has occurred by providing an implementation.
21679                  * @param {Roo.dd.DragDrop} target The drop target
21680                  * @param {Event} e The event object
21681                  * @param {String} id The id of the dropped element
21682                  * @method afterDragDrop
21683                  */
21684                 this.afterDragDrop(target, e, id);
21685             }
21686         }
21687         delete this.cachedTarget;
21688     },
21689
21690     /**
21691      * An empty function by default, but provided so that you can perform a custom action before the dragged
21692      * item is dropped onto the target and optionally cancel the onDragDrop.
21693      * @param {Roo.dd.DragDrop} target The drop target
21694      * @param {Event} e The event object
21695      * @param {String} id The id of the dragged element
21696      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21697      */
21698     beforeDragDrop : function(target, e, id){
21699         return true;
21700     },
21701
21702     // private
21703     onValidDrop : function(target, e, id){
21704         this.hideProxy();
21705         if(this.afterValidDrop){
21706             /**
21707              * An empty function by default, but provided so that you can perform a custom action
21708              * after a valid drop has occurred by providing an implementation.
21709              * @param {Object} target The target DD 
21710              * @param {Event} e The event object
21711              * @param {String} id The id of the dropped element
21712              * @method afterInvalidDrop
21713              */
21714             this.afterValidDrop(target, e, id);
21715         }
21716     },
21717
21718     // private
21719     getRepairXY : function(e, data){
21720         return this.el.getXY();  
21721     },
21722
21723     // private
21724     onInvalidDrop : function(target, e, id){
21725         this.beforeInvalidDrop(target, e, id);
21726         if(this.cachedTarget){
21727             if(this.cachedTarget.isNotifyTarget){
21728                 this.cachedTarget.notifyOut(this, e, this.dragData);
21729             }
21730             this.cacheTarget = null;
21731         }
21732         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21733
21734         if(this.afterInvalidDrop){
21735             /**
21736              * An empty function by default, but provided so that you can perform a custom action
21737              * after an invalid drop has occurred by providing an implementation.
21738              * @param {Event} e The event object
21739              * @param {String} id The id of the dropped element
21740              * @method afterInvalidDrop
21741              */
21742             this.afterInvalidDrop(e, id);
21743         }
21744     },
21745
21746     // private
21747     afterRepair : function(){
21748         if(Roo.enableFx){
21749             this.el.highlight(this.hlColor || "c3daf9");
21750         }
21751         this.dragging = false;
21752     },
21753
21754     /**
21755      * An empty function by default, but provided so that you can perform a custom action after an invalid
21756      * drop has occurred.
21757      * @param {Roo.dd.DragDrop} target The drop target
21758      * @param {Event} e The event object
21759      * @param {String} id The id of the dragged element
21760      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21761      */
21762     beforeInvalidDrop : function(target, e, id){
21763         return true;
21764     },
21765
21766     // private
21767     handleMouseDown : function(e){
21768         if(this.dragging) {
21769             return;
21770         }
21771         var data = this.getDragData(e);
21772         if(data && this.onBeforeDrag(data, e) !== false){
21773             this.dragData = data;
21774             this.proxy.stop();
21775             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21776         } 
21777     },
21778
21779     /**
21780      * An empty function by default, but provided so that you can perform a custom action before the initial
21781      * drag event begins and optionally cancel it.
21782      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21783      * @param {Event} e The event object
21784      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21785      */
21786     onBeforeDrag : function(data, e){
21787         return true;
21788     },
21789
21790     /**
21791      * An empty function by default, but provided so that you can perform a custom action once the initial
21792      * drag event has begun.  The drag cannot be canceled from this function.
21793      * @param {Number} x The x position of the click on the dragged object
21794      * @param {Number} y The y position of the click on the dragged object
21795      */
21796     onStartDrag : Roo.emptyFn,
21797
21798     // private - YUI override
21799     startDrag : function(x, y){
21800         this.proxy.reset();
21801         this.dragging = true;
21802         this.proxy.update("");
21803         this.onInitDrag(x, y);
21804         this.proxy.show();
21805     },
21806
21807     // private
21808     onInitDrag : function(x, y){
21809         var clone = this.el.dom.cloneNode(true);
21810         clone.id = Roo.id(); // prevent duplicate ids
21811         this.proxy.update(clone);
21812         this.onStartDrag(x, y);
21813         return true;
21814     },
21815
21816     /**
21817      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21818      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21819      */
21820     getProxy : function(){
21821         return this.proxy;  
21822     },
21823
21824     /**
21825      * Hides the drag source's {@link Roo.dd.StatusProxy}
21826      */
21827     hideProxy : function(){
21828         this.proxy.hide();  
21829         this.proxy.reset(true);
21830         this.dragging = false;
21831     },
21832
21833     // private
21834     triggerCacheRefresh : function(){
21835         Roo.dd.DDM.refreshCache(this.groups);
21836     },
21837
21838     // private - override to prevent hiding
21839     b4EndDrag: function(e) {
21840     },
21841
21842     // private - override to prevent moving
21843     endDrag : function(e){
21844         this.onEndDrag(this.dragData, e);
21845     },
21846
21847     // private
21848     onEndDrag : function(data, e){
21849     },
21850     
21851     // private - pin to cursor
21852     autoOffset : function(x, y) {
21853         this.setDelta(-12, -20);
21854     }    
21855 });/*
21856  * Based on:
21857  * Ext JS Library 1.1.1
21858  * Copyright(c) 2006-2007, Ext JS, LLC.
21859  *
21860  * Originally Released Under LGPL - original licence link has changed is not relivant.
21861  *
21862  * Fork - LGPL
21863  * <script type="text/javascript">
21864  */
21865
21866
21867 /**
21868  * @class Roo.dd.DropTarget
21869  * @extends Roo.dd.DDTarget
21870  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21871  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21872  * @constructor
21873  * @param {String/HTMLElement/Element} el The container element
21874  * @param {Object} config
21875  */
21876 Roo.dd.DropTarget = function(el, config){
21877     this.el = Roo.get(el);
21878     
21879     var listeners = false; ;
21880     if (config && config.listeners) {
21881         listeners= config.listeners;
21882         delete config.listeners;
21883     }
21884     Roo.apply(this, config);
21885     
21886     if(this.containerScroll){
21887         Roo.dd.ScrollManager.register(this.el);
21888     }
21889     this.addEvents( {
21890          /**
21891          * @scope Roo.dd.DropTarget
21892          */
21893          
21894          /**
21895          * @event enter
21896          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21897          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21898          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21899          * 
21900          * IMPORTANT : it should set this.overClass and this.dropAllowed
21901          * 
21902          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21903          * @param {Event} e The event
21904          * @param {Object} data An object containing arbitrary data supplied by the drag source
21905          */
21906         "enter" : true,
21907         
21908          /**
21909          * @event over
21910          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21911          * This method will be called on every mouse movement while the drag source is over the drop target.
21912          * This default implementation simply returns the dropAllowed config value.
21913          * 
21914          * IMPORTANT : it should set this.dropAllowed
21915          * 
21916          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21917          * @param {Event} e The event
21918          * @param {Object} data An object containing arbitrary data supplied by the drag source
21919          
21920          */
21921         "over" : true,
21922         /**
21923          * @event out
21924          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21925          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21926          * overClass (if any) from the drop element.
21927          * 
21928          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21929          * @param {Event} e The event
21930          * @param {Object} data An object containing arbitrary data supplied by the drag source
21931          */
21932          "out" : true,
21933          
21934         /**
21935          * @event drop
21936          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21937          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21938          * implementation that does something to process the drop event and returns true so that the drag source's
21939          * repair action does not run.
21940          * 
21941          * IMPORTANT : it should set this.success
21942          * 
21943          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21944          * @param {Event} e The event
21945          * @param {Object} data An object containing arbitrary data supplied by the drag source
21946         */
21947          "drop" : true
21948     });
21949             
21950      
21951     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21952         this.el.dom, 
21953         this.ddGroup || this.group,
21954         {
21955             isTarget: true,
21956             listeners : listeners || {} 
21957            
21958         
21959         }
21960     );
21961
21962 };
21963
21964 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21965     /**
21966      * @cfg {String} overClass
21967      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21968      */
21969      /**
21970      * @cfg {String} ddGroup
21971      * The drag drop group to handle drop events for
21972      */
21973      
21974     /**
21975      * @cfg {String} dropAllowed
21976      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21977      */
21978     dropAllowed : "x-dd-drop-ok",
21979     /**
21980      * @cfg {String} dropNotAllowed
21981      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21982      */
21983     dropNotAllowed : "x-dd-drop-nodrop",
21984     /**
21985      * @cfg {boolean} success
21986      * set this after drop listener.. 
21987      */
21988     success : false,
21989     /**
21990      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21991      * if the drop point is valid for over/enter..
21992      */
21993     valid : false,
21994     // private
21995     isTarget : true,
21996
21997     // private
21998     isNotifyTarget : true,
21999     
22000     /**
22001      * @hide
22002      */
22003     notifyEnter : function(dd, e, data)
22004     {
22005         this.valid = true;
22006         this.fireEvent('enter', dd, e, data);
22007         if(this.overClass){
22008             this.el.addClass(this.overClass);
22009         }
22010         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22011             this.valid ? this.dropAllowed : this.dropNotAllowed
22012         );
22013     },
22014
22015     /**
22016      * @hide
22017      */
22018     notifyOver : function(dd, e, data)
22019     {
22020         this.valid = true;
22021         this.fireEvent('over', dd, e, data);
22022         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22023             this.valid ? this.dropAllowed : this.dropNotAllowed
22024         );
22025     },
22026
22027     /**
22028      * @hide
22029      */
22030     notifyOut : function(dd, e, data)
22031     {
22032         this.fireEvent('out', dd, e, data);
22033         if(this.overClass){
22034             this.el.removeClass(this.overClass);
22035         }
22036     },
22037
22038     /**
22039      * @hide
22040      */
22041     notifyDrop : function(dd, e, data)
22042     {
22043         this.success = false;
22044         this.fireEvent('drop', dd, e, data);
22045         return this.success;
22046     }
22047 });/*
22048  * Based on:
22049  * Ext JS Library 1.1.1
22050  * Copyright(c) 2006-2007, Ext JS, LLC.
22051  *
22052  * Originally Released Under LGPL - original licence link has changed is not relivant.
22053  *
22054  * Fork - LGPL
22055  * <script type="text/javascript">
22056  */
22057
22058
22059 /**
22060  * @class Roo.dd.DragZone
22061  * @extends Roo.dd.DragSource
22062  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22063  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22064  * @constructor
22065  * @param {String/HTMLElement/Element} el The container element
22066  * @param {Object} config
22067  */
22068 Roo.dd.DragZone = function(el, config){
22069     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22070     if(this.containerScroll){
22071         Roo.dd.ScrollManager.register(this.el);
22072     }
22073 };
22074
22075 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22076     /**
22077      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22078      * for auto scrolling during drag operations.
22079      */
22080     /**
22081      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22082      * method after a failed drop (defaults to "c3daf9" - light blue)
22083      */
22084
22085     /**
22086      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22087      * for a valid target to drag based on the mouse down. Override this method
22088      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22089      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22090      * @param {EventObject} e The mouse down event
22091      * @return {Object} The dragData
22092      */
22093     getDragData : function(e){
22094         return Roo.dd.Registry.getHandleFromEvent(e);
22095     },
22096     
22097     /**
22098      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22099      * this.dragData.ddel
22100      * @param {Number} x The x position of the click on the dragged object
22101      * @param {Number} y The y position of the click on the dragged object
22102      * @return {Boolean} true to continue the drag, false to cancel
22103      */
22104     onInitDrag : function(x, y){
22105         this.proxy.update(this.dragData.ddel.cloneNode(true));
22106         this.onStartDrag(x, y);
22107         return true;
22108     },
22109     
22110     /**
22111      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22112      */
22113     afterRepair : function(){
22114         if(Roo.enableFx){
22115             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22116         }
22117         this.dragging = false;
22118     },
22119
22120     /**
22121      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22122      * the XY of this.dragData.ddel
22123      * @param {EventObject} e The mouse up event
22124      * @return {Array} The xy location (e.g. [100, 200])
22125      */
22126     getRepairXY : function(e){
22127         return Roo.Element.fly(this.dragData.ddel).getXY();  
22128     }
22129 });/*
22130  * Based on:
22131  * Ext JS Library 1.1.1
22132  * Copyright(c) 2006-2007, Ext JS, LLC.
22133  *
22134  * Originally Released Under LGPL - original licence link has changed is not relivant.
22135  *
22136  * Fork - LGPL
22137  * <script type="text/javascript">
22138  */
22139 /**
22140  * @class Roo.dd.DropZone
22141  * @extends Roo.dd.DropTarget
22142  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22143  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22144  * @constructor
22145  * @param {String/HTMLElement/Element} el The container element
22146  * @param {Object} config
22147  */
22148 Roo.dd.DropZone = function(el, config){
22149     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22150 };
22151
22152 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22153     /**
22154      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22155      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22156      * provide your own custom lookup.
22157      * @param {Event} e The event
22158      * @return {Object} data The custom data
22159      */
22160     getTargetFromEvent : function(e){
22161         return Roo.dd.Registry.getTargetFromEvent(e);
22162     },
22163
22164     /**
22165      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22166      * that it has registered.  This method has no default implementation and should be overridden to provide
22167      * node-specific processing if necessary.
22168      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22169      * {@link #getTargetFromEvent} for this node)
22170      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22171      * @param {Event} e The event
22172      * @param {Object} data An object containing arbitrary data supplied by the drag source
22173      */
22174     onNodeEnter : function(n, dd, e, data){
22175         
22176     },
22177
22178     /**
22179      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22180      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22181      * overridden to provide the proper feedback.
22182      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22183      * {@link #getTargetFromEvent} for this node)
22184      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22185      * @param {Event} e The event
22186      * @param {Object} data An object containing arbitrary data supplied by the drag source
22187      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22188      * underlying {@link Roo.dd.StatusProxy} can be updated
22189      */
22190     onNodeOver : function(n, dd, e, data){
22191         return this.dropAllowed;
22192     },
22193
22194     /**
22195      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22196      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22197      * node-specific processing if necessary.
22198      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22199      * {@link #getTargetFromEvent} for this node)
22200      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22201      * @param {Event} e The event
22202      * @param {Object} data An object containing arbitrary data supplied by the drag source
22203      */
22204     onNodeOut : function(n, dd, e, data){
22205         
22206     },
22207
22208     /**
22209      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22210      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22211      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22212      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22213      * {@link #getTargetFromEvent} for this node)
22214      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22215      * @param {Event} e The event
22216      * @param {Object} data An object containing arbitrary data supplied by the drag source
22217      * @return {Boolean} True if the drop was valid, else false
22218      */
22219     onNodeDrop : function(n, dd, e, data){
22220         return false;
22221     },
22222
22223     /**
22224      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22225      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22226      * it should be overridden to provide the proper feedback if necessary.
22227      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22228      * @param {Event} e The event
22229      * @param {Object} data An object containing arbitrary data supplied by the drag source
22230      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22231      * underlying {@link Roo.dd.StatusProxy} can be updated
22232      */
22233     onContainerOver : function(dd, e, data){
22234         return this.dropNotAllowed;
22235     },
22236
22237     /**
22238      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22239      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22240      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22241      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22242      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22243      * @param {Event} e The event
22244      * @param {Object} data An object containing arbitrary data supplied by the drag source
22245      * @return {Boolean} True if the drop was valid, else false
22246      */
22247     onContainerDrop : function(dd, e, data){
22248         return false;
22249     },
22250
22251     /**
22252      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22253      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22254      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22255      * you should override this method and provide a custom implementation.
22256      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22257      * @param {Event} e The event
22258      * @param {Object} data An object containing arbitrary data supplied by the drag source
22259      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22260      * underlying {@link Roo.dd.StatusProxy} can be updated
22261      */
22262     notifyEnter : function(dd, e, data){
22263         return this.dropNotAllowed;
22264     },
22265
22266     /**
22267      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22268      * This method will be called on every mouse movement while the drag source is over the drop zone.
22269      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22270      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22271      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22272      * registered node, it will call {@link #onContainerOver}.
22273      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22274      * @param {Event} e The event
22275      * @param {Object} data An object containing arbitrary data supplied by the drag source
22276      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22277      * underlying {@link Roo.dd.StatusProxy} can be updated
22278      */
22279     notifyOver : function(dd, e, data){
22280         var n = this.getTargetFromEvent(e);
22281         if(!n){ // not over valid drop target
22282             if(this.lastOverNode){
22283                 this.onNodeOut(this.lastOverNode, dd, e, data);
22284                 this.lastOverNode = null;
22285             }
22286             return this.onContainerOver(dd, e, data);
22287         }
22288         if(this.lastOverNode != n){
22289             if(this.lastOverNode){
22290                 this.onNodeOut(this.lastOverNode, dd, e, data);
22291             }
22292             this.onNodeEnter(n, dd, e, data);
22293             this.lastOverNode = n;
22294         }
22295         return this.onNodeOver(n, dd, e, data);
22296     },
22297
22298     /**
22299      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22300      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22301      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22302      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22303      * @param {Event} e The event
22304      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22305      */
22306     notifyOut : function(dd, e, data){
22307         if(this.lastOverNode){
22308             this.onNodeOut(this.lastOverNode, dd, e, data);
22309             this.lastOverNode = null;
22310         }
22311     },
22312
22313     /**
22314      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22315      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22316      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22317      * otherwise it will call {@link #onContainerDrop}.
22318      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22319      * @param {Event} e The event
22320      * @param {Object} data An object containing arbitrary data supplied by the drag source
22321      * @return {Boolean} True if the drop was valid, else false
22322      */
22323     notifyDrop : function(dd, e, data){
22324         if(this.lastOverNode){
22325             this.onNodeOut(this.lastOverNode, dd, e, data);
22326             this.lastOverNode = null;
22327         }
22328         var n = this.getTargetFromEvent(e);
22329         return n ?
22330             this.onNodeDrop(n, dd, e, data) :
22331             this.onContainerDrop(dd, e, data);
22332     },
22333
22334     // private
22335     triggerCacheRefresh : function(){
22336         Roo.dd.DDM.refreshCache(this.groups);
22337     }  
22338 });