sync
[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             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7198         },
7199
7200         /**
7201          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7202          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7203          * @param {String} selector The simple selector to test
7204          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7205                 search as a number or element (defaults to 10 || document.body)
7206          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7207          */
7208         up : function(simpleSelector, maxDepth){
7209             return this.findParentNode(simpleSelector, maxDepth, true);
7210         },
7211
7212
7213
7214         /**
7215          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7216          * @param {String} selector The simple selector to test
7217          * @return {Boolean} True if this element matches the selector, else false
7218          */
7219         is : function(simpleSelector){
7220             return Roo.DomQuery.is(this.dom, simpleSelector);
7221         },
7222
7223         /**
7224          * Perform animation on this element.
7225          * @param {Object} args The YUI animation control args
7226          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7227          * @param {Function} onComplete (optional) Function to call when animation completes
7228          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7229          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7230          * @return {Roo.Element} this
7231          */
7232         animate : function(args, duration, onComplete, easing, animType){
7233             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7234             return this;
7235         },
7236
7237         /*
7238          * @private Internal animation call
7239          */
7240         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7241             animType = animType || 'run';
7242             opt = opt || {};
7243             var anim = Roo.lib.Anim[animType](
7244                 this.dom, args,
7245                 (opt.duration || defaultDur) || .35,
7246                 (opt.easing || defaultEase) || 'easeOut',
7247                 function(){
7248                     Roo.callback(cb, this);
7249                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7250                 },
7251                 this
7252             );
7253             opt.anim = anim;
7254             return anim;
7255         },
7256
7257         // private legacy anim prep
7258         preanim : function(a, i){
7259             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7260         },
7261
7262         /**
7263          * Removes worthless text nodes
7264          * @param {Boolean} forceReclean (optional) By default the element
7265          * keeps track if it has been cleaned already so
7266          * you can call this over and over. However, if you update the element and
7267          * need to force a reclean, you can pass true.
7268          */
7269         clean : function(forceReclean){
7270             if(this.isCleaned && forceReclean !== true){
7271                 return this;
7272             }
7273             var ns = /\S/;
7274             var d = this.dom, n = d.firstChild, ni = -1;
7275             while(n){
7276                 var nx = n.nextSibling;
7277                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7278                     d.removeChild(n);
7279                 }else{
7280                     n.nodeIndex = ++ni;
7281                 }
7282                 n = nx;
7283             }
7284             this.isCleaned = true;
7285             return this;
7286         },
7287
7288         // private
7289         calcOffsetsTo : function(el){
7290             el = Roo.get(el);
7291             var d = el.dom;
7292             var restorePos = false;
7293             if(el.getStyle('position') == 'static'){
7294                 el.position('relative');
7295                 restorePos = true;
7296             }
7297             var x = 0, y =0;
7298             var op = this.dom;
7299             while(op && op != d && op.tagName != 'HTML'){
7300                 x+= op.offsetLeft;
7301                 y+= op.offsetTop;
7302                 op = op.offsetParent;
7303             }
7304             if(restorePos){
7305                 el.position('static');
7306             }
7307             return [x, y];
7308         },
7309
7310         /**
7311          * Scrolls this element into view within the passed container.
7312          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7313          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7314          * @return {Roo.Element} this
7315          */
7316         scrollIntoView : function(container, hscroll){
7317             var c = Roo.getDom(container) || document.body;
7318             var el = this.dom;
7319
7320             var o = this.calcOffsetsTo(c),
7321                 l = o[0],
7322                 t = o[1],
7323                 b = t+el.offsetHeight,
7324                 r = l+el.offsetWidth;
7325
7326             var ch = c.clientHeight;
7327             var ct = parseInt(c.scrollTop, 10);
7328             var cl = parseInt(c.scrollLeft, 10);
7329             var cb = ct + ch;
7330             var cr = cl + c.clientWidth;
7331
7332             if(t < ct){
7333                 c.scrollTop = t;
7334             }else if(b > cb){
7335                 c.scrollTop = b-ch;
7336             }
7337
7338             if(hscroll !== false){
7339                 if(l < cl){
7340                     c.scrollLeft = l;
7341                 }else if(r > cr){
7342                     c.scrollLeft = r-c.clientWidth;
7343                 }
7344             }
7345             return this;
7346         },
7347
7348         // private
7349         scrollChildIntoView : function(child, hscroll){
7350             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7351         },
7352
7353         /**
7354          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7355          * the new height may not be available immediately.
7356          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7357          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7358          * @param {Function} onComplete (optional) Function to call when animation completes
7359          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7360          * @return {Roo.Element} this
7361          */
7362         autoHeight : function(animate, duration, onComplete, easing){
7363             var oldHeight = this.getHeight();
7364             this.clip();
7365             this.setHeight(1); // force clipping
7366             setTimeout(function(){
7367                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7368                 if(!animate){
7369                     this.setHeight(height);
7370                     this.unclip();
7371                     if(typeof onComplete == "function"){
7372                         onComplete();
7373                     }
7374                 }else{
7375                     this.setHeight(oldHeight); // restore original height
7376                     this.setHeight(height, animate, duration, function(){
7377                         this.unclip();
7378                         if(typeof onComplete == "function") { onComplete(); }
7379                     }.createDelegate(this), easing);
7380                 }
7381             }.createDelegate(this), 0);
7382             return this;
7383         },
7384
7385         /**
7386          * Returns true if this element is an ancestor of the passed element
7387          * @param {HTMLElement/String} el The element to check
7388          * @return {Boolean} True if this element is an ancestor of el, else false
7389          */
7390         contains : function(el){
7391             if(!el){return false;}
7392             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7393         },
7394
7395         /**
7396          * Checks whether the element is currently visible using both visibility and display properties.
7397          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7398          * @return {Boolean} True if the element is currently visible, else false
7399          */
7400         isVisible : function(deep) {
7401             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7402             if(deep !== true || !vis){
7403                 return vis;
7404             }
7405             var p = this.dom.parentNode;
7406             while(p && p.tagName.toLowerCase() != "body"){
7407                 if(!Roo.fly(p, '_isVisible').isVisible()){
7408                     return false;
7409                 }
7410                 p = p.parentNode;
7411             }
7412             return true;
7413         },
7414
7415         /**
7416          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7417          * @param {String} selector The CSS selector
7418          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7419          * @return {CompositeElement/CompositeElementLite} The composite element
7420          */
7421         select : function(selector, unique){
7422             return El.select(selector, unique, this.dom);
7423         },
7424
7425         /**
7426          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7427          * @param {String} selector The CSS selector
7428          * @return {Array} An array of the matched nodes
7429          */
7430         query : function(selector, unique){
7431             return Roo.DomQuery.select(selector, this.dom);
7432         },
7433
7434         /**
7435          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7436          * @param {String} selector The CSS selector
7437          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7438          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7439          */
7440         child : function(selector, returnDom){
7441             var n = Roo.DomQuery.selectNode(selector, this.dom);
7442             return returnDom ? n : Roo.get(n);
7443         },
7444
7445         /**
7446          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7447          * @param {String} selector The CSS selector
7448          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7449          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7450          */
7451         down : function(selector, returnDom){
7452             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7453             return returnDom ? n : Roo.get(n);
7454         },
7455
7456         /**
7457          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7458          * @param {String} group The group the DD object is member of
7459          * @param {Object} config The DD config object
7460          * @param {Object} overrides An object containing methods to override/implement on the DD object
7461          * @return {Roo.dd.DD} The DD object
7462          */
7463         initDD : function(group, config, overrides){
7464             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7465             return Roo.apply(dd, overrides);
7466         },
7467
7468         /**
7469          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7470          * @param {String} group The group the DDProxy object is member of
7471          * @param {Object} config The DDProxy config object
7472          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7473          * @return {Roo.dd.DDProxy} The DDProxy object
7474          */
7475         initDDProxy : function(group, config, overrides){
7476             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7477             return Roo.apply(dd, overrides);
7478         },
7479
7480         /**
7481          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7482          * @param {String} group The group the DDTarget object is member of
7483          * @param {Object} config The DDTarget config object
7484          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7485          * @return {Roo.dd.DDTarget} The DDTarget object
7486          */
7487         initDDTarget : function(group, config, overrides){
7488             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7489             return Roo.apply(dd, overrides);
7490         },
7491
7492         /**
7493          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7494          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7495          * @param {Boolean} visible Whether the element is visible
7496          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7497          * @return {Roo.Element} this
7498          */
7499          setVisible : function(visible, animate){
7500             if(!animate || !A){
7501                 if(this.visibilityMode == El.DISPLAY){
7502                     this.setDisplayed(visible);
7503                 }else{
7504                     this.fixDisplay();
7505                     this.dom.style.visibility = visible ? "visible" : "hidden";
7506                 }
7507             }else{
7508                 // closure for composites
7509                 var dom = this.dom;
7510                 var visMode = this.visibilityMode;
7511                 if(visible){
7512                     this.setOpacity(.01);
7513                     this.setVisible(true);
7514                 }
7515                 this.anim({opacity: { to: (visible?1:0) }},
7516                       this.preanim(arguments, 1),
7517                       null, .35, 'easeIn', function(){
7518                          if(!visible){
7519                              if(visMode == El.DISPLAY){
7520                                  dom.style.display = "none";
7521                              }else{
7522                                  dom.style.visibility = "hidden";
7523                              }
7524                              Roo.get(dom).setOpacity(1);
7525                          }
7526                      });
7527             }
7528             return this;
7529         },
7530
7531         /**
7532          * Returns true if display is not "none"
7533          * @return {Boolean}
7534          */
7535         isDisplayed : function() {
7536             return this.getStyle("display") != "none";
7537         },
7538
7539         /**
7540          * Toggles the element's visibility or display, depending on visibility mode.
7541          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7542          * @return {Roo.Element} this
7543          */
7544         toggle : function(animate){
7545             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7546             return this;
7547         },
7548
7549         /**
7550          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7551          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7552          * @return {Roo.Element} this
7553          */
7554         setDisplayed : function(value) {
7555             if(typeof value == "boolean"){
7556                value = value ? this.originalDisplay : "none";
7557             }
7558             this.setStyle("display", value);
7559             return this;
7560         },
7561
7562         /**
7563          * Tries to focus the element. Any exceptions are caught and ignored.
7564          * @return {Roo.Element} this
7565          */
7566         focus : function() {
7567             try{
7568                 this.dom.focus();
7569             }catch(e){}
7570             return this;
7571         },
7572
7573         /**
7574          * Tries to blur the element. Any exceptions are caught and ignored.
7575          * @return {Roo.Element} this
7576          */
7577         blur : function() {
7578             try{
7579                 this.dom.blur();
7580             }catch(e){}
7581             return this;
7582         },
7583
7584         /**
7585          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7586          * @param {String/Array} className The CSS class to add, or an array of classes
7587          * @return {Roo.Element} this
7588          */
7589         addClass : function(className){
7590             if(className instanceof Array){
7591                 for(var i = 0, len = className.length; i < len; i++) {
7592                     this.addClass(className[i]);
7593                 }
7594             }else{
7595                 if(className && !this.hasClass(className)){
7596                     this.dom.className = this.dom.className + " " + className;
7597                 }
7598             }
7599             return this;
7600         },
7601
7602         /**
7603          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7604          * @param {String/Array} className The CSS class to add, or an array of classes
7605          * @return {Roo.Element} this
7606          */
7607         radioClass : function(className){
7608             var siblings = this.dom.parentNode.childNodes;
7609             for(var i = 0; i < siblings.length; i++) {
7610                 var s = siblings[i];
7611                 if(s.nodeType == 1){
7612                     Roo.get(s).removeClass(className);
7613                 }
7614             }
7615             this.addClass(className);
7616             return this;
7617         },
7618
7619         /**
7620          * Removes one or more CSS classes from the element.
7621          * @param {String/Array} className The CSS class to remove, or an array of classes
7622          * @return {Roo.Element} this
7623          */
7624         removeClass : function(className){
7625             if(!className || !this.dom.className){
7626                 return this;
7627             }
7628             if(className instanceof Array){
7629                 for(var i = 0, len = className.length; i < len; i++) {
7630                     this.removeClass(className[i]);
7631                 }
7632             }else{
7633                 if(this.hasClass(className)){
7634                     var re = this.classReCache[className];
7635                     if (!re) {
7636                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7637                        this.classReCache[className] = re;
7638                     }
7639                     this.dom.className =
7640                         this.dom.className.replace(re, " ");
7641                 }
7642             }
7643             return this;
7644         },
7645
7646         // private
7647         classReCache: {},
7648
7649         /**
7650          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7651          * @param {String} className The CSS class to toggle
7652          * @return {Roo.Element} this
7653          */
7654         toggleClass : function(className){
7655             if(this.hasClass(className)){
7656                 this.removeClass(className);
7657             }else{
7658                 this.addClass(className);
7659             }
7660             return this;
7661         },
7662
7663         /**
7664          * Checks if the specified CSS class exists on this element's DOM node.
7665          * @param {String} className The CSS class to check for
7666          * @return {Boolean} True if the class exists, else false
7667          */
7668         hasClass : function(className){
7669             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7670         },
7671
7672         /**
7673          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7674          * @param {String} oldClassName The CSS class to replace
7675          * @param {String} newClassName The replacement CSS class
7676          * @return {Roo.Element} this
7677          */
7678         replaceClass : function(oldClassName, newClassName){
7679             this.removeClass(oldClassName);
7680             this.addClass(newClassName);
7681             return this;
7682         },
7683
7684         /**
7685          * Returns an object with properties matching the styles requested.
7686          * For example, el.getStyles('color', 'font-size', 'width') might return
7687          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7688          * @param {String} style1 A style name
7689          * @param {String} style2 A style name
7690          * @param {String} etc.
7691          * @return {Object} The style object
7692          */
7693         getStyles : function(){
7694             var a = arguments, len = a.length, r = {};
7695             for(var i = 0; i < len; i++){
7696                 r[a[i]] = this.getStyle(a[i]);
7697             }
7698             return r;
7699         },
7700
7701         /**
7702          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7703          * @param {String} property The style property whose value is returned.
7704          * @return {String} The current value of the style property for this element.
7705          */
7706         getStyle : function(){
7707             return view && view.getComputedStyle ?
7708                 function(prop){
7709                     var el = this.dom, v, cs, camel;
7710                     if(prop == 'float'){
7711                         prop = "cssFloat";
7712                     }
7713                     if(el.style && (v = el.style[prop])){
7714                         return v;
7715                     }
7716                     if(cs = view.getComputedStyle(el, "")){
7717                         if(!(camel = propCache[prop])){
7718                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7719                         }
7720                         return cs[camel];
7721                     }
7722                     return null;
7723                 } :
7724                 function(prop){
7725                     var el = this.dom, v, cs, camel;
7726                     if(prop == 'opacity'){
7727                         if(typeof el.style.filter == 'string'){
7728                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7729                             if(m){
7730                                 var fv = parseFloat(m[1]);
7731                                 if(!isNaN(fv)){
7732                                     return fv ? fv / 100 : 0;
7733                                 }
7734                             }
7735                         }
7736                         return 1;
7737                     }else if(prop == 'float'){
7738                         prop = "styleFloat";
7739                     }
7740                     if(!(camel = propCache[prop])){
7741                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7742                     }
7743                     if(v = el.style[camel]){
7744                         return v;
7745                     }
7746                     if(cs = el.currentStyle){
7747                         return cs[camel];
7748                     }
7749                     return null;
7750                 };
7751         }(),
7752
7753         /**
7754          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7755          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7756          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7757          * @return {Roo.Element} this
7758          */
7759         setStyle : function(prop, value){
7760             if(typeof prop == "string"){
7761                 
7762                 if (prop == 'float') {
7763                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7764                     return this;
7765                 }
7766                 
7767                 var camel;
7768                 if(!(camel = propCache[prop])){
7769                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7770                 }
7771                 
7772                 if(camel == 'opacity') {
7773                     this.setOpacity(value);
7774                 }else{
7775                     this.dom.style[camel] = value;
7776                 }
7777             }else{
7778                 for(var style in prop){
7779                     if(typeof prop[style] != "function"){
7780                        this.setStyle(style, prop[style]);
7781                     }
7782                 }
7783             }
7784             return this;
7785         },
7786
7787         /**
7788          * More flexible version of {@link #setStyle} for setting style properties.
7789          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7790          * a function which returns such a specification.
7791          * @return {Roo.Element} this
7792          */
7793         applyStyles : function(style){
7794             Roo.DomHelper.applyStyles(this.dom, style);
7795             return this;
7796         },
7797
7798         /**
7799           * 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).
7800           * @return {Number} The X position of the element
7801           */
7802         getX : function(){
7803             return D.getX(this.dom);
7804         },
7805
7806         /**
7807           * 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).
7808           * @return {Number} The Y position of the element
7809           */
7810         getY : function(){
7811             return D.getY(this.dom);
7812         },
7813
7814         /**
7815           * 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).
7816           * @return {Array} The XY position of the element
7817           */
7818         getXY : function(){
7819             return D.getXY(this.dom);
7820         },
7821
7822         /**
7823          * 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).
7824          * @param {Number} The X position of the element
7825          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7826          * @return {Roo.Element} this
7827          */
7828         setX : function(x, animate){
7829             if(!animate || !A){
7830                 D.setX(this.dom, x);
7831             }else{
7832                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7833             }
7834             return this;
7835         },
7836
7837         /**
7838          * 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).
7839          * @param {Number} The Y position of the element
7840          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7841          * @return {Roo.Element} this
7842          */
7843         setY : function(y, animate){
7844             if(!animate || !A){
7845                 D.setY(this.dom, y);
7846             }else{
7847                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7848             }
7849             return this;
7850         },
7851
7852         /**
7853          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7854          * @param {String} left The left CSS property value
7855          * @return {Roo.Element} this
7856          */
7857         setLeft : function(left){
7858             this.setStyle("left", this.addUnits(left));
7859             return this;
7860         },
7861
7862         /**
7863          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7864          * @param {String} top The top CSS property value
7865          * @return {Roo.Element} this
7866          */
7867         setTop : function(top){
7868             this.setStyle("top", this.addUnits(top));
7869             return this;
7870         },
7871
7872         /**
7873          * Sets the element's CSS right style.
7874          * @param {String} right The right CSS property value
7875          * @return {Roo.Element} this
7876          */
7877         setRight : function(right){
7878             this.setStyle("right", this.addUnits(right));
7879             return this;
7880         },
7881
7882         /**
7883          * Sets the element's CSS bottom style.
7884          * @param {String} bottom The bottom CSS property value
7885          * @return {Roo.Element} this
7886          */
7887         setBottom : function(bottom){
7888             this.setStyle("bottom", this.addUnits(bottom));
7889             return this;
7890         },
7891
7892         /**
7893          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7894          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7895          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7896          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7897          * @return {Roo.Element} this
7898          */
7899         setXY : function(pos, animate){
7900             if(!animate || !A){
7901                 D.setXY(this.dom, pos);
7902             }else{
7903                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7904             }
7905             return this;
7906         },
7907
7908         /**
7909          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7910          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7911          * @param {Number} x X value for new position (coordinates are page-based)
7912          * @param {Number} y Y value for new position (coordinates are page-based)
7913          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7914          * @return {Roo.Element} this
7915          */
7916         setLocation : function(x, y, animate){
7917             this.setXY([x, y], this.preanim(arguments, 2));
7918             return this;
7919         },
7920
7921         /**
7922          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7923          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7924          * @param {Number} x X value for new position (coordinates are page-based)
7925          * @param {Number} y Y value for new position (coordinates are page-based)
7926          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7927          * @return {Roo.Element} this
7928          */
7929         moveTo : function(x, y, animate){
7930             this.setXY([x, y], this.preanim(arguments, 2));
7931             return this;
7932         },
7933
7934         /**
7935          * Returns the region of the given element.
7936          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7937          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7938          */
7939         getRegion : function(){
7940             return D.getRegion(this.dom);
7941         },
7942
7943         /**
7944          * Returns the offset height of the element
7945          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7946          * @return {Number} The element's height
7947          */
7948         getHeight : function(contentHeight){
7949             var h = this.dom.offsetHeight || 0;
7950             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7951         },
7952
7953         /**
7954          * Returns the offset width of the element
7955          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7956          * @return {Number} The element's width
7957          */
7958         getWidth : function(contentWidth){
7959             var w = this.dom.offsetWidth || 0;
7960             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7961         },
7962
7963         /**
7964          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7965          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7966          * if a height has not been set using CSS.
7967          * @return {Number}
7968          */
7969         getComputedHeight : function(){
7970             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7971             if(!h){
7972                 h = parseInt(this.getStyle('height'), 10) || 0;
7973                 if(!this.isBorderBox()){
7974                     h += this.getFrameWidth('tb');
7975                 }
7976             }
7977             return h;
7978         },
7979
7980         /**
7981          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7982          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7983          * if a width has not been set using CSS.
7984          * @return {Number}
7985          */
7986         getComputedWidth : function(){
7987             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7988             if(!w){
7989                 w = parseInt(this.getStyle('width'), 10) || 0;
7990                 if(!this.isBorderBox()){
7991                     w += this.getFrameWidth('lr');
7992                 }
7993             }
7994             return w;
7995         },
7996
7997         /**
7998          * Returns the size of the element.
7999          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8000          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8001          */
8002         getSize : function(contentSize){
8003             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8004         },
8005
8006         /**
8007          * Returns the width and height of the viewport.
8008          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8009          */
8010         getViewSize : function(){
8011             var d = this.dom, doc = document, aw = 0, ah = 0;
8012             if(d == doc || d == doc.body){
8013                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8014             }else{
8015                 return {
8016                     width : d.clientWidth,
8017                     height: d.clientHeight
8018                 };
8019             }
8020         },
8021
8022         /**
8023          * Returns the value of the "value" attribute
8024          * @param {Boolean} asNumber true to parse the value as a number
8025          * @return {String/Number}
8026          */
8027         getValue : function(asNumber){
8028             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8029         },
8030
8031         // private
8032         adjustWidth : function(width){
8033             if(typeof width == "number"){
8034                 if(this.autoBoxAdjust && !this.isBorderBox()){
8035                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8036                 }
8037                 if(width < 0){
8038                     width = 0;
8039                 }
8040             }
8041             return width;
8042         },
8043
8044         // private
8045         adjustHeight : function(height){
8046             if(typeof height == "number"){
8047                if(this.autoBoxAdjust && !this.isBorderBox()){
8048                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8049                }
8050                if(height < 0){
8051                    height = 0;
8052                }
8053             }
8054             return height;
8055         },
8056
8057         /**
8058          * Set the width of the element
8059          * @param {Number} width The new width
8060          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8061          * @return {Roo.Element} this
8062          */
8063         setWidth : function(width, animate){
8064             width = this.adjustWidth(width);
8065             if(!animate || !A){
8066                 this.dom.style.width = this.addUnits(width);
8067             }else{
8068                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8069             }
8070             return this;
8071         },
8072
8073         /**
8074          * Set the height of the element
8075          * @param {Number} height The new height
8076          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8077          * @return {Roo.Element} this
8078          */
8079          setHeight : function(height, animate){
8080             height = this.adjustHeight(height);
8081             if(!animate || !A){
8082                 this.dom.style.height = this.addUnits(height);
8083             }else{
8084                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8085             }
8086             return this;
8087         },
8088
8089         /**
8090          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8091          * @param {Number} width The new width
8092          * @param {Number} height The new height
8093          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8094          * @return {Roo.Element} this
8095          */
8096          setSize : function(width, height, animate){
8097             if(typeof width == "object"){ // in case of object from getSize()
8098                 height = width.height; width = width.width;
8099             }
8100             width = this.adjustWidth(width); height = this.adjustHeight(height);
8101             if(!animate || !A){
8102                 this.dom.style.width = this.addUnits(width);
8103                 this.dom.style.height = this.addUnits(height);
8104             }else{
8105                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8106             }
8107             return this;
8108         },
8109
8110         /**
8111          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8112          * @param {Number} x X value for new position (coordinates are page-based)
8113          * @param {Number} y Y value for new position (coordinates are page-based)
8114          * @param {Number} width The new width
8115          * @param {Number} height The new height
8116          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8117          * @return {Roo.Element} this
8118          */
8119         setBounds : function(x, y, width, height, animate){
8120             if(!animate || !A){
8121                 this.setSize(width, height);
8122                 this.setLocation(x, y);
8123             }else{
8124                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8125                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8126                               this.preanim(arguments, 4), 'motion');
8127             }
8128             return this;
8129         },
8130
8131         /**
8132          * 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.
8133          * @param {Roo.lib.Region} region The region to fill
8134          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8135          * @return {Roo.Element} this
8136          */
8137         setRegion : function(region, animate){
8138             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8139             return this;
8140         },
8141
8142         /**
8143          * Appends an event handler
8144          *
8145          * @param {String}   eventName     The type of event to append
8146          * @param {Function} fn        The method the event invokes
8147          * @param {Object} scope       (optional) The scope (this object) of the fn
8148          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8149          */
8150         addListener : function(eventName, fn, scope, options){
8151             if (this.dom) {
8152                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8153             }
8154         },
8155
8156         /**
8157          * Removes an event handler from this element
8158          * @param {String} eventName the type of event to remove
8159          * @param {Function} fn the method the event invokes
8160          * @return {Roo.Element} this
8161          */
8162         removeListener : function(eventName, fn){
8163             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8164             return this;
8165         },
8166
8167         /**
8168          * Removes all previous added listeners from this element
8169          * @return {Roo.Element} this
8170          */
8171         removeAllListeners : function(){
8172             E.purgeElement(this.dom);
8173             return this;
8174         },
8175
8176         relayEvent : function(eventName, observable){
8177             this.on(eventName, function(e){
8178                 observable.fireEvent(eventName, e);
8179             });
8180         },
8181
8182         /**
8183          * Set the opacity of the element
8184          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8185          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8186          * @return {Roo.Element} this
8187          */
8188          setOpacity : function(opacity, animate){
8189             if(!animate || !A){
8190                 var s = this.dom.style;
8191                 if(Roo.isIE){
8192                     s.zoom = 1;
8193                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8194                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8195                 }else{
8196                     s.opacity = opacity;
8197                 }
8198             }else{
8199                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8200             }
8201             return this;
8202         },
8203
8204         /**
8205          * Gets the left X coordinate
8206          * @param {Boolean} local True to get the local css position instead of page coordinate
8207          * @return {Number}
8208          */
8209         getLeft : function(local){
8210             if(!local){
8211                 return this.getX();
8212             }else{
8213                 return parseInt(this.getStyle("left"), 10) || 0;
8214             }
8215         },
8216
8217         /**
8218          * Gets the right X coordinate of the element (element X position + element width)
8219          * @param {Boolean} local True to get the local css position instead of page coordinate
8220          * @return {Number}
8221          */
8222         getRight : function(local){
8223             if(!local){
8224                 return this.getX() + this.getWidth();
8225             }else{
8226                 return (this.getLeft(true) + this.getWidth()) || 0;
8227             }
8228         },
8229
8230         /**
8231          * Gets the top Y coordinate
8232          * @param {Boolean} local True to get the local css position instead of page coordinate
8233          * @return {Number}
8234          */
8235         getTop : function(local) {
8236             if(!local){
8237                 return this.getY();
8238             }else{
8239                 return parseInt(this.getStyle("top"), 10) || 0;
8240             }
8241         },
8242
8243         /**
8244          * Gets the bottom Y coordinate of the element (element Y position + element height)
8245          * @param {Boolean} local True to get the local css position instead of page coordinate
8246          * @return {Number}
8247          */
8248         getBottom : function(local){
8249             if(!local){
8250                 return this.getY() + this.getHeight();
8251             }else{
8252                 return (this.getTop(true) + this.getHeight()) || 0;
8253             }
8254         },
8255
8256         /**
8257         * Initializes positioning on this element. If a desired position is not passed, it will make the
8258         * the element positioned relative IF it is not already positioned.
8259         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8260         * @param {Number} zIndex (optional) The zIndex to apply
8261         * @param {Number} x (optional) Set the page X position
8262         * @param {Number} y (optional) Set the page Y position
8263         */
8264         position : function(pos, zIndex, x, y){
8265             if(!pos){
8266                if(this.getStyle('position') == 'static'){
8267                    this.setStyle('position', 'relative');
8268                }
8269             }else{
8270                 this.setStyle("position", pos);
8271             }
8272             if(zIndex){
8273                 this.setStyle("z-index", zIndex);
8274             }
8275             if(x !== undefined && y !== undefined){
8276                 this.setXY([x, y]);
8277             }else if(x !== undefined){
8278                 this.setX(x);
8279             }else if(y !== undefined){
8280                 this.setY(y);
8281             }
8282         },
8283
8284         /**
8285         * Clear positioning back to the default when the document was loaded
8286         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8287         * @return {Roo.Element} this
8288          */
8289         clearPositioning : function(value){
8290             value = value ||'';
8291             this.setStyle({
8292                 "left": value,
8293                 "right": value,
8294                 "top": value,
8295                 "bottom": value,
8296                 "z-index": "",
8297                 "position" : "static"
8298             });
8299             return this;
8300         },
8301
8302         /**
8303         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8304         * snapshot before performing an update and then restoring the element.
8305         * @return {Object}
8306         */
8307         getPositioning : function(){
8308             var l = this.getStyle("left");
8309             var t = this.getStyle("top");
8310             return {
8311                 "position" : this.getStyle("position"),
8312                 "left" : l,
8313                 "right" : l ? "" : this.getStyle("right"),
8314                 "top" : t,
8315                 "bottom" : t ? "" : this.getStyle("bottom"),
8316                 "z-index" : this.getStyle("z-index")
8317             };
8318         },
8319
8320         /**
8321          * Gets the width of the border(s) for the specified side(s)
8322          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8323          * passing lr would get the border (l)eft width + the border (r)ight width.
8324          * @return {Number} The width of the sides passed added together
8325          */
8326         getBorderWidth : function(side){
8327             return this.addStyles(side, El.borders);
8328         },
8329
8330         /**
8331          * Gets the width of the padding(s) for the specified side(s)
8332          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8333          * passing lr would get the padding (l)eft + the padding (r)ight.
8334          * @return {Number} The padding of the sides passed added together
8335          */
8336         getPadding : function(side){
8337             return this.addStyles(side, El.paddings);
8338         },
8339
8340         /**
8341         * Set positioning with an object returned by getPositioning().
8342         * @param {Object} posCfg
8343         * @return {Roo.Element} this
8344          */
8345         setPositioning : function(pc){
8346             this.applyStyles(pc);
8347             if(pc.right == "auto"){
8348                 this.dom.style.right = "";
8349             }
8350             if(pc.bottom == "auto"){
8351                 this.dom.style.bottom = "";
8352             }
8353             return this;
8354         },
8355
8356         // private
8357         fixDisplay : function(){
8358             if(this.getStyle("display") == "none"){
8359                 this.setStyle("visibility", "hidden");
8360                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8361                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8362                     this.setStyle("display", "block");
8363                 }
8364             }
8365         },
8366
8367         /**
8368          * Quick set left and top adding default units
8369          * @param {String} left The left CSS property value
8370          * @param {String} top The top CSS property value
8371          * @return {Roo.Element} this
8372          */
8373          setLeftTop : function(left, top){
8374             this.dom.style.left = this.addUnits(left);
8375             this.dom.style.top = this.addUnits(top);
8376             return this;
8377         },
8378
8379         /**
8380          * Move this element relative to its current position.
8381          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8382          * @param {Number} distance How far to move the element in pixels
8383          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8384          * @return {Roo.Element} this
8385          */
8386          move : function(direction, distance, animate){
8387             var xy = this.getXY();
8388             direction = direction.toLowerCase();
8389             switch(direction){
8390                 case "l":
8391                 case "left":
8392                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8393                     break;
8394                case "r":
8395                case "right":
8396                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8397                     break;
8398                case "t":
8399                case "top":
8400                case "up":
8401                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8402                     break;
8403                case "b":
8404                case "bottom":
8405                case "down":
8406                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8407                     break;
8408             }
8409             return this;
8410         },
8411
8412         /**
8413          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8414          * @return {Roo.Element} this
8415          */
8416         clip : function(){
8417             if(!this.isClipped){
8418                this.isClipped = true;
8419                this.originalClip = {
8420                    "o": this.getStyle("overflow"),
8421                    "x": this.getStyle("overflow-x"),
8422                    "y": this.getStyle("overflow-y")
8423                };
8424                this.setStyle("overflow", "hidden");
8425                this.setStyle("overflow-x", "hidden");
8426                this.setStyle("overflow-y", "hidden");
8427             }
8428             return this;
8429         },
8430
8431         /**
8432          *  Return clipping (overflow) to original clipping before clip() was called
8433          * @return {Roo.Element} this
8434          */
8435         unclip : function(){
8436             if(this.isClipped){
8437                 this.isClipped = false;
8438                 var o = this.originalClip;
8439                 if(o.o){this.setStyle("overflow", o.o);}
8440                 if(o.x){this.setStyle("overflow-x", o.x);}
8441                 if(o.y){this.setStyle("overflow-y", o.y);}
8442             }
8443             return this;
8444         },
8445
8446
8447         /**
8448          * Gets the x,y coordinates specified by the anchor position on the element.
8449          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8450          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8451          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8452          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8453          * @return {Array} [x, y] An array containing the element's x and y coordinates
8454          */
8455         getAnchorXY : function(anchor, local, s){
8456             //Passing a different size is useful for pre-calculating anchors,
8457             //especially for anchored animations that change the el size.
8458
8459             var w, h, vp = false;
8460             if(!s){
8461                 var d = this.dom;
8462                 if(d == document.body || d == document){
8463                     vp = true;
8464                     w = D.getViewWidth(); h = D.getViewHeight();
8465                 }else{
8466                     w = this.getWidth(); h = this.getHeight();
8467                 }
8468             }else{
8469                 w = s.width;  h = s.height;
8470             }
8471             var x = 0, y = 0, r = Math.round;
8472             switch((anchor || "tl").toLowerCase()){
8473                 case "c":
8474                     x = r(w*.5);
8475                     y = r(h*.5);
8476                 break;
8477                 case "t":
8478                     x = r(w*.5);
8479                     y = 0;
8480                 break;
8481                 case "l":
8482                     x = 0;
8483                     y = r(h*.5);
8484                 break;
8485                 case "r":
8486                     x = w;
8487                     y = r(h*.5);
8488                 break;
8489                 case "b":
8490                     x = r(w*.5);
8491                     y = h;
8492                 break;
8493                 case "tl":
8494                     x = 0;
8495                     y = 0;
8496                 break;
8497                 case "bl":
8498                     x = 0;
8499                     y = h;
8500                 break;
8501                 case "br":
8502                     x = w;
8503                     y = h;
8504                 break;
8505                 case "tr":
8506                     x = w;
8507                     y = 0;
8508                 break;
8509             }
8510             if(local === true){
8511                 return [x, y];
8512             }
8513             if(vp){
8514                 var sc = this.getScroll();
8515                 return [x + sc.left, y + sc.top];
8516             }
8517             //Add the element's offset xy
8518             var o = this.getXY();
8519             return [x+o[0], y+o[1]];
8520         },
8521
8522         /**
8523          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8524          * supported position values.
8525          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8526          * @param {String} position The position to align to.
8527          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8528          * @return {Array} [x, y]
8529          */
8530         getAlignToXY : function(el, p, o){
8531             el = Roo.get(el);
8532             var d = this.dom;
8533             if(!el.dom){
8534                 throw "Element.alignTo with an element that doesn't exist";
8535             }
8536             var c = false; //constrain to viewport
8537             var p1 = "", p2 = "";
8538             o = o || [0,0];
8539
8540             if(!p){
8541                 p = "tl-bl";
8542             }else if(p == "?"){
8543                 p = "tl-bl?";
8544             }else if(p.indexOf("-") == -1){
8545                 p = "tl-" + p;
8546             }
8547             p = p.toLowerCase();
8548             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8549             if(!m){
8550                throw "Element.alignTo with an invalid alignment " + p;
8551             }
8552             p1 = m[1]; p2 = m[2]; c = !!m[3];
8553
8554             //Subtract the aligned el's internal xy from the target's offset xy
8555             //plus custom offset to get the aligned el's new offset xy
8556             var a1 = this.getAnchorXY(p1, true);
8557             var a2 = el.getAnchorXY(p2, false);
8558             var x = a2[0] - a1[0] + o[0];
8559             var y = a2[1] - a1[1] + o[1];
8560             if(c){
8561                 //constrain the aligned el to viewport if necessary
8562                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8563                 // 5px of margin for ie
8564                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8565
8566                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8567                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8568                 //otherwise swap the aligned el to the opposite border of the target.
8569                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8570                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8571                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8572                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8573
8574                var doc = document;
8575                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8576                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8577
8578                if((x+w) > dw + scrollX){
8579                     x = swapX ? r.left-w : dw+scrollX-w;
8580                 }
8581                if(x < scrollX){
8582                    x = swapX ? r.right : scrollX;
8583                }
8584                if((y+h) > dh + scrollY){
8585                     y = swapY ? r.top-h : dh+scrollY-h;
8586                 }
8587                if (y < scrollY){
8588                    y = swapY ? r.bottom : scrollY;
8589                }
8590             }
8591             return [x,y];
8592         },
8593
8594         // private
8595         getConstrainToXY : function(){
8596             var os = {top:0, left:0, bottom:0, right: 0};
8597
8598             return function(el, local, offsets, proposedXY){
8599                 el = Roo.get(el);
8600                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8601
8602                 var vw, vh, vx = 0, vy = 0;
8603                 if(el.dom == document.body || el.dom == document){
8604                     vw = Roo.lib.Dom.getViewWidth();
8605                     vh = Roo.lib.Dom.getViewHeight();
8606                 }else{
8607                     vw = el.dom.clientWidth;
8608                     vh = el.dom.clientHeight;
8609                     if(!local){
8610                         var vxy = el.getXY();
8611                         vx = vxy[0];
8612                         vy = vxy[1];
8613                     }
8614                 }
8615
8616                 var s = el.getScroll();
8617
8618                 vx += offsets.left + s.left;
8619                 vy += offsets.top + s.top;
8620
8621                 vw -= offsets.right;
8622                 vh -= offsets.bottom;
8623
8624                 var vr = vx+vw;
8625                 var vb = vy+vh;
8626
8627                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8628                 var x = xy[0], y = xy[1];
8629                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8630
8631                 // only move it if it needs it
8632                 var moved = false;
8633
8634                 // first validate right/bottom
8635                 if((x + w) > vr){
8636                     x = vr - w;
8637                     moved = true;
8638                 }
8639                 if((y + h) > vb){
8640                     y = vb - h;
8641                     moved = true;
8642                 }
8643                 // then make sure top/left isn't negative
8644                 if(x < vx){
8645                     x = vx;
8646                     moved = true;
8647                 }
8648                 if(y < vy){
8649                     y = vy;
8650                     moved = true;
8651                 }
8652                 return moved ? [x, y] : false;
8653             };
8654         }(),
8655
8656         // private
8657         adjustForConstraints : function(xy, parent, offsets){
8658             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8659         },
8660
8661         /**
8662          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8663          * document it aligns it to the viewport.
8664          * The position parameter is optional, and can be specified in any one of the following formats:
8665          * <ul>
8666          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8667          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8668          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8669          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8670          *   <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
8671          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8672          * </ul>
8673          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8674          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8675          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8676          * that specified in order to enforce the viewport constraints.
8677          * Following are all of the supported anchor positions:
8678     <pre>
8679     Value  Description
8680     -----  -----------------------------
8681     tl     The top left corner (default)
8682     t      The center of the top edge
8683     tr     The top right corner
8684     l      The center of the left edge
8685     c      In the center of the element
8686     r      The center of the right edge
8687     bl     The bottom left corner
8688     b      The center of the bottom edge
8689     br     The bottom right corner
8690     </pre>
8691     Example Usage:
8692     <pre><code>
8693     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8694     el.alignTo("other-el");
8695
8696     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8697     el.alignTo("other-el", "tr?");
8698
8699     // align the bottom right corner of el with the center left edge of other-el
8700     el.alignTo("other-el", "br-l?");
8701
8702     // align the center of el with the bottom left corner of other-el and
8703     // adjust the x position by -6 pixels (and the y position by 0)
8704     el.alignTo("other-el", "c-bl", [-6, 0]);
8705     </code></pre>
8706          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8707          * @param {String} position The position to align to.
8708          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8709          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8710          * @return {Roo.Element} this
8711          */
8712         alignTo : function(element, position, offsets, animate){
8713             var xy = this.getAlignToXY(element, position, offsets);
8714             this.setXY(xy, this.preanim(arguments, 3));
8715             return this;
8716         },
8717
8718         /**
8719          * Anchors an element to another element and realigns it when the window is resized.
8720          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8721          * @param {String} position The position to align to.
8722          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8723          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8724          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8725          * is a number, it is used as the buffer delay (defaults to 50ms).
8726          * @param {Function} callback The function to call after the animation finishes
8727          * @return {Roo.Element} this
8728          */
8729         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8730             var action = function(){
8731                 this.alignTo(el, alignment, offsets, animate);
8732                 Roo.callback(callback, this);
8733             };
8734             Roo.EventManager.onWindowResize(action, this);
8735             var tm = typeof monitorScroll;
8736             if(tm != 'undefined'){
8737                 Roo.EventManager.on(window, 'scroll', action, this,
8738                     {buffer: tm == 'number' ? monitorScroll : 50});
8739             }
8740             action.call(this); // align immediately
8741             return this;
8742         },
8743         /**
8744          * Clears any opacity settings from this element. Required in some cases for IE.
8745          * @return {Roo.Element} this
8746          */
8747         clearOpacity : function(){
8748             if (window.ActiveXObject) {
8749                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8750                     this.dom.style.filter = "";
8751                 }
8752             } else {
8753                 this.dom.style.opacity = "";
8754                 this.dom.style["-moz-opacity"] = "";
8755                 this.dom.style["-khtml-opacity"] = "";
8756             }
8757             return this;
8758         },
8759
8760         /**
8761          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8762          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8763          * @return {Roo.Element} this
8764          */
8765         hide : function(animate){
8766             this.setVisible(false, this.preanim(arguments, 0));
8767             return this;
8768         },
8769
8770         /**
8771         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8772         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8773          * @return {Roo.Element} this
8774          */
8775         show : function(animate){
8776             this.setVisible(true, this.preanim(arguments, 0));
8777             return this;
8778         },
8779
8780         /**
8781          * @private Test if size has a unit, otherwise appends the default
8782          */
8783         addUnits : function(size){
8784             return Roo.Element.addUnits(size, this.defaultUnit);
8785         },
8786
8787         /**
8788          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8789          * @return {Roo.Element} this
8790          */
8791         beginMeasure : function(){
8792             var el = this.dom;
8793             if(el.offsetWidth || el.offsetHeight){
8794                 return this; // offsets work already
8795             }
8796             var changed = [];
8797             var p = this.dom, b = document.body; // start with this element
8798             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8799                 var pe = Roo.get(p);
8800                 if(pe.getStyle('display') == 'none'){
8801                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8802                     p.style.visibility = "hidden";
8803                     p.style.display = "block";
8804                 }
8805                 p = p.parentNode;
8806             }
8807             this._measureChanged = changed;
8808             return this;
8809
8810         },
8811
8812         /**
8813          * Restores displays to before beginMeasure was called
8814          * @return {Roo.Element} this
8815          */
8816         endMeasure : function(){
8817             var changed = this._measureChanged;
8818             if(changed){
8819                 for(var i = 0, len = changed.length; i < len; i++) {
8820                     var r = changed[i];
8821                     r.el.style.visibility = r.visibility;
8822                     r.el.style.display = "none";
8823                 }
8824                 this._measureChanged = null;
8825             }
8826             return this;
8827         },
8828
8829         /**
8830         * Update the innerHTML of this element, optionally searching for and processing scripts
8831         * @param {String} html The new HTML
8832         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8833         * @param {Function} callback For async script loading you can be noticed when the update completes
8834         * @return {Roo.Element} this
8835          */
8836         update : function(html, loadScripts, callback){
8837             if(typeof html == "undefined"){
8838                 html = "";
8839             }
8840             if(loadScripts !== true){
8841                 this.dom.innerHTML = html;
8842                 if(typeof callback == "function"){
8843                     callback();
8844                 }
8845                 return this;
8846             }
8847             var id = Roo.id();
8848             var dom = this.dom;
8849
8850             html += '<span id="' + id + '"></span>';
8851
8852             E.onAvailable(id, function(){
8853                 var hd = document.getElementsByTagName("head")[0];
8854                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8855                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8856                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8857
8858                 var match;
8859                 while(match = re.exec(html)){
8860                     var attrs = match[1];
8861                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8862                     if(srcMatch && srcMatch[2]){
8863                        var s = document.createElement("script");
8864                        s.src = srcMatch[2];
8865                        var typeMatch = attrs.match(typeRe);
8866                        if(typeMatch && typeMatch[2]){
8867                            s.type = typeMatch[2];
8868                        }
8869                        hd.appendChild(s);
8870                     }else if(match[2] && match[2].length > 0){
8871                         if(window.execScript) {
8872                            window.execScript(match[2]);
8873                         } else {
8874                             /**
8875                              * eval:var:id
8876                              * eval:var:dom
8877                              * eval:var:html
8878                              * 
8879                              */
8880                            window.eval(match[2]);
8881                         }
8882                     }
8883                 }
8884                 var el = document.getElementById(id);
8885                 if(el){el.parentNode.removeChild(el);}
8886                 if(typeof callback == "function"){
8887                     callback();
8888                 }
8889             });
8890             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8891             return this;
8892         },
8893
8894         /**
8895          * Direct access to the UpdateManager update() method (takes the same parameters).
8896          * @param {String/Function} url The url for this request or a function to call to get the url
8897          * @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}
8898          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8899          * @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.
8900          * @return {Roo.Element} this
8901          */
8902         load : function(){
8903             var um = this.getUpdateManager();
8904             um.update.apply(um, arguments);
8905             return this;
8906         },
8907
8908         /**
8909         * Gets this element's UpdateManager
8910         * @return {Roo.UpdateManager} The UpdateManager
8911         */
8912         getUpdateManager : function(){
8913             if(!this.updateManager){
8914                 this.updateManager = new Roo.UpdateManager(this);
8915             }
8916             return this.updateManager;
8917         },
8918
8919         /**
8920          * Disables text selection for this element (normalized across browsers)
8921          * @return {Roo.Element} this
8922          */
8923         unselectable : function(){
8924             this.dom.unselectable = "on";
8925             this.swallowEvent("selectstart", true);
8926             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8927             this.addClass("x-unselectable");
8928             return this;
8929         },
8930
8931         /**
8932         * Calculates the x, y to center this element on the screen
8933         * @return {Array} The x, y values [x, y]
8934         */
8935         getCenterXY : function(){
8936             return this.getAlignToXY(document, 'c-c');
8937         },
8938
8939         /**
8940         * Centers the Element in either the viewport, or another Element.
8941         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8942         */
8943         center : function(centerIn){
8944             this.alignTo(centerIn || document, 'c-c');
8945             return this;
8946         },
8947
8948         /**
8949          * Tests various css rules/browsers to determine if this element uses a border box
8950          * @return {Boolean}
8951          */
8952         isBorderBox : function(){
8953             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8954         },
8955
8956         /**
8957          * Return a box {x, y, width, height} that can be used to set another elements
8958          * size/location to match this element.
8959          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8960          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8961          * @return {Object} box An object in the format {x, y, width, height}
8962          */
8963         getBox : function(contentBox, local){
8964             var xy;
8965             if(!local){
8966                 xy = this.getXY();
8967             }else{
8968                 var left = parseInt(this.getStyle("left"), 10) || 0;
8969                 var top = parseInt(this.getStyle("top"), 10) || 0;
8970                 xy = [left, top];
8971             }
8972             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8973             if(!contentBox){
8974                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8975             }else{
8976                 var l = this.getBorderWidth("l")+this.getPadding("l");
8977                 var r = this.getBorderWidth("r")+this.getPadding("r");
8978                 var t = this.getBorderWidth("t")+this.getPadding("t");
8979                 var b = this.getBorderWidth("b")+this.getPadding("b");
8980                 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)};
8981             }
8982             bx.right = bx.x + bx.width;
8983             bx.bottom = bx.y + bx.height;
8984             return bx;
8985         },
8986
8987         /**
8988          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8989          for more information about the sides.
8990          * @param {String} sides
8991          * @return {Number}
8992          */
8993         getFrameWidth : function(sides, onlyContentBox){
8994             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8995         },
8996
8997         /**
8998          * 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.
8999          * @param {Object} box The box to fill {x, y, width, height}
9000          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9001          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9002          * @return {Roo.Element} this
9003          */
9004         setBox : function(box, adjust, animate){
9005             var w = box.width, h = box.height;
9006             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9007                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9008                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9009             }
9010             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9011             return this;
9012         },
9013
9014         /**
9015          * Forces the browser to repaint this element
9016          * @return {Roo.Element} this
9017          */
9018          repaint : function(){
9019             var dom = this.dom;
9020             this.addClass("x-repaint");
9021             setTimeout(function(){
9022                 Roo.get(dom).removeClass("x-repaint");
9023             }, 1);
9024             return this;
9025         },
9026
9027         /**
9028          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9029          * then it returns the calculated width of the sides (see getPadding)
9030          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9031          * @return {Object/Number}
9032          */
9033         getMargins : function(side){
9034             if(!side){
9035                 return {
9036                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9037                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9038                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9039                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9040                 };
9041             }else{
9042                 return this.addStyles(side, El.margins);
9043              }
9044         },
9045
9046         // private
9047         addStyles : function(sides, styles){
9048             var val = 0, v, w;
9049             for(var i = 0, len = sides.length; i < len; i++){
9050                 v = this.getStyle(styles[sides.charAt(i)]);
9051                 if(v){
9052                      w = parseInt(v, 10);
9053                      if(w){ val += w; }
9054                 }
9055             }
9056             return val;
9057         },
9058
9059         /**
9060          * Creates a proxy element of this element
9061          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9062          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9063          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9064          * @return {Roo.Element} The new proxy element
9065          */
9066         createProxy : function(config, renderTo, matchBox){
9067             if(renderTo){
9068                 renderTo = Roo.getDom(renderTo);
9069             }else{
9070                 renderTo = document.body;
9071             }
9072             config = typeof config == "object" ?
9073                 config : {tag : "div", cls: config};
9074             var proxy = Roo.DomHelper.append(renderTo, config, true);
9075             if(matchBox){
9076                proxy.setBox(this.getBox());
9077             }
9078             return proxy;
9079         },
9080
9081         /**
9082          * Puts a mask over this element to disable user interaction. Requires core.css.
9083          * This method can only be applied to elements which accept child nodes.
9084          * @param {String} msg (optional) A message to display in the mask
9085          * @param {String} msgCls (optional) A css class to apply to the msg element
9086          * @return {Element} The mask  element
9087          */
9088         mask : function(msg, msgCls)
9089         {
9090             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9091                 this.setStyle("position", "relative");
9092             }
9093             if(!this._mask){
9094                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9095             }
9096             this.addClass("x-masked");
9097             this._mask.setDisplayed(true);
9098             
9099             // we wander
9100             var z = 0;
9101             var dom = this.dom;
9102             while (dom && dom.style) {
9103                 if (!isNaN(parseInt(dom.style.zIndex))) {
9104                     z = Math.max(z, parseInt(dom.style.zIndex));
9105                 }
9106                 dom = dom.parentNode;
9107             }
9108             // if we are masking the body - then it hides everything..
9109             if (this.dom == document.body) {
9110                 z = 1000000;
9111                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9112                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9113             }
9114            
9115             if(typeof msg == 'string'){
9116                 if(!this._maskMsg){
9117                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9118                 }
9119                 var mm = this._maskMsg;
9120                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9121                 if (mm.dom.firstChild) { // weird IE issue?
9122                     mm.dom.firstChild.innerHTML = msg;
9123                 }
9124                 mm.setDisplayed(true);
9125                 mm.center(this);
9126                 mm.setStyle('z-index', z + 102);
9127             }
9128             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9129                 this._mask.setHeight(this.getHeight());
9130             }
9131             this._mask.setStyle('z-index', z + 100);
9132             
9133             return this._mask;
9134         },
9135
9136         /**
9137          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9138          * it is cached for reuse.
9139          */
9140         unmask : function(removeEl){
9141             if(this._mask){
9142                 if(removeEl === true){
9143                     this._mask.remove();
9144                     delete this._mask;
9145                     if(this._maskMsg){
9146                         this._maskMsg.remove();
9147                         delete this._maskMsg;
9148                     }
9149                 }else{
9150                     this._mask.setDisplayed(false);
9151                     if(this._maskMsg){
9152                         this._maskMsg.setDisplayed(false);
9153                     }
9154                 }
9155             }
9156             this.removeClass("x-masked");
9157         },
9158
9159         /**
9160          * Returns true if this element is masked
9161          * @return {Boolean}
9162          */
9163         isMasked : function(){
9164             return this._mask && this._mask.isVisible();
9165         },
9166
9167         /**
9168          * Creates an iframe shim for this element to keep selects and other windowed objects from
9169          * showing through.
9170          * @return {Roo.Element} The new shim element
9171          */
9172         createShim : function(){
9173             var el = document.createElement('iframe');
9174             el.frameBorder = 'no';
9175             el.className = 'roo-shim';
9176             if(Roo.isIE && Roo.isSecure){
9177                 el.src = Roo.SSL_SECURE_URL;
9178             }
9179             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9180             shim.autoBoxAdjust = false;
9181             return shim;
9182         },
9183
9184         /**
9185          * Removes this element from the DOM and deletes it from the cache
9186          */
9187         remove : function(){
9188             if(this.dom.parentNode){
9189                 this.dom.parentNode.removeChild(this.dom);
9190             }
9191             delete El.cache[this.dom.id];
9192         },
9193
9194         /**
9195          * Sets up event handlers to add and remove a css class when the mouse is over this element
9196          * @param {String} className
9197          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9198          * mouseout events for children elements
9199          * @return {Roo.Element} this
9200          */
9201         addClassOnOver : function(className, preventFlicker){
9202             this.on("mouseover", function(){
9203                 Roo.fly(this, '_internal').addClass(className);
9204             }, this.dom);
9205             var removeFn = function(e){
9206                 if(preventFlicker !== true || !e.within(this, true)){
9207                     Roo.fly(this, '_internal').removeClass(className);
9208                 }
9209             };
9210             this.on("mouseout", removeFn, this.dom);
9211             return this;
9212         },
9213
9214         /**
9215          * Sets up event handlers to add and remove a css class when this element has the focus
9216          * @param {String} className
9217          * @return {Roo.Element} this
9218          */
9219         addClassOnFocus : function(className){
9220             this.on("focus", function(){
9221                 Roo.fly(this, '_internal').addClass(className);
9222             }, this.dom);
9223             this.on("blur", function(){
9224                 Roo.fly(this, '_internal').removeClass(className);
9225             }, this.dom);
9226             return this;
9227         },
9228         /**
9229          * 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)
9230          * @param {String} className
9231          * @return {Roo.Element} this
9232          */
9233         addClassOnClick : function(className){
9234             var dom = this.dom;
9235             this.on("mousedown", function(){
9236                 Roo.fly(dom, '_internal').addClass(className);
9237                 var d = Roo.get(document);
9238                 var fn = function(){
9239                     Roo.fly(dom, '_internal').removeClass(className);
9240                     d.removeListener("mouseup", fn);
9241                 };
9242                 d.on("mouseup", fn);
9243             });
9244             return this;
9245         },
9246
9247         /**
9248          * Stops the specified event from bubbling and optionally prevents the default action
9249          * @param {String} eventName
9250          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9251          * @return {Roo.Element} this
9252          */
9253         swallowEvent : function(eventName, preventDefault){
9254             var fn = function(e){
9255                 e.stopPropagation();
9256                 if(preventDefault){
9257                     e.preventDefault();
9258                 }
9259             };
9260             if(eventName instanceof Array){
9261                 for(var i = 0, len = eventName.length; i < len; i++){
9262                      this.on(eventName[i], fn);
9263                 }
9264                 return this;
9265             }
9266             this.on(eventName, fn);
9267             return this;
9268         },
9269
9270         /**
9271          * @private
9272          */
9273       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9274
9275         /**
9276          * Sizes this element to its parent element's dimensions performing
9277          * neccessary box adjustments.
9278          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9279          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9280          * @return {Roo.Element} this
9281          */
9282         fitToParent : function(monitorResize, targetParent) {
9283           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9284           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9285           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9286             return;
9287           }
9288           var p = Roo.get(targetParent || this.dom.parentNode);
9289           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9290           if (monitorResize === true) {
9291             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9292             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9293           }
9294           return this;
9295         },
9296
9297         /**
9298          * Gets the next sibling, skipping text nodes
9299          * @return {HTMLElement} The next sibling or null
9300          */
9301         getNextSibling : function(){
9302             var n = this.dom.nextSibling;
9303             while(n && n.nodeType != 1){
9304                 n = n.nextSibling;
9305             }
9306             return n;
9307         },
9308
9309         /**
9310          * Gets the previous sibling, skipping text nodes
9311          * @return {HTMLElement} The previous sibling or null
9312          */
9313         getPrevSibling : function(){
9314             var n = this.dom.previousSibling;
9315             while(n && n.nodeType != 1){
9316                 n = n.previousSibling;
9317             }
9318             return n;
9319         },
9320
9321
9322         /**
9323          * Appends the passed element(s) to this element
9324          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9325          * @return {Roo.Element} this
9326          */
9327         appendChild: function(el){
9328             el = Roo.get(el);
9329             el.appendTo(this);
9330             return this;
9331         },
9332
9333         /**
9334          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9335          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9336          * automatically generated with the specified attributes.
9337          * @param {HTMLElement} insertBefore (optional) a child element of this element
9338          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9339          * @return {Roo.Element} The new child element
9340          */
9341         createChild: function(config, insertBefore, returnDom){
9342             config = config || {tag:'div'};
9343             if(insertBefore){
9344                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9345             }
9346             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9347         },
9348
9349         /**
9350          * Appends this element to the passed element
9351          * @param {String/HTMLElement/Element} el The new parent element
9352          * @return {Roo.Element} this
9353          */
9354         appendTo: function(el){
9355             el = Roo.getDom(el);
9356             el.appendChild(this.dom);
9357             return this;
9358         },
9359
9360         /**
9361          * Inserts this element before the passed element in the DOM
9362          * @param {String/HTMLElement/Element} el The element to insert before
9363          * @return {Roo.Element} this
9364          */
9365         insertBefore: function(el){
9366             el = Roo.getDom(el);
9367             el.parentNode.insertBefore(this.dom, el);
9368             return this;
9369         },
9370
9371         /**
9372          * Inserts this element after the passed element in the DOM
9373          * @param {String/HTMLElement/Element} el The element to insert after
9374          * @return {Roo.Element} this
9375          */
9376         insertAfter: function(el){
9377             el = Roo.getDom(el);
9378             el.parentNode.insertBefore(this.dom, el.nextSibling);
9379             return this;
9380         },
9381
9382         /**
9383          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9384          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9385          * @return {Roo.Element} The new child
9386          */
9387         insertFirst: function(el, returnDom){
9388             el = el || {};
9389             if(typeof el == 'object' && !el.nodeType){ // dh config
9390                 return this.createChild(el, this.dom.firstChild, returnDom);
9391             }else{
9392                 el = Roo.getDom(el);
9393                 this.dom.insertBefore(el, this.dom.firstChild);
9394                 return !returnDom ? Roo.get(el) : el;
9395             }
9396         },
9397
9398         /**
9399          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9400          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9401          * @param {String} where (optional) 'before' or 'after' defaults to before
9402          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9403          * @return {Roo.Element} the inserted Element
9404          */
9405         insertSibling: function(el, where, returnDom){
9406             where = where ? where.toLowerCase() : 'before';
9407             el = el || {};
9408             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9409
9410             if(typeof el == 'object' && !el.nodeType){ // dh config
9411                 if(where == 'after' && !this.dom.nextSibling){
9412                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9413                 }else{
9414                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9415                 }
9416
9417             }else{
9418                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9419                             where == 'before' ? this.dom : this.dom.nextSibling);
9420                 if(!returnDom){
9421                     rt = Roo.get(rt);
9422                 }
9423             }
9424             return rt;
9425         },
9426
9427         /**
9428          * Creates and wraps this element with another element
9429          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9430          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9431          * @return {HTMLElement/Element} The newly created wrapper element
9432          */
9433         wrap: function(config, returnDom){
9434             if(!config){
9435                 config = {tag: "div"};
9436             }
9437             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9438             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9439             return newEl;
9440         },
9441
9442         /**
9443          * Replaces the passed element with this element
9444          * @param {String/HTMLElement/Element} el The element to replace
9445          * @return {Roo.Element} this
9446          */
9447         replace: function(el){
9448             el = Roo.get(el);
9449             this.insertBefore(el);
9450             el.remove();
9451             return this;
9452         },
9453
9454         /**
9455          * Inserts an html fragment into this element
9456          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9457          * @param {String} html The HTML fragment
9458          * @param {Boolean} returnEl True to return an Roo.Element
9459          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9460          */
9461         insertHtml : function(where, html, returnEl){
9462             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9463             return returnEl ? Roo.get(el) : el;
9464         },
9465
9466         /**
9467          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9468          * @param {Object} o The object with the attributes
9469          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9470          * @return {Roo.Element} this
9471          */
9472         set : function(o, useSet){
9473             var el = this.dom;
9474             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9475             for(var attr in o){
9476                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9477                 if(attr=="cls"){
9478                     el.className = o["cls"];
9479                 }else{
9480                     if(useSet) {
9481                         el.setAttribute(attr, o[attr]);
9482                     } else {
9483                         el[attr] = o[attr];
9484                     }
9485                 }
9486             }
9487             if(o.style){
9488                 Roo.DomHelper.applyStyles(el, o.style);
9489             }
9490             return this;
9491         },
9492
9493         /**
9494          * Convenience method for constructing a KeyMap
9495          * @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:
9496          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9497          * @param {Function} fn The function to call
9498          * @param {Object} scope (optional) The scope of the function
9499          * @return {Roo.KeyMap} The KeyMap created
9500          */
9501         addKeyListener : function(key, fn, scope){
9502             var config;
9503             if(typeof key != "object" || key instanceof Array){
9504                 config = {
9505                     key: key,
9506                     fn: fn,
9507                     scope: scope
9508                 };
9509             }else{
9510                 config = {
9511                     key : key.key,
9512                     shift : key.shift,
9513                     ctrl : key.ctrl,
9514                     alt : key.alt,
9515                     fn: fn,
9516                     scope: scope
9517                 };
9518             }
9519             return new Roo.KeyMap(this, config);
9520         },
9521
9522         /**
9523          * Creates a KeyMap for this element
9524          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9525          * @return {Roo.KeyMap} The KeyMap created
9526          */
9527         addKeyMap : function(config){
9528             return new Roo.KeyMap(this, config);
9529         },
9530
9531         /**
9532          * Returns true if this element is scrollable.
9533          * @return {Boolean}
9534          */
9535          isScrollable : function(){
9536             var dom = this.dom;
9537             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9538         },
9539
9540         /**
9541          * 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().
9542          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9543          * @param {Number} value The new scroll value
9544          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9545          * @return {Element} this
9546          */
9547
9548         scrollTo : function(side, value, animate){
9549             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9550             if(!animate || !A){
9551                 this.dom[prop] = value;
9552             }else{
9553                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9554                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9555             }
9556             return this;
9557         },
9558
9559         /**
9560          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9561          * within this element's scrollable range.
9562          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9563          * @param {Number} distance How far to scroll the element in pixels
9564          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9565          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9566          * was scrolled as far as it could go.
9567          */
9568          scroll : function(direction, distance, animate){
9569              if(!this.isScrollable()){
9570                  return;
9571              }
9572              var el = this.dom;
9573              var l = el.scrollLeft, t = el.scrollTop;
9574              var w = el.scrollWidth, h = el.scrollHeight;
9575              var cw = el.clientWidth, ch = el.clientHeight;
9576              direction = direction.toLowerCase();
9577              var scrolled = false;
9578              var a = this.preanim(arguments, 2);
9579              switch(direction){
9580                  case "l":
9581                  case "left":
9582                      if(w - l > cw){
9583                          var v = Math.min(l + distance, w-cw);
9584                          this.scrollTo("left", v, a);
9585                          scrolled = true;
9586                      }
9587                      break;
9588                 case "r":
9589                 case "right":
9590                      if(l > 0){
9591                          var v = Math.max(l - distance, 0);
9592                          this.scrollTo("left", v, a);
9593                          scrolled = true;
9594                      }
9595                      break;
9596                 case "t":
9597                 case "top":
9598                 case "up":
9599                      if(t > 0){
9600                          var v = Math.max(t - distance, 0);
9601                          this.scrollTo("top", v, a);
9602                          scrolled = true;
9603                      }
9604                      break;
9605                 case "b":
9606                 case "bottom":
9607                 case "down":
9608                      if(h - t > ch){
9609                          var v = Math.min(t + distance, h-ch);
9610                          this.scrollTo("top", v, a);
9611                          scrolled = true;
9612                      }
9613                      break;
9614              }
9615              return scrolled;
9616         },
9617
9618         /**
9619          * Translates the passed page coordinates into left/top css values for this element
9620          * @param {Number/Array} x The page x or an array containing [x, y]
9621          * @param {Number} y The page y
9622          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9623          */
9624         translatePoints : function(x, y){
9625             if(typeof x == 'object' || x instanceof Array){
9626                 y = x[1]; x = x[0];
9627             }
9628             var p = this.getStyle('position');
9629             var o = this.getXY();
9630
9631             var l = parseInt(this.getStyle('left'), 10);
9632             var t = parseInt(this.getStyle('top'), 10);
9633
9634             if(isNaN(l)){
9635                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9636             }
9637             if(isNaN(t)){
9638                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9639             }
9640
9641             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9642         },
9643
9644         /**
9645          * Returns the current scroll position of the element.
9646          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9647          */
9648         getScroll : function(){
9649             var d = this.dom, doc = document;
9650             if(d == doc || d == doc.body){
9651                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9652                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9653                 return {left: l, top: t};
9654             }else{
9655                 return {left: d.scrollLeft, top: d.scrollTop};
9656             }
9657         },
9658
9659         /**
9660          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9661          * are convert to standard 6 digit hex color.
9662          * @param {String} attr The css attribute
9663          * @param {String} defaultValue The default value to use when a valid color isn't found
9664          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9665          * YUI color anims.
9666          */
9667         getColor : function(attr, defaultValue, prefix){
9668             var v = this.getStyle(attr);
9669             if(!v || v == "transparent" || v == "inherit") {
9670                 return defaultValue;
9671             }
9672             var color = typeof prefix == "undefined" ? "#" : prefix;
9673             if(v.substr(0, 4) == "rgb("){
9674                 var rvs = v.slice(4, v.length -1).split(",");
9675                 for(var i = 0; i < 3; i++){
9676                     var h = parseInt(rvs[i]).toString(16);
9677                     if(h < 16){
9678                         h = "0" + h;
9679                     }
9680                     color += h;
9681                 }
9682             } else {
9683                 if(v.substr(0, 1) == "#"){
9684                     if(v.length == 4) {
9685                         for(var i = 1; i < 4; i++){
9686                             var c = v.charAt(i);
9687                             color +=  c + c;
9688                         }
9689                     }else if(v.length == 7){
9690                         color += v.substr(1);
9691                     }
9692                 }
9693             }
9694             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9695         },
9696
9697         /**
9698          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9699          * gradient background, rounded corners and a 4-way shadow.
9700          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9701          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9702          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9703          * @return {Roo.Element} this
9704          */
9705         boxWrap : function(cls){
9706             cls = cls || 'x-box';
9707             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9708             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9709             return el;
9710         },
9711
9712         /**
9713          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9714          * @param {String} namespace The namespace in which to look for the attribute
9715          * @param {String} name The attribute name
9716          * @return {String} The attribute value
9717          */
9718         getAttributeNS : Roo.isIE ? function(ns, name){
9719             var d = this.dom;
9720             var type = typeof d[ns+":"+name];
9721             if(type != 'undefined' && type != 'unknown'){
9722                 return d[ns+":"+name];
9723             }
9724             return d[name];
9725         } : function(ns, name){
9726             var d = this.dom;
9727             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9728         },
9729         
9730         
9731         /**
9732          * Sets or Returns the value the dom attribute value
9733          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9734          * @param {String} value (optional) The value to set the attribute to
9735          * @return {String} The attribute value
9736          */
9737         attr : function(name){
9738             if (arguments.length > 1) {
9739                 this.dom.setAttribute(name, arguments[1]);
9740                 return arguments[1];
9741             }
9742             if (typeof(name) == 'object') {
9743                 for(var i in name) {
9744                     this.attr(i, name[i]);
9745                 }
9746                 return name;
9747             }
9748             
9749             
9750             if (!this.dom.hasAttribute(name)) {
9751                 return undefined;
9752             }
9753             return this.dom.getAttribute(name);
9754         }
9755         
9756         
9757         
9758     };
9759
9760     var ep = El.prototype;
9761
9762     /**
9763      * Appends an event handler (Shorthand for addListener)
9764      * @param {String}   eventName     The type of event to append
9765      * @param {Function} fn        The method the event invokes
9766      * @param {Object} scope       (optional) The scope (this object) of the fn
9767      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9768      * @method
9769      */
9770     ep.on = ep.addListener;
9771         // backwards compat
9772     ep.mon = ep.addListener;
9773
9774     /**
9775      * Removes an event handler from this element (shorthand for removeListener)
9776      * @param {String} eventName the type of event to remove
9777      * @param {Function} fn the method the event invokes
9778      * @return {Roo.Element} this
9779      * @method
9780      */
9781     ep.un = ep.removeListener;
9782
9783     /**
9784      * true to automatically adjust width and height settings for box-model issues (default to true)
9785      */
9786     ep.autoBoxAdjust = true;
9787
9788     // private
9789     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9790
9791     // private
9792     El.addUnits = function(v, defaultUnit){
9793         if(v === "" || v == "auto"){
9794             return v;
9795         }
9796         if(v === undefined){
9797             return '';
9798         }
9799         if(typeof v == "number" || !El.unitPattern.test(v)){
9800             return v + (defaultUnit || 'px');
9801         }
9802         return v;
9803     };
9804
9805     // special markup used throughout Roo when box wrapping elements
9806     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>';
9807     /**
9808      * Visibility mode constant - Use visibility to hide element
9809      * @static
9810      * @type Number
9811      */
9812     El.VISIBILITY = 1;
9813     /**
9814      * Visibility mode constant - Use display to hide element
9815      * @static
9816      * @type Number
9817      */
9818     El.DISPLAY = 2;
9819
9820     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9821     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9822     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9823
9824
9825
9826     /**
9827      * @private
9828      */
9829     El.cache = {};
9830
9831     var docEl;
9832
9833     /**
9834      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9835      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9836      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9837      * @return {Element} The Element object
9838      * @static
9839      */
9840     El.get = function(el){
9841         var ex, elm, id;
9842         if(!el){ return null; }
9843         if(typeof el == "string"){ // element id
9844             if(!(elm = document.getElementById(el))){
9845                 return null;
9846             }
9847             if(ex = El.cache[el]){
9848                 ex.dom = elm;
9849             }else{
9850                 ex = El.cache[el] = new El(elm);
9851             }
9852             return ex;
9853         }else if(el.tagName){ // dom element
9854             if(!(id = el.id)){
9855                 id = Roo.id(el);
9856             }
9857             if(ex = El.cache[id]){
9858                 ex.dom = el;
9859             }else{
9860                 ex = El.cache[id] = new El(el);
9861             }
9862             return ex;
9863         }else if(el instanceof El){
9864             if(el != docEl){
9865                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9866                                                               // catch case where it hasn't been appended
9867                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9868             }
9869             return el;
9870         }else if(el.isComposite){
9871             return el;
9872         }else if(el instanceof Array){
9873             return El.select(el);
9874         }else if(el == document){
9875             // create a bogus element object representing the document object
9876             if(!docEl){
9877                 var f = function(){};
9878                 f.prototype = El.prototype;
9879                 docEl = new f();
9880                 docEl.dom = document;
9881             }
9882             return docEl;
9883         }
9884         return null;
9885     };
9886
9887     // private
9888     El.uncache = function(el){
9889         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9890             if(a[i]){
9891                 delete El.cache[a[i].id || a[i]];
9892             }
9893         }
9894     };
9895
9896     // private
9897     // Garbage collection - uncache elements/purge listeners on orphaned elements
9898     // so we don't hold a reference and cause the browser to retain them
9899     El.garbageCollect = function(){
9900         if(!Roo.enableGarbageCollector){
9901             clearInterval(El.collectorThread);
9902             return;
9903         }
9904         for(var eid in El.cache){
9905             var el = El.cache[eid], d = el.dom;
9906             // -------------------------------------------------------
9907             // Determining what is garbage:
9908             // -------------------------------------------------------
9909             // !d
9910             // dom node is null, definitely garbage
9911             // -------------------------------------------------------
9912             // !d.parentNode
9913             // no parentNode == direct orphan, definitely garbage
9914             // -------------------------------------------------------
9915             // !d.offsetParent && !document.getElementById(eid)
9916             // display none elements have no offsetParent so we will
9917             // also try to look it up by it's id. However, check
9918             // offsetParent first so we don't do unneeded lookups.
9919             // This enables collection of elements that are not orphans
9920             // directly, but somewhere up the line they have an orphan
9921             // parent.
9922             // -------------------------------------------------------
9923             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9924                 delete El.cache[eid];
9925                 if(d && Roo.enableListenerCollection){
9926                     E.purgeElement(d);
9927                 }
9928             }
9929         }
9930     }
9931     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9932
9933
9934     // dom is optional
9935     El.Flyweight = function(dom){
9936         this.dom = dom;
9937     };
9938     El.Flyweight.prototype = El.prototype;
9939
9940     El._flyweights = {};
9941     /**
9942      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9943      * the dom node can be overwritten by other code.
9944      * @param {String/HTMLElement} el The dom node or id
9945      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9946      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9947      * @static
9948      * @return {Element} The shared Element object
9949      */
9950     El.fly = function(el, named){
9951         named = named || '_global';
9952         el = Roo.getDom(el);
9953         if(!el){
9954             return null;
9955         }
9956         if(!El._flyweights[named]){
9957             El._flyweights[named] = new El.Flyweight();
9958         }
9959         El._flyweights[named].dom = el;
9960         return El._flyweights[named];
9961     };
9962
9963     /**
9964      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9965      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9966      * Shorthand of {@link Roo.Element#get}
9967      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9968      * @return {Element} The Element object
9969      * @member Roo
9970      * @method get
9971      */
9972     Roo.get = El.get;
9973     /**
9974      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9975      * the dom node can be overwritten by other code.
9976      * Shorthand of {@link Roo.Element#fly}
9977      * @param {String/HTMLElement} el The dom node or id
9978      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9979      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9980      * @static
9981      * @return {Element} The shared Element object
9982      * @member Roo
9983      * @method fly
9984      */
9985     Roo.fly = El.fly;
9986
9987     // speedy lookup for elements never to box adjust
9988     var noBoxAdjust = Roo.isStrict ? {
9989         select:1
9990     } : {
9991         input:1, select:1, textarea:1
9992     };
9993     if(Roo.isIE || Roo.isGecko){
9994         noBoxAdjust['button'] = 1;
9995     }
9996
9997
9998     Roo.EventManager.on(window, 'unload', function(){
9999         delete El.cache;
10000         delete El._flyweights;
10001     });
10002 })();
10003
10004
10005
10006
10007 if(Roo.DomQuery){
10008     Roo.Element.selectorFunction = Roo.DomQuery.select;
10009 }
10010
10011 Roo.Element.select = function(selector, unique, root){
10012     var els;
10013     if(typeof selector == "string"){
10014         els = Roo.Element.selectorFunction(selector, root);
10015     }else if(selector.length !== undefined){
10016         els = selector;
10017     }else{
10018         throw "Invalid selector";
10019     }
10020     if(unique === true){
10021         return new Roo.CompositeElement(els);
10022     }else{
10023         return new Roo.CompositeElementLite(els);
10024     }
10025 };
10026 /**
10027  * Selects elements based on the passed CSS selector to enable working on them as 1.
10028  * @param {String/Array} selector The CSS selector or an array of elements
10029  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10030  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10031  * @return {CompositeElementLite/CompositeElement}
10032  * @member Roo
10033  * @method select
10034  */
10035 Roo.select = Roo.Element.select;
10036
10037
10038
10039
10040
10041
10042
10043
10044
10045
10046
10047
10048
10049
10050 /*
10051  * Based on:
10052  * Ext JS Library 1.1.1
10053  * Copyright(c) 2006-2007, Ext JS, LLC.
10054  *
10055  * Originally Released Under LGPL - original licence link has changed is not relivant.
10056  *
10057  * Fork - LGPL
10058  * <script type="text/javascript">
10059  */
10060
10061
10062
10063 //Notifies Element that fx methods are available
10064 Roo.enableFx = true;
10065
10066 /**
10067  * @class Roo.Fx
10068  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10069  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10070  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10071  * Element effects to work.</p><br/>
10072  *
10073  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10074  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10075  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10076  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10077  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10078  * expected results and should be done with care.</p><br/>
10079  *
10080  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10081  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10082 <pre>
10083 Value  Description
10084 -----  -----------------------------
10085 tl     The top left corner
10086 t      The center of the top edge
10087 tr     The top right corner
10088 l      The center of the left edge
10089 r      The center of the right edge
10090 bl     The bottom left corner
10091 b      The center of the bottom edge
10092 br     The bottom right corner
10093 </pre>
10094  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10095  * below are common options that can be passed to any Fx method.</b>
10096  * @cfg {Function} callback A function called when the effect is finished
10097  * @cfg {Object} scope The scope of the effect function
10098  * @cfg {String} easing A valid Easing value for the effect
10099  * @cfg {String} afterCls A css class to apply after the effect
10100  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10101  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10102  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10103  * effects that end with the element being visually hidden, ignored otherwise)
10104  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10105  * a function which returns such a specification that will be applied to the Element after the effect finishes
10106  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10107  * @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
10108  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10109  */
10110 Roo.Fx = {
10111         /**
10112          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10113          * origin for the slide effect.  This function automatically handles wrapping the element with
10114          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10115          * Usage:
10116          *<pre><code>
10117 // default: slide the element in from the top
10118 el.slideIn();
10119
10120 // custom: slide the element in from the right with a 2-second duration
10121 el.slideIn('r', { duration: 2 });
10122
10123 // common config options shown with default values
10124 el.slideIn('t', {
10125     easing: 'easeOut',
10126     duration: .5
10127 });
10128 </code></pre>
10129          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10130          * @param {Object} options (optional) Object literal with any of the Fx config options
10131          * @return {Roo.Element} The Element
10132          */
10133     slideIn : function(anchor, o){
10134         var el = this.getFxEl();
10135         o = o || {};
10136
10137         el.queueFx(o, function(){
10138
10139             anchor = anchor || "t";
10140
10141             // fix display to visibility
10142             this.fixDisplay();
10143
10144             // restore values after effect
10145             var r = this.getFxRestore();
10146             var b = this.getBox();
10147             // fixed size for slide
10148             this.setSize(b);
10149
10150             // wrap if needed
10151             var wrap = this.fxWrap(r.pos, o, "hidden");
10152
10153             var st = this.dom.style;
10154             st.visibility = "visible";
10155             st.position = "absolute";
10156
10157             // clear out temp styles after slide and unwrap
10158             var after = function(){
10159                 el.fxUnwrap(wrap, r.pos, o);
10160                 st.width = r.width;
10161                 st.height = r.height;
10162                 el.afterFx(o);
10163             };
10164             // time to calc the positions
10165             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10166
10167             switch(anchor.toLowerCase()){
10168                 case "t":
10169                     wrap.setSize(b.width, 0);
10170                     st.left = st.bottom = "0";
10171                     a = {height: bh};
10172                 break;
10173                 case "l":
10174                     wrap.setSize(0, b.height);
10175                     st.right = st.top = "0";
10176                     a = {width: bw};
10177                 break;
10178                 case "r":
10179                     wrap.setSize(0, b.height);
10180                     wrap.setX(b.right);
10181                     st.left = st.top = "0";
10182                     a = {width: bw, points: pt};
10183                 break;
10184                 case "b":
10185                     wrap.setSize(b.width, 0);
10186                     wrap.setY(b.bottom);
10187                     st.left = st.top = "0";
10188                     a = {height: bh, points: pt};
10189                 break;
10190                 case "tl":
10191                     wrap.setSize(0, 0);
10192                     st.right = st.bottom = "0";
10193                     a = {width: bw, height: bh};
10194                 break;
10195                 case "bl":
10196                     wrap.setSize(0, 0);
10197                     wrap.setY(b.y+b.height);
10198                     st.right = st.top = "0";
10199                     a = {width: bw, height: bh, points: pt};
10200                 break;
10201                 case "br":
10202                     wrap.setSize(0, 0);
10203                     wrap.setXY([b.right, b.bottom]);
10204                     st.left = st.top = "0";
10205                     a = {width: bw, height: bh, points: pt};
10206                 break;
10207                 case "tr":
10208                     wrap.setSize(0, 0);
10209                     wrap.setX(b.x+b.width);
10210                     st.left = st.bottom = "0";
10211                     a = {width: bw, height: bh, points: pt};
10212                 break;
10213             }
10214             this.dom.style.visibility = "visible";
10215             wrap.show();
10216
10217             arguments.callee.anim = wrap.fxanim(a,
10218                 o,
10219                 'motion',
10220                 .5,
10221                 'easeOut', after);
10222         });
10223         return this;
10224     },
10225     
10226         /**
10227          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10228          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10229          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10230          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10231          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10232          * Usage:
10233          *<pre><code>
10234 // default: slide the element out to the top
10235 el.slideOut();
10236
10237 // custom: slide the element out to the right with a 2-second duration
10238 el.slideOut('r', { duration: 2 });
10239
10240 // common config options shown with default values
10241 el.slideOut('t', {
10242     easing: 'easeOut',
10243     duration: .5,
10244     remove: false,
10245     useDisplay: false
10246 });
10247 </code></pre>
10248          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10249          * @param {Object} options (optional) Object literal with any of the Fx config options
10250          * @return {Roo.Element} The Element
10251          */
10252     slideOut : function(anchor, o){
10253         var el = this.getFxEl();
10254         o = o || {};
10255
10256         el.queueFx(o, function(){
10257
10258             anchor = anchor || "t";
10259
10260             // restore values after effect
10261             var r = this.getFxRestore();
10262             
10263             var b = this.getBox();
10264             // fixed size for slide
10265             this.setSize(b);
10266
10267             // wrap if needed
10268             var wrap = this.fxWrap(r.pos, o, "visible");
10269
10270             var st = this.dom.style;
10271             st.visibility = "visible";
10272             st.position = "absolute";
10273
10274             wrap.setSize(b);
10275
10276             var after = function(){
10277                 if(o.useDisplay){
10278                     el.setDisplayed(false);
10279                 }else{
10280                     el.hide();
10281                 }
10282
10283                 el.fxUnwrap(wrap, r.pos, o);
10284
10285                 st.width = r.width;
10286                 st.height = r.height;
10287
10288                 el.afterFx(o);
10289             };
10290
10291             var a, zero = {to: 0};
10292             switch(anchor.toLowerCase()){
10293                 case "t":
10294                     st.left = st.bottom = "0";
10295                     a = {height: zero};
10296                 break;
10297                 case "l":
10298                     st.right = st.top = "0";
10299                     a = {width: zero};
10300                 break;
10301                 case "r":
10302                     st.left = st.top = "0";
10303                     a = {width: zero, points: {to:[b.right, b.y]}};
10304                 break;
10305                 case "b":
10306                     st.left = st.top = "0";
10307                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10308                 break;
10309                 case "tl":
10310                     st.right = st.bottom = "0";
10311                     a = {width: zero, height: zero};
10312                 break;
10313                 case "bl":
10314                     st.right = st.top = "0";
10315                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10316                 break;
10317                 case "br":
10318                     st.left = st.top = "0";
10319                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10320                 break;
10321                 case "tr":
10322                     st.left = st.bottom = "0";
10323                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10324                 break;
10325             }
10326
10327             arguments.callee.anim = wrap.fxanim(a,
10328                 o,
10329                 'motion',
10330                 .5,
10331                 "easeOut", after);
10332         });
10333         return this;
10334     },
10335
10336         /**
10337          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10338          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10339          * The element must be removed from the DOM using the 'remove' config option if desired.
10340          * Usage:
10341          *<pre><code>
10342 // default
10343 el.puff();
10344
10345 // common config options shown with default values
10346 el.puff({
10347     easing: 'easeOut',
10348     duration: .5,
10349     remove: false,
10350     useDisplay: false
10351 });
10352 </code></pre>
10353          * @param {Object} options (optional) Object literal with any of the Fx config options
10354          * @return {Roo.Element} The Element
10355          */
10356     puff : function(o){
10357         var el = this.getFxEl();
10358         o = o || {};
10359
10360         el.queueFx(o, function(){
10361             this.clearOpacity();
10362             this.show();
10363
10364             // restore values after effect
10365             var r = this.getFxRestore();
10366             var st = this.dom.style;
10367
10368             var after = function(){
10369                 if(o.useDisplay){
10370                     el.setDisplayed(false);
10371                 }else{
10372                     el.hide();
10373                 }
10374
10375                 el.clearOpacity();
10376
10377                 el.setPositioning(r.pos);
10378                 st.width = r.width;
10379                 st.height = r.height;
10380                 st.fontSize = '';
10381                 el.afterFx(o);
10382             };
10383
10384             var width = this.getWidth();
10385             var height = this.getHeight();
10386
10387             arguments.callee.anim = this.fxanim({
10388                     width : {to: this.adjustWidth(width * 2)},
10389                     height : {to: this.adjustHeight(height * 2)},
10390                     points : {by: [-(width * .5), -(height * .5)]},
10391                     opacity : {to: 0},
10392                     fontSize: {to:200, unit: "%"}
10393                 },
10394                 o,
10395                 'motion',
10396                 .5,
10397                 "easeOut", after);
10398         });
10399         return this;
10400     },
10401
10402         /**
10403          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10404          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10405          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10406          * Usage:
10407          *<pre><code>
10408 // default
10409 el.switchOff();
10410
10411 // all config options shown with default values
10412 el.switchOff({
10413     easing: 'easeIn',
10414     duration: .3,
10415     remove: false,
10416     useDisplay: false
10417 });
10418 </code></pre>
10419          * @param {Object} options (optional) Object literal with any of the Fx config options
10420          * @return {Roo.Element} The Element
10421          */
10422     switchOff : function(o){
10423         var el = this.getFxEl();
10424         o = o || {};
10425
10426         el.queueFx(o, function(){
10427             this.clearOpacity();
10428             this.clip();
10429
10430             // restore values after effect
10431             var r = this.getFxRestore();
10432             var st = this.dom.style;
10433
10434             var after = function(){
10435                 if(o.useDisplay){
10436                     el.setDisplayed(false);
10437                 }else{
10438                     el.hide();
10439                 }
10440
10441                 el.clearOpacity();
10442                 el.setPositioning(r.pos);
10443                 st.width = r.width;
10444                 st.height = r.height;
10445
10446                 el.afterFx(o);
10447             };
10448
10449             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10450                 this.clearOpacity();
10451                 (function(){
10452                     this.fxanim({
10453                         height:{to:1},
10454                         points:{by:[0, this.getHeight() * .5]}
10455                     }, o, 'motion', 0.3, 'easeIn', after);
10456                 }).defer(100, this);
10457             });
10458         });
10459         return this;
10460     },
10461
10462     /**
10463      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10464      * changed using the "attr" config option) and then fading back to the original color. If no original
10465      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10466      * Usage:
10467 <pre><code>
10468 // default: highlight background to yellow
10469 el.highlight();
10470
10471 // custom: highlight foreground text to blue for 2 seconds
10472 el.highlight("0000ff", { attr: 'color', duration: 2 });
10473
10474 // common config options shown with default values
10475 el.highlight("ffff9c", {
10476     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10477     endColor: (current color) or "ffffff",
10478     easing: 'easeIn',
10479     duration: 1
10480 });
10481 </code></pre>
10482      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10483      * @param {Object} options (optional) Object literal with any of the Fx config options
10484      * @return {Roo.Element} The Element
10485      */ 
10486     highlight : function(color, o){
10487         var el = this.getFxEl();
10488         o = o || {};
10489
10490         el.queueFx(o, function(){
10491             color = color || "ffff9c";
10492             attr = o.attr || "backgroundColor";
10493
10494             this.clearOpacity();
10495             this.show();
10496
10497             var origColor = this.getColor(attr);
10498             var restoreColor = this.dom.style[attr];
10499             endColor = (o.endColor || origColor) || "ffffff";
10500
10501             var after = function(){
10502                 el.dom.style[attr] = restoreColor;
10503                 el.afterFx(o);
10504             };
10505
10506             var a = {};
10507             a[attr] = {from: color, to: endColor};
10508             arguments.callee.anim = this.fxanim(a,
10509                 o,
10510                 'color',
10511                 1,
10512                 'easeIn', after);
10513         });
10514         return this;
10515     },
10516
10517    /**
10518     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10519     * Usage:
10520 <pre><code>
10521 // default: a single light blue ripple
10522 el.frame();
10523
10524 // custom: 3 red ripples lasting 3 seconds total
10525 el.frame("ff0000", 3, { duration: 3 });
10526
10527 // common config options shown with default values
10528 el.frame("C3DAF9", 1, {
10529     duration: 1 //duration of entire animation (not each individual ripple)
10530     // Note: Easing is not configurable and will be ignored if included
10531 });
10532 </code></pre>
10533     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10534     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10535     * @param {Object} options (optional) Object literal with any of the Fx config options
10536     * @return {Roo.Element} The Element
10537     */
10538     frame : function(color, count, o){
10539         var el = this.getFxEl();
10540         o = o || {};
10541
10542         el.queueFx(o, function(){
10543             color = color || "#C3DAF9";
10544             if(color.length == 6){
10545                 color = "#" + color;
10546             }
10547             count = count || 1;
10548             duration = o.duration || 1;
10549             this.show();
10550
10551             var b = this.getBox();
10552             var animFn = function(){
10553                 var proxy = this.createProxy({
10554
10555                      style:{
10556                         visbility:"hidden",
10557                         position:"absolute",
10558                         "z-index":"35000", // yee haw
10559                         border:"0px solid " + color
10560                      }
10561                   });
10562                 var scale = Roo.isBorderBox ? 2 : 1;
10563                 proxy.animate({
10564                     top:{from:b.y, to:b.y - 20},
10565                     left:{from:b.x, to:b.x - 20},
10566                     borderWidth:{from:0, to:10},
10567                     opacity:{from:1, to:0},
10568                     height:{from:b.height, to:(b.height + (20*scale))},
10569                     width:{from:b.width, to:(b.width + (20*scale))}
10570                 }, duration, function(){
10571                     proxy.remove();
10572                 });
10573                 if(--count > 0){
10574                      animFn.defer((duration/2)*1000, this);
10575                 }else{
10576                     el.afterFx(o);
10577                 }
10578             };
10579             animFn.call(this);
10580         });
10581         return this;
10582     },
10583
10584    /**
10585     * Creates a pause before any subsequent queued effects begin.  If there are
10586     * no effects queued after the pause it will have no effect.
10587     * Usage:
10588 <pre><code>
10589 el.pause(1);
10590 </code></pre>
10591     * @param {Number} seconds The length of time to pause (in seconds)
10592     * @return {Roo.Element} The Element
10593     */
10594     pause : function(seconds){
10595         var el = this.getFxEl();
10596         var o = {};
10597
10598         el.queueFx(o, function(){
10599             setTimeout(function(){
10600                 el.afterFx(o);
10601             }, seconds * 1000);
10602         });
10603         return this;
10604     },
10605
10606    /**
10607     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10608     * using the "endOpacity" config option.
10609     * Usage:
10610 <pre><code>
10611 // default: fade in from opacity 0 to 100%
10612 el.fadeIn();
10613
10614 // custom: fade in from opacity 0 to 75% over 2 seconds
10615 el.fadeIn({ endOpacity: .75, duration: 2});
10616
10617 // common config options shown with default values
10618 el.fadeIn({
10619     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10620     easing: 'easeOut',
10621     duration: .5
10622 });
10623 </code></pre>
10624     * @param {Object} options (optional) Object literal with any of the Fx config options
10625     * @return {Roo.Element} The Element
10626     */
10627     fadeIn : function(o){
10628         var el = this.getFxEl();
10629         o = o || {};
10630         el.queueFx(o, function(){
10631             this.setOpacity(0);
10632             this.fixDisplay();
10633             this.dom.style.visibility = 'visible';
10634             var to = o.endOpacity || 1;
10635             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10636                 o, null, .5, "easeOut", function(){
10637                 if(to == 1){
10638                     this.clearOpacity();
10639                 }
10640                 el.afterFx(o);
10641             });
10642         });
10643         return this;
10644     },
10645
10646    /**
10647     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10648     * using the "endOpacity" config option.
10649     * Usage:
10650 <pre><code>
10651 // default: fade out from the element's current opacity to 0
10652 el.fadeOut();
10653
10654 // custom: fade out from the element's current opacity to 25% over 2 seconds
10655 el.fadeOut({ endOpacity: .25, duration: 2});
10656
10657 // common config options shown with default values
10658 el.fadeOut({
10659     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10660     easing: 'easeOut',
10661     duration: .5
10662     remove: false,
10663     useDisplay: false
10664 });
10665 </code></pre>
10666     * @param {Object} options (optional) Object literal with any of the Fx config options
10667     * @return {Roo.Element} The Element
10668     */
10669     fadeOut : function(o){
10670         var el = this.getFxEl();
10671         o = o || {};
10672         el.queueFx(o, function(){
10673             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10674                 o, null, .5, "easeOut", function(){
10675                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10676                      this.dom.style.display = "none";
10677                 }else{
10678                      this.dom.style.visibility = "hidden";
10679                 }
10680                 this.clearOpacity();
10681                 el.afterFx(o);
10682             });
10683         });
10684         return this;
10685     },
10686
10687    /**
10688     * Animates the transition of an element's dimensions from a starting height/width
10689     * to an ending height/width.
10690     * Usage:
10691 <pre><code>
10692 // change height and width to 100x100 pixels
10693 el.scale(100, 100);
10694
10695 // common config options shown with default values.  The height and width will default to
10696 // the element's existing values if passed as null.
10697 el.scale(
10698     [element's width],
10699     [element's height], {
10700     easing: 'easeOut',
10701     duration: .35
10702 });
10703 </code></pre>
10704     * @param {Number} width  The new width (pass undefined to keep the original width)
10705     * @param {Number} height  The new height (pass undefined to keep the original height)
10706     * @param {Object} options (optional) Object literal with any of the Fx config options
10707     * @return {Roo.Element} The Element
10708     */
10709     scale : function(w, h, o){
10710         this.shift(Roo.apply({}, o, {
10711             width: w,
10712             height: h
10713         }));
10714         return this;
10715     },
10716
10717    /**
10718     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10719     * Any of these properties not specified in the config object will not be changed.  This effect 
10720     * requires that at least one new dimension, position or opacity setting must be passed in on
10721     * the config object in order for the function to have any effect.
10722     * Usage:
10723 <pre><code>
10724 // slide the element horizontally to x position 200 while changing the height and opacity
10725 el.shift({ x: 200, height: 50, opacity: .8 });
10726
10727 // common config options shown with default values.
10728 el.shift({
10729     width: [element's width],
10730     height: [element's height],
10731     x: [element's x position],
10732     y: [element's y position],
10733     opacity: [element's opacity],
10734     easing: 'easeOut',
10735     duration: .35
10736 });
10737 </code></pre>
10738     * @param {Object} options  Object literal with any of the Fx config options
10739     * @return {Roo.Element} The Element
10740     */
10741     shift : function(o){
10742         var el = this.getFxEl();
10743         o = o || {};
10744         el.queueFx(o, function(){
10745             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10746             if(w !== undefined){
10747                 a.width = {to: this.adjustWidth(w)};
10748             }
10749             if(h !== undefined){
10750                 a.height = {to: this.adjustHeight(h)};
10751             }
10752             if(x !== undefined || y !== undefined){
10753                 a.points = {to: [
10754                     x !== undefined ? x : this.getX(),
10755                     y !== undefined ? y : this.getY()
10756                 ]};
10757             }
10758             if(op !== undefined){
10759                 a.opacity = {to: op};
10760             }
10761             if(o.xy !== undefined){
10762                 a.points = {to: o.xy};
10763             }
10764             arguments.callee.anim = this.fxanim(a,
10765                 o, 'motion', .35, "easeOut", function(){
10766                 el.afterFx(o);
10767             });
10768         });
10769         return this;
10770     },
10771
10772         /**
10773          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10774          * ending point of the effect.
10775          * Usage:
10776          *<pre><code>
10777 // default: slide the element downward while fading out
10778 el.ghost();
10779
10780 // custom: slide the element out to the right with a 2-second duration
10781 el.ghost('r', { duration: 2 });
10782
10783 // common config options shown with default values
10784 el.ghost('b', {
10785     easing: 'easeOut',
10786     duration: .5
10787     remove: false,
10788     useDisplay: false
10789 });
10790 </code></pre>
10791          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10792          * @param {Object} options (optional) Object literal with any of the Fx config options
10793          * @return {Roo.Element} The Element
10794          */
10795     ghost : function(anchor, o){
10796         var el = this.getFxEl();
10797         o = o || {};
10798
10799         el.queueFx(o, function(){
10800             anchor = anchor || "b";
10801
10802             // restore values after effect
10803             var r = this.getFxRestore();
10804             var w = this.getWidth(),
10805                 h = this.getHeight();
10806
10807             var st = this.dom.style;
10808
10809             var after = function(){
10810                 if(o.useDisplay){
10811                     el.setDisplayed(false);
10812                 }else{
10813                     el.hide();
10814                 }
10815
10816                 el.clearOpacity();
10817                 el.setPositioning(r.pos);
10818                 st.width = r.width;
10819                 st.height = r.height;
10820
10821                 el.afterFx(o);
10822             };
10823
10824             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10825             switch(anchor.toLowerCase()){
10826                 case "t":
10827                     pt.by = [0, -h];
10828                 break;
10829                 case "l":
10830                     pt.by = [-w, 0];
10831                 break;
10832                 case "r":
10833                     pt.by = [w, 0];
10834                 break;
10835                 case "b":
10836                     pt.by = [0, h];
10837                 break;
10838                 case "tl":
10839                     pt.by = [-w, -h];
10840                 break;
10841                 case "bl":
10842                     pt.by = [-w, h];
10843                 break;
10844                 case "br":
10845                     pt.by = [w, h];
10846                 break;
10847                 case "tr":
10848                     pt.by = [w, -h];
10849                 break;
10850             }
10851
10852             arguments.callee.anim = this.fxanim(a,
10853                 o,
10854                 'motion',
10855                 .5,
10856                 "easeOut", after);
10857         });
10858         return this;
10859     },
10860
10861         /**
10862          * Ensures that all effects queued after syncFx is called on the element are
10863          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10864          * @return {Roo.Element} The Element
10865          */
10866     syncFx : function(){
10867         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10868             block : false,
10869             concurrent : true,
10870             stopFx : false
10871         });
10872         return this;
10873     },
10874
10875         /**
10876          * Ensures that all effects queued after sequenceFx is called on the element are
10877          * run in sequence.  This is the opposite of {@link #syncFx}.
10878          * @return {Roo.Element} The Element
10879          */
10880     sequenceFx : function(){
10881         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10882             block : false,
10883             concurrent : false,
10884             stopFx : false
10885         });
10886         return this;
10887     },
10888
10889         /* @private */
10890     nextFx : function(){
10891         var ef = this.fxQueue[0];
10892         if(ef){
10893             ef.call(this);
10894         }
10895     },
10896
10897         /**
10898          * Returns true if the element has any effects actively running or queued, else returns false.
10899          * @return {Boolean} True if element has active effects, else false
10900          */
10901     hasActiveFx : function(){
10902         return this.fxQueue && this.fxQueue[0];
10903     },
10904
10905         /**
10906          * Stops any running effects and clears the element's internal effects queue if it contains
10907          * any additional effects that haven't started yet.
10908          * @return {Roo.Element} The Element
10909          */
10910     stopFx : function(){
10911         if(this.hasActiveFx()){
10912             var cur = this.fxQueue[0];
10913             if(cur && cur.anim && cur.anim.isAnimated()){
10914                 this.fxQueue = [cur]; // clear out others
10915                 cur.anim.stop(true);
10916             }
10917         }
10918         return this;
10919     },
10920
10921         /* @private */
10922     beforeFx : function(o){
10923         if(this.hasActiveFx() && !o.concurrent){
10924            if(o.stopFx){
10925                this.stopFx();
10926                return true;
10927            }
10928            return false;
10929         }
10930         return true;
10931     },
10932
10933         /**
10934          * Returns true if the element is currently blocking so that no other effect can be queued
10935          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10936          * used to ensure that an effect initiated by a user action runs to completion prior to the
10937          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10938          * @return {Boolean} True if blocking, else false
10939          */
10940     hasFxBlock : function(){
10941         var q = this.fxQueue;
10942         return q && q[0] && q[0].block;
10943     },
10944
10945         /* @private */
10946     queueFx : function(o, fn){
10947         if(!this.fxQueue){
10948             this.fxQueue = [];
10949         }
10950         if(!this.hasFxBlock()){
10951             Roo.applyIf(o, this.fxDefaults);
10952             if(!o.concurrent){
10953                 var run = this.beforeFx(o);
10954                 fn.block = o.block;
10955                 this.fxQueue.push(fn);
10956                 if(run){
10957                     this.nextFx();
10958                 }
10959             }else{
10960                 fn.call(this);
10961             }
10962         }
10963         return this;
10964     },
10965
10966         /* @private */
10967     fxWrap : function(pos, o, vis){
10968         var wrap;
10969         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10970             var wrapXY;
10971             if(o.fixPosition){
10972                 wrapXY = this.getXY();
10973             }
10974             var div = document.createElement("div");
10975             div.style.visibility = vis;
10976             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10977             wrap.setPositioning(pos);
10978             if(wrap.getStyle("position") == "static"){
10979                 wrap.position("relative");
10980             }
10981             this.clearPositioning('auto');
10982             wrap.clip();
10983             wrap.dom.appendChild(this.dom);
10984             if(wrapXY){
10985                 wrap.setXY(wrapXY);
10986             }
10987         }
10988         return wrap;
10989     },
10990
10991         /* @private */
10992     fxUnwrap : function(wrap, pos, o){
10993         this.clearPositioning();
10994         this.setPositioning(pos);
10995         if(!o.wrap){
10996             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10997             wrap.remove();
10998         }
10999     },
11000
11001         /* @private */
11002     getFxRestore : function(){
11003         var st = this.dom.style;
11004         return {pos: this.getPositioning(), width: st.width, height : st.height};
11005     },
11006
11007         /* @private */
11008     afterFx : function(o){
11009         if(o.afterStyle){
11010             this.applyStyles(o.afterStyle);
11011         }
11012         if(o.afterCls){
11013             this.addClass(o.afterCls);
11014         }
11015         if(o.remove === true){
11016             this.remove();
11017         }
11018         Roo.callback(o.callback, o.scope, [this]);
11019         if(!o.concurrent){
11020             this.fxQueue.shift();
11021             this.nextFx();
11022         }
11023     },
11024
11025         /* @private */
11026     getFxEl : function(){ // support for composite element fx
11027         return Roo.get(this.dom);
11028     },
11029
11030         /* @private */
11031     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11032         animType = animType || 'run';
11033         opt = opt || {};
11034         var anim = Roo.lib.Anim[animType](
11035             this.dom, args,
11036             (opt.duration || defaultDur) || .35,
11037             (opt.easing || defaultEase) || 'easeOut',
11038             function(){
11039                 Roo.callback(cb, this);
11040             },
11041             this
11042         );
11043         opt.anim = anim;
11044         return anim;
11045     }
11046 };
11047
11048 // backwords compat
11049 Roo.Fx.resize = Roo.Fx.scale;
11050
11051 //When included, Roo.Fx is automatically applied to Element so that all basic
11052 //effects are available directly via the Element API
11053 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11054  * Based on:
11055  * Ext JS Library 1.1.1
11056  * Copyright(c) 2006-2007, Ext JS, LLC.
11057  *
11058  * Originally Released Under LGPL - original licence link has changed is not relivant.
11059  *
11060  * Fork - LGPL
11061  * <script type="text/javascript">
11062  */
11063
11064
11065 /**
11066  * @class Roo.CompositeElement
11067  * Standard composite class. Creates a Roo.Element for every element in the collection.
11068  * <br><br>
11069  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11070  * actions will be performed on all the elements in this collection.</b>
11071  * <br><br>
11072  * All methods return <i>this</i> and can be chained.
11073  <pre><code>
11074  var els = Roo.select("#some-el div.some-class", true);
11075  // or select directly from an existing element
11076  var el = Roo.get('some-el');
11077  el.select('div.some-class', true);
11078
11079  els.setWidth(100); // all elements become 100 width
11080  els.hide(true); // all elements fade out and hide
11081  // or
11082  els.setWidth(100).hide(true);
11083  </code></pre>
11084  */
11085 Roo.CompositeElement = function(els){
11086     this.elements = [];
11087     this.addElements(els);
11088 };
11089 Roo.CompositeElement.prototype = {
11090     isComposite: true,
11091     addElements : function(els){
11092         if(!els) {
11093             return this;
11094         }
11095         if(typeof els == "string"){
11096             els = Roo.Element.selectorFunction(els);
11097         }
11098         var yels = this.elements;
11099         var index = yels.length-1;
11100         for(var i = 0, len = els.length; i < len; i++) {
11101                 yels[++index] = Roo.get(els[i]);
11102         }
11103         return this;
11104     },
11105
11106     /**
11107     * Clears this composite and adds the elements returned by the passed selector.
11108     * @param {String/Array} els A string CSS selector, an array of elements or an element
11109     * @return {CompositeElement} this
11110     */
11111     fill : function(els){
11112         this.elements = [];
11113         this.add(els);
11114         return this;
11115     },
11116
11117     /**
11118     * Filters this composite to only elements that match the passed selector.
11119     * @param {String} selector A string CSS selector
11120     * @param {Boolean} inverse return inverse filter (not matches)
11121     * @return {CompositeElement} this
11122     */
11123     filter : function(selector, inverse){
11124         var els = [];
11125         inverse = inverse || false;
11126         this.each(function(el){
11127             var match = inverse ? !el.is(selector) : el.is(selector);
11128             if(match){
11129                 els[els.length] = el.dom;
11130             }
11131         });
11132         this.fill(els);
11133         return this;
11134     },
11135
11136     invoke : function(fn, args){
11137         var els = this.elements;
11138         for(var i = 0, len = els.length; i < len; i++) {
11139                 Roo.Element.prototype[fn].apply(els[i], args);
11140         }
11141         return this;
11142     },
11143     /**
11144     * Adds elements to this composite.
11145     * @param {String/Array} els A string CSS selector, an array of elements or an element
11146     * @return {CompositeElement} this
11147     */
11148     add : function(els){
11149         if(typeof els == "string"){
11150             this.addElements(Roo.Element.selectorFunction(els));
11151         }else if(els.length !== undefined){
11152             this.addElements(els);
11153         }else{
11154             this.addElements([els]);
11155         }
11156         return this;
11157     },
11158     /**
11159     * Calls the passed function passing (el, this, index) for each element in this composite.
11160     * @param {Function} fn The function to call
11161     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11162     * @return {CompositeElement} this
11163     */
11164     each : function(fn, scope){
11165         var els = this.elements;
11166         for(var i = 0, len = els.length; i < len; i++){
11167             if(fn.call(scope || els[i], els[i], this, i) === false) {
11168                 break;
11169             }
11170         }
11171         return this;
11172     },
11173
11174     /**
11175      * Returns the Element object at the specified index
11176      * @param {Number} index
11177      * @return {Roo.Element}
11178      */
11179     item : function(index){
11180         return this.elements[index] || null;
11181     },
11182
11183     /**
11184      * Returns the first Element
11185      * @return {Roo.Element}
11186      */
11187     first : function(){
11188         return this.item(0);
11189     },
11190
11191     /**
11192      * Returns the last Element
11193      * @return {Roo.Element}
11194      */
11195     last : function(){
11196         return this.item(this.elements.length-1);
11197     },
11198
11199     /**
11200      * Returns the number of elements in this composite
11201      * @return Number
11202      */
11203     getCount : function(){
11204         return this.elements.length;
11205     },
11206
11207     /**
11208      * Returns true if this composite contains the passed element
11209      * @return Boolean
11210      */
11211     contains : function(el){
11212         return this.indexOf(el) !== -1;
11213     },
11214
11215     /**
11216      * Returns true if this composite contains the passed element
11217      * @return Boolean
11218      */
11219     indexOf : function(el){
11220         return this.elements.indexOf(Roo.get(el));
11221     },
11222
11223
11224     /**
11225     * Removes the specified element(s).
11226     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11227     * or an array of any of those.
11228     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11229     * @return {CompositeElement} this
11230     */
11231     removeElement : function(el, removeDom){
11232         if(el instanceof Array){
11233             for(var i = 0, len = el.length; i < len; i++){
11234                 this.removeElement(el[i]);
11235             }
11236             return this;
11237         }
11238         var index = typeof el == 'number' ? el : this.indexOf(el);
11239         if(index !== -1){
11240             if(removeDom){
11241                 var d = this.elements[index];
11242                 if(d.dom){
11243                     d.remove();
11244                 }else{
11245                     d.parentNode.removeChild(d);
11246                 }
11247             }
11248             this.elements.splice(index, 1);
11249         }
11250         return this;
11251     },
11252
11253     /**
11254     * Replaces the specified element with the passed element.
11255     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11256     * to replace.
11257     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11258     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11259     * @return {CompositeElement} this
11260     */
11261     replaceElement : function(el, replacement, domReplace){
11262         var index = typeof el == 'number' ? el : this.indexOf(el);
11263         if(index !== -1){
11264             if(domReplace){
11265                 this.elements[index].replaceWith(replacement);
11266             }else{
11267                 this.elements.splice(index, 1, Roo.get(replacement))
11268             }
11269         }
11270         return this;
11271     },
11272
11273     /**
11274      * Removes all elements.
11275      */
11276     clear : function(){
11277         this.elements = [];
11278     }
11279 };
11280 (function(){
11281     Roo.CompositeElement.createCall = function(proto, fnName){
11282         if(!proto[fnName]){
11283             proto[fnName] = function(){
11284                 return this.invoke(fnName, arguments);
11285             };
11286         }
11287     };
11288     for(var fnName in Roo.Element.prototype){
11289         if(typeof Roo.Element.prototype[fnName] == "function"){
11290             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11291         }
11292     };
11293 })();
11294 /*
11295  * Based on:
11296  * Ext JS Library 1.1.1
11297  * Copyright(c) 2006-2007, Ext JS, LLC.
11298  *
11299  * Originally Released Under LGPL - original licence link has changed is not relivant.
11300  *
11301  * Fork - LGPL
11302  * <script type="text/javascript">
11303  */
11304
11305 /**
11306  * @class Roo.CompositeElementLite
11307  * @extends Roo.CompositeElement
11308  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11309  <pre><code>
11310  var els = Roo.select("#some-el div.some-class");
11311  // or select directly from an existing element
11312  var el = Roo.get('some-el');
11313  el.select('div.some-class');
11314
11315  els.setWidth(100); // all elements become 100 width
11316  els.hide(true); // all elements fade out and hide
11317  // or
11318  els.setWidth(100).hide(true);
11319  </code></pre><br><br>
11320  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11321  * actions will be performed on all the elements in this collection.</b>
11322  */
11323 Roo.CompositeElementLite = function(els){
11324     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11325     this.el = new Roo.Element.Flyweight();
11326 };
11327 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11328     addElements : function(els){
11329         if(els){
11330             if(els instanceof Array){
11331                 this.elements = this.elements.concat(els);
11332             }else{
11333                 var yels = this.elements;
11334                 var index = yels.length-1;
11335                 for(var i = 0, len = els.length; i < len; i++) {
11336                     yels[++index] = els[i];
11337                 }
11338             }
11339         }
11340         return this;
11341     },
11342     invoke : function(fn, args){
11343         var els = this.elements;
11344         var el = this.el;
11345         for(var i = 0, len = els.length; i < len; i++) {
11346             el.dom = els[i];
11347                 Roo.Element.prototype[fn].apply(el, args);
11348         }
11349         return this;
11350     },
11351     /**
11352      * Returns a flyweight Element of the dom element object at the specified index
11353      * @param {Number} index
11354      * @return {Roo.Element}
11355      */
11356     item : function(index){
11357         if(!this.elements[index]){
11358             return null;
11359         }
11360         this.el.dom = this.elements[index];
11361         return this.el;
11362     },
11363
11364     // fixes scope with flyweight
11365     addListener : function(eventName, handler, scope, opt){
11366         var els = this.elements;
11367         for(var i = 0, len = els.length; i < len; i++) {
11368             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11369         }
11370         return this;
11371     },
11372
11373     /**
11374     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11375     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11376     * a reference to the dom node, use el.dom.</b>
11377     * @param {Function} fn The function to call
11378     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11379     * @return {CompositeElement} this
11380     */
11381     each : function(fn, scope){
11382         var els = this.elements;
11383         var el = this.el;
11384         for(var i = 0, len = els.length; i < len; i++){
11385             el.dom = els[i];
11386                 if(fn.call(scope || el, el, this, i) === false){
11387                 break;
11388             }
11389         }
11390         return this;
11391     },
11392
11393     indexOf : function(el){
11394         return this.elements.indexOf(Roo.getDom(el));
11395     },
11396
11397     replaceElement : function(el, replacement, domReplace){
11398         var index = typeof el == 'number' ? el : this.indexOf(el);
11399         if(index !== -1){
11400             replacement = Roo.getDom(replacement);
11401             if(domReplace){
11402                 var d = this.elements[index];
11403                 d.parentNode.insertBefore(replacement, d);
11404                 d.parentNode.removeChild(d);
11405             }
11406             this.elements.splice(index, 1, replacement);
11407         }
11408         return this;
11409     }
11410 });
11411 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11412
11413 /*
11414  * Based on:
11415  * Ext JS Library 1.1.1
11416  * Copyright(c) 2006-2007, Ext JS, LLC.
11417  *
11418  * Originally Released Under LGPL - original licence link has changed is not relivant.
11419  *
11420  * Fork - LGPL
11421  * <script type="text/javascript">
11422  */
11423
11424  
11425
11426 /**
11427  * @class Roo.data.Connection
11428  * @extends Roo.util.Observable
11429  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11430  * either to a configured URL, or to a URL specified at request time.<br><br>
11431  * <p>
11432  * Requests made by this class are asynchronous, and will return immediately. No data from
11433  * the server will be available to the statement immediately following the {@link #request} call.
11434  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11435  * <p>
11436  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11437  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11438  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11439  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11440  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11441  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11442  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11443  * standard DOM methods.
11444  * @constructor
11445  * @param {Object} config a configuration object.
11446  */
11447 Roo.data.Connection = function(config){
11448     Roo.apply(this, config);
11449     this.addEvents({
11450         /**
11451          * @event beforerequest
11452          * Fires before a network request is made to retrieve a data object.
11453          * @param {Connection} conn This Connection object.
11454          * @param {Object} options The options config object passed to the {@link #request} method.
11455          */
11456         "beforerequest" : true,
11457         /**
11458          * @event requestcomplete
11459          * Fires if the request was successfully completed.
11460          * @param {Connection} conn This Connection object.
11461          * @param {Object} response The XHR object containing the response data.
11462          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11463          * @param {Object} options The options config object passed to the {@link #request} method.
11464          */
11465         "requestcomplete" : true,
11466         /**
11467          * @event requestexception
11468          * Fires if an error HTTP status was returned from the server.
11469          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11470          * @param {Connection} conn This Connection object.
11471          * @param {Object} response The XHR object containing the response data.
11472          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11473          * @param {Object} options The options config object passed to the {@link #request} method.
11474          */
11475         "requestexception" : true
11476     });
11477     Roo.data.Connection.superclass.constructor.call(this);
11478 };
11479
11480 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11481     /**
11482      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11483      */
11484     /**
11485      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11486      * extra parameters to each request made by this object. (defaults to undefined)
11487      */
11488     /**
11489      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11490      *  to each request made by this object. (defaults to undefined)
11491      */
11492     /**
11493      * @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)
11494      */
11495     /**
11496      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11497      */
11498     timeout : 30000,
11499     /**
11500      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11501      * @type Boolean
11502      */
11503     autoAbort:false,
11504
11505     /**
11506      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11507      * @type Boolean
11508      */
11509     disableCaching: true,
11510
11511     /**
11512      * Sends an HTTP request to a remote server.
11513      * @param {Object} options An object which may contain the following properties:<ul>
11514      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11515      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11516      * request, a url encoded string or a function to call to get either.</li>
11517      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11518      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11519      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11520      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11521      * <li>options {Object} The parameter to the request call.</li>
11522      * <li>success {Boolean} True if the request succeeded.</li>
11523      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11524      * </ul></li>
11525      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11526      * The callback is passed the following parameters:<ul>
11527      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11528      * <li>options {Object} The parameter to the request call.</li>
11529      * </ul></li>
11530      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11531      * The callback is passed the following parameters:<ul>
11532      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11533      * <li>options {Object} The parameter to the request call.</li>
11534      * </ul></li>
11535      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11536      * for the callback function. Defaults to the browser window.</li>
11537      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11538      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11539      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11540      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11541      * params for the post data. Any params will be appended to the URL.</li>
11542      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11543      * </ul>
11544      * @return {Number} transactionId
11545      */
11546     request : function(o){
11547         if(this.fireEvent("beforerequest", this, o) !== false){
11548             var p = o.params;
11549
11550             if(typeof p == "function"){
11551                 p = p.call(o.scope||window, o);
11552             }
11553             if(typeof p == "object"){
11554                 p = Roo.urlEncode(o.params);
11555             }
11556             if(this.extraParams){
11557                 var extras = Roo.urlEncode(this.extraParams);
11558                 p = p ? (p + '&' + extras) : extras;
11559             }
11560
11561             var url = o.url || this.url;
11562             if(typeof url == 'function'){
11563                 url = url.call(o.scope||window, o);
11564             }
11565
11566             if(o.form){
11567                 var form = Roo.getDom(o.form);
11568                 url = url || form.action;
11569
11570                 var enctype = form.getAttribute("enctype");
11571                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11572                     return this.doFormUpload(o, p, url);
11573                 }
11574                 var f = Roo.lib.Ajax.serializeForm(form);
11575                 p = p ? (p + '&' + f) : f;
11576             }
11577
11578             var hs = o.headers;
11579             if(this.defaultHeaders){
11580                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11581                 if(!o.headers){
11582                     o.headers = hs;
11583                 }
11584             }
11585
11586             var cb = {
11587                 success: this.handleResponse,
11588                 failure: this.handleFailure,
11589                 scope: this,
11590                 argument: {options: o},
11591                 timeout : o.timeout || this.timeout
11592             };
11593
11594             var method = o.method||this.method||(p ? "POST" : "GET");
11595
11596             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11597                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11598             }
11599
11600             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11601                 if(o.autoAbort){
11602                     this.abort();
11603                 }
11604             }else if(this.autoAbort !== false){
11605                 this.abort();
11606             }
11607
11608             if((method == 'GET' && p) || o.xmlData){
11609                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11610                 p = '';
11611             }
11612             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11613             return this.transId;
11614         }else{
11615             Roo.callback(o.callback, o.scope, [o, null, null]);
11616             return null;
11617         }
11618     },
11619
11620     /**
11621      * Determine whether this object has a request outstanding.
11622      * @param {Number} transactionId (Optional) defaults to the last transaction
11623      * @return {Boolean} True if there is an outstanding request.
11624      */
11625     isLoading : function(transId){
11626         if(transId){
11627             return Roo.lib.Ajax.isCallInProgress(transId);
11628         }else{
11629             return this.transId ? true : false;
11630         }
11631     },
11632
11633     /**
11634      * Aborts any outstanding request.
11635      * @param {Number} transactionId (Optional) defaults to the last transaction
11636      */
11637     abort : function(transId){
11638         if(transId || this.isLoading()){
11639             Roo.lib.Ajax.abort(transId || this.transId);
11640         }
11641     },
11642
11643     // private
11644     handleResponse : function(response){
11645         this.transId = false;
11646         var options = response.argument.options;
11647         response.argument = options ? options.argument : null;
11648         this.fireEvent("requestcomplete", this, response, options);
11649         Roo.callback(options.success, options.scope, [response, options]);
11650         Roo.callback(options.callback, options.scope, [options, true, response]);
11651     },
11652
11653     // private
11654     handleFailure : function(response, e){
11655         this.transId = false;
11656         var options = response.argument.options;
11657         response.argument = options ? options.argument : null;
11658         this.fireEvent("requestexception", this, response, options, e);
11659         Roo.callback(options.failure, options.scope, [response, options]);
11660         Roo.callback(options.callback, options.scope, [options, false, response]);
11661     },
11662
11663     // private
11664     doFormUpload : function(o, ps, url){
11665         var id = Roo.id();
11666         var frame = document.createElement('iframe');
11667         frame.id = id;
11668         frame.name = id;
11669         frame.className = 'x-hidden';
11670         if(Roo.isIE){
11671             frame.src = Roo.SSL_SECURE_URL;
11672         }
11673         document.body.appendChild(frame);
11674
11675         if(Roo.isIE){
11676            document.frames[id].name = id;
11677         }
11678
11679         var form = Roo.getDom(o.form);
11680         form.target = id;
11681         form.method = 'POST';
11682         form.enctype = form.encoding = 'multipart/form-data';
11683         if(url){
11684             form.action = url;
11685         }
11686
11687         var hiddens, hd;
11688         if(ps){ // add dynamic params
11689             hiddens = [];
11690             ps = Roo.urlDecode(ps, false);
11691             for(var k in ps){
11692                 if(ps.hasOwnProperty(k)){
11693                     hd = document.createElement('input');
11694                     hd.type = 'hidden';
11695                     hd.name = k;
11696                     hd.value = ps[k];
11697                     form.appendChild(hd);
11698                     hiddens.push(hd);
11699                 }
11700             }
11701         }
11702
11703         function cb(){
11704             var r = {  // bogus response object
11705                 responseText : '',
11706                 responseXML : null
11707             };
11708
11709             r.argument = o ? o.argument : null;
11710
11711             try { //
11712                 var doc;
11713                 if(Roo.isIE){
11714                     doc = frame.contentWindow.document;
11715                 }else {
11716                     doc = (frame.contentDocument || window.frames[id].document);
11717                 }
11718                 if(doc && doc.body){
11719                     r.responseText = doc.body.innerHTML;
11720                 }
11721                 if(doc && doc.XMLDocument){
11722                     r.responseXML = doc.XMLDocument;
11723                 }else {
11724                     r.responseXML = doc;
11725                 }
11726             }
11727             catch(e) {
11728                 // ignore
11729             }
11730
11731             Roo.EventManager.removeListener(frame, 'load', cb, this);
11732
11733             this.fireEvent("requestcomplete", this, r, o);
11734             Roo.callback(o.success, o.scope, [r, o]);
11735             Roo.callback(o.callback, o.scope, [o, true, r]);
11736
11737             setTimeout(function(){document.body.removeChild(frame);}, 100);
11738         }
11739
11740         Roo.EventManager.on(frame, 'load', cb, this);
11741         form.submit();
11742
11743         if(hiddens){ // remove dynamic params
11744             for(var i = 0, len = hiddens.length; i < len; i++){
11745                 form.removeChild(hiddens[i]);
11746             }
11747         }
11748     }
11749 });
11750 /*
11751  * Based on:
11752  * Ext JS Library 1.1.1
11753  * Copyright(c) 2006-2007, Ext JS, LLC.
11754  *
11755  * Originally Released Under LGPL - original licence link has changed is not relivant.
11756  *
11757  * Fork - LGPL
11758  * <script type="text/javascript">
11759  */
11760  
11761 /**
11762  * Global Ajax request class.
11763  * 
11764  * @class Roo.Ajax
11765  * @extends Roo.data.Connection
11766  * @static
11767  * 
11768  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11769  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11770  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11771  * @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)
11772  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11773  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11774  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11775  */
11776 Roo.Ajax = new Roo.data.Connection({
11777     // fix up the docs
11778     /**
11779      * @scope Roo.Ajax
11780      * @type {Boolear} 
11781      */
11782     autoAbort : false,
11783
11784     /**
11785      * Serialize the passed form into a url encoded string
11786      * @scope Roo.Ajax
11787      * @param {String/HTMLElement} form
11788      * @return {String}
11789      */
11790     serializeForm : function(form){
11791         return Roo.lib.Ajax.serializeForm(form);
11792     }
11793 });/*
11794  * Based on:
11795  * Ext JS Library 1.1.1
11796  * Copyright(c) 2006-2007, Ext JS, LLC.
11797  *
11798  * Originally Released Under LGPL - original licence link has changed is not relivant.
11799  *
11800  * Fork - LGPL
11801  * <script type="text/javascript">
11802  */
11803
11804  
11805 /**
11806  * @class Roo.UpdateManager
11807  * @extends Roo.util.Observable
11808  * Provides AJAX-style update for Element object.<br><br>
11809  * Usage:<br>
11810  * <pre><code>
11811  * // Get it from a Roo.Element object
11812  * var el = Roo.get("foo");
11813  * var mgr = el.getUpdateManager();
11814  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11815  * ...
11816  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11817  * <br>
11818  * // or directly (returns the same UpdateManager instance)
11819  * var mgr = new Roo.UpdateManager("myElementId");
11820  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11821  * mgr.on("update", myFcnNeedsToKnow);
11822  * <br>
11823    // short handed call directly from the element object
11824    Roo.get("foo").load({
11825         url: "bar.php",
11826         scripts:true,
11827         params: "for=bar",
11828         text: "Loading Foo..."
11829    });
11830  * </code></pre>
11831  * @constructor
11832  * Create new UpdateManager directly.
11833  * @param {String/HTMLElement/Roo.Element} el The element to update
11834  * @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).
11835  */
11836 Roo.UpdateManager = function(el, forceNew){
11837     el = Roo.get(el);
11838     if(!forceNew && el.updateManager){
11839         return el.updateManager;
11840     }
11841     /**
11842      * The Element object
11843      * @type Roo.Element
11844      */
11845     this.el = el;
11846     /**
11847      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11848      * @type String
11849      */
11850     this.defaultUrl = null;
11851
11852     this.addEvents({
11853         /**
11854          * @event beforeupdate
11855          * Fired before an update is made, return false from your handler and the update is cancelled.
11856          * @param {Roo.Element} el
11857          * @param {String/Object/Function} url
11858          * @param {String/Object} params
11859          */
11860         "beforeupdate": true,
11861         /**
11862          * @event update
11863          * Fired after successful update is made.
11864          * @param {Roo.Element} el
11865          * @param {Object} oResponseObject The response Object
11866          */
11867         "update": true,
11868         /**
11869          * @event failure
11870          * Fired on update failure.
11871          * @param {Roo.Element} el
11872          * @param {Object} oResponseObject The response Object
11873          */
11874         "failure": true
11875     });
11876     var d = Roo.UpdateManager.defaults;
11877     /**
11878      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11879      * @type String
11880      */
11881     this.sslBlankUrl = d.sslBlankUrl;
11882     /**
11883      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11884      * @type Boolean
11885      */
11886     this.disableCaching = d.disableCaching;
11887     /**
11888      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11889      * @type String
11890      */
11891     this.indicatorText = d.indicatorText;
11892     /**
11893      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11894      * @type String
11895      */
11896     this.showLoadIndicator = d.showLoadIndicator;
11897     /**
11898      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11899      * @type Number
11900      */
11901     this.timeout = d.timeout;
11902
11903     /**
11904      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11905      * @type Boolean
11906      */
11907     this.loadScripts = d.loadScripts;
11908
11909     /**
11910      * Transaction object of current executing transaction
11911      */
11912     this.transaction = null;
11913
11914     /**
11915      * @private
11916      */
11917     this.autoRefreshProcId = null;
11918     /**
11919      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11920      * @type Function
11921      */
11922     this.refreshDelegate = this.refresh.createDelegate(this);
11923     /**
11924      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11925      * @type Function
11926      */
11927     this.updateDelegate = this.update.createDelegate(this);
11928     /**
11929      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11930      * @type Function
11931      */
11932     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11933     /**
11934      * @private
11935      */
11936     this.successDelegate = this.processSuccess.createDelegate(this);
11937     /**
11938      * @private
11939      */
11940     this.failureDelegate = this.processFailure.createDelegate(this);
11941
11942     if(!this.renderer){
11943      /**
11944       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11945       */
11946     this.renderer = new Roo.UpdateManager.BasicRenderer();
11947     }
11948     
11949     Roo.UpdateManager.superclass.constructor.call(this);
11950 };
11951
11952 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11953     /**
11954      * Get the Element this UpdateManager is bound to
11955      * @return {Roo.Element} The element
11956      */
11957     getEl : function(){
11958         return this.el;
11959     },
11960     /**
11961      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11962      * @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:
11963 <pre><code>
11964 um.update({<br/>
11965     url: "your-url.php",<br/>
11966     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11967     callback: yourFunction,<br/>
11968     scope: yourObject, //(optional scope)  <br/>
11969     discardUrl: false, <br/>
11970     nocache: false,<br/>
11971     text: "Loading...",<br/>
11972     timeout: 30,<br/>
11973     scripts: false<br/>
11974 });
11975 </code></pre>
11976      * The only required property is url. The optional properties nocache, text and scripts
11977      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11978      * @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}
11979      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11980      * @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.
11981      */
11982     update : function(url, params, callback, discardUrl){
11983         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11984             var method = this.method,
11985                 cfg;
11986             if(typeof url == "object"){ // must be config object
11987                 cfg = url;
11988                 url = cfg.url;
11989                 params = params || cfg.params;
11990                 callback = callback || cfg.callback;
11991                 discardUrl = discardUrl || cfg.discardUrl;
11992                 if(callback && cfg.scope){
11993                     callback = callback.createDelegate(cfg.scope);
11994                 }
11995                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11996                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11997                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11998                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11999                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12000             }
12001             this.showLoading();
12002             if(!discardUrl){
12003                 this.defaultUrl = url;
12004             }
12005             if(typeof url == "function"){
12006                 url = url.call(this);
12007             }
12008
12009             method = method || (params ? "POST" : "GET");
12010             if(method == "GET"){
12011                 url = this.prepareUrl(url);
12012             }
12013
12014             var o = Roo.apply(cfg ||{}, {
12015                 url : url,
12016                 params: params,
12017                 success: this.successDelegate,
12018                 failure: this.failureDelegate,
12019                 callback: undefined,
12020                 timeout: (this.timeout*1000),
12021                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12022             });
12023             Roo.log("updated manager called with timeout of " + o.timeout);
12024             this.transaction = Roo.Ajax.request(o);
12025         }
12026     },
12027
12028     /**
12029      * 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.
12030      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12031      * @param {String/HTMLElement} form The form Id or form element
12032      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12033      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12034      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12035      */
12036     formUpdate : function(form, url, reset, callback){
12037         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12038             if(typeof url == "function"){
12039                 url = url.call(this);
12040             }
12041             form = Roo.getDom(form);
12042             this.transaction = Roo.Ajax.request({
12043                 form: form,
12044                 url:url,
12045                 success: this.successDelegate,
12046                 failure: this.failureDelegate,
12047                 timeout: (this.timeout*1000),
12048                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12049             });
12050             this.showLoading.defer(1, this);
12051         }
12052     },
12053
12054     /**
12055      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12056      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12057      */
12058     refresh : function(callback){
12059         if(this.defaultUrl == null){
12060             return;
12061         }
12062         this.update(this.defaultUrl, null, callback, true);
12063     },
12064
12065     /**
12066      * Set this element to auto refresh.
12067      * @param {Number} interval How often to update (in seconds).
12068      * @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)
12069      * @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}
12070      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12071      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12072      */
12073     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12074         if(refreshNow){
12075             this.update(url || this.defaultUrl, params, callback, true);
12076         }
12077         if(this.autoRefreshProcId){
12078             clearInterval(this.autoRefreshProcId);
12079         }
12080         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12081     },
12082
12083     /**
12084      * Stop auto refresh on this element.
12085      */
12086      stopAutoRefresh : function(){
12087         if(this.autoRefreshProcId){
12088             clearInterval(this.autoRefreshProcId);
12089             delete this.autoRefreshProcId;
12090         }
12091     },
12092
12093     isAutoRefreshing : function(){
12094        return this.autoRefreshProcId ? true : false;
12095     },
12096     /**
12097      * Called to update the element to "Loading" state. Override to perform custom action.
12098      */
12099     showLoading : function(){
12100         if(this.showLoadIndicator){
12101             this.el.update(this.indicatorText);
12102         }
12103     },
12104
12105     /**
12106      * Adds unique parameter to query string if disableCaching = true
12107      * @private
12108      */
12109     prepareUrl : function(url){
12110         if(this.disableCaching){
12111             var append = "_dc=" + (new Date().getTime());
12112             if(url.indexOf("?") !== -1){
12113                 url += "&" + append;
12114             }else{
12115                 url += "?" + append;
12116             }
12117         }
12118         return url;
12119     },
12120
12121     /**
12122      * @private
12123      */
12124     processSuccess : function(response){
12125         this.transaction = null;
12126         if(response.argument.form && response.argument.reset){
12127             try{ // put in try/catch since some older FF releases had problems with this
12128                 response.argument.form.reset();
12129             }catch(e){}
12130         }
12131         if(this.loadScripts){
12132             this.renderer.render(this.el, response, this,
12133                 this.updateComplete.createDelegate(this, [response]));
12134         }else{
12135             this.renderer.render(this.el, response, this);
12136             this.updateComplete(response);
12137         }
12138     },
12139
12140     updateComplete : function(response){
12141         this.fireEvent("update", this.el, response);
12142         if(typeof response.argument.callback == "function"){
12143             response.argument.callback(this.el, true, response);
12144         }
12145     },
12146
12147     /**
12148      * @private
12149      */
12150     processFailure : function(response){
12151         this.transaction = null;
12152         this.fireEvent("failure", this.el, response);
12153         if(typeof response.argument.callback == "function"){
12154             response.argument.callback(this.el, false, response);
12155         }
12156     },
12157
12158     /**
12159      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12160      * @param {Object} renderer The object implementing the render() method
12161      */
12162     setRenderer : function(renderer){
12163         this.renderer = renderer;
12164     },
12165
12166     getRenderer : function(){
12167        return this.renderer;
12168     },
12169
12170     /**
12171      * Set the defaultUrl used for updates
12172      * @param {String/Function} defaultUrl The url or a function to call to get the url
12173      */
12174     setDefaultUrl : function(defaultUrl){
12175         this.defaultUrl = defaultUrl;
12176     },
12177
12178     /**
12179      * Aborts the executing transaction
12180      */
12181     abort : function(){
12182         if(this.transaction){
12183             Roo.Ajax.abort(this.transaction);
12184         }
12185     },
12186
12187     /**
12188      * Returns true if an update is in progress
12189      * @return {Boolean}
12190      */
12191     isUpdating : function(){
12192         if(this.transaction){
12193             return Roo.Ajax.isLoading(this.transaction);
12194         }
12195         return false;
12196     }
12197 });
12198
12199 /**
12200  * @class Roo.UpdateManager.defaults
12201  * @static (not really - but it helps the doc tool)
12202  * The defaults collection enables customizing the default properties of UpdateManager
12203  */
12204    Roo.UpdateManager.defaults = {
12205        /**
12206          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12207          * @type Number
12208          */
12209          timeout : 30,
12210
12211          /**
12212          * True to process scripts by default (Defaults to false).
12213          * @type Boolean
12214          */
12215         loadScripts : false,
12216
12217         /**
12218         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12219         * @type String
12220         */
12221         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12222         /**
12223          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12224          * @type Boolean
12225          */
12226         disableCaching : false,
12227         /**
12228          * Whether to show indicatorText when loading (Defaults to true).
12229          * @type Boolean
12230          */
12231         showLoadIndicator : true,
12232         /**
12233          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12234          * @type String
12235          */
12236         indicatorText : '<div class="loading-indicator">Loading...</div>'
12237    };
12238
12239 /**
12240  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12241  *Usage:
12242  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12243  * @param {String/HTMLElement/Roo.Element} el The element to update
12244  * @param {String} url The url
12245  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12246  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12247  * @static
12248  * @deprecated
12249  * @member Roo.UpdateManager
12250  */
12251 Roo.UpdateManager.updateElement = function(el, url, params, options){
12252     var um = Roo.get(el, true).getUpdateManager();
12253     Roo.apply(um, options);
12254     um.update(url, params, options ? options.callback : null);
12255 };
12256 // alias for backwards compat
12257 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12258 /**
12259  * @class Roo.UpdateManager.BasicRenderer
12260  * Default Content renderer. Updates the elements innerHTML with the responseText.
12261  */
12262 Roo.UpdateManager.BasicRenderer = function(){};
12263
12264 Roo.UpdateManager.BasicRenderer.prototype = {
12265     /**
12266      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12267      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12268      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12269      * @param {Roo.Element} el The element being rendered
12270      * @param {Object} response The YUI Connect response object
12271      * @param {UpdateManager} updateManager The calling update manager
12272      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12273      */
12274      render : function(el, response, updateManager, callback){
12275         el.update(response.responseText, updateManager.loadScripts, callback);
12276     }
12277 };
12278 /*
12279  * Based on:
12280  * Roo JS
12281  * (c)) Alan Knowles
12282  * Licence : LGPL
12283  */
12284
12285
12286 /**
12287  * @class Roo.DomTemplate
12288  * @extends Roo.Template
12289  * An effort at a dom based template engine..
12290  *
12291  * Similar to XTemplate, except it uses dom parsing to create the template..
12292  *
12293  * Supported features:
12294  *
12295  *  Tags:
12296
12297 <pre><code>
12298       {a_variable} - output encoded.
12299       {a_variable.format:("Y-m-d")} - call a method on the variable
12300       {a_variable:raw} - unencoded output
12301       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12302       {a_variable:this.method_on_template(...)} - call a method on the template object.
12303  
12304 </code></pre>
12305  *  The tpl tag:
12306 <pre><code>
12307         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12308         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12309         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12310         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12311   
12312 </code></pre>
12313  *      
12314  */
12315 Roo.DomTemplate = function()
12316 {
12317      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12318      if (this.html) {
12319         this.compile();
12320      }
12321 };
12322
12323
12324 Roo.extend(Roo.DomTemplate, Roo.Template, {
12325     /**
12326      * id counter for sub templates.
12327      */
12328     id : 0,
12329     /**
12330      * flag to indicate if dom parser is inside a pre,
12331      * it will strip whitespace if not.
12332      */
12333     inPre : false,
12334     
12335     /**
12336      * The various sub templates
12337      */
12338     tpls : false,
12339     
12340     
12341     
12342     /**
12343      *
12344      * basic tag replacing syntax
12345      * WORD:WORD()
12346      *
12347      * // you can fake an object call by doing this
12348      *  x.t:(test,tesT) 
12349      * 
12350      */
12351     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12352     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12353     
12354     iterChild : function (node, method) {
12355         
12356         var oldPre = this.inPre;
12357         if (node.tagName == 'PRE') {
12358             this.inPre = true;
12359         }
12360         for( var i = 0; i < node.childNodes.length; i++) {
12361             method.call(this, node.childNodes[i]);
12362         }
12363         this.inPre = oldPre;
12364     },
12365     
12366     
12367     
12368     /**
12369      * compile the template
12370      *
12371      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12372      *
12373      */
12374     compile: function()
12375     {
12376         var s = this.html;
12377         
12378         // covert the html into DOM...
12379         var doc = false;
12380         var div =false;
12381         try {
12382             doc = document.implementation.createHTMLDocument("");
12383             doc.documentElement.innerHTML =   this.html  ;
12384             div = doc.documentElement;
12385         } catch (e) {
12386             // old IE... - nasty -- it causes all sorts of issues.. with
12387             // images getting pulled from server..
12388             div = document.createElement('div');
12389             div.innerHTML = this.html;
12390         }
12391         //doc.documentElement.innerHTML = htmlBody
12392          
12393         
12394         
12395         this.tpls = [];
12396         var _t = this;
12397         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12398         
12399         var tpls = this.tpls;
12400         
12401         // create a top level template from the snippet..
12402         
12403         //Roo.log(div.innerHTML);
12404         
12405         var tpl = {
12406             uid : 'master',
12407             id : this.id++,
12408             attr : false,
12409             value : false,
12410             body : div.innerHTML,
12411             
12412             forCall : false,
12413             execCall : false,
12414             dom : div,
12415             isTop : true
12416             
12417         };
12418         tpls.unshift(tpl);
12419         
12420         
12421         // compile them...
12422         this.tpls = [];
12423         Roo.each(tpls, function(tp){
12424             this.compileTpl(tp);
12425             this.tpls[tp.id] = tp;
12426         }, this);
12427         
12428         this.master = tpls[0];
12429         return this;
12430         
12431         
12432     },
12433     
12434     compileNode : function(node, istop) {
12435         // test for
12436         //Roo.log(node);
12437         
12438         
12439         // skip anything not a tag..
12440         if (node.nodeType != 1) {
12441             if (node.nodeType == 3 && !this.inPre) {
12442                 // reduce white space..
12443                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12444                 
12445             }
12446             return;
12447         }
12448         
12449         var tpl = {
12450             uid : false,
12451             id : false,
12452             attr : false,
12453             value : false,
12454             body : '',
12455             
12456             forCall : false,
12457             execCall : false,
12458             dom : false,
12459             isTop : istop
12460             
12461             
12462         };
12463         
12464         
12465         switch(true) {
12466             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12467             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12468             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12469             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12470             // no default..
12471         }
12472         
12473         
12474         if (!tpl.attr) {
12475             // just itterate children..
12476             this.iterChild(node,this.compileNode);
12477             return;
12478         }
12479         tpl.uid = this.id++;
12480         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12481         node.removeAttribute('roo-'+ tpl.attr);
12482         if (tpl.attr != 'name') {
12483             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12484             node.parentNode.replaceChild(placeholder,  node);
12485         } else {
12486             
12487             var placeholder =  document.createElement('span');
12488             placeholder.className = 'roo-tpl-' + tpl.value;
12489             node.parentNode.replaceChild(placeholder,  node);
12490         }
12491         
12492         // parent now sees '{domtplXXXX}
12493         this.iterChild(node,this.compileNode);
12494         
12495         // we should now have node body...
12496         var div = document.createElement('div');
12497         div.appendChild(node);
12498         tpl.dom = node;
12499         // this has the unfortunate side effect of converting tagged attributes
12500         // eg. href="{...}" into %7C...%7D
12501         // this has been fixed by searching for those combo's although it's a bit hacky..
12502         
12503         
12504         tpl.body = div.innerHTML;
12505         
12506         
12507          
12508         tpl.id = tpl.uid;
12509         switch(tpl.attr) {
12510             case 'for' :
12511                 switch (tpl.value) {
12512                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12513                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12514                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12515                 }
12516                 break;
12517             
12518             case 'exec':
12519                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12520                 break;
12521             
12522             case 'if':     
12523                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12524                 break;
12525             
12526             case 'name':
12527                 tpl.id  = tpl.value; // replace non characters???
12528                 break;
12529             
12530         }
12531         
12532         
12533         this.tpls.push(tpl);
12534         
12535         
12536         
12537     },
12538     
12539     
12540     
12541     
12542     /**
12543      * Compile a segment of the template into a 'sub-template'
12544      *
12545      * 
12546      * 
12547      *
12548      */
12549     compileTpl : function(tpl)
12550     {
12551         var fm = Roo.util.Format;
12552         var useF = this.disableFormats !== true;
12553         
12554         var sep = Roo.isGecko ? "+\n" : ",\n";
12555         
12556         var undef = function(str) {
12557             Roo.debug && Roo.log("Property not found :"  + str);
12558             return '';
12559         };
12560           
12561         //Roo.log(tpl.body);
12562         
12563         
12564         
12565         var fn = function(m, lbrace, name, format, args)
12566         {
12567             //Roo.log("ARGS");
12568             //Roo.log(arguments);
12569             args = args ? args.replace(/\\'/g,"'") : args;
12570             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12571             if (typeof(format) == 'undefined') {
12572                 format =  'htmlEncode'; 
12573             }
12574             if (format == 'raw' ) {
12575                 format = false;
12576             }
12577             
12578             if(name.substr(0, 6) == 'domtpl'){
12579                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12580             }
12581             
12582             // build an array of options to determine if value is undefined..
12583             
12584             // basically get 'xxxx.yyyy' then do
12585             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12586             //    (function () { Roo.log("Property not found"); return ''; })() :
12587             //    ......
12588             
12589             var udef_ar = [];
12590             var lookfor = '';
12591             Roo.each(name.split('.'), function(st) {
12592                 lookfor += (lookfor.length ? '.': '') + st;
12593                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12594             });
12595             
12596             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12597             
12598             
12599             if(format && useF){
12600                 
12601                 args = args ? ',' + args : "";
12602                  
12603                 if(format.substr(0, 5) != "this."){
12604                     format = "fm." + format + '(';
12605                 }else{
12606                     format = 'this.call("'+ format.substr(5) + '", ';
12607                     args = ", values";
12608                 }
12609                 
12610                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12611             }
12612              
12613             if (args && args.length) {
12614                 // called with xxyx.yuu:(test,test)
12615                 // change to ()
12616                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12617             }
12618             // raw.. - :raw modifier..
12619             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12620             
12621         };
12622         var body;
12623         // branched to use + in gecko and [].join() in others
12624         if(Roo.isGecko){
12625             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12626                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12627                     "';};};";
12628         }else{
12629             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12630             body.push(tpl.body.replace(/(\r\n|\n)/g,
12631                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12632             body.push("'].join('');};};");
12633             body = body.join('');
12634         }
12635         
12636         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12637        
12638         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12639         eval(body);
12640         
12641         return this;
12642     },
12643      
12644     /**
12645      * same as applyTemplate, except it's done to one of the subTemplates
12646      * when using named templates, you can do:
12647      *
12648      * var str = pl.applySubTemplate('your-name', values);
12649      *
12650      * 
12651      * @param {Number} id of the template
12652      * @param {Object} values to apply to template
12653      * @param {Object} parent (normaly the instance of this object)
12654      */
12655     applySubTemplate : function(id, values, parent)
12656     {
12657         
12658         
12659         var t = this.tpls[id];
12660         
12661         
12662         try { 
12663             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12664                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12665                 return '';
12666             }
12667         } catch(e) {
12668             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12669             Roo.log(values);
12670           
12671             return '';
12672         }
12673         try { 
12674             
12675             if(t.execCall && t.execCall.call(this, values, parent)){
12676                 return '';
12677             }
12678         } catch(e) {
12679             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12680             Roo.log(values);
12681             return '';
12682         }
12683         
12684         try {
12685             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12686             parent = t.target ? values : parent;
12687             if(t.forCall && vs instanceof Array){
12688                 var buf = [];
12689                 for(var i = 0, len = vs.length; i < len; i++){
12690                     try {
12691                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12692                     } catch (e) {
12693                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12694                         Roo.log(e.body);
12695                         //Roo.log(t.compiled);
12696                         Roo.log(vs[i]);
12697                     }   
12698                 }
12699                 return buf.join('');
12700             }
12701         } catch (e) {
12702             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12703             Roo.log(values);
12704             return '';
12705         }
12706         try {
12707             return t.compiled.call(this, vs, parent);
12708         } catch (e) {
12709             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12710             Roo.log(e.body);
12711             //Roo.log(t.compiled);
12712             Roo.log(values);
12713             return '';
12714         }
12715     },
12716
12717    
12718
12719     applyTemplate : function(values){
12720         return this.master.compiled.call(this, values, {});
12721         //var s = this.subs;
12722     },
12723
12724     apply : function(){
12725         return this.applyTemplate.apply(this, arguments);
12726     }
12727
12728  });
12729
12730 Roo.DomTemplate.from = function(el){
12731     el = Roo.getDom(el);
12732     return new Roo.Domtemplate(el.value || el.innerHTML);
12733 };/*
12734  * Based on:
12735  * Ext JS Library 1.1.1
12736  * Copyright(c) 2006-2007, Ext JS, LLC.
12737  *
12738  * Originally Released Under LGPL - original licence link has changed is not relivant.
12739  *
12740  * Fork - LGPL
12741  * <script type="text/javascript">
12742  */
12743
12744 /**
12745  * @class Roo.util.DelayedTask
12746  * Provides a convenient method of performing setTimeout where a new
12747  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12748  * You can use this class to buffer
12749  * the keypress events for a certain number of milliseconds, and perform only if they stop
12750  * for that amount of time.
12751  * @constructor The parameters to this constructor serve as defaults and are not required.
12752  * @param {Function} fn (optional) The default function to timeout
12753  * @param {Object} scope (optional) The default scope of that timeout
12754  * @param {Array} args (optional) The default Array of arguments
12755  */
12756 Roo.util.DelayedTask = function(fn, scope, args){
12757     var id = null, d, t;
12758
12759     var call = function(){
12760         var now = new Date().getTime();
12761         if(now - t >= d){
12762             clearInterval(id);
12763             id = null;
12764             fn.apply(scope, args || []);
12765         }
12766     };
12767     /**
12768      * Cancels any pending timeout and queues a new one
12769      * @param {Number} delay The milliseconds to delay
12770      * @param {Function} newFn (optional) Overrides function passed to constructor
12771      * @param {Object} newScope (optional) Overrides scope passed to constructor
12772      * @param {Array} newArgs (optional) Overrides args passed to constructor
12773      */
12774     this.delay = function(delay, newFn, newScope, newArgs){
12775         if(id && delay != d){
12776             this.cancel();
12777         }
12778         d = delay;
12779         t = new Date().getTime();
12780         fn = newFn || fn;
12781         scope = newScope || scope;
12782         args = newArgs || args;
12783         if(!id){
12784             id = setInterval(call, d);
12785         }
12786     };
12787
12788     /**
12789      * Cancel the last queued timeout
12790      */
12791     this.cancel = function(){
12792         if(id){
12793             clearInterval(id);
12794             id = null;
12795         }
12796     };
12797 };/*
12798  * Based on:
12799  * Ext JS Library 1.1.1
12800  * Copyright(c) 2006-2007, Ext JS, LLC.
12801  *
12802  * Originally Released Under LGPL - original licence link has changed is not relivant.
12803  *
12804  * Fork - LGPL
12805  * <script type="text/javascript">
12806  */
12807  
12808  
12809 Roo.util.TaskRunner = function(interval){
12810     interval = interval || 10;
12811     var tasks = [], removeQueue = [];
12812     var id = 0;
12813     var running = false;
12814
12815     var stopThread = function(){
12816         running = false;
12817         clearInterval(id);
12818         id = 0;
12819     };
12820
12821     var startThread = function(){
12822         if(!running){
12823             running = true;
12824             id = setInterval(runTasks, interval);
12825         }
12826     };
12827
12828     var removeTask = function(task){
12829         removeQueue.push(task);
12830         if(task.onStop){
12831             task.onStop();
12832         }
12833     };
12834
12835     var runTasks = function(){
12836         if(removeQueue.length > 0){
12837             for(var i = 0, len = removeQueue.length; i < len; i++){
12838                 tasks.remove(removeQueue[i]);
12839             }
12840             removeQueue = [];
12841             if(tasks.length < 1){
12842                 stopThread();
12843                 return;
12844             }
12845         }
12846         var now = new Date().getTime();
12847         for(var i = 0, len = tasks.length; i < len; ++i){
12848             var t = tasks[i];
12849             var itime = now - t.taskRunTime;
12850             if(t.interval <= itime){
12851                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12852                 t.taskRunTime = now;
12853                 if(rt === false || t.taskRunCount === t.repeat){
12854                     removeTask(t);
12855                     return;
12856                 }
12857             }
12858             if(t.duration && t.duration <= (now - t.taskStartTime)){
12859                 removeTask(t);
12860             }
12861         }
12862     };
12863
12864     /**
12865      * Queues a new task.
12866      * @param {Object} task
12867      */
12868     this.start = function(task){
12869         tasks.push(task);
12870         task.taskStartTime = new Date().getTime();
12871         task.taskRunTime = 0;
12872         task.taskRunCount = 0;
12873         startThread();
12874         return task;
12875     };
12876
12877     this.stop = function(task){
12878         removeTask(task);
12879         return task;
12880     };
12881
12882     this.stopAll = function(){
12883         stopThread();
12884         for(var i = 0, len = tasks.length; i < len; i++){
12885             if(tasks[i].onStop){
12886                 tasks[i].onStop();
12887             }
12888         }
12889         tasks = [];
12890         removeQueue = [];
12891     };
12892 };
12893
12894 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12895  * Based on:
12896  * Ext JS Library 1.1.1
12897  * Copyright(c) 2006-2007, Ext JS, LLC.
12898  *
12899  * Originally Released Under LGPL - original licence link has changed is not relivant.
12900  *
12901  * Fork - LGPL
12902  * <script type="text/javascript">
12903  */
12904
12905  
12906 /**
12907  * @class Roo.util.MixedCollection
12908  * @extends Roo.util.Observable
12909  * A Collection class that maintains both numeric indexes and keys and exposes events.
12910  * @constructor
12911  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12912  * collection (defaults to false)
12913  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12914  * and return the key value for that item.  This is used when available to look up the key on items that
12915  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12916  * equivalent to providing an implementation for the {@link #getKey} method.
12917  */
12918 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12919     this.items = [];
12920     this.map = {};
12921     this.keys = [];
12922     this.length = 0;
12923     this.addEvents({
12924         /**
12925          * @event clear
12926          * Fires when the collection is cleared.
12927          */
12928         "clear" : true,
12929         /**
12930          * @event add
12931          * Fires when an item is added to the collection.
12932          * @param {Number} index The index at which the item was added.
12933          * @param {Object} o The item added.
12934          * @param {String} key The key associated with the added item.
12935          */
12936         "add" : true,
12937         /**
12938          * @event replace
12939          * Fires when an item is replaced in the collection.
12940          * @param {String} key he key associated with the new added.
12941          * @param {Object} old The item being replaced.
12942          * @param {Object} new The new item.
12943          */
12944         "replace" : true,
12945         /**
12946          * @event remove
12947          * Fires when an item is removed from the collection.
12948          * @param {Object} o The item being removed.
12949          * @param {String} key (optional) The key associated with the removed item.
12950          */
12951         "remove" : true,
12952         "sort" : true
12953     });
12954     this.allowFunctions = allowFunctions === true;
12955     if(keyFn){
12956         this.getKey = keyFn;
12957     }
12958     Roo.util.MixedCollection.superclass.constructor.call(this);
12959 };
12960
12961 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12962     allowFunctions : false,
12963     
12964 /**
12965  * Adds an item to the collection.
12966  * @param {String} key The key to associate with the item
12967  * @param {Object} o The item to add.
12968  * @return {Object} The item added.
12969  */
12970     add : function(key, o){
12971         if(arguments.length == 1){
12972             o = arguments[0];
12973             key = this.getKey(o);
12974         }
12975         if(typeof key == "undefined" || key === null){
12976             this.length++;
12977             this.items.push(o);
12978             this.keys.push(null);
12979         }else{
12980             var old = this.map[key];
12981             if(old){
12982                 return this.replace(key, o);
12983             }
12984             this.length++;
12985             this.items.push(o);
12986             this.map[key] = o;
12987             this.keys.push(key);
12988         }
12989         this.fireEvent("add", this.length-1, o, key);
12990         return o;
12991     },
12992        
12993 /**
12994   * MixedCollection has a generic way to fetch keys if you implement getKey.
12995 <pre><code>
12996 // normal way
12997 var mc = new Roo.util.MixedCollection();
12998 mc.add(someEl.dom.id, someEl);
12999 mc.add(otherEl.dom.id, otherEl);
13000 //and so on
13001
13002 // using getKey
13003 var mc = new Roo.util.MixedCollection();
13004 mc.getKey = function(el){
13005    return el.dom.id;
13006 };
13007 mc.add(someEl);
13008 mc.add(otherEl);
13009
13010 // or via the constructor
13011 var mc = new Roo.util.MixedCollection(false, function(el){
13012    return el.dom.id;
13013 });
13014 mc.add(someEl);
13015 mc.add(otherEl);
13016 </code></pre>
13017  * @param o {Object} The item for which to find the key.
13018  * @return {Object} The key for the passed item.
13019  */
13020     getKey : function(o){
13021          return o.id; 
13022     },
13023    
13024 /**
13025  * Replaces an item in the collection.
13026  * @param {String} key The key associated with the item to replace, or the item to replace.
13027  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13028  * @return {Object}  The new item.
13029  */
13030     replace : function(key, o){
13031         if(arguments.length == 1){
13032             o = arguments[0];
13033             key = this.getKey(o);
13034         }
13035         var old = this.item(key);
13036         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13037              return this.add(key, o);
13038         }
13039         var index = this.indexOfKey(key);
13040         this.items[index] = o;
13041         this.map[key] = o;
13042         this.fireEvent("replace", key, old, o);
13043         return o;
13044     },
13045    
13046 /**
13047  * Adds all elements of an Array or an Object to the collection.
13048  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13049  * an Array of values, each of which are added to the collection.
13050  */
13051     addAll : function(objs){
13052         if(arguments.length > 1 || objs instanceof Array){
13053             var args = arguments.length > 1 ? arguments : objs;
13054             for(var i = 0, len = args.length; i < len; i++){
13055                 this.add(args[i]);
13056             }
13057         }else{
13058             for(var key in objs){
13059                 if(this.allowFunctions || typeof objs[key] != "function"){
13060                     this.add(key, objs[key]);
13061                 }
13062             }
13063         }
13064     },
13065    
13066 /**
13067  * Executes the specified function once for every item in the collection, passing each
13068  * item as the first and only parameter. returning false from the function will stop the iteration.
13069  * @param {Function} fn The function to execute for each item.
13070  * @param {Object} scope (optional) The scope in which to execute the function.
13071  */
13072     each : function(fn, scope){
13073         var items = [].concat(this.items); // each safe for removal
13074         for(var i = 0, len = items.length; i < len; i++){
13075             if(fn.call(scope || items[i], items[i], i, len) === false){
13076                 break;
13077             }
13078         }
13079     },
13080    
13081 /**
13082  * Executes the specified function once for every key in the collection, passing each
13083  * key, and its associated item as the first two parameters.
13084  * @param {Function} fn The function to execute for each item.
13085  * @param {Object} scope (optional) The scope in which to execute the function.
13086  */
13087     eachKey : function(fn, scope){
13088         for(var i = 0, len = this.keys.length; i < len; i++){
13089             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13090         }
13091     },
13092    
13093 /**
13094  * Returns the first item in the collection which elicits a true return value from the
13095  * passed selection function.
13096  * @param {Function} fn The selection function to execute for each item.
13097  * @param {Object} scope (optional) The scope in which to execute the function.
13098  * @return {Object} The first item in the collection which returned true from the selection function.
13099  */
13100     find : function(fn, scope){
13101         for(var i = 0, len = this.items.length; i < len; i++){
13102             if(fn.call(scope || window, this.items[i], this.keys[i])){
13103                 return this.items[i];
13104             }
13105         }
13106         return null;
13107     },
13108    
13109 /**
13110  * Inserts an item at the specified index in the collection.
13111  * @param {Number} index The index to insert the item at.
13112  * @param {String} key The key to associate with the new item, or the item itself.
13113  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13114  * @return {Object} The item inserted.
13115  */
13116     insert : function(index, key, o){
13117         if(arguments.length == 2){
13118             o = arguments[1];
13119             key = this.getKey(o);
13120         }
13121         if(index >= this.length){
13122             return this.add(key, o);
13123         }
13124         this.length++;
13125         this.items.splice(index, 0, o);
13126         if(typeof key != "undefined" && key != null){
13127             this.map[key] = o;
13128         }
13129         this.keys.splice(index, 0, key);
13130         this.fireEvent("add", index, o, key);
13131         return o;
13132     },
13133    
13134 /**
13135  * Removed an item from the collection.
13136  * @param {Object} o The item to remove.
13137  * @return {Object} The item removed.
13138  */
13139     remove : function(o){
13140         return this.removeAt(this.indexOf(o));
13141     },
13142    
13143 /**
13144  * Remove an item from a specified index in the collection.
13145  * @param {Number} index The index within the collection of the item to remove.
13146  */
13147     removeAt : function(index){
13148         if(index < this.length && index >= 0){
13149             this.length--;
13150             var o = this.items[index];
13151             this.items.splice(index, 1);
13152             var key = this.keys[index];
13153             if(typeof key != "undefined"){
13154                 delete this.map[key];
13155             }
13156             this.keys.splice(index, 1);
13157             this.fireEvent("remove", o, key);
13158         }
13159     },
13160    
13161 /**
13162  * Removed an item associated with the passed key fom the collection.
13163  * @param {String} key The key of the item to remove.
13164  */
13165     removeKey : function(key){
13166         return this.removeAt(this.indexOfKey(key));
13167     },
13168    
13169 /**
13170  * Returns the number of items in the collection.
13171  * @return {Number} the number of items in the collection.
13172  */
13173     getCount : function(){
13174         return this.length; 
13175     },
13176    
13177 /**
13178  * Returns index within the collection of the passed Object.
13179  * @param {Object} o The item to find the index of.
13180  * @return {Number} index of the item.
13181  */
13182     indexOf : function(o){
13183         if(!this.items.indexOf){
13184             for(var i = 0, len = this.items.length; i < len; i++){
13185                 if(this.items[i] == o) {
13186                     return i;
13187                 }
13188             }
13189             return -1;
13190         }else{
13191             return this.items.indexOf(o);
13192         }
13193     },
13194    
13195 /**
13196  * Returns index within the collection of the passed key.
13197  * @param {String} key The key to find the index of.
13198  * @return {Number} index of the key.
13199  */
13200     indexOfKey : function(key){
13201         if(!this.keys.indexOf){
13202             for(var i = 0, len = this.keys.length; i < len; i++){
13203                 if(this.keys[i] == key) {
13204                     return i;
13205                 }
13206             }
13207             return -1;
13208         }else{
13209             return this.keys.indexOf(key);
13210         }
13211     },
13212    
13213 /**
13214  * Returns the item associated with the passed key OR index. Key has priority over index.
13215  * @param {String/Number} key The key or index of the item.
13216  * @return {Object} The item associated with the passed key.
13217  */
13218     item : function(key){
13219         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13220         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13221     },
13222     
13223 /**
13224  * Returns the item at the specified index.
13225  * @param {Number} index The index of the item.
13226  * @return {Object}
13227  */
13228     itemAt : function(index){
13229         return this.items[index];
13230     },
13231     
13232 /**
13233  * Returns the item associated with the passed key.
13234  * @param {String/Number} key The key of the item.
13235  * @return {Object} The item associated with the passed key.
13236  */
13237     key : function(key){
13238         return this.map[key];
13239     },
13240    
13241 /**
13242  * Returns true if the collection contains the passed Object as an item.
13243  * @param {Object} o  The Object to look for in the collection.
13244  * @return {Boolean} True if the collection contains the Object as an item.
13245  */
13246     contains : function(o){
13247         return this.indexOf(o) != -1;
13248     },
13249    
13250 /**
13251  * Returns true if the collection contains the passed Object as a key.
13252  * @param {String} key The key to look for in the collection.
13253  * @return {Boolean} True if the collection contains the Object as a key.
13254  */
13255     containsKey : function(key){
13256         return typeof this.map[key] != "undefined";
13257     },
13258    
13259 /**
13260  * Removes all items from the collection.
13261  */
13262     clear : function(){
13263         this.length = 0;
13264         this.items = [];
13265         this.keys = [];
13266         this.map = {};
13267         this.fireEvent("clear");
13268     },
13269    
13270 /**
13271  * Returns the first item in the collection.
13272  * @return {Object} the first item in the collection..
13273  */
13274     first : function(){
13275         return this.items[0]; 
13276     },
13277    
13278 /**
13279  * Returns the last item in the collection.
13280  * @return {Object} the last item in the collection..
13281  */
13282     last : function(){
13283         return this.items[this.length-1];   
13284     },
13285     
13286     _sort : function(property, dir, fn){
13287         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13288         fn = fn || function(a, b){
13289             return a-b;
13290         };
13291         var c = [], k = this.keys, items = this.items;
13292         for(var i = 0, len = items.length; i < len; i++){
13293             c[c.length] = {key: k[i], value: items[i], index: i};
13294         }
13295         c.sort(function(a, b){
13296             var v = fn(a[property], b[property]) * dsc;
13297             if(v == 0){
13298                 v = (a.index < b.index ? -1 : 1);
13299             }
13300             return v;
13301         });
13302         for(var i = 0, len = c.length; i < len; i++){
13303             items[i] = c[i].value;
13304             k[i] = c[i].key;
13305         }
13306         this.fireEvent("sort", this);
13307     },
13308     
13309     /**
13310      * Sorts this collection with the passed comparison function
13311      * @param {String} direction (optional) "ASC" or "DESC"
13312      * @param {Function} fn (optional) comparison function
13313      */
13314     sort : function(dir, fn){
13315         this._sort("value", dir, fn);
13316     },
13317     
13318     /**
13319      * Sorts this collection by keys
13320      * @param {String} direction (optional) "ASC" or "DESC"
13321      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13322      */
13323     keySort : function(dir, fn){
13324         this._sort("key", dir, fn || function(a, b){
13325             return String(a).toUpperCase()-String(b).toUpperCase();
13326         });
13327     },
13328     
13329     /**
13330      * Returns a range of items in this collection
13331      * @param {Number} startIndex (optional) defaults to 0
13332      * @param {Number} endIndex (optional) default to the last item
13333      * @return {Array} An array of items
13334      */
13335     getRange : function(start, end){
13336         var items = this.items;
13337         if(items.length < 1){
13338             return [];
13339         }
13340         start = start || 0;
13341         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13342         var r = [];
13343         if(start <= end){
13344             for(var i = start; i <= end; i++) {
13345                     r[r.length] = items[i];
13346             }
13347         }else{
13348             for(var i = start; i >= end; i--) {
13349                     r[r.length] = items[i];
13350             }
13351         }
13352         return r;
13353     },
13354         
13355     /**
13356      * Filter the <i>objects</i> in this collection by a specific property. 
13357      * Returns a new collection that has been filtered.
13358      * @param {String} property A property on your objects
13359      * @param {String/RegExp} value Either string that the property values 
13360      * should start with or a RegExp to test against the property
13361      * @return {MixedCollection} The new filtered collection
13362      */
13363     filter : function(property, value){
13364         if(!value.exec){ // not a regex
13365             value = String(value);
13366             if(value.length == 0){
13367                 return this.clone();
13368             }
13369             value = new RegExp("^" + Roo.escapeRe(value), "i");
13370         }
13371         return this.filterBy(function(o){
13372             return o && value.test(o[property]);
13373         });
13374         },
13375     
13376     /**
13377      * Filter by a function. * Returns a new collection that has been filtered.
13378      * The passed function will be called with each 
13379      * object in the collection. If the function returns true, the value is included 
13380      * otherwise it is filtered.
13381      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13382      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13383      * @return {MixedCollection} The new filtered collection
13384      */
13385     filterBy : function(fn, scope){
13386         var r = new Roo.util.MixedCollection();
13387         r.getKey = this.getKey;
13388         var k = this.keys, it = this.items;
13389         for(var i = 0, len = it.length; i < len; i++){
13390             if(fn.call(scope||this, it[i], k[i])){
13391                                 r.add(k[i], it[i]);
13392                         }
13393         }
13394         return r;
13395     },
13396     
13397     /**
13398      * Creates a duplicate of this collection
13399      * @return {MixedCollection}
13400      */
13401     clone : function(){
13402         var r = new Roo.util.MixedCollection();
13403         var k = this.keys, it = this.items;
13404         for(var i = 0, len = it.length; i < len; i++){
13405             r.add(k[i], it[i]);
13406         }
13407         r.getKey = this.getKey;
13408         return r;
13409     }
13410 });
13411 /**
13412  * Returns the item associated with the passed key or index.
13413  * @method
13414  * @param {String/Number} key The key or index of the item.
13415  * @return {Object} The item associated with the passed key.
13416  */
13417 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13418  * Based on:
13419  * Ext JS Library 1.1.1
13420  * Copyright(c) 2006-2007, Ext JS, LLC.
13421  *
13422  * Originally Released Under LGPL - original licence link has changed is not relivant.
13423  *
13424  * Fork - LGPL
13425  * <script type="text/javascript">
13426  */
13427 /**
13428  * @class Roo.util.JSON
13429  * Modified version of Douglas Crockford"s json.js that doesn"t
13430  * mess with the Object prototype 
13431  * http://www.json.org/js.html
13432  * @singleton
13433  */
13434 Roo.util.JSON = new (function(){
13435     var useHasOwn = {}.hasOwnProperty ? true : false;
13436     
13437     // crashes Safari in some instances
13438     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13439     
13440     var pad = function(n) {
13441         return n < 10 ? "0" + n : n;
13442     };
13443     
13444     var m = {
13445         "\b": '\\b',
13446         "\t": '\\t',
13447         "\n": '\\n',
13448         "\f": '\\f',
13449         "\r": '\\r',
13450         '"' : '\\"',
13451         "\\": '\\\\'
13452     };
13453
13454     var encodeString = function(s){
13455         if (/["\\\x00-\x1f]/.test(s)) {
13456             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13457                 var c = m[b];
13458                 if(c){
13459                     return c;
13460                 }
13461                 c = b.charCodeAt();
13462                 return "\\u00" +
13463                     Math.floor(c / 16).toString(16) +
13464                     (c % 16).toString(16);
13465             }) + '"';
13466         }
13467         return '"' + s + '"';
13468     };
13469     
13470     var encodeArray = function(o){
13471         var a = ["["], b, i, l = o.length, v;
13472             for (i = 0; i < l; i += 1) {
13473                 v = o[i];
13474                 switch (typeof v) {
13475                     case "undefined":
13476                     case "function":
13477                     case "unknown":
13478                         break;
13479                     default:
13480                         if (b) {
13481                             a.push(',');
13482                         }
13483                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13484                         b = true;
13485                 }
13486             }
13487             a.push("]");
13488             return a.join("");
13489     };
13490     
13491     var encodeDate = function(o){
13492         return '"' + o.getFullYear() + "-" +
13493                 pad(o.getMonth() + 1) + "-" +
13494                 pad(o.getDate()) + "T" +
13495                 pad(o.getHours()) + ":" +
13496                 pad(o.getMinutes()) + ":" +
13497                 pad(o.getSeconds()) + '"';
13498     };
13499     
13500     /**
13501      * Encodes an Object, Array or other value
13502      * @param {Mixed} o The variable to encode
13503      * @return {String} The JSON string
13504      */
13505     this.encode = function(o)
13506     {
13507         // should this be extended to fully wrap stringify..
13508         
13509         if(typeof o == "undefined" || o === null){
13510             return "null";
13511         }else if(o instanceof Array){
13512             return encodeArray(o);
13513         }else if(o instanceof Date){
13514             return encodeDate(o);
13515         }else if(typeof o == "string"){
13516             return encodeString(o);
13517         }else if(typeof o == "number"){
13518             return isFinite(o) ? String(o) : "null";
13519         }else if(typeof o == "boolean"){
13520             return String(o);
13521         }else {
13522             var a = ["{"], b, i, v;
13523             for (i in o) {
13524                 if(!useHasOwn || o.hasOwnProperty(i)) {
13525                     v = o[i];
13526                     switch (typeof v) {
13527                     case "undefined":
13528                     case "function":
13529                     case "unknown":
13530                         break;
13531                     default:
13532                         if(b){
13533                             a.push(',');
13534                         }
13535                         a.push(this.encode(i), ":",
13536                                 v === null ? "null" : this.encode(v));
13537                         b = true;
13538                     }
13539                 }
13540             }
13541             a.push("}");
13542             return a.join("");
13543         }
13544     };
13545     
13546     /**
13547      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13548      * @param {String} json The JSON string
13549      * @return {Object} The resulting object
13550      */
13551     this.decode = function(json){
13552         
13553         return  /** eval:var:json */ eval("(" + json + ')');
13554     };
13555 })();
13556 /** 
13557  * Shorthand for {@link Roo.util.JSON#encode}
13558  * @member Roo encode 
13559  * @method */
13560 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13561 /** 
13562  * Shorthand for {@link Roo.util.JSON#decode}
13563  * @member Roo decode 
13564  * @method */
13565 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13566 /*
13567  * Based on:
13568  * Ext JS Library 1.1.1
13569  * Copyright(c) 2006-2007, Ext JS, LLC.
13570  *
13571  * Originally Released Under LGPL - original licence link has changed is not relivant.
13572  *
13573  * Fork - LGPL
13574  * <script type="text/javascript">
13575  */
13576  
13577 /**
13578  * @class Roo.util.Format
13579  * Reusable data formatting functions
13580  * @singleton
13581  */
13582 Roo.util.Format = function(){
13583     var trimRe = /^\s+|\s+$/g;
13584     return {
13585         /**
13586          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13587          * @param {String} value The string to truncate
13588          * @param {Number} length The maximum length to allow before truncating
13589          * @return {String} The converted text
13590          */
13591         ellipsis : function(value, len){
13592             if(value && value.length > len){
13593                 return value.substr(0, len-3)+"...";
13594             }
13595             return value;
13596         },
13597
13598         /**
13599          * Checks a reference and converts it to empty string if it is undefined
13600          * @param {Mixed} value Reference to check
13601          * @return {Mixed} Empty string if converted, otherwise the original value
13602          */
13603         undef : function(value){
13604             return typeof value != "undefined" ? value : "";
13605         },
13606
13607         /**
13608          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13609          * @param {String} value The string to encode
13610          * @return {String} The encoded text
13611          */
13612         htmlEncode : function(value){
13613             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13614         },
13615
13616         /**
13617          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13618          * @param {String} value The string to decode
13619          * @return {String} The decoded text
13620          */
13621         htmlDecode : function(value){
13622             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13623         },
13624
13625         /**
13626          * Trims any whitespace from either side of a string
13627          * @param {String} value The text to trim
13628          * @return {String} The trimmed text
13629          */
13630         trim : function(value){
13631             return String(value).replace(trimRe, "");
13632         },
13633
13634         /**
13635          * Returns a substring from within an original string
13636          * @param {String} value The original text
13637          * @param {Number} start The start index of the substring
13638          * @param {Number} length The length of the substring
13639          * @return {String} The substring
13640          */
13641         substr : function(value, start, length){
13642             return String(value).substr(start, length);
13643         },
13644
13645         /**
13646          * Converts a string to all lower case letters
13647          * @param {String} value The text to convert
13648          * @return {String} The converted text
13649          */
13650         lowercase : function(value){
13651             return String(value).toLowerCase();
13652         },
13653
13654         /**
13655          * Converts a string to all upper case letters
13656          * @param {String} value The text to convert
13657          * @return {String} The converted text
13658          */
13659         uppercase : function(value){
13660             return String(value).toUpperCase();
13661         },
13662
13663         /**
13664          * Converts the first character only of a string to upper case
13665          * @param {String} value The text to convert
13666          * @return {String} The converted text
13667          */
13668         capitalize : function(value){
13669             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13670         },
13671
13672         // private
13673         call : function(value, fn){
13674             if(arguments.length > 2){
13675                 var args = Array.prototype.slice.call(arguments, 2);
13676                 args.unshift(value);
13677                  
13678                 return /** eval:var:value */  eval(fn).apply(window, args);
13679             }else{
13680                 /** eval:var:value */
13681                 return /** eval:var:value */ eval(fn).call(window, value);
13682             }
13683         },
13684
13685        
13686         /**
13687          * safer version of Math.toFixed..??/
13688          * @param {Number/String} value The numeric value to format
13689          * @param {Number/String} value Decimal places 
13690          * @return {String} The formatted currency string
13691          */
13692         toFixed : function(v, n)
13693         {
13694             // why not use to fixed - precision is buggered???
13695             if (!n) {
13696                 return Math.round(v-0);
13697             }
13698             var fact = Math.pow(10,n+1);
13699             v = (Math.round((v-0)*fact))/fact;
13700             var z = (''+fact).substring(2);
13701             if (v == Math.floor(v)) {
13702                 return Math.floor(v) + '.' + z;
13703             }
13704             
13705             // now just padd decimals..
13706             var ps = String(v).split('.');
13707             var fd = (ps[1] + z);
13708             var r = fd.substring(0,n); 
13709             var rm = fd.substring(n); 
13710             if (rm < 5) {
13711                 return ps[0] + '.' + r;
13712             }
13713             r*=1; // turn it into a number;
13714             r++;
13715             if (String(r).length != n) {
13716                 ps[0]*=1;
13717                 ps[0]++;
13718                 r = String(r).substring(1); // chop the end off.
13719             }
13720             
13721             return ps[0] + '.' + r;
13722              
13723         },
13724         
13725         /**
13726          * Format a number as US currency
13727          * @param {Number/String} value The numeric value to format
13728          * @return {String} The formatted currency string
13729          */
13730         usMoney : function(v){
13731             return '$' + Roo.util.Format.number(v);
13732         },
13733         
13734         /**
13735          * Format a number
13736          * eventually this should probably emulate php's number_format
13737          * @param {Number/String} value The numeric value to format
13738          * @param {Number} decimals number of decimal places
13739          * @return {String} The formatted currency string
13740          */
13741         number : function(v,decimals)
13742         {
13743             // multiply and round.
13744             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13745             var mul = Math.pow(10, decimals);
13746             var zero = String(mul).substring(1);
13747             v = (Math.round((v-0)*mul))/mul;
13748             
13749             // if it's '0' number.. then
13750             
13751             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13752             v = String(v);
13753             var ps = v.split('.');
13754             var whole = ps[0];
13755             
13756             
13757             var r = /(\d+)(\d{3})/;
13758             // add comma's
13759             while (r.test(whole)) {
13760                 whole = whole.replace(r, '$1' + ',' + '$2');
13761             }
13762             
13763             
13764             var sub = ps[1] ?
13765                     // has decimals..
13766                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13767                     // does not have decimals
13768                     (decimals ? ('.' + zero) : '');
13769             
13770             
13771             return whole + sub ;
13772         },
13773         
13774         /**
13775          * Parse a value into a formatted date using the specified format pattern.
13776          * @param {Mixed} value The value to format
13777          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13778          * @return {String} The formatted date string
13779          */
13780         date : function(v, format){
13781             if(!v){
13782                 return "";
13783             }
13784             if(!(v instanceof Date)){
13785                 v = new Date(Date.parse(v));
13786             }
13787             return v.dateFormat(format || Roo.util.Format.defaults.date);
13788         },
13789
13790         /**
13791          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13792          * @param {String} format Any valid date format string
13793          * @return {Function} The date formatting function
13794          */
13795         dateRenderer : function(format){
13796             return function(v){
13797                 return Roo.util.Format.date(v, format);  
13798             };
13799         },
13800
13801         // private
13802         stripTagsRE : /<\/?[^>]+>/gi,
13803         
13804         /**
13805          * Strips all HTML tags
13806          * @param {Mixed} value The text from which to strip tags
13807          * @return {String} The stripped text
13808          */
13809         stripTags : function(v){
13810             return !v ? v : String(v).replace(this.stripTagsRE, "");
13811         }
13812     };
13813 }();
13814 Roo.util.Format.defaults = {
13815     date : 'd/M/Y'
13816 };/*
13817  * Based on:
13818  * Ext JS Library 1.1.1
13819  * Copyright(c) 2006-2007, Ext JS, LLC.
13820  *
13821  * Originally Released Under LGPL - original licence link has changed is not relivant.
13822  *
13823  * Fork - LGPL
13824  * <script type="text/javascript">
13825  */
13826
13827
13828  
13829
13830 /**
13831  * @class Roo.MasterTemplate
13832  * @extends Roo.Template
13833  * Provides a template that can have child templates. The syntax is:
13834 <pre><code>
13835 var t = new Roo.MasterTemplate(
13836         '&lt;select name="{name}"&gt;',
13837                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13838         '&lt;/select&gt;'
13839 );
13840 t.add('options', {value: 'foo', text: 'bar'});
13841 // or you can add multiple child elements in one shot
13842 t.addAll('options', [
13843     {value: 'foo', text: 'bar'},
13844     {value: 'foo2', text: 'bar2'},
13845     {value: 'foo3', text: 'bar3'}
13846 ]);
13847 // then append, applying the master template values
13848 t.append('my-form', {name: 'my-select'});
13849 </code></pre>
13850 * A name attribute for the child template is not required if you have only one child
13851 * template or you want to refer to them by index.
13852  */
13853 Roo.MasterTemplate = function(){
13854     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13855     this.originalHtml = this.html;
13856     var st = {};
13857     var m, re = this.subTemplateRe;
13858     re.lastIndex = 0;
13859     var subIndex = 0;
13860     while(m = re.exec(this.html)){
13861         var name = m[1], content = m[2];
13862         st[subIndex] = {
13863             name: name,
13864             index: subIndex,
13865             buffer: [],
13866             tpl : new Roo.Template(content)
13867         };
13868         if(name){
13869             st[name] = st[subIndex];
13870         }
13871         st[subIndex].tpl.compile();
13872         st[subIndex].tpl.call = this.call.createDelegate(this);
13873         subIndex++;
13874     }
13875     this.subCount = subIndex;
13876     this.subs = st;
13877 };
13878 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13879     /**
13880     * The regular expression used to match sub templates
13881     * @type RegExp
13882     * @property
13883     */
13884     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13885
13886     /**
13887      * Applies the passed values to a child template.
13888      * @param {String/Number} name (optional) The name or index of the child template
13889      * @param {Array/Object} values The values to be applied to the template
13890      * @return {MasterTemplate} this
13891      */
13892      add : function(name, values){
13893         if(arguments.length == 1){
13894             values = arguments[0];
13895             name = 0;
13896         }
13897         var s = this.subs[name];
13898         s.buffer[s.buffer.length] = s.tpl.apply(values);
13899         return this;
13900     },
13901
13902     /**
13903      * Applies all the passed values to a child template.
13904      * @param {String/Number} name (optional) The name or index of the child template
13905      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13906      * @param {Boolean} reset (optional) True to reset the template first
13907      * @return {MasterTemplate} this
13908      */
13909     fill : function(name, values, reset){
13910         var a = arguments;
13911         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13912             values = a[0];
13913             name = 0;
13914             reset = a[1];
13915         }
13916         if(reset){
13917             this.reset();
13918         }
13919         for(var i = 0, len = values.length; i < len; i++){
13920             this.add(name, values[i]);
13921         }
13922         return this;
13923     },
13924
13925     /**
13926      * Resets the template for reuse
13927      * @return {MasterTemplate} this
13928      */
13929      reset : function(){
13930         var s = this.subs;
13931         for(var i = 0; i < this.subCount; i++){
13932             s[i].buffer = [];
13933         }
13934         return this;
13935     },
13936
13937     applyTemplate : function(values){
13938         var s = this.subs;
13939         var replaceIndex = -1;
13940         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13941             return s[++replaceIndex].buffer.join("");
13942         });
13943         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13944     },
13945
13946     apply : function(){
13947         return this.applyTemplate.apply(this, arguments);
13948     },
13949
13950     compile : function(){return this;}
13951 });
13952
13953 /**
13954  * Alias for fill().
13955  * @method
13956  */
13957 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13958  /**
13959  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13960  * var tpl = Roo.MasterTemplate.from('element-id');
13961  * @param {String/HTMLElement} el
13962  * @param {Object} config
13963  * @static
13964  */
13965 Roo.MasterTemplate.from = function(el, config){
13966     el = Roo.getDom(el);
13967     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13968 };/*
13969  * Based on:
13970  * Ext JS Library 1.1.1
13971  * Copyright(c) 2006-2007, Ext JS, LLC.
13972  *
13973  * Originally Released Under LGPL - original licence link has changed is not relivant.
13974  *
13975  * Fork - LGPL
13976  * <script type="text/javascript">
13977  */
13978
13979  
13980 /**
13981  * @class Roo.util.CSS
13982  * Utility class for manipulating CSS rules
13983  * @singleton
13984  */
13985 Roo.util.CSS = function(){
13986         var rules = null;
13987         var doc = document;
13988
13989     var camelRe = /(-[a-z])/gi;
13990     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13991
13992    return {
13993    /**
13994     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13995     * tag and appended to the HEAD of the document.
13996     * @param {String|Object} cssText The text containing the css rules
13997     * @param {String} id An id to add to the stylesheet for later removal
13998     * @return {StyleSheet}
13999     */
14000     createStyleSheet : function(cssText, id){
14001         var ss;
14002         var head = doc.getElementsByTagName("head")[0];
14003         var nrules = doc.createElement("style");
14004         nrules.setAttribute("type", "text/css");
14005         if(id){
14006             nrules.setAttribute("id", id);
14007         }
14008         if (typeof(cssText) != 'string') {
14009             // support object maps..
14010             // not sure if this a good idea.. 
14011             // perhaps it should be merged with the general css handling
14012             // and handle js style props.
14013             var cssTextNew = [];
14014             for(var n in cssText) {
14015                 var citems = [];
14016                 for(var k in cssText[n]) {
14017                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14018                 }
14019                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14020                 
14021             }
14022             cssText = cssTextNew.join("\n");
14023             
14024         }
14025        
14026        
14027        if(Roo.isIE){
14028            head.appendChild(nrules);
14029            ss = nrules.styleSheet;
14030            ss.cssText = cssText;
14031        }else{
14032            try{
14033                 nrules.appendChild(doc.createTextNode(cssText));
14034            }catch(e){
14035                nrules.cssText = cssText; 
14036            }
14037            head.appendChild(nrules);
14038            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14039        }
14040        this.cacheStyleSheet(ss);
14041        return ss;
14042    },
14043
14044    /**
14045     * Removes a style or link tag by id
14046     * @param {String} id The id of the tag
14047     */
14048    removeStyleSheet : function(id){
14049        var existing = doc.getElementById(id);
14050        if(existing){
14051            existing.parentNode.removeChild(existing);
14052        }
14053    },
14054
14055    /**
14056     * Dynamically swaps an existing stylesheet reference for a new one
14057     * @param {String} id The id of an existing link tag to remove
14058     * @param {String} url The href of the new stylesheet to include
14059     */
14060    swapStyleSheet : function(id, url){
14061        this.removeStyleSheet(id);
14062        var ss = doc.createElement("link");
14063        ss.setAttribute("rel", "stylesheet");
14064        ss.setAttribute("type", "text/css");
14065        ss.setAttribute("id", id);
14066        ss.setAttribute("href", url);
14067        doc.getElementsByTagName("head")[0].appendChild(ss);
14068    },
14069    
14070    /**
14071     * Refresh the rule cache if you have dynamically added stylesheets
14072     * @return {Object} An object (hash) of rules indexed by selector
14073     */
14074    refreshCache : function(){
14075        return this.getRules(true);
14076    },
14077
14078    // private
14079    cacheStyleSheet : function(stylesheet){
14080        if(!rules){
14081            rules = {};
14082        }
14083        try{// try catch for cross domain access issue
14084            var ssRules = stylesheet.cssRules || stylesheet.rules;
14085            for(var j = ssRules.length-1; j >= 0; --j){
14086                rules[ssRules[j].selectorText] = ssRules[j];
14087            }
14088        }catch(e){}
14089    },
14090    
14091    /**
14092     * Gets all css rules for the document
14093     * @param {Boolean} refreshCache true to refresh the internal cache
14094     * @return {Object} An object (hash) of rules indexed by selector
14095     */
14096    getRules : function(refreshCache){
14097                 if(rules == null || refreshCache){
14098                         rules = {};
14099                         var ds = doc.styleSheets;
14100                         for(var i =0, len = ds.length; i < len; i++){
14101                             try{
14102                         this.cacheStyleSheet(ds[i]);
14103                     }catch(e){} 
14104                 }
14105                 }
14106                 return rules;
14107         },
14108         
14109         /**
14110     * Gets an an individual CSS rule by selector(s)
14111     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14112     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14113     * @return {CSSRule} The CSS rule or null if one is not found
14114     */
14115    getRule : function(selector, refreshCache){
14116                 var rs = this.getRules(refreshCache);
14117                 if(!(selector instanceof Array)){
14118                     return rs[selector];
14119                 }
14120                 for(var i = 0; i < selector.length; i++){
14121                         if(rs[selector[i]]){
14122                                 return rs[selector[i]];
14123                         }
14124                 }
14125                 return null;
14126         },
14127         
14128         
14129         /**
14130     * Updates a rule property
14131     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14132     * @param {String} property The css property
14133     * @param {String} value The new value for the property
14134     * @return {Boolean} true If a rule was found and updated
14135     */
14136    updateRule : function(selector, property, value){
14137                 if(!(selector instanceof Array)){
14138                         var rule = this.getRule(selector);
14139                         if(rule){
14140                                 rule.style[property.replace(camelRe, camelFn)] = value;
14141                                 return true;
14142                         }
14143                 }else{
14144                         for(var i = 0; i < selector.length; i++){
14145                                 if(this.updateRule(selector[i], property, value)){
14146                                         return true;
14147                                 }
14148                         }
14149                 }
14150                 return false;
14151         }
14152    };   
14153 }();/*
14154  * Based on:
14155  * Ext JS Library 1.1.1
14156  * Copyright(c) 2006-2007, Ext JS, LLC.
14157  *
14158  * Originally Released Under LGPL - original licence link has changed is not relivant.
14159  *
14160  * Fork - LGPL
14161  * <script type="text/javascript">
14162  */
14163
14164  
14165
14166 /**
14167  * @class Roo.util.ClickRepeater
14168  * @extends Roo.util.Observable
14169  * 
14170  * A wrapper class which can be applied to any element. Fires a "click" event while the
14171  * mouse is pressed. The interval between firings may be specified in the config but
14172  * defaults to 10 milliseconds.
14173  * 
14174  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14175  * 
14176  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14177  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14178  * Similar to an autorepeat key delay.
14179  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14180  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14181  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14182  *           "interval" and "delay" are ignored. "immediate" is honored.
14183  * @cfg {Boolean} preventDefault True to prevent the default click event
14184  * @cfg {Boolean} stopDefault True to stop the default click event
14185  * 
14186  * @history
14187  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14188  *     2007-02-02 jvs Renamed to ClickRepeater
14189  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14190  *
14191  *  @constructor
14192  * @param {String/HTMLElement/Element} el The element to listen on
14193  * @param {Object} config
14194  **/
14195 Roo.util.ClickRepeater = function(el, config)
14196 {
14197     this.el = Roo.get(el);
14198     this.el.unselectable();
14199
14200     Roo.apply(this, config);
14201
14202     this.addEvents({
14203     /**
14204      * @event mousedown
14205      * Fires when the mouse button is depressed.
14206      * @param {Roo.util.ClickRepeater} this
14207      */
14208         "mousedown" : true,
14209     /**
14210      * @event click
14211      * Fires on a specified interval during the time the element is pressed.
14212      * @param {Roo.util.ClickRepeater} this
14213      */
14214         "click" : true,
14215     /**
14216      * @event mouseup
14217      * Fires when the mouse key is released.
14218      * @param {Roo.util.ClickRepeater} this
14219      */
14220         "mouseup" : true
14221     });
14222
14223     this.el.on("mousedown", this.handleMouseDown, this);
14224     if(this.preventDefault || this.stopDefault){
14225         this.el.on("click", function(e){
14226             if(this.preventDefault){
14227                 e.preventDefault();
14228             }
14229             if(this.stopDefault){
14230                 e.stopEvent();
14231             }
14232         }, this);
14233     }
14234
14235     // allow inline handler
14236     if(this.handler){
14237         this.on("click", this.handler,  this.scope || this);
14238     }
14239
14240     Roo.util.ClickRepeater.superclass.constructor.call(this);
14241 };
14242
14243 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14244     interval : 20,
14245     delay: 250,
14246     preventDefault : true,
14247     stopDefault : false,
14248     timer : 0,
14249
14250     // private
14251     handleMouseDown : function(){
14252         clearTimeout(this.timer);
14253         this.el.blur();
14254         if(this.pressClass){
14255             this.el.addClass(this.pressClass);
14256         }
14257         this.mousedownTime = new Date();
14258
14259         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14260         this.el.on("mouseout", this.handleMouseOut, this);
14261
14262         this.fireEvent("mousedown", this);
14263         this.fireEvent("click", this);
14264         
14265         this.timer = this.click.defer(this.delay || this.interval, this);
14266     },
14267
14268     // private
14269     click : function(){
14270         this.fireEvent("click", this);
14271         this.timer = this.click.defer(this.getInterval(), this);
14272     },
14273
14274     // private
14275     getInterval: function(){
14276         if(!this.accelerate){
14277             return this.interval;
14278         }
14279         var pressTime = this.mousedownTime.getElapsed();
14280         if(pressTime < 500){
14281             return 400;
14282         }else if(pressTime < 1700){
14283             return 320;
14284         }else if(pressTime < 2600){
14285             return 250;
14286         }else if(pressTime < 3500){
14287             return 180;
14288         }else if(pressTime < 4400){
14289             return 140;
14290         }else if(pressTime < 5300){
14291             return 80;
14292         }else if(pressTime < 6200){
14293             return 50;
14294         }else{
14295             return 10;
14296         }
14297     },
14298
14299     // private
14300     handleMouseOut : function(){
14301         clearTimeout(this.timer);
14302         if(this.pressClass){
14303             this.el.removeClass(this.pressClass);
14304         }
14305         this.el.on("mouseover", this.handleMouseReturn, this);
14306     },
14307
14308     // private
14309     handleMouseReturn : function(){
14310         this.el.un("mouseover", this.handleMouseReturn);
14311         if(this.pressClass){
14312             this.el.addClass(this.pressClass);
14313         }
14314         this.click();
14315     },
14316
14317     // private
14318     handleMouseUp : function(){
14319         clearTimeout(this.timer);
14320         this.el.un("mouseover", this.handleMouseReturn);
14321         this.el.un("mouseout", this.handleMouseOut);
14322         Roo.get(document).un("mouseup", this.handleMouseUp);
14323         this.el.removeClass(this.pressClass);
14324         this.fireEvent("mouseup", this);
14325     }
14326 });/*
14327  * Based on:
14328  * Ext JS Library 1.1.1
14329  * Copyright(c) 2006-2007, Ext JS, LLC.
14330  *
14331  * Originally Released Under LGPL - original licence link has changed is not relivant.
14332  *
14333  * Fork - LGPL
14334  * <script type="text/javascript">
14335  */
14336
14337  
14338 /**
14339  * @class Roo.KeyNav
14340  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14341  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14342  * way to implement custom navigation schemes for any UI component.</p>
14343  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14344  * pageUp, pageDown, del, home, end.  Usage:</p>
14345  <pre><code>
14346 var nav = new Roo.KeyNav("my-element", {
14347     "left" : function(e){
14348         this.moveLeft(e.ctrlKey);
14349     },
14350     "right" : function(e){
14351         this.moveRight(e.ctrlKey);
14352     },
14353     "enter" : function(e){
14354         this.save();
14355     },
14356     scope : this
14357 });
14358 </code></pre>
14359  * @constructor
14360  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14361  * @param {Object} config The config
14362  */
14363 Roo.KeyNav = function(el, config){
14364     this.el = Roo.get(el);
14365     Roo.apply(this, config);
14366     if(!this.disabled){
14367         this.disabled = true;
14368         this.enable();
14369     }
14370 };
14371
14372 Roo.KeyNav.prototype = {
14373     /**
14374      * @cfg {Boolean} disabled
14375      * True to disable this KeyNav instance (defaults to false)
14376      */
14377     disabled : false,
14378     /**
14379      * @cfg {String} defaultEventAction
14380      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14381      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14382      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14383      */
14384     defaultEventAction: "stopEvent",
14385     /**
14386      * @cfg {Boolean} forceKeyDown
14387      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14388      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14389      * handle keydown instead of keypress.
14390      */
14391     forceKeyDown : false,
14392
14393     // private
14394     prepareEvent : function(e){
14395         var k = e.getKey();
14396         var h = this.keyToHandler[k];
14397         //if(h && this[h]){
14398         //    e.stopPropagation();
14399         //}
14400         if(Roo.isSafari && h && k >= 37 && k <= 40){
14401             e.stopEvent();
14402         }
14403     },
14404
14405     // private
14406     relay : function(e){
14407         var k = e.getKey();
14408         var h = this.keyToHandler[k];
14409         if(h && this[h]){
14410             if(this.doRelay(e, this[h], h) !== true){
14411                 e[this.defaultEventAction]();
14412             }
14413         }
14414     },
14415
14416     // private
14417     doRelay : function(e, h, hname){
14418         return h.call(this.scope || this, e);
14419     },
14420
14421     // possible handlers
14422     enter : false,
14423     left : false,
14424     right : false,
14425     up : false,
14426     down : false,
14427     tab : false,
14428     esc : false,
14429     pageUp : false,
14430     pageDown : false,
14431     del : false,
14432     home : false,
14433     end : false,
14434
14435     // quick lookup hash
14436     keyToHandler : {
14437         37 : "left",
14438         39 : "right",
14439         38 : "up",
14440         40 : "down",
14441         33 : "pageUp",
14442         34 : "pageDown",
14443         46 : "del",
14444         36 : "home",
14445         35 : "end",
14446         13 : "enter",
14447         27 : "esc",
14448         9  : "tab"
14449     },
14450
14451         /**
14452          * Enable this KeyNav
14453          */
14454         enable: function(){
14455                 if(this.disabled){
14456             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14457             // the EventObject will normalize Safari automatically
14458             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14459                 this.el.on("keydown", this.relay,  this);
14460             }else{
14461                 this.el.on("keydown", this.prepareEvent,  this);
14462                 this.el.on("keypress", this.relay,  this);
14463             }
14464                     this.disabled = false;
14465                 }
14466         },
14467
14468         /**
14469          * Disable this KeyNav
14470          */
14471         disable: function(){
14472                 if(!this.disabled){
14473                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14474                 this.el.un("keydown", this.relay);
14475             }else{
14476                 this.el.un("keydown", this.prepareEvent);
14477                 this.el.un("keypress", this.relay);
14478             }
14479                     this.disabled = true;
14480                 }
14481         }
14482 };/*
14483  * Based on:
14484  * Ext JS Library 1.1.1
14485  * Copyright(c) 2006-2007, Ext JS, LLC.
14486  *
14487  * Originally Released Under LGPL - original licence link has changed is not relivant.
14488  *
14489  * Fork - LGPL
14490  * <script type="text/javascript">
14491  */
14492
14493  
14494 /**
14495  * @class Roo.KeyMap
14496  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14497  * The constructor accepts the same config object as defined by {@link #addBinding}.
14498  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14499  * combination it will call the function with this signature (if the match is a multi-key
14500  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14501  * A KeyMap can also handle a string representation of keys.<br />
14502  * Usage:
14503  <pre><code>
14504 // map one key by key code
14505 var map = new Roo.KeyMap("my-element", {
14506     key: 13, // or Roo.EventObject.ENTER
14507     fn: myHandler,
14508     scope: myObject
14509 });
14510
14511 // map multiple keys to one action by string
14512 var map = new Roo.KeyMap("my-element", {
14513     key: "a\r\n\t",
14514     fn: myHandler,
14515     scope: myObject
14516 });
14517
14518 // map multiple keys to multiple actions by strings and array of codes
14519 var map = new Roo.KeyMap("my-element", [
14520     {
14521         key: [10,13],
14522         fn: function(){ alert("Return was pressed"); }
14523     }, {
14524         key: "abc",
14525         fn: function(){ alert('a, b or c was pressed'); }
14526     }, {
14527         key: "\t",
14528         ctrl:true,
14529         shift:true,
14530         fn: function(){ alert('Control + shift + tab was pressed.'); }
14531     }
14532 ]);
14533 </code></pre>
14534  * <b>Note: A KeyMap starts enabled</b>
14535  * @constructor
14536  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14537  * @param {Object} config The config (see {@link #addBinding})
14538  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14539  */
14540 Roo.KeyMap = function(el, config, eventName){
14541     this.el  = Roo.get(el);
14542     this.eventName = eventName || "keydown";
14543     this.bindings = [];
14544     if(config){
14545         this.addBinding(config);
14546     }
14547     this.enable();
14548 };
14549
14550 Roo.KeyMap.prototype = {
14551     /**
14552      * True to stop the event from bubbling and prevent the default browser action if the
14553      * key was handled by the KeyMap (defaults to false)
14554      * @type Boolean
14555      */
14556     stopEvent : false,
14557
14558     /**
14559      * Add a new binding to this KeyMap. The following config object properties are supported:
14560      * <pre>
14561 Property    Type             Description
14562 ----------  ---------------  ----------------------------------------------------------------------
14563 key         String/Array     A single keycode or an array of keycodes to handle
14564 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14565 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14566 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14567 fn          Function         The function to call when KeyMap finds the expected key combination
14568 scope       Object           The scope of the callback function
14569 </pre>
14570      *
14571      * Usage:
14572      * <pre><code>
14573 // Create a KeyMap
14574 var map = new Roo.KeyMap(document, {
14575     key: Roo.EventObject.ENTER,
14576     fn: handleKey,
14577     scope: this
14578 });
14579
14580 //Add a new binding to the existing KeyMap later
14581 map.addBinding({
14582     key: 'abc',
14583     shift: true,
14584     fn: handleKey,
14585     scope: this
14586 });
14587 </code></pre>
14588      * @param {Object/Array} config A single KeyMap config or an array of configs
14589      */
14590         addBinding : function(config){
14591         if(config instanceof Array){
14592             for(var i = 0, len = config.length; i < len; i++){
14593                 this.addBinding(config[i]);
14594             }
14595             return;
14596         }
14597         var keyCode = config.key,
14598             shift = config.shift, 
14599             ctrl = config.ctrl, 
14600             alt = config.alt,
14601             fn = config.fn,
14602             scope = config.scope;
14603         if(typeof keyCode == "string"){
14604             var ks = [];
14605             var keyString = keyCode.toUpperCase();
14606             for(var j = 0, len = keyString.length; j < len; j++){
14607                 ks.push(keyString.charCodeAt(j));
14608             }
14609             keyCode = ks;
14610         }
14611         var keyArray = keyCode instanceof Array;
14612         var handler = function(e){
14613             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14614                 var k = e.getKey();
14615                 if(keyArray){
14616                     for(var i = 0, len = keyCode.length; i < len; i++){
14617                         if(keyCode[i] == k){
14618                           if(this.stopEvent){
14619                               e.stopEvent();
14620                           }
14621                           fn.call(scope || window, k, e);
14622                           return;
14623                         }
14624                     }
14625                 }else{
14626                     if(k == keyCode){
14627                         if(this.stopEvent){
14628                            e.stopEvent();
14629                         }
14630                         fn.call(scope || window, k, e);
14631                     }
14632                 }
14633             }
14634         };
14635         this.bindings.push(handler);  
14636         },
14637
14638     /**
14639      * Shorthand for adding a single key listener
14640      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14641      * following options:
14642      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14643      * @param {Function} fn The function to call
14644      * @param {Object} scope (optional) The scope of the function
14645      */
14646     on : function(key, fn, scope){
14647         var keyCode, shift, ctrl, alt;
14648         if(typeof key == "object" && !(key instanceof Array)){
14649             keyCode = key.key;
14650             shift = key.shift;
14651             ctrl = key.ctrl;
14652             alt = key.alt;
14653         }else{
14654             keyCode = key;
14655         }
14656         this.addBinding({
14657             key: keyCode,
14658             shift: shift,
14659             ctrl: ctrl,
14660             alt: alt,
14661             fn: fn,
14662             scope: scope
14663         })
14664     },
14665
14666     // private
14667     handleKeyDown : function(e){
14668             if(this.enabled){ //just in case
14669             var b = this.bindings;
14670             for(var i = 0, len = b.length; i < len; i++){
14671                 b[i].call(this, e);
14672             }
14673             }
14674         },
14675         
14676         /**
14677          * Returns true if this KeyMap is enabled
14678          * @return {Boolean} 
14679          */
14680         isEnabled : function(){
14681             return this.enabled;  
14682         },
14683         
14684         /**
14685          * Enables this KeyMap
14686          */
14687         enable: function(){
14688                 if(!this.enabled){
14689                     this.el.on(this.eventName, this.handleKeyDown, this);
14690                     this.enabled = true;
14691                 }
14692         },
14693
14694         /**
14695          * Disable this KeyMap
14696          */
14697         disable: function(){
14698                 if(this.enabled){
14699                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14700                     this.enabled = false;
14701                 }
14702         }
14703 };/*
14704  * Based on:
14705  * Ext JS Library 1.1.1
14706  * Copyright(c) 2006-2007, Ext JS, LLC.
14707  *
14708  * Originally Released Under LGPL - original licence link has changed is not relivant.
14709  *
14710  * Fork - LGPL
14711  * <script type="text/javascript">
14712  */
14713
14714  
14715 /**
14716  * @class Roo.util.TextMetrics
14717  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14718  * wide, in pixels, a given block of text will be.
14719  * @singleton
14720  */
14721 Roo.util.TextMetrics = function(){
14722     var shared;
14723     return {
14724         /**
14725          * Measures the size of the specified text
14726          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14727          * that can affect the size of the rendered text
14728          * @param {String} text The text to measure
14729          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14730          * in order to accurately measure the text height
14731          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14732          */
14733         measure : function(el, text, fixedWidth){
14734             if(!shared){
14735                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14736             }
14737             shared.bind(el);
14738             shared.setFixedWidth(fixedWidth || 'auto');
14739             return shared.getSize(text);
14740         },
14741
14742         /**
14743          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14744          * the overhead of multiple calls to initialize the style properties on each measurement.
14745          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14746          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14747          * in order to accurately measure the text height
14748          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14749          */
14750         createInstance : function(el, fixedWidth){
14751             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14752         }
14753     };
14754 }();
14755
14756  
14757
14758 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14759     var ml = new Roo.Element(document.createElement('div'));
14760     document.body.appendChild(ml.dom);
14761     ml.position('absolute');
14762     ml.setLeftTop(-1000, -1000);
14763     ml.hide();
14764
14765     if(fixedWidth){
14766         ml.setWidth(fixedWidth);
14767     }
14768      
14769     var instance = {
14770         /**
14771          * Returns the size of the specified text based on the internal element's style and width properties
14772          * @memberOf Roo.util.TextMetrics.Instance#
14773          * @param {String} text The text to measure
14774          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14775          */
14776         getSize : function(text){
14777             ml.update(text);
14778             var s = ml.getSize();
14779             ml.update('');
14780             return s;
14781         },
14782
14783         /**
14784          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14785          * that can affect the size of the rendered text
14786          * @memberOf Roo.util.TextMetrics.Instance#
14787          * @param {String/HTMLElement} el The element, dom node or id
14788          */
14789         bind : function(el){
14790             ml.setStyle(
14791                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14792             );
14793         },
14794
14795         /**
14796          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14797          * to set a fixed width in order to accurately measure the text height.
14798          * @memberOf Roo.util.TextMetrics.Instance#
14799          * @param {Number} width The width to set on the element
14800          */
14801         setFixedWidth : function(width){
14802             ml.setWidth(width);
14803         },
14804
14805         /**
14806          * Returns the measured width of the specified text
14807          * @memberOf Roo.util.TextMetrics.Instance#
14808          * @param {String} text The text to measure
14809          * @return {Number} width The width in pixels
14810          */
14811         getWidth : function(text){
14812             ml.dom.style.width = 'auto';
14813             return this.getSize(text).width;
14814         },
14815
14816         /**
14817          * Returns the measured height of the specified text.  For multiline text, be sure to call
14818          * {@link #setFixedWidth} if necessary.
14819          * @memberOf Roo.util.TextMetrics.Instance#
14820          * @param {String} text The text to measure
14821          * @return {Number} height The height in pixels
14822          */
14823         getHeight : function(text){
14824             return this.getSize(text).height;
14825         }
14826     };
14827
14828     instance.bind(bindTo);
14829
14830     return instance;
14831 };
14832
14833 // backwards compat
14834 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14835  * Based on:
14836  * Ext JS Library 1.1.1
14837  * Copyright(c) 2006-2007, Ext JS, LLC.
14838  *
14839  * Originally Released Under LGPL - original licence link has changed is not relivant.
14840  *
14841  * Fork - LGPL
14842  * <script type="text/javascript">
14843  */
14844
14845 /**
14846  * @class Roo.state.Provider
14847  * Abstract base class for state provider implementations. This class provides methods
14848  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14849  * Provider interface.
14850  */
14851 Roo.state.Provider = function(){
14852     /**
14853      * @event statechange
14854      * Fires when a state change occurs.
14855      * @param {Provider} this This state provider
14856      * @param {String} key The state key which was changed
14857      * @param {String} value The encoded value for the state
14858      */
14859     this.addEvents({
14860         "statechange": true
14861     });
14862     this.state = {};
14863     Roo.state.Provider.superclass.constructor.call(this);
14864 };
14865 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14866     /**
14867      * Returns the current value for a key
14868      * @param {String} name The key name
14869      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14870      * @return {Mixed} The state data
14871      */
14872     get : function(name, defaultValue){
14873         return typeof this.state[name] == "undefined" ?
14874             defaultValue : this.state[name];
14875     },
14876     
14877     /**
14878      * Clears a value from the state
14879      * @param {String} name The key name
14880      */
14881     clear : function(name){
14882         delete this.state[name];
14883         this.fireEvent("statechange", this, name, null);
14884     },
14885     
14886     /**
14887      * Sets the value for a key
14888      * @param {String} name The key name
14889      * @param {Mixed} value The value to set
14890      */
14891     set : function(name, value){
14892         this.state[name] = value;
14893         this.fireEvent("statechange", this, name, value);
14894     },
14895     
14896     /**
14897      * Decodes a string previously encoded with {@link #encodeValue}.
14898      * @param {String} value The value to decode
14899      * @return {Mixed} The decoded value
14900      */
14901     decodeValue : function(cookie){
14902         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14903         var matches = re.exec(unescape(cookie));
14904         if(!matches || !matches[1]) {
14905             return; // non state cookie
14906         }
14907         var type = matches[1];
14908         var v = matches[2];
14909         switch(type){
14910             case "n":
14911                 return parseFloat(v);
14912             case "d":
14913                 return new Date(Date.parse(v));
14914             case "b":
14915                 return (v == "1");
14916             case "a":
14917                 var all = [];
14918                 var values = v.split("^");
14919                 for(var i = 0, len = values.length; i < len; i++){
14920                     all.push(this.decodeValue(values[i]));
14921                 }
14922                 return all;
14923            case "o":
14924                 var all = {};
14925                 var values = v.split("^");
14926                 for(var i = 0, len = values.length; i < len; i++){
14927                     var kv = values[i].split("=");
14928                     all[kv[0]] = this.decodeValue(kv[1]);
14929                 }
14930                 return all;
14931            default:
14932                 return v;
14933         }
14934     },
14935     
14936     /**
14937      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14938      * @param {Mixed} value The value to encode
14939      * @return {String} The encoded value
14940      */
14941     encodeValue : function(v){
14942         var enc;
14943         if(typeof v == "number"){
14944             enc = "n:" + v;
14945         }else if(typeof v == "boolean"){
14946             enc = "b:" + (v ? "1" : "0");
14947         }else if(v instanceof Date){
14948             enc = "d:" + v.toGMTString();
14949         }else if(v instanceof Array){
14950             var flat = "";
14951             for(var i = 0, len = v.length; i < len; i++){
14952                 flat += this.encodeValue(v[i]);
14953                 if(i != len-1) {
14954                     flat += "^";
14955                 }
14956             }
14957             enc = "a:" + flat;
14958         }else if(typeof v == "object"){
14959             var flat = "";
14960             for(var key in v){
14961                 if(typeof v[key] != "function"){
14962                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14963                 }
14964             }
14965             enc = "o:" + flat.substring(0, flat.length-1);
14966         }else{
14967             enc = "s:" + v;
14968         }
14969         return escape(enc);        
14970     }
14971 });
14972
14973 /*
14974  * Based on:
14975  * Ext JS Library 1.1.1
14976  * Copyright(c) 2006-2007, Ext JS, LLC.
14977  *
14978  * Originally Released Under LGPL - original licence link has changed is not relivant.
14979  *
14980  * Fork - LGPL
14981  * <script type="text/javascript">
14982  */
14983 /**
14984  * @class Roo.state.Manager
14985  * This is the global state manager. By default all components that are "state aware" check this class
14986  * for state information if you don't pass them a custom state provider. In order for this class
14987  * to be useful, it must be initialized with a provider when your application initializes.
14988  <pre><code>
14989 // in your initialization function
14990 init : function(){
14991    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14992    ...
14993    // supposed you have a {@link Roo.BorderLayout}
14994    var layout = new Roo.BorderLayout(...);
14995    layout.restoreState();
14996    // or a {Roo.BasicDialog}
14997    var dialog = new Roo.BasicDialog(...);
14998    dialog.restoreState();
14999  </code></pre>
15000  * @singleton
15001  */
15002 Roo.state.Manager = function(){
15003     var provider = new Roo.state.Provider();
15004     
15005     return {
15006         /**
15007          * Configures the default state provider for your application
15008          * @param {Provider} stateProvider The state provider to set
15009          */
15010         setProvider : function(stateProvider){
15011             provider = stateProvider;
15012         },
15013         
15014         /**
15015          * Returns the current value for a key
15016          * @param {String} name The key name
15017          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15018          * @return {Mixed} The state data
15019          */
15020         get : function(key, defaultValue){
15021             return provider.get(key, defaultValue);
15022         },
15023         
15024         /**
15025          * Sets the value for a key
15026          * @param {String} name The key name
15027          * @param {Mixed} value The state data
15028          */
15029          set : function(key, value){
15030             provider.set(key, value);
15031         },
15032         
15033         /**
15034          * Clears a value from the state
15035          * @param {String} name The key name
15036          */
15037         clear : function(key){
15038             provider.clear(key);
15039         },
15040         
15041         /**
15042          * Gets the currently configured state provider
15043          * @return {Provider} The state provider
15044          */
15045         getProvider : function(){
15046             return provider;
15047         }
15048     };
15049 }();
15050 /*
15051  * Based on:
15052  * Ext JS Library 1.1.1
15053  * Copyright(c) 2006-2007, Ext JS, LLC.
15054  *
15055  * Originally Released Under LGPL - original licence link has changed is not relivant.
15056  *
15057  * Fork - LGPL
15058  * <script type="text/javascript">
15059  */
15060 /**
15061  * @class Roo.state.CookieProvider
15062  * @extends Roo.state.Provider
15063  * The default Provider implementation which saves state via cookies.
15064  * <br />Usage:
15065  <pre><code>
15066    var cp = new Roo.state.CookieProvider({
15067        path: "/cgi-bin/",
15068        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15069        domain: "roojs.com"
15070    })
15071    Roo.state.Manager.setProvider(cp);
15072  </code></pre>
15073  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15074  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15075  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15076  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15077  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15078  * domain the page is running on including the 'www' like 'www.roojs.com')
15079  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15080  * @constructor
15081  * Create a new CookieProvider
15082  * @param {Object} config The configuration object
15083  */
15084 Roo.state.CookieProvider = function(config){
15085     Roo.state.CookieProvider.superclass.constructor.call(this);
15086     this.path = "/";
15087     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15088     this.domain = null;
15089     this.secure = false;
15090     Roo.apply(this, config);
15091     this.state = this.readCookies();
15092 };
15093
15094 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15095     // private
15096     set : function(name, value){
15097         if(typeof value == "undefined" || value === null){
15098             this.clear(name);
15099             return;
15100         }
15101         this.setCookie(name, value);
15102         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15103     },
15104
15105     // private
15106     clear : function(name){
15107         this.clearCookie(name);
15108         Roo.state.CookieProvider.superclass.clear.call(this, name);
15109     },
15110
15111     // private
15112     readCookies : function(){
15113         var cookies = {};
15114         var c = document.cookie + ";";
15115         var re = /\s?(.*?)=(.*?);/g;
15116         var matches;
15117         while((matches = re.exec(c)) != null){
15118             var name = matches[1];
15119             var value = matches[2];
15120             if(name && name.substring(0,3) == "ys-"){
15121                 cookies[name.substr(3)] = this.decodeValue(value);
15122             }
15123         }
15124         return cookies;
15125     },
15126
15127     // private
15128     setCookie : function(name, value){
15129         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15130            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15131            ((this.path == null) ? "" : ("; path=" + this.path)) +
15132            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15133            ((this.secure == true) ? "; secure" : "");
15134     },
15135
15136     // private
15137     clearCookie : function(name){
15138         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15139            ((this.path == null) ? "" : ("; path=" + this.path)) +
15140            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15141            ((this.secure == true) ? "; secure" : "");
15142     }
15143 });/*
15144  * Based on:
15145  * Ext JS Library 1.1.1
15146  * Copyright(c) 2006-2007, Ext JS, LLC.
15147  *
15148  * Originally Released Under LGPL - original licence link has changed is not relivant.
15149  *
15150  * Fork - LGPL
15151  * <script type="text/javascript">
15152  */
15153  
15154
15155 /**
15156  * @class Roo.ComponentMgr
15157  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15158  * @singleton
15159  */
15160 Roo.ComponentMgr = function(){
15161     var all = new Roo.util.MixedCollection();
15162
15163     return {
15164         /**
15165          * Registers a component.
15166          * @param {Roo.Component} c The component
15167          */
15168         register : function(c){
15169             all.add(c);
15170         },
15171
15172         /**
15173          * Unregisters a component.
15174          * @param {Roo.Component} c The component
15175          */
15176         unregister : function(c){
15177             all.remove(c);
15178         },
15179
15180         /**
15181          * Returns a component by id
15182          * @param {String} id The component id
15183          */
15184         get : function(id){
15185             return all.get(id);
15186         },
15187
15188         /**
15189          * Registers a function that will be called when a specified component is added to ComponentMgr
15190          * @param {String} id The component id
15191          * @param {Funtction} fn The callback function
15192          * @param {Object} scope The scope of the callback
15193          */
15194         onAvailable : function(id, fn, scope){
15195             all.on("add", function(index, o){
15196                 if(o.id == id){
15197                     fn.call(scope || o, o);
15198                     all.un("add", fn, scope);
15199                 }
15200             });
15201         }
15202     };
15203 }();/*
15204  * Based on:
15205  * Ext JS Library 1.1.1
15206  * Copyright(c) 2006-2007, Ext JS, LLC.
15207  *
15208  * Originally Released Under LGPL - original licence link has changed is not relivant.
15209  *
15210  * Fork - LGPL
15211  * <script type="text/javascript">
15212  */
15213  
15214 /**
15215  * @class Roo.Component
15216  * @extends Roo.util.Observable
15217  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15218  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15219  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15220  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15221  * All visual components (widgets) that require rendering into a layout should subclass Component.
15222  * @constructor
15223  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15224  * 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
15225  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15226  */
15227 Roo.Component = function(config){
15228     config = config || {};
15229     if(config.tagName || config.dom || typeof config == "string"){ // element object
15230         config = {el: config, id: config.id || config};
15231     }
15232     this.initialConfig = config;
15233
15234     Roo.apply(this, config);
15235     this.addEvents({
15236         /**
15237          * @event disable
15238          * Fires after the component is disabled.
15239              * @param {Roo.Component} this
15240              */
15241         disable : true,
15242         /**
15243          * @event enable
15244          * Fires after the component is enabled.
15245              * @param {Roo.Component} this
15246              */
15247         enable : true,
15248         /**
15249          * @event beforeshow
15250          * Fires before the component is shown.  Return false to stop the show.
15251              * @param {Roo.Component} this
15252              */
15253         beforeshow : true,
15254         /**
15255          * @event show
15256          * Fires after the component is shown.
15257              * @param {Roo.Component} this
15258              */
15259         show : true,
15260         /**
15261          * @event beforehide
15262          * Fires before the component is hidden. Return false to stop the hide.
15263              * @param {Roo.Component} this
15264              */
15265         beforehide : true,
15266         /**
15267          * @event hide
15268          * Fires after the component is hidden.
15269              * @param {Roo.Component} this
15270              */
15271         hide : true,
15272         /**
15273          * @event beforerender
15274          * Fires before the component is rendered. Return false to stop the render.
15275              * @param {Roo.Component} this
15276              */
15277         beforerender : true,
15278         /**
15279          * @event render
15280          * Fires after the component is rendered.
15281              * @param {Roo.Component} this
15282              */
15283         render : true,
15284         /**
15285          * @event beforedestroy
15286          * Fires before the component is destroyed. Return false to stop the destroy.
15287              * @param {Roo.Component} this
15288              */
15289         beforedestroy : true,
15290         /**
15291          * @event destroy
15292          * Fires after the component is destroyed.
15293              * @param {Roo.Component} this
15294              */
15295         destroy : true
15296     });
15297     if(!this.id){
15298         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15299     }
15300     Roo.ComponentMgr.register(this);
15301     Roo.Component.superclass.constructor.call(this);
15302     this.initComponent();
15303     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15304         this.render(this.renderTo);
15305         delete this.renderTo;
15306     }
15307 };
15308
15309 /** @private */
15310 Roo.Component.AUTO_ID = 1000;
15311
15312 Roo.extend(Roo.Component, Roo.util.Observable, {
15313     /**
15314      * @scope Roo.Component.prototype
15315      * @type {Boolean}
15316      * true if this component is hidden. Read-only.
15317      */
15318     hidden : false,
15319     /**
15320      * @type {Boolean}
15321      * true if this component is disabled. Read-only.
15322      */
15323     disabled : false,
15324     /**
15325      * @type {Boolean}
15326      * true if this component has been rendered. Read-only.
15327      */
15328     rendered : false,
15329     
15330     /** @cfg {String} disableClass
15331      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15332      */
15333     disabledClass : "x-item-disabled",
15334         /** @cfg {Boolean} allowDomMove
15335          * Whether the component can move the Dom node when rendering (defaults to true).
15336          */
15337     allowDomMove : true,
15338     /** @cfg {String} hideMode (display|visibility)
15339      * How this component should hidden. Supported values are
15340      * "visibility" (css visibility), "offsets" (negative offset position) and
15341      * "display" (css display) - defaults to "display".
15342      */
15343     hideMode: 'display',
15344
15345     /** @private */
15346     ctype : "Roo.Component",
15347
15348     /**
15349      * @cfg {String} actionMode 
15350      * which property holds the element that used for  hide() / show() / disable() / enable()
15351      * default is 'el' 
15352      */
15353     actionMode : "el",
15354
15355     /** @private */
15356     getActionEl : function(){
15357         return this[this.actionMode];
15358     },
15359
15360     initComponent : Roo.emptyFn,
15361     /**
15362      * If this is a lazy rendering component, render it to its container element.
15363      * @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.
15364      */
15365     render : function(container, position){
15366         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15367             if(!container && this.el){
15368                 this.el = Roo.get(this.el);
15369                 container = this.el.dom.parentNode;
15370                 this.allowDomMove = false;
15371             }
15372             this.container = Roo.get(container);
15373             this.rendered = true;
15374             if(position !== undefined){
15375                 if(typeof position == 'number'){
15376                     position = this.container.dom.childNodes[position];
15377                 }else{
15378                     position = Roo.getDom(position);
15379                 }
15380             }
15381             this.onRender(this.container, position || null);
15382             if(this.cls){
15383                 this.el.addClass(this.cls);
15384                 delete this.cls;
15385             }
15386             if(this.style){
15387                 this.el.applyStyles(this.style);
15388                 delete this.style;
15389             }
15390             this.fireEvent("render", this);
15391             this.afterRender(this.container);
15392             if(this.hidden){
15393                 this.hide();
15394             }
15395             if(this.disabled){
15396                 this.disable();
15397             }
15398         }
15399         return this;
15400     },
15401
15402     /** @private */
15403     // default function is not really useful
15404     onRender : function(ct, position){
15405         if(this.el){
15406             this.el = Roo.get(this.el);
15407             if(this.allowDomMove !== false){
15408                 ct.dom.insertBefore(this.el.dom, position);
15409             }
15410         }
15411     },
15412
15413     /** @private */
15414     getAutoCreate : function(){
15415         var cfg = typeof this.autoCreate == "object" ?
15416                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15417         if(this.id && !cfg.id){
15418             cfg.id = this.id;
15419         }
15420         return cfg;
15421     },
15422
15423     /** @private */
15424     afterRender : Roo.emptyFn,
15425
15426     /**
15427      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15428      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15429      */
15430     destroy : function(){
15431         if(this.fireEvent("beforedestroy", this) !== false){
15432             this.purgeListeners();
15433             this.beforeDestroy();
15434             if(this.rendered){
15435                 this.el.removeAllListeners();
15436                 this.el.remove();
15437                 if(this.actionMode == "container"){
15438                     this.container.remove();
15439                 }
15440             }
15441             this.onDestroy();
15442             Roo.ComponentMgr.unregister(this);
15443             this.fireEvent("destroy", this);
15444         }
15445     },
15446
15447         /** @private */
15448     beforeDestroy : function(){
15449
15450     },
15451
15452         /** @private */
15453         onDestroy : function(){
15454
15455     },
15456
15457     /**
15458      * Returns the underlying {@link Roo.Element}.
15459      * @return {Roo.Element} The element
15460      */
15461     getEl : function(){
15462         return this.el;
15463     },
15464
15465     /**
15466      * Returns the id of this component.
15467      * @return {String}
15468      */
15469     getId : function(){
15470         return this.id;
15471     },
15472
15473     /**
15474      * Try to focus this component.
15475      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15476      * @return {Roo.Component} this
15477      */
15478     focus : function(selectText){
15479         if(this.rendered){
15480             this.el.focus();
15481             if(selectText === true){
15482                 this.el.dom.select();
15483             }
15484         }
15485         return this;
15486     },
15487
15488     /** @private */
15489     blur : function(){
15490         if(this.rendered){
15491             this.el.blur();
15492         }
15493         return this;
15494     },
15495
15496     /**
15497      * Disable this component.
15498      * @return {Roo.Component} this
15499      */
15500     disable : function(){
15501         if(this.rendered){
15502             this.onDisable();
15503         }
15504         this.disabled = true;
15505         this.fireEvent("disable", this);
15506         return this;
15507     },
15508
15509         // private
15510     onDisable : function(){
15511         this.getActionEl().addClass(this.disabledClass);
15512         this.el.dom.disabled = true;
15513     },
15514
15515     /**
15516      * Enable this component.
15517      * @return {Roo.Component} this
15518      */
15519     enable : function(){
15520         
15521         Roo.log('------------firing enable------------');
15522         
15523         if(this.rendered){
15524             this.onEnable();
15525         }
15526         
15527         this.disabled = false;
15528         this.fireEvent("enable", this);
15529         return this;
15530     },
15531
15532         // private
15533     onEnable : function(){
15534         this.getActionEl().removeClass(this.disabledClass);
15535         this.el.dom.disabled = false;
15536     },
15537
15538     /**
15539      * Convenience function for setting disabled/enabled by boolean.
15540      * @param {Boolean} disabled
15541      */
15542     setDisabled : function(disabled){
15543         this[disabled ? "disable" : "enable"]();
15544     },
15545
15546     /**
15547      * Show this component.
15548      * @return {Roo.Component} this
15549      */
15550     show: function(){
15551         if(this.fireEvent("beforeshow", this) !== false){
15552             this.hidden = false;
15553             if(this.rendered){
15554                 this.onShow();
15555             }
15556             this.fireEvent("show", this);
15557         }
15558         return this;
15559     },
15560
15561     // private
15562     onShow : function(){
15563         var ae = this.getActionEl();
15564         if(this.hideMode == 'visibility'){
15565             ae.dom.style.visibility = "visible";
15566         }else if(this.hideMode == 'offsets'){
15567             ae.removeClass('x-hidden');
15568         }else{
15569             ae.dom.style.display = "";
15570         }
15571     },
15572
15573     /**
15574      * Hide this component.
15575      * @return {Roo.Component} this
15576      */
15577     hide: function(){
15578         if(this.fireEvent("beforehide", this) !== false){
15579             this.hidden = true;
15580             if(this.rendered){
15581                 this.onHide();
15582             }
15583             this.fireEvent("hide", this);
15584         }
15585         return this;
15586     },
15587
15588     // private
15589     onHide : function(){
15590         var ae = this.getActionEl();
15591         if(this.hideMode == 'visibility'){
15592             ae.dom.style.visibility = "hidden";
15593         }else if(this.hideMode == 'offsets'){
15594             ae.addClass('x-hidden');
15595         }else{
15596             ae.dom.style.display = "none";
15597         }
15598     },
15599
15600     /**
15601      * Convenience function to hide or show this component by boolean.
15602      * @param {Boolean} visible True to show, false to hide
15603      * @return {Roo.Component} this
15604      */
15605     setVisible: function(visible){
15606         if(visible) {
15607             this.show();
15608         }else{
15609             this.hide();
15610         }
15611         return this;
15612     },
15613
15614     /**
15615      * Returns true if this component is visible.
15616      */
15617     isVisible : function(){
15618         return this.getActionEl().isVisible();
15619     },
15620
15621     cloneConfig : function(overrides){
15622         overrides = overrides || {};
15623         var id = overrides.id || Roo.id();
15624         var cfg = Roo.applyIf(overrides, this.initialConfig);
15625         cfg.id = id; // prevent dup id
15626         return new this.constructor(cfg);
15627     }
15628 });/*
15629  * Based on:
15630  * Ext JS Library 1.1.1
15631  * Copyright(c) 2006-2007, Ext JS, LLC.
15632  *
15633  * Originally Released Under LGPL - original licence link has changed is not relivant.
15634  *
15635  * Fork - LGPL
15636  * <script type="text/javascript">
15637  */
15638
15639 /**
15640  * @class Roo.BoxComponent
15641  * @extends Roo.Component
15642  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15643  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15644  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15645  * layout containers.
15646  * @constructor
15647  * @param {Roo.Element/String/Object} config The configuration options.
15648  */
15649 Roo.BoxComponent = function(config){
15650     Roo.Component.call(this, config);
15651     this.addEvents({
15652         /**
15653          * @event resize
15654          * Fires after the component is resized.
15655              * @param {Roo.Component} this
15656              * @param {Number} adjWidth The box-adjusted width that was set
15657              * @param {Number} adjHeight The box-adjusted height that was set
15658              * @param {Number} rawWidth The width that was originally specified
15659              * @param {Number} rawHeight The height that was originally specified
15660              */
15661         resize : true,
15662         /**
15663          * @event move
15664          * Fires after the component is moved.
15665              * @param {Roo.Component} this
15666              * @param {Number} x The new x position
15667              * @param {Number} y The new y position
15668              */
15669         move : true
15670     });
15671 };
15672
15673 Roo.extend(Roo.BoxComponent, Roo.Component, {
15674     // private, set in afterRender to signify that the component has been rendered
15675     boxReady : false,
15676     // private, used to defer height settings to subclasses
15677     deferHeight: false,
15678     /** @cfg {Number} width
15679      * width (optional) size of component
15680      */
15681      /** @cfg {Number} height
15682      * height (optional) size of component
15683      */
15684      
15685     /**
15686      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15687      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15688      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15689      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15690      * @return {Roo.BoxComponent} this
15691      */
15692     setSize : function(w, h){
15693         // support for standard size objects
15694         if(typeof w == 'object'){
15695             h = w.height;
15696             w = w.width;
15697         }
15698         // not rendered
15699         if(!this.boxReady){
15700             this.width = w;
15701             this.height = h;
15702             return this;
15703         }
15704
15705         // prevent recalcs when not needed
15706         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15707             return this;
15708         }
15709         this.lastSize = {width: w, height: h};
15710
15711         var adj = this.adjustSize(w, h);
15712         var aw = adj.width, ah = adj.height;
15713         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15714             var rz = this.getResizeEl();
15715             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15716                 rz.setSize(aw, ah);
15717             }else if(!this.deferHeight && ah !== undefined){
15718                 rz.setHeight(ah);
15719             }else if(aw !== undefined){
15720                 rz.setWidth(aw);
15721             }
15722             this.onResize(aw, ah, w, h);
15723             this.fireEvent('resize', this, aw, ah, w, h);
15724         }
15725         return this;
15726     },
15727
15728     /**
15729      * Gets the current size of the component's underlying element.
15730      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15731      */
15732     getSize : function(){
15733         return this.el.getSize();
15734     },
15735
15736     /**
15737      * Gets the current XY position of the component's underlying element.
15738      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15739      * @return {Array} The XY position of the element (e.g., [100, 200])
15740      */
15741     getPosition : function(local){
15742         if(local === true){
15743             return [this.el.getLeft(true), this.el.getTop(true)];
15744         }
15745         return this.xy || this.el.getXY();
15746     },
15747
15748     /**
15749      * Gets the current box measurements of the component's underlying element.
15750      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15751      * @returns {Object} box An object in the format {x, y, width, height}
15752      */
15753     getBox : function(local){
15754         var s = this.el.getSize();
15755         if(local){
15756             s.x = this.el.getLeft(true);
15757             s.y = this.el.getTop(true);
15758         }else{
15759             var xy = this.xy || this.el.getXY();
15760             s.x = xy[0];
15761             s.y = xy[1];
15762         }
15763         return s;
15764     },
15765
15766     /**
15767      * Sets the current box measurements of the component's underlying element.
15768      * @param {Object} box An object in the format {x, y, width, height}
15769      * @returns {Roo.BoxComponent} this
15770      */
15771     updateBox : function(box){
15772         this.setSize(box.width, box.height);
15773         this.setPagePosition(box.x, box.y);
15774         return this;
15775     },
15776
15777     // protected
15778     getResizeEl : function(){
15779         return this.resizeEl || this.el;
15780     },
15781
15782     // protected
15783     getPositionEl : function(){
15784         return this.positionEl || this.el;
15785     },
15786
15787     /**
15788      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15789      * This method fires the move event.
15790      * @param {Number} left The new left
15791      * @param {Number} top The new top
15792      * @returns {Roo.BoxComponent} this
15793      */
15794     setPosition : function(x, y){
15795         this.x = x;
15796         this.y = y;
15797         if(!this.boxReady){
15798             return this;
15799         }
15800         var adj = this.adjustPosition(x, y);
15801         var ax = adj.x, ay = adj.y;
15802
15803         var el = this.getPositionEl();
15804         if(ax !== undefined || ay !== undefined){
15805             if(ax !== undefined && ay !== undefined){
15806                 el.setLeftTop(ax, ay);
15807             }else if(ax !== undefined){
15808                 el.setLeft(ax);
15809             }else if(ay !== undefined){
15810                 el.setTop(ay);
15811             }
15812             this.onPosition(ax, ay);
15813             this.fireEvent('move', this, ax, ay);
15814         }
15815         return this;
15816     },
15817
15818     /**
15819      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15820      * This method fires the move event.
15821      * @param {Number} x The new x position
15822      * @param {Number} y The new y position
15823      * @returns {Roo.BoxComponent} this
15824      */
15825     setPagePosition : function(x, y){
15826         this.pageX = x;
15827         this.pageY = y;
15828         if(!this.boxReady){
15829             return;
15830         }
15831         if(x === undefined || y === undefined){ // cannot translate undefined points
15832             return;
15833         }
15834         var p = this.el.translatePoints(x, y);
15835         this.setPosition(p.left, p.top);
15836         return this;
15837     },
15838
15839     // private
15840     onRender : function(ct, position){
15841         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15842         if(this.resizeEl){
15843             this.resizeEl = Roo.get(this.resizeEl);
15844         }
15845         if(this.positionEl){
15846             this.positionEl = Roo.get(this.positionEl);
15847         }
15848     },
15849
15850     // private
15851     afterRender : function(){
15852         Roo.BoxComponent.superclass.afterRender.call(this);
15853         this.boxReady = true;
15854         this.setSize(this.width, this.height);
15855         if(this.x || this.y){
15856             this.setPosition(this.x, this.y);
15857         }
15858         if(this.pageX || this.pageY){
15859             this.setPagePosition(this.pageX, this.pageY);
15860         }
15861     },
15862
15863     /**
15864      * Force the component's size to recalculate based on the underlying element's current height and width.
15865      * @returns {Roo.BoxComponent} this
15866      */
15867     syncSize : function(){
15868         delete this.lastSize;
15869         this.setSize(this.el.getWidth(), this.el.getHeight());
15870         return this;
15871     },
15872
15873     /**
15874      * Called after the component is resized, this method is empty by default but can be implemented by any
15875      * subclass that needs to perform custom logic after a resize occurs.
15876      * @param {Number} adjWidth The box-adjusted width that was set
15877      * @param {Number} adjHeight The box-adjusted height that was set
15878      * @param {Number} rawWidth The width that was originally specified
15879      * @param {Number} rawHeight The height that was originally specified
15880      */
15881     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15882
15883     },
15884
15885     /**
15886      * Called after the component is moved, this method is empty by default but can be implemented by any
15887      * subclass that needs to perform custom logic after a move occurs.
15888      * @param {Number} x The new x position
15889      * @param {Number} y The new y position
15890      */
15891     onPosition : function(x, y){
15892
15893     },
15894
15895     // private
15896     adjustSize : function(w, h){
15897         if(this.autoWidth){
15898             w = 'auto';
15899         }
15900         if(this.autoHeight){
15901             h = 'auto';
15902         }
15903         return {width : w, height: h};
15904     },
15905
15906     // private
15907     adjustPosition : function(x, y){
15908         return {x : x, y: y};
15909     }
15910 });/*
15911  * Original code for Roojs - LGPL
15912  * <script type="text/javascript">
15913  */
15914  
15915 /**
15916  * @class Roo.XComponent
15917  * A delayed Element creator...
15918  * Or a way to group chunks of interface together.
15919  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15920  *  used in conjunction with XComponent.build() it will create an instance of each element,
15921  *  then call addxtype() to build the User interface.
15922  * 
15923  * Mypart.xyx = new Roo.XComponent({
15924
15925     parent : 'Mypart.xyz', // empty == document.element.!!
15926     order : '001',
15927     name : 'xxxx'
15928     region : 'xxxx'
15929     disabled : function() {} 
15930      
15931     tree : function() { // return an tree of xtype declared components
15932         var MODULE = this;
15933         return 
15934         {
15935             xtype : 'NestedLayoutPanel',
15936             // technicall
15937         }
15938      ]
15939  *})
15940  *
15941  *
15942  * It can be used to build a big heiracy, with parent etc.
15943  * or you can just use this to render a single compoent to a dom element
15944  * MYPART.render(Roo.Element | String(id) | dom_element )
15945  *
15946  *
15947  * Usage patterns.
15948  *
15949  * Classic Roo
15950  *
15951  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15952  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15953  *
15954  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15955  *
15956  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15957  * - if mulitple topModules exist, the last one is defined as the top module.
15958  *
15959  * Embeded Roo
15960  * 
15961  * When the top level or multiple modules are to embedded into a existing HTML page,
15962  * the parent element can container '#id' of the element where the module will be drawn.
15963  *
15964  * Bootstrap Roo
15965  *
15966  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15967  * it relies more on a include mechanism, where sub modules are included into an outer page.
15968  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15969  * 
15970  * Bootstrap Roo Included elements
15971  *
15972  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15973  * hence confusing the component builder as it thinks there are multiple top level elements. 
15974  *
15975  * 
15976  * 
15977  * @extends Roo.util.Observable
15978  * @constructor
15979  * @param cfg {Object} configuration of component
15980  * 
15981  */
15982 Roo.XComponent = function(cfg) {
15983     Roo.apply(this, cfg);
15984     this.addEvents({ 
15985         /**
15986              * @event built
15987              * Fires when this the componnt is built
15988              * @param {Roo.XComponent} c the component
15989              */
15990         'built' : true
15991         
15992     });
15993     this.region = this.region || 'center'; // default..
15994     Roo.XComponent.register(this);
15995     this.modules = false;
15996     this.el = false; // where the layout goes..
15997     
15998     
15999 }
16000 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16001     /**
16002      * @property el
16003      * The created element (with Roo.factory())
16004      * @type {Roo.Layout}
16005      */
16006     el  : false,
16007     
16008     /**
16009      * @property el
16010      * for BC  - use el in new code
16011      * @type {Roo.Layout}
16012      */
16013     panel : false,
16014     
16015     /**
16016      * @property layout
16017      * for BC  - use el in new code
16018      * @type {Roo.Layout}
16019      */
16020     layout : false,
16021     
16022      /**
16023      * @cfg {Function|boolean} disabled
16024      * If this module is disabled by some rule, return true from the funtion
16025      */
16026     disabled : false,
16027     
16028     /**
16029      * @cfg {String} parent 
16030      * Name of parent element which it get xtype added to..
16031      */
16032     parent: false,
16033     
16034     /**
16035      * @cfg {String} order
16036      * Used to set the order in which elements are created (usefull for multiple tabs)
16037      */
16038     
16039     order : false,
16040     /**
16041      * @cfg {String} name
16042      * String to display while loading.
16043      */
16044     name : false,
16045     /**
16046      * @cfg {String} region
16047      * Region to render component to (defaults to center)
16048      */
16049     region : 'center',
16050     
16051     /**
16052      * @cfg {Array} items
16053      * A single item array - the first element is the root of the tree..
16054      * It's done this way to stay compatible with the Xtype system...
16055      */
16056     items : false,
16057     
16058     /**
16059      * @property _tree
16060      * The method that retuns the tree of parts that make up this compoennt 
16061      * @type {function}
16062      */
16063     _tree  : false,
16064     
16065      /**
16066      * render
16067      * render element to dom or tree
16068      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16069      */
16070     
16071     render : function(el)
16072     {
16073         
16074         el = el || false;
16075         var hp = this.parent ? 1 : 0;
16076         Roo.debug &&  Roo.log(this);
16077         
16078         var tree = this._tree ? this._tree() : this.tree();
16079
16080         
16081         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16082             // if parent is a '#.....' string, then let's use that..
16083             var ename = this.parent.substr(1);
16084             this.parent = false;
16085             Roo.debug && Roo.log(ename);
16086             switch (ename) {
16087                 case 'bootstrap-body':
16088                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16089                         // this is the BorderLayout standard?
16090                        this.parent = { el : true };
16091                        break;
16092                     }
16093                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16094                         // need to insert stuff...
16095                         this.parent =  {
16096                              el : new Roo.bootstrap.layout.Border({
16097                                  el : document.body, 
16098                      
16099                                  center: {
16100                                     titlebar: false,
16101                                     autoScroll:false,
16102                                     closeOnTab: true,
16103                                     tabPosition: 'top',
16104                                       //resizeTabs: true,
16105                                     alwaysShowTabs: true,
16106                                     hideTabs: false
16107                                      //minTabWidth: 140
16108                                  }
16109                              })
16110                         
16111                          };
16112                          break;
16113                     }
16114                          
16115                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16116                         this.parent = { el :  new  Roo.bootstrap.Body() };
16117                         Roo.debug && Roo.log("setting el to doc body");
16118                          
16119                     } else {
16120                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16121                     }
16122                     break;
16123                 case 'bootstrap':
16124                     this.parent = { el : true};
16125                     // fall through
16126                 default:
16127                     el = Roo.get(ename);
16128                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16129                         this.parent = { el : true};
16130                     }
16131                     
16132                     break;
16133             }
16134                 
16135             
16136             if (!el && !this.parent) {
16137                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16138                 return;
16139             }
16140         }
16141         
16142         Roo.debug && Roo.log("EL:");
16143         Roo.debug && Roo.log(el);
16144         Roo.debug && Roo.log("this.parent.el:");
16145         Roo.debug && Roo.log(this.parent.el);
16146         
16147
16148         // altertive root elements ??? - we need a better way to indicate these.
16149         var is_alt = Roo.XComponent.is_alt ||
16150                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16151                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16152                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16153         
16154         
16155         
16156         if (!this.parent && is_alt) {
16157             //el = Roo.get(document.body);
16158             this.parent = { el : true };
16159         }
16160             
16161             
16162         
16163         if (!this.parent) {
16164             
16165             Roo.debug && Roo.log("no parent - creating one");
16166             
16167             el = el ? Roo.get(el) : false;      
16168             
16169             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16170                 
16171                 this.parent =  {
16172                     el : new Roo.bootstrap.layout.Border({
16173                         el: el || document.body,
16174                     
16175                         center: {
16176                             titlebar: false,
16177                             autoScroll:false,
16178                             closeOnTab: true,
16179                             tabPosition: 'top',
16180                              //resizeTabs: true,
16181                             alwaysShowTabs: false,
16182                             hideTabs: true,
16183                             minTabWidth: 140,
16184                             overflow: 'visible'
16185                          }
16186                      })
16187                 };
16188             } else {
16189             
16190                 // it's a top level one..
16191                 this.parent =  {
16192                     el : new Roo.BorderLayout(el || document.body, {
16193                         center: {
16194                             titlebar: false,
16195                             autoScroll:false,
16196                             closeOnTab: true,
16197                             tabPosition: 'top',
16198                              //resizeTabs: true,
16199                             alwaysShowTabs: el && hp? false :  true,
16200                             hideTabs: el || !hp ? true :  false,
16201                             minTabWidth: 140
16202                          }
16203                     })
16204                 };
16205             }
16206         }
16207         
16208         if (!this.parent.el) {
16209                 // probably an old style ctor, which has been disabled.
16210                 return;
16211
16212         }
16213                 // The 'tree' method is  '_tree now' 
16214             
16215         tree.region = tree.region || this.region;
16216         var is_body = false;
16217         if (this.parent.el === true) {
16218             // bootstrap... - body..
16219             if (el) {
16220                 tree.el = el;
16221             }
16222             this.parent.el = Roo.factory(tree);
16223             is_body = true;
16224         }
16225         
16226         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16227         this.fireEvent('built', this);
16228         
16229         this.panel = this.el;
16230         this.layout = this.panel.layout;
16231         this.parentLayout = this.parent.layout  || false;  
16232          
16233     }
16234     
16235 });
16236
16237 Roo.apply(Roo.XComponent, {
16238     /**
16239      * @property  hideProgress
16240      * true to disable the building progress bar.. usefull on single page renders.
16241      * @type Boolean
16242      */
16243     hideProgress : false,
16244     /**
16245      * @property  buildCompleted
16246      * True when the builder has completed building the interface.
16247      * @type Boolean
16248      */
16249     buildCompleted : false,
16250      
16251     /**
16252      * @property  topModule
16253      * the upper most module - uses document.element as it's constructor.
16254      * @type Object
16255      */
16256      
16257     topModule  : false,
16258       
16259     /**
16260      * @property  modules
16261      * array of modules to be created by registration system.
16262      * @type {Array} of Roo.XComponent
16263      */
16264     
16265     modules : [],
16266     /**
16267      * @property  elmodules
16268      * array of modules to be created by which use #ID 
16269      * @type {Array} of Roo.XComponent
16270      */
16271      
16272     elmodules : [],
16273
16274      /**
16275      * @property  is_alt
16276      * Is an alternative Root - normally used by bootstrap or other systems,
16277      *    where the top element in the tree can wrap 'body' 
16278      * @type {boolean}  (default false)
16279      */
16280      
16281     is_alt : false,
16282     /**
16283      * @property  build_from_html
16284      * Build elements from html - used by bootstrap HTML stuff 
16285      *    - this is cleared after build is completed
16286      * @type {boolean}    (default false)
16287      */
16288      
16289     build_from_html : false,
16290     /**
16291      * Register components to be built later.
16292      *
16293      * This solves the following issues
16294      * - Building is not done on page load, but after an authentication process has occured.
16295      * - Interface elements are registered on page load
16296      * - Parent Interface elements may not be loaded before child, so this handles that..
16297      * 
16298      *
16299      * example:
16300      * 
16301      * MyApp.register({
16302           order : '000001',
16303           module : 'Pman.Tab.projectMgr',
16304           region : 'center',
16305           parent : 'Pman.layout',
16306           disabled : false,  // or use a function..
16307         })
16308      
16309      * * @param {Object} details about module
16310      */
16311     register : function(obj) {
16312                 
16313         Roo.XComponent.event.fireEvent('register', obj);
16314         switch(typeof(obj.disabled) ) {
16315                 
16316             case 'undefined':
16317                 break;
16318             
16319             case 'function':
16320                 if ( obj.disabled() ) {
16321                         return;
16322                 }
16323                 break;
16324             
16325             default:
16326                 if (obj.disabled) {
16327                         return;
16328                 }
16329                 break;
16330         }
16331                 
16332         this.modules.push(obj);
16333          
16334     },
16335     /**
16336      * convert a string to an object..
16337      * eg. 'AAA.BBB' -> finds AAA.BBB
16338
16339      */
16340     
16341     toObject : function(str)
16342     {
16343         if (!str || typeof(str) == 'object') {
16344             return str;
16345         }
16346         if (str.substring(0,1) == '#') {
16347             return str;
16348         }
16349
16350         var ar = str.split('.');
16351         var rt, o;
16352         rt = ar.shift();
16353             /** eval:var:o */
16354         try {
16355             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16356         } catch (e) {
16357             throw "Module not found : " + str;
16358         }
16359         
16360         if (o === false) {
16361             throw "Module not found : " + str;
16362         }
16363         Roo.each(ar, function(e) {
16364             if (typeof(o[e]) == 'undefined') {
16365                 throw "Module not found : " + str;
16366             }
16367             o = o[e];
16368         });
16369         
16370         return o;
16371         
16372     },
16373     
16374     
16375     /**
16376      * move modules into their correct place in the tree..
16377      * 
16378      */
16379     preBuild : function ()
16380     {
16381         var _t = this;
16382         Roo.each(this.modules , function (obj)
16383         {
16384             Roo.XComponent.event.fireEvent('beforebuild', obj);
16385             
16386             var opar = obj.parent;
16387             try { 
16388                 obj.parent = this.toObject(opar);
16389             } catch(e) {
16390                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16391                 return;
16392             }
16393             
16394             if (!obj.parent) {
16395                 Roo.debug && Roo.log("GOT top level module");
16396                 Roo.debug && Roo.log(obj);
16397                 obj.modules = new Roo.util.MixedCollection(false, 
16398                     function(o) { return o.order + '' }
16399                 );
16400                 this.topModule = obj;
16401                 return;
16402             }
16403                         // parent is a string (usually a dom element name..)
16404             if (typeof(obj.parent) == 'string') {
16405                 this.elmodules.push(obj);
16406                 return;
16407             }
16408             if (obj.parent.constructor != Roo.XComponent) {
16409                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16410             }
16411             if (!obj.parent.modules) {
16412                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16413                     function(o) { return o.order + '' }
16414                 );
16415             }
16416             if (obj.parent.disabled) {
16417                 obj.disabled = true;
16418             }
16419             obj.parent.modules.add(obj);
16420         }, this);
16421     },
16422     
16423      /**
16424      * make a list of modules to build.
16425      * @return {Array} list of modules. 
16426      */ 
16427     
16428     buildOrder : function()
16429     {
16430         var _this = this;
16431         var cmp = function(a,b) {   
16432             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16433         };
16434         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16435             throw "No top level modules to build";
16436         }
16437         
16438         // make a flat list in order of modules to build.
16439         var mods = this.topModule ? [ this.topModule ] : [];
16440                 
16441         
16442         // elmodules (is a list of DOM based modules )
16443         Roo.each(this.elmodules, function(e) {
16444             mods.push(e);
16445             if (!this.topModule &&
16446                 typeof(e.parent) == 'string' &&
16447                 e.parent.substring(0,1) == '#' &&
16448                 Roo.get(e.parent.substr(1))
16449                ) {
16450                 
16451                 _this.topModule = e;
16452             }
16453             
16454         });
16455
16456         
16457         // add modules to their parents..
16458         var addMod = function(m) {
16459             Roo.debug && Roo.log("build Order: add: " + m.name);
16460                 
16461             mods.push(m);
16462             if (m.modules && !m.disabled) {
16463                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16464                 m.modules.keySort('ASC',  cmp );
16465                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16466     
16467                 m.modules.each(addMod);
16468             } else {
16469                 Roo.debug && Roo.log("build Order: no child modules");
16470             }
16471             // not sure if this is used any more..
16472             if (m.finalize) {
16473                 m.finalize.name = m.name + " (clean up) ";
16474                 mods.push(m.finalize);
16475             }
16476             
16477         }
16478         if (this.topModule && this.topModule.modules) { 
16479             this.topModule.modules.keySort('ASC',  cmp );
16480             this.topModule.modules.each(addMod);
16481         } 
16482         return mods;
16483     },
16484     
16485      /**
16486      * Build the registered modules.
16487      * @param {Object} parent element.
16488      * @param {Function} optional method to call after module has been added.
16489      * 
16490      */ 
16491    
16492     build : function(opts) 
16493     {
16494         
16495         if (typeof(opts) != 'undefined') {
16496             Roo.apply(this,opts);
16497         }
16498         
16499         this.preBuild();
16500         var mods = this.buildOrder();
16501       
16502         //this.allmods = mods;
16503         //Roo.debug && Roo.log(mods);
16504         //return;
16505         if (!mods.length) { // should not happen
16506             throw "NO modules!!!";
16507         }
16508         
16509         
16510         var msg = "Building Interface...";
16511         // flash it up as modal - so we store the mask!?
16512         if (!this.hideProgress && Roo.MessageBox) {
16513             Roo.MessageBox.show({ title: 'loading' });
16514             Roo.MessageBox.show({
16515                title: "Please wait...",
16516                msg: msg,
16517                width:450,
16518                progress:true,
16519                closable:false,
16520                modal: false
16521               
16522             });
16523         }
16524         var total = mods.length;
16525         
16526         var _this = this;
16527         var progressRun = function() {
16528             if (!mods.length) {
16529                 Roo.debug && Roo.log('hide?');
16530                 if (!this.hideProgress && Roo.MessageBox) {
16531                     Roo.MessageBox.hide();
16532                 }
16533                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16534                 
16535                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16536                 
16537                 // THE END...
16538                 return false;   
16539             }
16540             
16541             var m = mods.shift();
16542             
16543             
16544             Roo.debug && Roo.log(m);
16545             // not sure if this is supported any more.. - modules that are are just function
16546             if (typeof(m) == 'function') { 
16547                 m.call(this);
16548                 return progressRun.defer(10, _this);
16549             } 
16550             
16551             
16552             msg = "Building Interface " + (total  - mods.length) + 
16553                     " of " + total + 
16554                     (m.name ? (' - ' + m.name) : '');
16555                         Roo.debug && Roo.log(msg);
16556             if (!_this.hideProgress &&  Roo.MessageBox) { 
16557                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16558             }
16559             
16560          
16561             // is the module disabled?
16562             var disabled = (typeof(m.disabled) == 'function') ?
16563                 m.disabled.call(m.module.disabled) : m.disabled;    
16564             
16565             
16566             if (disabled) {
16567                 return progressRun(); // we do not update the display!
16568             }
16569             
16570             // now build 
16571             
16572                         
16573                         
16574             m.render();
16575             // it's 10 on top level, and 1 on others??? why...
16576             return progressRun.defer(10, _this);
16577              
16578         }
16579         progressRun.defer(1, _this);
16580      
16581         
16582         
16583     },
16584         
16585         
16586         /**
16587          * Event Object.
16588          *
16589          *
16590          */
16591         event: false, 
16592     /**
16593          * wrapper for event.on - aliased later..  
16594          * Typically use to register a event handler for register:
16595          *
16596          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16597          *
16598          */
16599     on : false
16600    
16601     
16602     
16603 });
16604
16605 Roo.XComponent.event = new Roo.util.Observable({
16606                 events : { 
16607                         /**
16608                          * @event register
16609                          * Fires when an Component is registered,
16610                          * set the disable property on the Component to stop registration.
16611                          * @param {Roo.XComponent} c the component being registerd.
16612                          * 
16613                          */
16614                         'register' : true,
16615             /**
16616                          * @event beforebuild
16617                          * Fires before each Component is built
16618                          * can be used to apply permissions.
16619                          * @param {Roo.XComponent} c the component being registerd.
16620                          * 
16621                          */
16622                         'beforebuild' : true,
16623                         /**
16624                          * @event buildcomplete
16625                          * Fires on the top level element when all elements have been built
16626                          * @param {Roo.XComponent} the top level component.
16627                          */
16628                         'buildcomplete' : true
16629                         
16630                 }
16631 });
16632
16633 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16634  //
16635  /**
16636  * marked - a markdown parser
16637  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16638  * https://github.com/chjj/marked
16639  */
16640
16641
16642 /**
16643  *
16644  * Roo.Markdown - is a very crude wrapper around marked..
16645  *
16646  * usage:
16647  * 
16648  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16649  * 
16650  * Note: move the sample code to the bottom of this
16651  * file before uncommenting it.
16652  *
16653  */
16654
16655 Roo.Markdown = {};
16656 Roo.Markdown.toHtml = function(text) {
16657     
16658     var c = new Roo.Markdown.marked.setOptions({
16659             renderer: new Roo.Markdown.marked.Renderer(),
16660             gfm: true,
16661             tables: true,
16662             breaks: false,
16663             pedantic: false,
16664             sanitize: false,
16665             smartLists: true,
16666             smartypants: false
16667           });
16668     // A FEW HACKS!!?
16669     
16670     text = text.replace(/\\\n/g,' ');
16671     return Roo.Markdown.marked(text);
16672 };
16673 //
16674 // converter
16675 //
16676 // Wraps all "globals" so that the only thing
16677 // exposed is makeHtml().
16678 //
16679 (function() {
16680     
16681     /**
16682      * Block-Level Grammar
16683      */
16684     
16685     var block = {
16686       newline: /^\n+/,
16687       code: /^( {4}[^\n]+\n*)+/,
16688       fences: noop,
16689       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16690       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16691       nptable: noop,
16692       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16693       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16694       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16695       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16696       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16697       table: noop,
16698       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16699       text: /^[^\n]+/
16700     };
16701     
16702     block.bullet = /(?:[*+-]|\d+\.)/;
16703     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16704     block.item = replace(block.item, 'gm')
16705       (/bull/g, block.bullet)
16706       ();
16707     
16708     block.list = replace(block.list)
16709       (/bull/g, block.bullet)
16710       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16711       ('def', '\\n+(?=' + block.def.source + ')')
16712       ();
16713     
16714     block.blockquote = replace(block.blockquote)
16715       ('def', block.def)
16716       ();
16717     
16718     block._tag = '(?!(?:'
16719       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16720       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16721       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16722     
16723     block.html = replace(block.html)
16724       ('comment', /<!--[\s\S]*?-->/)
16725       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16726       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16727       (/tag/g, block._tag)
16728       ();
16729     
16730     block.paragraph = replace(block.paragraph)
16731       ('hr', block.hr)
16732       ('heading', block.heading)
16733       ('lheading', block.lheading)
16734       ('blockquote', block.blockquote)
16735       ('tag', '<' + block._tag)
16736       ('def', block.def)
16737       ();
16738     
16739     /**
16740      * Normal Block Grammar
16741      */
16742     
16743     block.normal = merge({}, block);
16744     
16745     /**
16746      * GFM Block Grammar
16747      */
16748     
16749     block.gfm = merge({}, block.normal, {
16750       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16751       paragraph: /^/,
16752       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16753     });
16754     
16755     block.gfm.paragraph = replace(block.paragraph)
16756       ('(?!', '(?!'
16757         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16758         + block.list.source.replace('\\1', '\\3') + '|')
16759       ();
16760     
16761     /**
16762      * GFM + Tables Block Grammar
16763      */
16764     
16765     block.tables = merge({}, block.gfm, {
16766       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16767       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16768     });
16769     
16770     /**
16771      * Block Lexer
16772      */
16773     
16774     function Lexer(options) {
16775       this.tokens = [];
16776       this.tokens.links = {};
16777       this.options = options || marked.defaults;
16778       this.rules = block.normal;
16779     
16780       if (this.options.gfm) {
16781         if (this.options.tables) {
16782           this.rules = block.tables;
16783         } else {
16784           this.rules = block.gfm;
16785         }
16786       }
16787     }
16788     
16789     /**
16790      * Expose Block Rules
16791      */
16792     
16793     Lexer.rules = block;
16794     
16795     /**
16796      * Static Lex Method
16797      */
16798     
16799     Lexer.lex = function(src, options) {
16800       var lexer = new Lexer(options);
16801       return lexer.lex(src);
16802     };
16803     
16804     /**
16805      * Preprocessing
16806      */
16807     
16808     Lexer.prototype.lex = function(src) {
16809       src = src
16810         .replace(/\r\n|\r/g, '\n')
16811         .replace(/\t/g, '    ')
16812         .replace(/\u00a0/g, ' ')
16813         .replace(/\u2424/g, '\n');
16814     
16815       return this.token(src, true);
16816     };
16817     
16818     /**
16819      * Lexing
16820      */
16821     
16822     Lexer.prototype.token = function(src, top, bq) {
16823       var src = src.replace(/^ +$/gm, '')
16824         , next
16825         , loose
16826         , cap
16827         , bull
16828         , b
16829         , item
16830         , space
16831         , i
16832         , l;
16833     
16834       while (src) {
16835         // newline
16836         if (cap = this.rules.newline.exec(src)) {
16837           src = src.substring(cap[0].length);
16838           if (cap[0].length > 1) {
16839             this.tokens.push({
16840               type: 'space'
16841             });
16842           }
16843         }
16844     
16845         // code
16846         if (cap = this.rules.code.exec(src)) {
16847           src = src.substring(cap[0].length);
16848           cap = cap[0].replace(/^ {4}/gm, '');
16849           this.tokens.push({
16850             type: 'code',
16851             text: !this.options.pedantic
16852               ? cap.replace(/\n+$/, '')
16853               : cap
16854           });
16855           continue;
16856         }
16857     
16858         // fences (gfm)
16859         if (cap = this.rules.fences.exec(src)) {
16860           src = src.substring(cap[0].length);
16861           this.tokens.push({
16862             type: 'code',
16863             lang: cap[2],
16864             text: cap[3] || ''
16865           });
16866           continue;
16867         }
16868     
16869         // heading
16870         if (cap = this.rules.heading.exec(src)) {
16871           src = src.substring(cap[0].length);
16872           this.tokens.push({
16873             type: 'heading',
16874             depth: cap[1].length,
16875             text: cap[2]
16876           });
16877           continue;
16878         }
16879     
16880         // table no leading pipe (gfm)
16881         if (top && (cap = this.rules.nptable.exec(src))) {
16882           src = src.substring(cap[0].length);
16883     
16884           item = {
16885             type: 'table',
16886             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16887             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16888             cells: cap[3].replace(/\n$/, '').split('\n')
16889           };
16890     
16891           for (i = 0; i < item.align.length; i++) {
16892             if (/^ *-+: *$/.test(item.align[i])) {
16893               item.align[i] = 'right';
16894             } else if (/^ *:-+: *$/.test(item.align[i])) {
16895               item.align[i] = 'center';
16896             } else if (/^ *:-+ *$/.test(item.align[i])) {
16897               item.align[i] = 'left';
16898             } else {
16899               item.align[i] = null;
16900             }
16901           }
16902     
16903           for (i = 0; i < item.cells.length; i++) {
16904             item.cells[i] = item.cells[i].split(/ *\| */);
16905           }
16906     
16907           this.tokens.push(item);
16908     
16909           continue;
16910         }
16911     
16912         // lheading
16913         if (cap = this.rules.lheading.exec(src)) {
16914           src = src.substring(cap[0].length);
16915           this.tokens.push({
16916             type: 'heading',
16917             depth: cap[2] === '=' ? 1 : 2,
16918             text: cap[1]
16919           });
16920           continue;
16921         }
16922     
16923         // hr
16924         if (cap = this.rules.hr.exec(src)) {
16925           src = src.substring(cap[0].length);
16926           this.tokens.push({
16927             type: 'hr'
16928           });
16929           continue;
16930         }
16931     
16932         // blockquote
16933         if (cap = this.rules.blockquote.exec(src)) {
16934           src = src.substring(cap[0].length);
16935     
16936           this.tokens.push({
16937             type: 'blockquote_start'
16938           });
16939     
16940           cap = cap[0].replace(/^ *> ?/gm, '');
16941     
16942           // Pass `top` to keep the current
16943           // "toplevel" state. This is exactly
16944           // how markdown.pl works.
16945           this.token(cap, top, true);
16946     
16947           this.tokens.push({
16948             type: 'blockquote_end'
16949           });
16950     
16951           continue;
16952         }
16953     
16954         // list
16955         if (cap = this.rules.list.exec(src)) {
16956           src = src.substring(cap[0].length);
16957           bull = cap[2];
16958     
16959           this.tokens.push({
16960             type: 'list_start',
16961             ordered: bull.length > 1
16962           });
16963     
16964           // Get each top-level item.
16965           cap = cap[0].match(this.rules.item);
16966     
16967           next = false;
16968           l = cap.length;
16969           i = 0;
16970     
16971           for (; i < l; i++) {
16972             item = cap[i];
16973     
16974             // Remove the list item's bullet
16975             // so it is seen as the next token.
16976             space = item.length;
16977             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16978     
16979             // Outdent whatever the
16980             // list item contains. Hacky.
16981             if (~item.indexOf('\n ')) {
16982               space -= item.length;
16983               item = !this.options.pedantic
16984                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16985                 : item.replace(/^ {1,4}/gm, '');
16986             }
16987     
16988             // Determine whether the next list item belongs here.
16989             // Backpedal if it does not belong in this list.
16990             if (this.options.smartLists && i !== l - 1) {
16991               b = block.bullet.exec(cap[i + 1])[0];
16992               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16993                 src = cap.slice(i + 1).join('\n') + src;
16994                 i = l - 1;
16995               }
16996             }
16997     
16998             // Determine whether item is loose or not.
16999             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17000             // for discount behavior.
17001             loose = next || /\n\n(?!\s*$)/.test(item);
17002             if (i !== l - 1) {
17003               next = item.charAt(item.length - 1) === '\n';
17004               if (!loose) { loose = next; }
17005             }
17006     
17007             this.tokens.push({
17008               type: loose
17009                 ? 'loose_item_start'
17010                 : 'list_item_start'
17011             });
17012     
17013             // Recurse.
17014             this.token(item, false, bq);
17015     
17016             this.tokens.push({
17017               type: 'list_item_end'
17018             });
17019           }
17020     
17021           this.tokens.push({
17022             type: 'list_end'
17023           });
17024     
17025           continue;
17026         }
17027     
17028         // html
17029         if (cap = this.rules.html.exec(src)) {
17030           src = src.substring(cap[0].length);
17031           this.tokens.push({
17032             type: this.options.sanitize
17033               ? 'paragraph'
17034               : 'html',
17035             pre: !this.options.sanitizer
17036               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17037             text: cap[0]
17038           });
17039           continue;
17040         }
17041     
17042         // def
17043         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17044           src = src.substring(cap[0].length);
17045           this.tokens.links[cap[1].toLowerCase()] = {
17046             href: cap[2],
17047             title: cap[3]
17048           };
17049           continue;
17050         }
17051     
17052         // table (gfm)
17053         if (top && (cap = this.rules.table.exec(src))) {
17054           src = src.substring(cap[0].length);
17055     
17056           item = {
17057             type: 'table',
17058             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17059             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17060             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17061           };
17062     
17063           for (i = 0; i < item.align.length; i++) {
17064             if (/^ *-+: *$/.test(item.align[i])) {
17065               item.align[i] = 'right';
17066             } else if (/^ *:-+: *$/.test(item.align[i])) {
17067               item.align[i] = 'center';
17068             } else if (/^ *:-+ *$/.test(item.align[i])) {
17069               item.align[i] = 'left';
17070             } else {
17071               item.align[i] = null;
17072             }
17073           }
17074     
17075           for (i = 0; i < item.cells.length; i++) {
17076             item.cells[i] = item.cells[i]
17077               .replace(/^ *\| *| *\| *$/g, '')
17078               .split(/ *\| */);
17079           }
17080     
17081           this.tokens.push(item);
17082     
17083           continue;
17084         }
17085     
17086         // top-level paragraph
17087         if (top && (cap = this.rules.paragraph.exec(src))) {
17088           src = src.substring(cap[0].length);
17089           this.tokens.push({
17090             type: 'paragraph',
17091             text: cap[1].charAt(cap[1].length - 1) === '\n'
17092               ? cap[1].slice(0, -1)
17093               : cap[1]
17094           });
17095           continue;
17096         }
17097     
17098         // text
17099         if (cap = this.rules.text.exec(src)) {
17100           // Top-level should never reach here.
17101           src = src.substring(cap[0].length);
17102           this.tokens.push({
17103             type: 'text',
17104             text: cap[0]
17105           });
17106           continue;
17107         }
17108     
17109         if (src) {
17110           throw new
17111             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17112         }
17113       }
17114     
17115       return this.tokens;
17116     };
17117     
17118     /**
17119      * Inline-Level Grammar
17120      */
17121     
17122     var inline = {
17123       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17124       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17125       url: noop,
17126       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17127       link: /^!?\[(inside)\]\(href\)/,
17128       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17129       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17130       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17131       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17132       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17133       br: /^ {2,}\n(?!\s*$)/,
17134       del: noop,
17135       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17136     };
17137     
17138     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17139     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17140     
17141     inline.link = replace(inline.link)
17142       ('inside', inline._inside)
17143       ('href', inline._href)
17144       ();
17145     
17146     inline.reflink = replace(inline.reflink)
17147       ('inside', inline._inside)
17148       ();
17149     
17150     /**
17151      * Normal Inline Grammar
17152      */
17153     
17154     inline.normal = merge({}, inline);
17155     
17156     /**
17157      * Pedantic Inline Grammar
17158      */
17159     
17160     inline.pedantic = merge({}, inline.normal, {
17161       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17162       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17163     });
17164     
17165     /**
17166      * GFM Inline Grammar
17167      */
17168     
17169     inline.gfm = merge({}, inline.normal, {
17170       escape: replace(inline.escape)('])', '~|])')(),
17171       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17172       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17173       text: replace(inline.text)
17174         (']|', '~]|')
17175         ('|', '|https?://|')
17176         ()
17177     });
17178     
17179     /**
17180      * GFM + Line Breaks Inline Grammar
17181      */
17182     
17183     inline.breaks = merge({}, inline.gfm, {
17184       br: replace(inline.br)('{2,}', '*')(),
17185       text: replace(inline.gfm.text)('{2,}', '*')()
17186     });
17187     
17188     /**
17189      * Inline Lexer & Compiler
17190      */
17191     
17192     function InlineLexer(links, options) {
17193       this.options = options || marked.defaults;
17194       this.links = links;
17195       this.rules = inline.normal;
17196       this.renderer = this.options.renderer || new Renderer;
17197       this.renderer.options = this.options;
17198     
17199       if (!this.links) {
17200         throw new
17201           Error('Tokens array requires a `links` property.');
17202       }
17203     
17204       if (this.options.gfm) {
17205         if (this.options.breaks) {
17206           this.rules = inline.breaks;
17207         } else {
17208           this.rules = inline.gfm;
17209         }
17210       } else if (this.options.pedantic) {
17211         this.rules = inline.pedantic;
17212       }
17213     }
17214     
17215     /**
17216      * Expose Inline Rules
17217      */
17218     
17219     InlineLexer.rules = inline;
17220     
17221     /**
17222      * Static Lexing/Compiling Method
17223      */
17224     
17225     InlineLexer.output = function(src, links, options) {
17226       var inline = new InlineLexer(links, options);
17227       return inline.output(src);
17228     };
17229     
17230     /**
17231      * Lexing/Compiling
17232      */
17233     
17234     InlineLexer.prototype.output = function(src) {
17235       var out = ''
17236         , link
17237         , text
17238         , href
17239         , cap;
17240     
17241       while (src) {
17242         // escape
17243         if (cap = this.rules.escape.exec(src)) {
17244           src = src.substring(cap[0].length);
17245           out += cap[1];
17246           continue;
17247         }
17248     
17249         // autolink
17250         if (cap = this.rules.autolink.exec(src)) {
17251           src = src.substring(cap[0].length);
17252           if (cap[2] === '@') {
17253             text = cap[1].charAt(6) === ':'
17254               ? this.mangle(cap[1].substring(7))
17255               : this.mangle(cap[1]);
17256             href = this.mangle('mailto:') + text;
17257           } else {
17258             text = escape(cap[1]);
17259             href = text;
17260           }
17261           out += this.renderer.link(href, null, text);
17262           continue;
17263         }
17264     
17265         // url (gfm)
17266         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17267           src = src.substring(cap[0].length);
17268           text = escape(cap[1]);
17269           href = text;
17270           out += this.renderer.link(href, null, text);
17271           continue;
17272         }
17273     
17274         // tag
17275         if (cap = this.rules.tag.exec(src)) {
17276           if (!this.inLink && /^<a /i.test(cap[0])) {
17277             this.inLink = true;
17278           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17279             this.inLink = false;
17280           }
17281           src = src.substring(cap[0].length);
17282           out += this.options.sanitize
17283             ? this.options.sanitizer
17284               ? this.options.sanitizer(cap[0])
17285               : escape(cap[0])
17286             : cap[0];
17287           continue;
17288         }
17289     
17290         // link
17291         if (cap = this.rules.link.exec(src)) {
17292           src = src.substring(cap[0].length);
17293           this.inLink = true;
17294           out += this.outputLink(cap, {
17295             href: cap[2],
17296             title: cap[3]
17297           });
17298           this.inLink = false;
17299           continue;
17300         }
17301     
17302         // reflink, nolink
17303         if ((cap = this.rules.reflink.exec(src))
17304             || (cap = this.rules.nolink.exec(src))) {
17305           src = src.substring(cap[0].length);
17306           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17307           link = this.links[link.toLowerCase()];
17308           if (!link || !link.href) {
17309             out += cap[0].charAt(0);
17310             src = cap[0].substring(1) + src;
17311             continue;
17312           }
17313           this.inLink = true;
17314           out += this.outputLink(cap, link);
17315           this.inLink = false;
17316           continue;
17317         }
17318     
17319         // strong
17320         if (cap = this.rules.strong.exec(src)) {
17321           src = src.substring(cap[0].length);
17322           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17323           continue;
17324         }
17325     
17326         // em
17327         if (cap = this.rules.em.exec(src)) {
17328           src = src.substring(cap[0].length);
17329           out += this.renderer.em(this.output(cap[2] || cap[1]));
17330           continue;
17331         }
17332     
17333         // code
17334         if (cap = this.rules.code.exec(src)) {
17335           src = src.substring(cap[0].length);
17336           out += this.renderer.codespan(escape(cap[2], true));
17337           continue;
17338         }
17339     
17340         // br
17341         if (cap = this.rules.br.exec(src)) {
17342           src = src.substring(cap[0].length);
17343           out += this.renderer.br();
17344           continue;
17345         }
17346     
17347         // del (gfm)
17348         if (cap = this.rules.del.exec(src)) {
17349           src = src.substring(cap[0].length);
17350           out += this.renderer.del(this.output(cap[1]));
17351           continue;
17352         }
17353     
17354         // text
17355         if (cap = this.rules.text.exec(src)) {
17356           src = src.substring(cap[0].length);
17357           out += this.renderer.text(escape(this.smartypants(cap[0])));
17358           continue;
17359         }
17360     
17361         if (src) {
17362           throw new
17363             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17364         }
17365       }
17366     
17367       return out;
17368     };
17369     
17370     /**
17371      * Compile Link
17372      */
17373     
17374     InlineLexer.prototype.outputLink = function(cap, link) {
17375       var href = escape(link.href)
17376         , title = link.title ? escape(link.title) : null;
17377     
17378       return cap[0].charAt(0) !== '!'
17379         ? this.renderer.link(href, title, this.output(cap[1]))
17380         : this.renderer.image(href, title, escape(cap[1]));
17381     };
17382     
17383     /**
17384      * Smartypants Transformations
17385      */
17386     
17387     InlineLexer.prototype.smartypants = function(text) {
17388       if (!this.options.smartypants)  { return text; }
17389       return text
17390         // em-dashes
17391         .replace(/---/g, '\u2014')
17392         // en-dashes
17393         .replace(/--/g, '\u2013')
17394         // opening singles
17395         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17396         // closing singles & apostrophes
17397         .replace(/'/g, '\u2019')
17398         // opening doubles
17399         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17400         // closing doubles
17401         .replace(/"/g, '\u201d')
17402         // ellipses
17403         .replace(/\.{3}/g, '\u2026');
17404     };
17405     
17406     /**
17407      * Mangle Links
17408      */
17409     
17410     InlineLexer.prototype.mangle = function(text) {
17411       if (!this.options.mangle) { return text; }
17412       var out = ''
17413         , l = text.length
17414         , i = 0
17415         , ch;
17416     
17417       for (; i < l; i++) {
17418         ch = text.charCodeAt(i);
17419         if (Math.random() > 0.5) {
17420           ch = 'x' + ch.toString(16);
17421         }
17422         out += '&#' + ch + ';';
17423       }
17424     
17425       return out;
17426     };
17427     
17428     /**
17429      * Renderer
17430      */
17431     
17432     function Renderer(options) {
17433       this.options = options || {};
17434     }
17435     
17436     Renderer.prototype.code = function(code, lang, escaped) {
17437       if (this.options.highlight) {
17438         var out = this.options.highlight(code, lang);
17439         if (out != null && out !== code) {
17440           escaped = true;
17441           code = out;
17442         }
17443       } else {
17444             // hack!!! - it's already escapeD?
17445             escaped = true;
17446       }
17447     
17448       if (!lang) {
17449         return '<pre><code>'
17450           + (escaped ? code : escape(code, true))
17451           + '\n</code></pre>';
17452       }
17453     
17454       return '<pre><code class="'
17455         + this.options.langPrefix
17456         + escape(lang, true)
17457         + '">'
17458         + (escaped ? code : escape(code, true))
17459         + '\n</code></pre>\n';
17460     };
17461     
17462     Renderer.prototype.blockquote = function(quote) {
17463       return '<blockquote>\n' + quote + '</blockquote>\n';
17464     };
17465     
17466     Renderer.prototype.html = function(html) {
17467       return html;
17468     };
17469     
17470     Renderer.prototype.heading = function(text, level, raw) {
17471       return '<h'
17472         + level
17473         + ' id="'
17474         + this.options.headerPrefix
17475         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17476         + '">'
17477         + text
17478         + '</h'
17479         + level
17480         + '>\n';
17481     };
17482     
17483     Renderer.prototype.hr = function() {
17484       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17485     };
17486     
17487     Renderer.prototype.list = function(body, ordered) {
17488       var type = ordered ? 'ol' : 'ul';
17489       return '<' + type + '>\n' + body + '</' + type + '>\n';
17490     };
17491     
17492     Renderer.prototype.listitem = function(text) {
17493       return '<li>' + text + '</li>\n';
17494     };
17495     
17496     Renderer.prototype.paragraph = function(text) {
17497       return '<p>' + text + '</p>\n';
17498     };
17499     
17500     Renderer.prototype.table = function(header, body) {
17501       return '<table class="table table-striped">\n'
17502         + '<thead>\n'
17503         + header
17504         + '</thead>\n'
17505         + '<tbody>\n'
17506         + body
17507         + '</tbody>\n'
17508         + '</table>\n';
17509     };
17510     
17511     Renderer.prototype.tablerow = function(content) {
17512       return '<tr>\n' + content + '</tr>\n';
17513     };
17514     
17515     Renderer.prototype.tablecell = function(content, flags) {
17516       var type = flags.header ? 'th' : 'td';
17517       var tag = flags.align
17518         ? '<' + type + ' style="text-align:' + flags.align + '">'
17519         : '<' + type + '>';
17520       return tag + content + '</' + type + '>\n';
17521     };
17522     
17523     // span level renderer
17524     Renderer.prototype.strong = function(text) {
17525       return '<strong>' + text + '</strong>';
17526     };
17527     
17528     Renderer.prototype.em = function(text) {
17529       return '<em>' + text + '</em>';
17530     };
17531     
17532     Renderer.prototype.codespan = function(text) {
17533       return '<code>' + text + '</code>';
17534     };
17535     
17536     Renderer.prototype.br = function() {
17537       return this.options.xhtml ? '<br/>' : '<br>';
17538     };
17539     
17540     Renderer.prototype.del = function(text) {
17541       return '<del>' + text + '</del>';
17542     };
17543     
17544     Renderer.prototype.link = function(href, title, text) {
17545       if (this.options.sanitize) {
17546         try {
17547           var prot = decodeURIComponent(unescape(href))
17548             .replace(/[^\w:]/g, '')
17549             .toLowerCase();
17550         } catch (e) {
17551           return '';
17552         }
17553         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17554           return '';
17555         }
17556       }
17557       var out = '<a href="' + href + '"';
17558       if (title) {
17559         out += ' title="' + title + '"';
17560       }
17561       out += '>' + text + '</a>';
17562       return out;
17563     };
17564     
17565     Renderer.prototype.image = function(href, title, text) {
17566       var out = '<img src="' + href + '" alt="' + text + '"';
17567       if (title) {
17568         out += ' title="' + title + '"';
17569       }
17570       out += this.options.xhtml ? '/>' : '>';
17571       return out;
17572     };
17573     
17574     Renderer.prototype.text = function(text) {
17575       return text;
17576     };
17577     
17578     /**
17579      * Parsing & Compiling
17580      */
17581     
17582     function Parser(options) {
17583       this.tokens = [];
17584       this.token = null;
17585       this.options = options || marked.defaults;
17586       this.options.renderer = this.options.renderer || new Renderer;
17587       this.renderer = this.options.renderer;
17588       this.renderer.options = this.options;
17589     }
17590     
17591     /**
17592      * Static Parse Method
17593      */
17594     
17595     Parser.parse = function(src, options, renderer) {
17596       var parser = new Parser(options, renderer);
17597       return parser.parse(src);
17598     };
17599     
17600     /**
17601      * Parse Loop
17602      */
17603     
17604     Parser.prototype.parse = function(src) {
17605       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17606       this.tokens = src.reverse();
17607     
17608       var out = '';
17609       while (this.next()) {
17610         out += this.tok();
17611       }
17612     
17613       return out;
17614     };
17615     
17616     /**
17617      * Next Token
17618      */
17619     
17620     Parser.prototype.next = function() {
17621       return this.token = this.tokens.pop();
17622     };
17623     
17624     /**
17625      * Preview Next Token
17626      */
17627     
17628     Parser.prototype.peek = function() {
17629       return this.tokens[this.tokens.length - 1] || 0;
17630     };
17631     
17632     /**
17633      * Parse Text Tokens
17634      */
17635     
17636     Parser.prototype.parseText = function() {
17637       var body = this.token.text;
17638     
17639       while (this.peek().type === 'text') {
17640         body += '\n' + this.next().text;
17641       }
17642     
17643       return this.inline.output(body);
17644     };
17645     
17646     /**
17647      * Parse Current Token
17648      */
17649     
17650     Parser.prototype.tok = function() {
17651       switch (this.token.type) {
17652         case 'space': {
17653           return '';
17654         }
17655         case 'hr': {
17656           return this.renderer.hr();
17657         }
17658         case 'heading': {
17659           return this.renderer.heading(
17660             this.inline.output(this.token.text),
17661             this.token.depth,
17662             this.token.text);
17663         }
17664         case 'code': {
17665           return this.renderer.code(this.token.text,
17666             this.token.lang,
17667             this.token.escaped);
17668         }
17669         case 'table': {
17670           var header = ''
17671             , body = ''
17672             , i
17673             , row
17674             , cell
17675             , flags
17676             , j;
17677     
17678           // header
17679           cell = '';
17680           for (i = 0; i < this.token.header.length; i++) {
17681             flags = { header: true, align: this.token.align[i] };
17682             cell += this.renderer.tablecell(
17683               this.inline.output(this.token.header[i]),
17684               { header: true, align: this.token.align[i] }
17685             );
17686           }
17687           header += this.renderer.tablerow(cell);
17688     
17689           for (i = 0; i < this.token.cells.length; i++) {
17690             row = this.token.cells[i];
17691     
17692             cell = '';
17693             for (j = 0; j < row.length; j++) {
17694               cell += this.renderer.tablecell(
17695                 this.inline.output(row[j]),
17696                 { header: false, align: this.token.align[j] }
17697               );
17698             }
17699     
17700             body += this.renderer.tablerow(cell);
17701           }
17702           return this.renderer.table(header, body);
17703         }
17704         case 'blockquote_start': {
17705           var body = '';
17706     
17707           while (this.next().type !== 'blockquote_end') {
17708             body += this.tok();
17709           }
17710     
17711           return this.renderer.blockquote(body);
17712         }
17713         case 'list_start': {
17714           var body = ''
17715             , ordered = this.token.ordered;
17716     
17717           while (this.next().type !== 'list_end') {
17718             body += this.tok();
17719           }
17720     
17721           return this.renderer.list(body, ordered);
17722         }
17723         case 'list_item_start': {
17724           var body = '';
17725     
17726           while (this.next().type !== 'list_item_end') {
17727             body += this.token.type === 'text'
17728               ? this.parseText()
17729               : this.tok();
17730           }
17731     
17732           return this.renderer.listitem(body);
17733         }
17734         case 'loose_item_start': {
17735           var body = '';
17736     
17737           while (this.next().type !== 'list_item_end') {
17738             body += this.tok();
17739           }
17740     
17741           return this.renderer.listitem(body);
17742         }
17743         case 'html': {
17744           var html = !this.token.pre && !this.options.pedantic
17745             ? this.inline.output(this.token.text)
17746             : this.token.text;
17747           return this.renderer.html(html);
17748         }
17749         case 'paragraph': {
17750           return this.renderer.paragraph(this.inline.output(this.token.text));
17751         }
17752         case 'text': {
17753           return this.renderer.paragraph(this.parseText());
17754         }
17755       }
17756     };
17757     
17758     /**
17759      * Helpers
17760      */
17761     
17762     function escape(html, encode) {
17763       return html
17764         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17765         .replace(/</g, '&lt;')
17766         .replace(/>/g, '&gt;')
17767         .replace(/"/g, '&quot;')
17768         .replace(/'/g, '&#39;');
17769     }
17770     
17771     function unescape(html) {
17772         // explicitly match decimal, hex, and named HTML entities 
17773       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17774         n = n.toLowerCase();
17775         if (n === 'colon') { return ':'; }
17776         if (n.charAt(0) === '#') {
17777           return n.charAt(1) === 'x'
17778             ? String.fromCharCode(parseInt(n.substring(2), 16))
17779             : String.fromCharCode(+n.substring(1));
17780         }
17781         return '';
17782       });
17783     }
17784     
17785     function replace(regex, opt) {
17786       regex = regex.source;
17787       opt = opt || '';
17788       return function self(name, val) {
17789         if (!name) { return new RegExp(regex, opt); }
17790         val = val.source || val;
17791         val = val.replace(/(^|[^\[])\^/g, '$1');
17792         regex = regex.replace(name, val);
17793         return self;
17794       };
17795     }
17796     
17797     function noop() {}
17798     noop.exec = noop;
17799     
17800     function merge(obj) {
17801       var i = 1
17802         , target
17803         , key;
17804     
17805       for (; i < arguments.length; i++) {
17806         target = arguments[i];
17807         for (key in target) {
17808           if (Object.prototype.hasOwnProperty.call(target, key)) {
17809             obj[key] = target[key];
17810           }
17811         }
17812       }
17813     
17814       return obj;
17815     }
17816     
17817     
17818     /**
17819      * Marked
17820      */
17821     
17822     function marked(src, opt, callback) {
17823       if (callback || typeof opt === 'function') {
17824         if (!callback) {
17825           callback = opt;
17826           opt = null;
17827         }
17828     
17829         opt = merge({}, marked.defaults, opt || {});
17830     
17831         var highlight = opt.highlight
17832           , tokens
17833           , pending
17834           , i = 0;
17835     
17836         try {
17837           tokens = Lexer.lex(src, opt)
17838         } catch (e) {
17839           return callback(e);
17840         }
17841     
17842         pending = tokens.length;
17843     
17844         var done = function(err) {
17845           if (err) {
17846             opt.highlight = highlight;
17847             return callback(err);
17848           }
17849     
17850           var out;
17851     
17852           try {
17853             out = Parser.parse(tokens, opt);
17854           } catch (e) {
17855             err = e;
17856           }
17857     
17858           opt.highlight = highlight;
17859     
17860           return err
17861             ? callback(err)
17862             : callback(null, out);
17863         };
17864     
17865         if (!highlight || highlight.length < 3) {
17866           return done();
17867         }
17868     
17869         delete opt.highlight;
17870     
17871         if (!pending) { return done(); }
17872     
17873         for (; i < tokens.length; i++) {
17874           (function(token) {
17875             if (token.type !== 'code') {
17876               return --pending || done();
17877             }
17878             return highlight(token.text, token.lang, function(err, code) {
17879               if (err) { return done(err); }
17880               if (code == null || code === token.text) {
17881                 return --pending || done();
17882               }
17883               token.text = code;
17884               token.escaped = true;
17885               --pending || done();
17886             });
17887           })(tokens[i]);
17888         }
17889     
17890         return;
17891       }
17892       try {
17893         if (opt) { opt = merge({}, marked.defaults, opt); }
17894         return Parser.parse(Lexer.lex(src, opt), opt);
17895       } catch (e) {
17896         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17897         if ((opt || marked.defaults).silent) {
17898           return '<p>An error occured:</p><pre>'
17899             + escape(e.message + '', true)
17900             + '</pre>';
17901         }
17902         throw e;
17903       }
17904     }
17905     
17906     /**
17907      * Options
17908      */
17909     
17910     marked.options =
17911     marked.setOptions = function(opt) {
17912       merge(marked.defaults, opt);
17913       return marked;
17914     };
17915     
17916     marked.defaults = {
17917       gfm: true,
17918       tables: true,
17919       breaks: false,
17920       pedantic: false,
17921       sanitize: false,
17922       sanitizer: null,
17923       mangle: true,
17924       smartLists: false,
17925       silent: false,
17926       highlight: null,
17927       langPrefix: 'lang-',
17928       smartypants: false,
17929       headerPrefix: '',
17930       renderer: new Renderer,
17931       xhtml: false
17932     };
17933     
17934     /**
17935      * Expose
17936      */
17937     
17938     marked.Parser = Parser;
17939     marked.parser = Parser.parse;
17940     
17941     marked.Renderer = Renderer;
17942     
17943     marked.Lexer = Lexer;
17944     marked.lexer = Lexer.lex;
17945     
17946     marked.InlineLexer = InlineLexer;
17947     marked.inlineLexer = InlineLexer.output;
17948     
17949     marked.parse = marked;
17950     
17951     Roo.Markdown.marked = marked;
17952
17953 })();/*
17954  * Based on:
17955  * Ext JS Library 1.1.1
17956  * Copyright(c) 2006-2007, Ext JS, LLC.
17957  *
17958  * Originally Released Under LGPL - original licence link has changed is not relivant.
17959  *
17960  * Fork - LGPL
17961  * <script type="text/javascript">
17962  */
17963
17964
17965
17966 /*
17967  * These classes are derivatives of the similarly named classes in the YUI Library.
17968  * The original license:
17969  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17970  * Code licensed under the BSD License:
17971  * http://developer.yahoo.net/yui/license.txt
17972  */
17973
17974 (function() {
17975
17976 var Event=Roo.EventManager;
17977 var Dom=Roo.lib.Dom;
17978
17979 /**
17980  * @class Roo.dd.DragDrop
17981  * @extends Roo.util.Observable
17982  * Defines the interface and base operation of items that that can be
17983  * dragged or can be drop targets.  It was designed to be extended, overriding
17984  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17985  * Up to three html elements can be associated with a DragDrop instance:
17986  * <ul>
17987  * <li>linked element: the element that is passed into the constructor.
17988  * This is the element which defines the boundaries for interaction with
17989  * other DragDrop objects.</li>
17990  * <li>handle element(s): The drag operation only occurs if the element that
17991  * was clicked matches a handle element.  By default this is the linked
17992  * element, but there are times that you will want only a portion of the
17993  * linked element to initiate the drag operation, and the setHandleElId()
17994  * method provides a way to define this.</li>
17995  * <li>drag element: this represents the element that would be moved along
17996  * with the cursor during a drag operation.  By default, this is the linked
17997  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
17998  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17999  * </li>
18000  * </ul>
18001  * This class should not be instantiated until the onload event to ensure that
18002  * the associated elements are available.
18003  * The following would define a DragDrop obj that would interact with any
18004  * other DragDrop obj in the "group1" group:
18005  * <pre>
18006  *  dd = new Roo.dd.DragDrop("div1", "group1");
18007  * </pre>
18008  * Since none of the event handlers have been implemented, nothing would
18009  * actually happen if you were to run the code above.  Normally you would
18010  * override this class or one of the default implementations, but you can
18011  * also override the methods you want on an instance of the class...
18012  * <pre>
18013  *  dd.onDragDrop = function(e, id) {
18014  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18015  *  }
18016  * </pre>
18017  * @constructor
18018  * @param {String} id of the element that is linked to this instance
18019  * @param {String} sGroup the group of related DragDrop objects
18020  * @param {object} config an object containing configurable attributes
18021  *                Valid properties for DragDrop:
18022  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18023  */
18024 Roo.dd.DragDrop = function(id, sGroup, config) {
18025     if (id) {
18026         this.init(id, sGroup, config);
18027     }
18028     
18029 };
18030
18031 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18032
18033     /**
18034      * The id of the element associated with this object.  This is what we
18035      * refer to as the "linked element" because the size and position of
18036      * this element is used to determine when the drag and drop objects have
18037      * interacted.
18038      * @property id
18039      * @type String
18040      */
18041     id: null,
18042
18043     /**
18044      * Configuration attributes passed into the constructor
18045      * @property config
18046      * @type object
18047      */
18048     config: null,
18049
18050     /**
18051      * The id of the element that will be dragged.  By default this is same
18052      * as the linked element , but could be changed to another element. Ex:
18053      * Roo.dd.DDProxy
18054      * @property dragElId
18055      * @type String
18056      * @private
18057      */
18058     dragElId: null,
18059
18060     /**
18061      * the id of the element that initiates the drag operation.  By default
18062      * this is the linked element, but could be changed to be a child of this
18063      * element.  This lets us do things like only starting the drag when the
18064      * header element within the linked html element is clicked.
18065      * @property handleElId
18066      * @type String
18067      * @private
18068      */
18069     handleElId: null,
18070
18071     /**
18072      * An associative array of HTML tags that will be ignored if clicked.
18073      * @property invalidHandleTypes
18074      * @type {string: string}
18075      */
18076     invalidHandleTypes: null,
18077
18078     /**
18079      * An associative array of ids for elements that will be ignored if clicked
18080      * @property invalidHandleIds
18081      * @type {string: string}
18082      */
18083     invalidHandleIds: null,
18084
18085     /**
18086      * An indexted array of css class names for elements that will be ignored
18087      * if clicked.
18088      * @property invalidHandleClasses
18089      * @type string[]
18090      */
18091     invalidHandleClasses: null,
18092
18093     /**
18094      * The linked element's absolute X position at the time the drag was
18095      * started
18096      * @property startPageX
18097      * @type int
18098      * @private
18099      */
18100     startPageX: 0,
18101
18102     /**
18103      * The linked element's absolute X position at the time the drag was
18104      * started
18105      * @property startPageY
18106      * @type int
18107      * @private
18108      */
18109     startPageY: 0,
18110
18111     /**
18112      * The group defines a logical collection of DragDrop objects that are
18113      * related.  Instances only get events when interacting with other
18114      * DragDrop object in the same group.  This lets us define multiple
18115      * groups using a single DragDrop subclass if we want.
18116      * @property groups
18117      * @type {string: string}
18118      */
18119     groups: null,
18120
18121     /**
18122      * Individual drag/drop instances can be locked.  This will prevent
18123      * onmousedown start drag.
18124      * @property locked
18125      * @type boolean
18126      * @private
18127      */
18128     locked: false,
18129
18130     /**
18131      * Lock this instance
18132      * @method lock
18133      */
18134     lock: function() { this.locked = true; },
18135
18136     /**
18137      * Unlock this instace
18138      * @method unlock
18139      */
18140     unlock: function() { this.locked = false; },
18141
18142     /**
18143      * By default, all insances can be a drop target.  This can be disabled by
18144      * setting isTarget to false.
18145      * @method isTarget
18146      * @type boolean
18147      */
18148     isTarget: true,
18149
18150     /**
18151      * The padding configured for this drag and drop object for calculating
18152      * the drop zone intersection with this object.
18153      * @method padding
18154      * @type int[]
18155      */
18156     padding: null,
18157
18158     /**
18159      * Cached reference to the linked element
18160      * @property _domRef
18161      * @private
18162      */
18163     _domRef: null,
18164
18165     /**
18166      * Internal typeof flag
18167      * @property __ygDragDrop
18168      * @private
18169      */
18170     __ygDragDrop: true,
18171
18172     /**
18173      * Set to true when horizontal contraints are applied
18174      * @property constrainX
18175      * @type boolean
18176      * @private
18177      */
18178     constrainX: false,
18179
18180     /**
18181      * Set to true when vertical contraints are applied
18182      * @property constrainY
18183      * @type boolean
18184      * @private
18185      */
18186     constrainY: false,
18187
18188     /**
18189      * The left constraint
18190      * @property minX
18191      * @type int
18192      * @private
18193      */
18194     minX: 0,
18195
18196     /**
18197      * The right constraint
18198      * @property maxX
18199      * @type int
18200      * @private
18201      */
18202     maxX: 0,
18203
18204     /**
18205      * The up constraint
18206      * @property minY
18207      * @type int
18208      * @type int
18209      * @private
18210      */
18211     minY: 0,
18212
18213     /**
18214      * The down constraint
18215      * @property maxY
18216      * @type int
18217      * @private
18218      */
18219     maxY: 0,
18220
18221     /**
18222      * Maintain offsets when we resetconstraints.  Set to true when you want
18223      * the position of the element relative to its parent to stay the same
18224      * when the page changes
18225      *
18226      * @property maintainOffset
18227      * @type boolean
18228      */
18229     maintainOffset: false,
18230
18231     /**
18232      * Array of pixel locations the element will snap to if we specified a
18233      * horizontal graduation/interval.  This array is generated automatically
18234      * when you define a tick interval.
18235      * @property xTicks
18236      * @type int[]
18237      */
18238     xTicks: null,
18239
18240     /**
18241      * Array of pixel locations the element will snap to if we specified a
18242      * vertical graduation/interval.  This array is generated automatically
18243      * when you define a tick interval.
18244      * @property yTicks
18245      * @type int[]
18246      */
18247     yTicks: null,
18248
18249     /**
18250      * By default the drag and drop instance will only respond to the primary
18251      * button click (left button for a right-handed mouse).  Set to true to
18252      * allow drag and drop to start with any mouse click that is propogated
18253      * by the browser
18254      * @property primaryButtonOnly
18255      * @type boolean
18256      */
18257     primaryButtonOnly: true,
18258
18259     /**
18260      * The availabe property is false until the linked dom element is accessible.
18261      * @property available
18262      * @type boolean
18263      */
18264     available: false,
18265
18266     /**
18267      * By default, drags can only be initiated if the mousedown occurs in the
18268      * region the linked element is.  This is done in part to work around a
18269      * bug in some browsers that mis-report the mousedown if the previous
18270      * mouseup happened outside of the window.  This property is set to true
18271      * if outer handles are defined.
18272      *
18273      * @property hasOuterHandles
18274      * @type boolean
18275      * @default false
18276      */
18277     hasOuterHandles: false,
18278
18279     /**
18280      * Code that executes immediately before the startDrag event
18281      * @method b4StartDrag
18282      * @private
18283      */
18284     b4StartDrag: function(x, y) { },
18285
18286     /**
18287      * Abstract method called after a drag/drop object is clicked
18288      * and the drag or mousedown time thresholds have beeen met.
18289      * @method startDrag
18290      * @param {int} X click location
18291      * @param {int} Y click location
18292      */
18293     startDrag: function(x, y) { /* override this */ },
18294
18295     /**
18296      * Code that executes immediately before the onDrag event
18297      * @method b4Drag
18298      * @private
18299      */
18300     b4Drag: function(e) { },
18301
18302     /**
18303      * Abstract method called during the onMouseMove event while dragging an
18304      * object.
18305      * @method onDrag
18306      * @param {Event} e the mousemove event
18307      */
18308     onDrag: function(e) { /* override this */ },
18309
18310     /**
18311      * Abstract method called when this element fist begins hovering over
18312      * another DragDrop obj
18313      * @method onDragEnter
18314      * @param {Event} e the mousemove event
18315      * @param {String|DragDrop[]} id In POINT mode, the element
18316      * id this is hovering over.  In INTERSECT mode, an array of one or more
18317      * dragdrop items being hovered over.
18318      */
18319     onDragEnter: function(e, id) { /* override this */ },
18320
18321     /**
18322      * Code that executes immediately before the onDragOver event
18323      * @method b4DragOver
18324      * @private
18325      */
18326     b4DragOver: function(e) { },
18327
18328     /**
18329      * Abstract method called when this element is hovering over another
18330      * DragDrop obj
18331      * @method onDragOver
18332      * @param {Event} e the mousemove event
18333      * @param {String|DragDrop[]} id In POINT mode, the element
18334      * id this is hovering over.  In INTERSECT mode, an array of dd items
18335      * being hovered over.
18336      */
18337     onDragOver: function(e, id) { /* override this */ },
18338
18339     /**
18340      * Code that executes immediately before the onDragOut event
18341      * @method b4DragOut
18342      * @private
18343      */
18344     b4DragOut: function(e) { },
18345
18346     /**
18347      * Abstract method called when we are no longer hovering over an element
18348      * @method onDragOut
18349      * @param {Event} e the mousemove event
18350      * @param {String|DragDrop[]} id In POINT mode, the element
18351      * id this was hovering over.  In INTERSECT mode, an array of dd items
18352      * that the mouse is no longer over.
18353      */
18354     onDragOut: function(e, id) { /* override this */ },
18355
18356     /**
18357      * Code that executes immediately before the onDragDrop event
18358      * @method b4DragDrop
18359      * @private
18360      */
18361     b4DragDrop: function(e) { },
18362
18363     /**
18364      * Abstract method called when this item is dropped on another DragDrop
18365      * obj
18366      * @method onDragDrop
18367      * @param {Event} e the mouseup event
18368      * @param {String|DragDrop[]} id In POINT mode, the element
18369      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18370      * was dropped on.
18371      */
18372     onDragDrop: function(e, id) { /* override this */ },
18373
18374     /**
18375      * Abstract method called when this item is dropped on an area with no
18376      * drop target
18377      * @method onInvalidDrop
18378      * @param {Event} e the mouseup event
18379      */
18380     onInvalidDrop: function(e) { /* override this */ },
18381
18382     /**
18383      * Code that executes immediately before the endDrag event
18384      * @method b4EndDrag
18385      * @private
18386      */
18387     b4EndDrag: function(e) { },
18388
18389     /**
18390      * Fired when we are done dragging the object
18391      * @method endDrag
18392      * @param {Event} e the mouseup event
18393      */
18394     endDrag: function(e) { /* override this */ },
18395
18396     /**
18397      * Code executed immediately before the onMouseDown event
18398      * @method b4MouseDown
18399      * @param {Event} e the mousedown event
18400      * @private
18401      */
18402     b4MouseDown: function(e) {  },
18403
18404     /**
18405      * Event handler that fires when a drag/drop obj gets a mousedown
18406      * @method onMouseDown
18407      * @param {Event} e the mousedown event
18408      */
18409     onMouseDown: function(e) { /* override this */ },
18410
18411     /**
18412      * Event handler that fires when a drag/drop obj gets a mouseup
18413      * @method onMouseUp
18414      * @param {Event} e the mouseup event
18415      */
18416     onMouseUp: function(e) { /* override this */ },
18417
18418     /**
18419      * Override the onAvailable method to do what is needed after the initial
18420      * position was determined.
18421      * @method onAvailable
18422      */
18423     onAvailable: function () {
18424     },
18425
18426     /*
18427      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18428      * @type Object
18429      */
18430     defaultPadding : {left:0, right:0, top:0, bottom:0},
18431
18432     /*
18433      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18434  *
18435  * Usage:
18436  <pre><code>
18437  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18438                 { dragElId: "existingProxyDiv" });
18439  dd.startDrag = function(){
18440      this.constrainTo("parent-id");
18441  };
18442  </code></pre>
18443  * Or you can initalize it using the {@link Roo.Element} object:
18444  <pre><code>
18445  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18446      startDrag : function(){
18447          this.constrainTo("parent-id");
18448      }
18449  });
18450  </code></pre>
18451      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18452      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18453      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18454      * an object containing the sides to pad. For example: {right:10, bottom:10}
18455      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18456      */
18457     constrainTo : function(constrainTo, pad, inContent){
18458         if(typeof pad == "number"){
18459             pad = {left: pad, right:pad, top:pad, bottom:pad};
18460         }
18461         pad = pad || this.defaultPadding;
18462         var b = Roo.get(this.getEl()).getBox();
18463         var ce = Roo.get(constrainTo);
18464         var s = ce.getScroll();
18465         var c, cd = ce.dom;
18466         if(cd == document.body){
18467             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18468         }else{
18469             xy = ce.getXY();
18470             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18471         }
18472
18473
18474         var topSpace = b.y - c.y;
18475         var leftSpace = b.x - c.x;
18476
18477         this.resetConstraints();
18478         this.setXConstraint(leftSpace - (pad.left||0), // left
18479                 c.width - leftSpace - b.width - (pad.right||0) //right
18480         );
18481         this.setYConstraint(topSpace - (pad.top||0), //top
18482                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18483         );
18484     },
18485
18486     /**
18487      * Returns a reference to the linked element
18488      * @method getEl
18489      * @return {HTMLElement} the html element
18490      */
18491     getEl: function() {
18492         if (!this._domRef) {
18493             this._domRef = Roo.getDom(this.id);
18494         }
18495
18496         return this._domRef;
18497     },
18498
18499     /**
18500      * Returns a reference to the actual element to drag.  By default this is
18501      * the same as the html element, but it can be assigned to another
18502      * element. An example of this can be found in Roo.dd.DDProxy
18503      * @method getDragEl
18504      * @return {HTMLElement} the html element
18505      */
18506     getDragEl: function() {
18507         return Roo.getDom(this.dragElId);
18508     },
18509
18510     /**
18511      * Sets up the DragDrop object.  Must be called in the constructor of any
18512      * Roo.dd.DragDrop subclass
18513      * @method init
18514      * @param id the id of the linked element
18515      * @param {String} sGroup the group of related items
18516      * @param {object} config configuration attributes
18517      */
18518     init: function(id, sGroup, config) {
18519         this.initTarget(id, sGroup, config);
18520         if (!Roo.isTouch) {
18521             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18522         }
18523         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18524         // Event.on(this.id, "selectstart", Event.preventDefault);
18525     },
18526
18527     /**
18528      * Initializes Targeting functionality only... the object does not
18529      * get a mousedown handler.
18530      * @method initTarget
18531      * @param id the id of the linked element
18532      * @param {String} sGroup the group of related items
18533      * @param {object} config configuration attributes
18534      */
18535     initTarget: function(id, sGroup, config) {
18536
18537         // configuration attributes
18538         this.config = config || {};
18539
18540         // create a local reference to the drag and drop manager
18541         this.DDM = Roo.dd.DDM;
18542         // initialize the groups array
18543         this.groups = {};
18544
18545         // assume that we have an element reference instead of an id if the
18546         // parameter is not a string
18547         if (typeof id !== "string") {
18548             id = Roo.id(id);
18549         }
18550
18551         // set the id
18552         this.id = id;
18553
18554         // add to an interaction group
18555         this.addToGroup((sGroup) ? sGroup : "default");
18556
18557         // We don't want to register this as the handle with the manager
18558         // so we just set the id rather than calling the setter.
18559         this.handleElId = id;
18560
18561         // the linked element is the element that gets dragged by default
18562         this.setDragElId(id);
18563
18564         // by default, clicked anchors will not start drag operations.
18565         this.invalidHandleTypes = { A: "A" };
18566         this.invalidHandleIds = {};
18567         this.invalidHandleClasses = [];
18568
18569         this.applyConfig();
18570
18571         this.handleOnAvailable();
18572     },
18573
18574     /**
18575      * Applies the configuration parameters that were passed into the constructor.
18576      * This is supposed to happen at each level through the inheritance chain.  So
18577      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18578      * DragDrop in order to get all of the parameters that are available in
18579      * each object.
18580      * @method applyConfig
18581      */
18582     applyConfig: function() {
18583
18584         // configurable properties:
18585         //    padding, isTarget, maintainOffset, primaryButtonOnly
18586         this.padding           = this.config.padding || [0, 0, 0, 0];
18587         this.isTarget          = (this.config.isTarget !== false);
18588         this.maintainOffset    = (this.config.maintainOffset);
18589         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18590
18591     },
18592
18593     /**
18594      * Executed when the linked element is available
18595      * @method handleOnAvailable
18596      * @private
18597      */
18598     handleOnAvailable: function() {
18599         this.available = true;
18600         this.resetConstraints();
18601         this.onAvailable();
18602     },
18603
18604      /**
18605      * Configures the padding for the target zone in px.  Effectively expands
18606      * (or reduces) the virtual object size for targeting calculations.
18607      * Supports css-style shorthand; if only one parameter is passed, all sides
18608      * will have that padding, and if only two are passed, the top and bottom
18609      * will have the first param, the left and right the second.
18610      * @method setPadding
18611      * @param {int} iTop    Top pad
18612      * @param {int} iRight  Right pad
18613      * @param {int} iBot    Bot pad
18614      * @param {int} iLeft   Left pad
18615      */
18616     setPadding: function(iTop, iRight, iBot, iLeft) {
18617         // this.padding = [iLeft, iRight, iTop, iBot];
18618         if (!iRight && 0 !== iRight) {
18619             this.padding = [iTop, iTop, iTop, iTop];
18620         } else if (!iBot && 0 !== iBot) {
18621             this.padding = [iTop, iRight, iTop, iRight];
18622         } else {
18623             this.padding = [iTop, iRight, iBot, iLeft];
18624         }
18625     },
18626
18627     /**
18628      * Stores the initial placement of the linked element.
18629      * @method setInitialPosition
18630      * @param {int} diffX   the X offset, default 0
18631      * @param {int} diffY   the Y offset, default 0
18632      */
18633     setInitPosition: function(diffX, diffY) {
18634         var el = this.getEl();
18635
18636         if (!this.DDM.verifyEl(el)) {
18637             return;
18638         }
18639
18640         var dx = diffX || 0;
18641         var dy = diffY || 0;
18642
18643         var p = Dom.getXY( el );
18644
18645         this.initPageX = p[0] - dx;
18646         this.initPageY = p[1] - dy;
18647
18648         this.lastPageX = p[0];
18649         this.lastPageY = p[1];
18650
18651
18652         this.setStartPosition(p);
18653     },
18654
18655     /**
18656      * Sets the start position of the element.  This is set when the obj
18657      * is initialized, the reset when a drag is started.
18658      * @method setStartPosition
18659      * @param pos current position (from previous lookup)
18660      * @private
18661      */
18662     setStartPosition: function(pos) {
18663         var p = pos || Dom.getXY( this.getEl() );
18664         this.deltaSetXY = null;
18665
18666         this.startPageX = p[0];
18667         this.startPageY = p[1];
18668     },
18669
18670     /**
18671      * Add this instance to a group of related drag/drop objects.  All
18672      * instances belong to at least one group, and can belong to as many
18673      * groups as needed.
18674      * @method addToGroup
18675      * @param sGroup {string} the name of the group
18676      */
18677     addToGroup: function(sGroup) {
18678         this.groups[sGroup] = true;
18679         this.DDM.regDragDrop(this, sGroup);
18680     },
18681
18682     /**
18683      * Remove's this instance from the supplied interaction group
18684      * @method removeFromGroup
18685      * @param {string}  sGroup  The group to drop
18686      */
18687     removeFromGroup: function(sGroup) {
18688         if (this.groups[sGroup]) {
18689             delete this.groups[sGroup];
18690         }
18691
18692         this.DDM.removeDDFromGroup(this, sGroup);
18693     },
18694
18695     /**
18696      * Allows you to specify that an element other than the linked element
18697      * will be moved with the cursor during a drag
18698      * @method setDragElId
18699      * @param id {string} the id of the element that will be used to initiate the drag
18700      */
18701     setDragElId: function(id) {
18702         this.dragElId = id;
18703     },
18704
18705     /**
18706      * Allows you to specify a child of the linked element that should be
18707      * used to initiate the drag operation.  An example of this would be if
18708      * you have a content div with text and links.  Clicking anywhere in the
18709      * content area would normally start the drag operation.  Use this method
18710      * to specify that an element inside of the content div is the element
18711      * that starts the drag operation.
18712      * @method setHandleElId
18713      * @param id {string} the id of the element that will be used to
18714      * initiate the drag.
18715      */
18716     setHandleElId: function(id) {
18717         if (typeof id !== "string") {
18718             id = Roo.id(id);
18719         }
18720         this.handleElId = id;
18721         this.DDM.regHandle(this.id, id);
18722     },
18723
18724     /**
18725      * Allows you to set an element outside of the linked element as a drag
18726      * handle
18727      * @method setOuterHandleElId
18728      * @param id the id of the element that will be used to initiate the drag
18729      */
18730     setOuterHandleElId: function(id) {
18731         if (typeof id !== "string") {
18732             id = Roo.id(id);
18733         }
18734         Event.on(id, "mousedown",
18735                 this.handleMouseDown, this);
18736         this.setHandleElId(id);
18737
18738         this.hasOuterHandles = true;
18739     },
18740
18741     /**
18742      * Remove all drag and drop hooks for this element
18743      * @method unreg
18744      */
18745     unreg: function() {
18746         Event.un(this.id, "mousedown",
18747                 this.handleMouseDown);
18748         Event.un(this.id, "touchstart",
18749                 this.handleMouseDown);
18750         this._domRef = null;
18751         this.DDM._remove(this);
18752     },
18753
18754     destroy : function(){
18755         this.unreg();
18756     },
18757
18758     /**
18759      * Returns true if this instance is locked, or the drag drop mgr is locked
18760      * (meaning that all drag/drop is disabled on the page.)
18761      * @method isLocked
18762      * @return {boolean} true if this obj or all drag/drop is locked, else
18763      * false
18764      */
18765     isLocked: function() {
18766         return (this.DDM.isLocked() || this.locked);
18767     },
18768
18769     /**
18770      * Fired when this object is clicked
18771      * @method handleMouseDown
18772      * @param {Event} e
18773      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18774      * @private
18775      */
18776     handleMouseDown: function(e, oDD){
18777      
18778         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18779             //Roo.log('not touch/ button !=0');
18780             return;
18781         }
18782         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18783             return; // double touch..
18784         }
18785         
18786
18787         if (this.isLocked()) {
18788             //Roo.log('locked');
18789             return;
18790         }
18791
18792         this.DDM.refreshCache(this.groups);
18793 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18794         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18795         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18796             //Roo.log('no outer handes or not over target');
18797                 // do nothing.
18798         } else {
18799 //            Roo.log('check validator');
18800             if (this.clickValidator(e)) {
18801 //                Roo.log('validate success');
18802                 // set the initial element position
18803                 this.setStartPosition();
18804
18805
18806                 this.b4MouseDown(e);
18807                 this.onMouseDown(e);
18808
18809                 this.DDM.handleMouseDown(e, this);
18810
18811                 this.DDM.stopEvent(e);
18812             } else {
18813
18814
18815             }
18816         }
18817     },
18818
18819     clickValidator: function(e) {
18820         var target = e.getTarget();
18821         return ( this.isValidHandleChild(target) &&
18822                     (this.id == this.handleElId ||
18823                         this.DDM.handleWasClicked(target, this.id)) );
18824     },
18825
18826     /**
18827      * Allows you to specify a tag name that should not start a drag operation
18828      * when clicked.  This is designed to facilitate embedding links within a
18829      * drag handle that do something other than start the drag.
18830      * @method addInvalidHandleType
18831      * @param {string} tagName the type of element to exclude
18832      */
18833     addInvalidHandleType: function(tagName) {
18834         var type = tagName.toUpperCase();
18835         this.invalidHandleTypes[type] = type;
18836     },
18837
18838     /**
18839      * Lets you to specify an element id for a child of a drag handle
18840      * that should not initiate a drag
18841      * @method addInvalidHandleId
18842      * @param {string} id the element id of the element you wish to ignore
18843      */
18844     addInvalidHandleId: function(id) {
18845         if (typeof id !== "string") {
18846             id = Roo.id(id);
18847         }
18848         this.invalidHandleIds[id] = id;
18849     },
18850
18851     /**
18852      * Lets you specify a css class of elements that will not initiate a drag
18853      * @method addInvalidHandleClass
18854      * @param {string} cssClass the class of the elements you wish to ignore
18855      */
18856     addInvalidHandleClass: function(cssClass) {
18857         this.invalidHandleClasses.push(cssClass);
18858     },
18859
18860     /**
18861      * Unsets an excluded tag name set by addInvalidHandleType
18862      * @method removeInvalidHandleType
18863      * @param {string} tagName the type of element to unexclude
18864      */
18865     removeInvalidHandleType: function(tagName) {
18866         var type = tagName.toUpperCase();
18867         // this.invalidHandleTypes[type] = null;
18868         delete this.invalidHandleTypes[type];
18869     },
18870
18871     /**
18872      * Unsets an invalid handle id
18873      * @method removeInvalidHandleId
18874      * @param {string} id the id of the element to re-enable
18875      */
18876     removeInvalidHandleId: function(id) {
18877         if (typeof id !== "string") {
18878             id = Roo.id(id);
18879         }
18880         delete this.invalidHandleIds[id];
18881     },
18882
18883     /**
18884      * Unsets an invalid css class
18885      * @method removeInvalidHandleClass
18886      * @param {string} cssClass the class of the element(s) you wish to
18887      * re-enable
18888      */
18889     removeInvalidHandleClass: function(cssClass) {
18890         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18891             if (this.invalidHandleClasses[i] == cssClass) {
18892                 delete this.invalidHandleClasses[i];
18893             }
18894         }
18895     },
18896
18897     /**
18898      * Checks the tag exclusion list to see if this click should be ignored
18899      * @method isValidHandleChild
18900      * @param {HTMLElement} node the HTMLElement to evaluate
18901      * @return {boolean} true if this is a valid tag type, false if not
18902      */
18903     isValidHandleChild: function(node) {
18904
18905         var valid = true;
18906         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18907         var nodeName;
18908         try {
18909             nodeName = node.nodeName.toUpperCase();
18910         } catch(e) {
18911             nodeName = node.nodeName;
18912         }
18913         valid = valid && !this.invalidHandleTypes[nodeName];
18914         valid = valid && !this.invalidHandleIds[node.id];
18915
18916         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18917             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18918         }
18919
18920
18921         return valid;
18922
18923     },
18924
18925     /**
18926      * Create the array of horizontal tick marks if an interval was specified
18927      * in setXConstraint().
18928      * @method setXTicks
18929      * @private
18930      */
18931     setXTicks: function(iStartX, iTickSize) {
18932         this.xTicks = [];
18933         this.xTickSize = iTickSize;
18934
18935         var tickMap = {};
18936
18937         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18938             if (!tickMap[i]) {
18939                 this.xTicks[this.xTicks.length] = i;
18940                 tickMap[i] = true;
18941             }
18942         }
18943
18944         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18945             if (!tickMap[i]) {
18946                 this.xTicks[this.xTicks.length] = i;
18947                 tickMap[i] = true;
18948             }
18949         }
18950
18951         this.xTicks.sort(this.DDM.numericSort) ;
18952     },
18953
18954     /**
18955      * Create the array of vertical tick marks if an interval was specified in
18956      * setYConstraint().
18957      * @method setYTicks
18958      * @private
18959      */
18960     setYTicks: function(iStartY, iTickSize) {
18961         this.yTicks = [];
18962         this.yTickSize = iTickSize;
18963
18964         var tickMap = {};
18965
18966         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18967             if (!tickMap[i]) {
18968                 this.yTicks[this.yTicks.length] = i;
18969                 tickMap[i] = true;
18970             }
18971         }
18972
18973         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18974             if (!tickMap[i]) {
18975                 this.yTicks[this.yTicks.length] = i;
18976                 tickMap[i] = true;
18977             }
18978         }
18979
18980         this.yTicks.sort(this.DDM.numericSort) ;
18981     },
18982
18983     /**
18984      * By default, the element can be dragged any place on the screen.  Use
18985      * this method to limit the horizontal travel of the element.  Pass in
18986      * 0,0 for the parameters if you want to lock the drag to the y axis.
18987      * @method setXConstraint
18988      * @param {int} iLeft the number of pixels the element can move to the left
18989      * @param {int} iRight the number of pixels the element can move to the
18990      * right
18991      * @param {int} iTickSize optional parameter for specifying that the
18992      * element
18993      * should move iTickSize pixels at a time.
18994      */
18995     setXConstraint: function(iLeft, iRight, iTickSize) {
18996         this.leftConstraint = iLeft;
18997         this.rightConstraint = iRight;
18998
18999         this.minX = this.initPageX - iLeft;
19000         this.maxX = this.initPageX + iRight;
19001         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19002
19003         this.constrainX = true;
19004     },
19005
19006     /**
19007      * Clears any constraints applied to this instance.  Also clears ticks
19008      * since they can't exist independent of a constraint at this time.
19009      * @method clearConstraints
19010      */
19011     clearConstraints: function() {
19012         this.constrainX = false;
19013         this.constrainY = false;
19014         this.clearTicks();
19015     },
19016
19017     /**
19018      * Clears any tick interval defined for this instance
19019      * @method clearTicks
19020      */
19021     clearTicks: function() {
19022         this.xTicks = null;
19023         this.yTicks = null;
19024         this.xTickSize = 0;
19025         this.yTickSize = 0;
19026     },
19027
19028     /**
19029      * By default, the element can be dragged any place on the screen.  Set
19030      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19031      * parameters if you want to lock the drag to the x axis.
19032      * @method setYConstraint
19033      * @param {int} iUp the number of pixels the element can move up
19034      * @param {int} iDown the number of pixels the element can move down
19035      * @param {int} iTickSize optional parameter for specifying that the
19036      * element should move iTickSize pixels at a time.
19037      */
19038     setYConstraint: function(iUp, iDown, iTickSize) {
19039         this.topConstraint = iUp;
19040         this.bottomConstraint = iDown;
19041
19042         this.minY = this.initPageY - iUp;
19043         this.maxY = this.initPageY + iDown;
19044         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19045
19046         this.constrainY = true;
19047
19048     },
19049
19050     /**
19051      * resetConstraints must be called if you manually reposition a dd element.
19052      * @method resetConstraints
19053      * @param {boolean} maintainOffset
19054      */
19055     resetConstraints: function() {
19056
19057
19058         // Maintain offsets if necessary
19059         if (this.initPageX || this.initPageX === 0) {
19060             // figure out how much this thing has moved
19061             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19062             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19063
19064             this.setInitPosition(dx, dy);
19065
19066         // This is the first time we have detected the element's position
19067         } else {
19068             this.setInitPosition();
19069         }
19070
19071         if (this.constrainX) {
19072             this.setXConstraint( this.leftConstraint,
19073                                  this.rightConstraint,
19074                                  this.xTickSize        );
19075         }
19076
19077         if (this.constrainY) {
19078             this.setYConstraint( this.topConstraint,
19079                                  this.bottomConstraint,
19080                                  this.yTickSize         );
19081         }
19082     },
19083
19084     /**
19085      * Normally the drag element is moved pixel by pixel, but we can specify
19086      * that it move a number of pixels at a time.  This method resolves the
19087      * location when we have it set up like this.
19088      * @method getTick
19089      * @param {int} val where we want to place the object
19090      * @param {int[]} tickArray sorted array of valid points
19091      * @return {int} the closest tick
19092      * @private
19093      */
19094     getTick: function(val, tickArray) {
19095
19096         if (!tickArray) {
19097             // If tick interval is not defined, it is effectively 1 pixel,
19098             // so we return the value passed to us.
19099             return val;
19100         } else if (tickArray[0] >= val) {
19101             // The value is lower than the first tick, so we return the first
19102             // tick.
19103             return tickArray[0];
19104         } else {
19105             for (var i=0, len=tickArray.length; i<len; ++i) {
19106                 var next = i + 1;
19107                 if (tickArray[next] && tickArray[next] >= val) {
19108                     var diff1 = val - tickArray[i];
19109                     var diff2 = tickArray[next] - val;
19110                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19111                 }
19112             }
19113
19114             // The value is larger than the last tick, so we return the last
19115             // tick.
19116             return tickArray[tickArray.length - 1];
19117         }
19118     },
19119
19120     /**
19121      * toString method
19122      * @method toString
19123      * @return {string} string representation of the dd obj
19124      */
19125     toString: function() {
19126         return ("DragDrop " + this.id);
19127     }
19128
19129 });
19130
19131 })();
19132 /*
19133  * Based on:
19134  * Ext JS Library 1.1.1
19135  * Copyright(c) 2006-2007, Ext JS, LLC.
19136  *
19137  * Originally Released Under LGPL - original licence link has changed is not relivant.
19138  *
19139  * Fork - LGPL
19140  * <script type="text/javascript">
19141  */
19142
19143
19144 /**
19145  * The drag and drop utility provides a framework for building drag and drop
19146  * applications.  In addition to enabling drag and drop for specific elements,
19147  * the drag and drop elements are tracked by the manager class, and the
19148  * interactions between the various elements are tracked during the drag and
19149  * the implementing code is notified about these important moments.
19150  */
19151
19152 // Only load the library once.  Rewriting the manager class would orphan
19153 // existing drag and drop instances.
19154 if (!Roo.dd.DragDropMgr) {
19155
19156 /**
19157  * @class Roo.dd.DragDropMgr
19158  * DragDropMgr is a singleton that tracks the element interaction for
19159  * all DragDrop items in the window.  Generally, you will not call
19160  * this class directly, but it does have helper methods that could
19161  * be useful in your DragDrop implementations.
19162  * @singleton
19163  */
19164 Roo.dd.DragDropMgr = function() {
19165
19166     var Event = Roo.EventManager;
19167
19168     return {
19169
19170         /**
19171          * Two dimensional Array of registered DragDrop objects.  The first
19172          * dimension is the DragDrop item group, the second the DragDrop
19173          * object.
19174          * @property ids
19175          * @type {string: string}
19176          * @private
19177          * @static
19178          */
19179         ids: {},
19180
19181         /**
19182          * Array of element ids defined as drag handles.  Used to determine
19183          * if the element that generated the mousedown event is actually the
19184          * handle and not the html element itself.
19185          * @property handleIds
19186          * @type {string: string}
19187          * @private
19188          * @static
19189          */
19190         handleIds: {},
19191
19192         /**
19193          * the DragDrop object that is currently being dragged
19194          * @property dragCurrent
19195          * @type DragDrop
19196          * @private
19197          * @static
19198          **/
19199         dragCurrent: null,
19200
19201         /**
19202          * the DragDrop object(s) that are being hovered over
19203          * @property dragOvers
19204          * @type Array
19205          * @private
19206          * @static
19207          */
19208         dragOvers: {},
19209
19210         /**
19211          * the X distance between the cursor and the object being dragged
19212          * @property deltaX
19213          * @type int
19214          * @private
19215          * @static
19216          */
19217         deltaX: 0,
19218
19219         /**
19220          * the Y distance between the cursor and the object being dragged
19221          * @property deltaY
19222          * @type int
19223          * @private
19224          * @static
19225          */
19226         deltaY: 0,
19227
19228         /**
19229          * Flag to determine if we should prevent the default behavior of the
19230          * events we define. By default this is true, but this can be set to
19231          * false if you need the default behavior (not recommended)
19232          * @property preventDefault
19233          * @type boolean
19234          * @static
19235          */
19236         preventDefault: true,
19237
19238         /**
19239          * Flag to determine if we should stop the propagation of the events
19240          * we generate. This is true by default but you may want to set it to
19241          * false if the html element contains other features that require the
19242          * mouse click.
19243          * @property stopPropagation
19244          * @type boolean
19245          * @static
19246          */
19247         stopPropagation: true,
19248
19249         /**
19250          * Internal flag that is set to true when drag and drop has been
19251          * intialized
19252          * @property initialized
19253          * @private
19254          * @static
19255          */
19256         initalized: false,
19257
19258         /**
19259          * All drag and drop can be disabled.
19260          * @property locked
19261          * @private
19262          * @static
19263          */
19264         locked: false,
19265
19266         /**
19267          * Called the first time an element is registered.
19268          * @method init
19269          * @private
19270          * @static
19271          */
19272         init: function() {
19273             this.initialized = true;
19274         },
19275
19276         /**
19277          * In point mode, drag and drop interaction is defined by the
19278          * location of the cursor during the drag/drop
19279          * @property POINT
19280          * @type int
19281          * @static
19282          */
19283         POINT: 0,
19284
19285         /**
19286          * In intersect mode, drag and drop interactio nis defined by the
19287          * overlap of two or more drag and drop objects.
19288          * @property INTERSECT
19289          * @type int
19290          * @static
19291          */
19292         INTERSECT: 1,
19293
19294         /**
19295          * The current drag and drop mode.  Default: POINT
19296          * @property mode
19297          * @type int
19298          * @static
19299          */
19300         mode: 0,
19301
19302         /**
19303          * Runs method on all drag and drop objects
19304          * @method _execOnAll
19305          * @private
19306          * @static
19307          */
19308         _execOnAll: function(sMethod, args) {
19309             for (var i in this.ids) {
19310                 for (var j in this.ids[i]) {
19311                     var oDD = this.ids[i][j];
19312                     if (! this.isTypeOfDD(oDD)) {
19313                         continue;
19314                     }
19315                     oDD[sMethod].apply(oDD, args);
19316                 }
19317             }
19318         },
19319
19320         /**
19321          * Drag and drop initialization.  Sets up the global event handlers
19322          * @method _onLoad
19323          * @private
19324          * @static
19325          */
19326         _onLoad: function() {
19327
19328             this.init();
19329
19330             if (!Roo.isTouch) {
19331                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19332                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19333             }
19334             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19335             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19336             
19337             Event.on(window,   "unload",    this._onUnload, this, true);
19338             Event.on(window,   "resize",    this._onResize, this, true);
19339             // Event.on(window,   "mouseout",    this._test);
19340
19341         },
19342
19343         /**
19344          * Reset constraints on all drag and drop objs
19345          * @method _onResize
19346          * @private
19347          * @static
19348          */
19349         _onResize: function(e) {
19350             this._execOnAll("resetConstraints", []);
19351         },
19352
19353         /**
19354          * Lock all drag and drop functionality
19355          * @method lock
19356          * @static
19357          */
19358         lock: function() { this.locked = true; },
19359
19360         /**
19361          * Unlock all drag and drop functionality
19362          * @method unlock
19363          * @static
19364          */
19365         unlock: function() { this.locked = false; },
19366
19367         /**
19368          * Is drag and drop locked?
19369          * @method isLocked
19370          * @return {boolean} True if drag and drop is locked, false otherwise.
19371          * @static
19372          */
19373         isLocked: function() { return this.locked; },
19374
19375         /**
19376          * Location cache that is set for all drag drop objects when a drag is
19377          * initiated, cleared when the drag is finished.
19378          * @property locationCache
19379          * @private
19380          * @static
19381          */
19382         locationCache: {},
19383
19384         /**
19385          * Set useCache to false if you want to force object the lookup of each
19386          * drag and drop linked element constantly during a drag.
19387          * @property useCache
19388          * @type boolean
19389          * @static
19390          */
19391         useCache: true,
19392
19393         /**
19394          * The number of pixels that the mouse needs to move after the
19395          * mousedown before the drag is initiated.  Default=3;
19396          * @property clickPixelThresh
19397          * @type int
19398          * @static
19399          */
19400         clickPixelThresh: 3,
19401
19402         /**
19403          * The number of milliseconds after the mousedown event to initiate the
19404          * drag if we don't get a mouseup event. Default=1000
19405          * @property clickTimeThresh
19406          * @type int
19407          * @static
19408          */
19409         clickTimeThresh: 350,
19410
19411         /**
19412          * Flag that indicates that either the drag pixel threshold or the
19413          * mousdown time threshold has been met
19414          * @property dragThreshMet
19415          * @type boolean
19416          * @private
19417          * @static
19418          */
19419         dragThreshMet: false,
19420
19421         /**
19422          * Timeout used for the click time threshold
19423          * @property clickTimeout
19424          * @type Object
19425          * @private
19426          * @static
19427          */
19428         clickTimeout: null,
19429
19430         /**
19431          * The X position of the mousedown event stored for later use when a
19432          * drag threshold is met.
19433          * @property startX
19434          * @type int
19435          * @private
19436          * @static
19437          */
19438         startX: 0,
19439
19440         /**
19441          * The Y position of the mousedown event stored for later use when a
19442          * drag threshold is met.
19443          * @property startY
19444          * @type int
19445          * @private
19446          * @static
19447          */
19448         startY: 0,
19449
19450         /**
19451          * Each DragDrop instance must be registered with the DragDropMgr.
19452          * This is executed in DragDrop.init()
19453          * @method regDragDrop
19454          * @param {DragDrop} oDD the DragDrop object to register
19455          * @param {String} sGroup the name of the group this element belongs to
19456          * @static
19457          */
19458         regDragDrop: function(oDD, sGroup) {
19459             if (!this.initialized) { this.init(); }
19460
19461             if (!this.ids[sGroup]) {
19462                 this.ids[sGroup] = {};
19463             }
19464             this.ids[sGroup][oDD.id] = oDD;
19465         },
19466
19467         /**
19468          * Removes the supplied dd instance from the supplied group. Executed
19469          * by DragDrop.removeFromGroup, so don't call this function directly.
19470          * @method removeDDFromGroup
19471          * @private
19472          * @static
19473          */
19474         removeDDFromGroup: function(oDD, sGroup) {
19475             if (!this.ids[sGroup]) {
19476                 this.ids[sGroup] = {};
19477             }
19478
19479             var obj = this.ids[sGroup];
19480             if (obj && obj[oDD.id]) {
19481                 delete obj[oDD.id];
19482             }
19483         },
19484
19485         /**
19486          * Unregisters a drag and drop item.  This is executed in
19487          * DragDrop.unreg, use that method instead of calling this directly.
19488          * @method _remove
19489          * @private
19490          * @static
19491          */
19492         _remove: function(oDD) {
19493             for (var g in oDD.groups) {
19494                 if (g && this.ids[g][oDD.id]) {
19495                     delete this.ids[g][oDD.id];
19496                 }
19497             }
19498             delete this.handleIds[oDD.id];
19499         },
19500
19501         /**
19502          * Each DragDrop handle element must be registered.  This is done
19503          * automatically when executing DragDrop.setHandleElId()
19504          * @method regHandle
19505          * @param {String} sDDId the DragDrop id this element is a handle for
19506          * @param {String} sHandleId the id of the element that is the drag
19507          * handle
19508          * @static
19509          */
19510         regHandle: function(sDDId, sHandleId) {
19511             if (!this.handleIds[sDDId]) {
19512                 this.handleIds[sDDId] = {};
19513             }
19514             this.handleIds[sDDId][sHandleId] = sHandleId;
19515         },
19516
19517         /**
19518          * Utility function to determine if a given element has been
19519          * registered as a drag drop item.
19520          * @method isDragDrop
19521          * @param {String} id the element id to check
19522          * @return {boolean} true if this element is a DragDrop item,
19523          * false otherwise
19524          * @static
19525          */
19526         isDragDrop: function(id) {
19527             return ( this.getDDById(id) ) ? true : false;
19528         },
19529
19530         /**
19531          * Returns the drag and drop instances that are in all groups the
19532          * passed in instance belongs to.
19533          * @method getRelated
19534          * @param {DragDrop} p_oDD the obj to get related data for
19535          * @param {boolean} bTargetsOnly if true, only return targetable objs
19536          * @return {DragDrop[]} the related instances
19537          * @static
19538          */
19539         getRelated: function(p_oDD, bTargetsOnly) {
19540             var oDDs = [];
19541             for (var i in p_oDD.groups) {
19542                 for (j in this.ids[i]) {
19543                     var dd = this.ids[i][j];
19544                     if (! this.isTypeOfDD(dd)) {
19545                         continue;
19546                     }
19547                     if (!bTargetsOnly || dd.isTarget) {
19548                         oDDs[oDDs.length] = dd;
19549                     }
19550                 }
19551             }
19552
19553             return oDDs;
19554         },
19555
19556         /**
19557          * Returns true if the specified dd target is a legal target for
19558          * the specifice drag obj
19559          * @method isLegalTarget
19560          * @param {DragDrop} the drag obj
19561          * @param {DragDrop} the target
19562          * @return {boolean} true if the target is a legal target for the
19563          * dd obj
19564          * @static
19565          */
19566         isLegalTarget: function (oDD, oTargetDD) {
19567             var targets = this.getRelated(oDD, true);
19568             for (var i=0, len=targets.length;i<len;++i) {
19569                 if (targets[i].id == oTargetDD.id) {
19570                     return true;
19571                 }
19572             }
19573
19574             return false;
19575         },
19576
19577         /**
19578          * My goal is to be able to transparently determine if an object is
19579          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19580          * returns "object", oDD.constructor.toString() always returns
19581          * "DragDrop" and not the name of the subclass.  So for now it just
19582          * evaluates a well-known variable in DragDrop.
19583          * @method isTypeOfDD
19584          * @param {Object} the object to evaluate
19585          * @return {boolean} true if typeof oDD = DragDrop
19586          * @static
19587          */
19588         isTypeOfDD: function (oDD) {
19589             return (oDD && oDD.__ygDragDrop);
19590         },
19591
19592         /**
19593          * Utility function to determine if a given element has been
19594          * registered as a drag drop handle for the given Drag Drop object.
19595          * @method isHandle
19596          * @param {String} id the element id to check
19597          * @return {boolean} true if this element is a DragDrop handle, false
19598          * otherwise
19599          * @static
19600          */
19601         isHandle: function(sDDId, sHandleId) {
19602             return ( this.handleIds[sDDId] &&
19603                             this.handleIds[sDDId][sHandleId] );
19604         },
19605
19606         /**
19607          * Returns the DragDrop instance for a given id
19608          * @method getDDById
19609          * @param {String} id the id of the DragDrop object
19610          * @return {DragDrop} the drag drop object, null if it is not found
19611          * @static
19612          */
19613         getDDById: function(id) {
19614             for (var i in this.ids) {
19615                 if (this.ids[i][id]) {
19616                     return this.ids[i][id];
19617                 }
19618             }
19619             return null;
19620         },
19621
19622         /**
19623          * Fired after a registered DragDrop object gets the mousedown event.
19624          * Sets up the events required to track the object being dragged
19625          * @method handleMouseDown
19626          * @param {Event} e the event
19627          * @param oDD the DragDrop object being dragged
19628          * @private
19629          * @static
19630          */
19631         handleMouseDown: function(e, oDD) {
19632             if(Roo.QuickTips){
19633                 Roo.QuickTips.disable();
19634             }
19635             this.currentTarget = e.getTarget();
19636
19637             this.dragCurrent = oDD;
19638
19639             var el = oDD.getEl();
19640
19641             // track start position
19642             this.startX = e.getPageX();
19643             this.startY = e.getPageY();
19644
19645             this.deltaX = this.startX - el.offsetLeft;
19646             this.deltaY = this.startY - el.offsetTop;
19647
19648             this.dragThreshMet = false;
19649
19650             this.clickTimeout = setTimeout(
19651                     function() {
19652                         var DDM = Roo.dd.DDM;
19653                         DDM.startDrag(DDM.startX, DDM.startY);
19654                     },
19655                     this.clickTimeThresh );
19656         },
19657
19658         /**
19659          * Fired when either the drag pixel threshol or the mousedown hold
19660          * time threshold has been met.
19661          * @method startDrag
19662          * @param x {int} the X position of the original mousedown
19663          * @param y {int} the Y position of the original mousedown
19664          * @static
19665          */
19666         startDrag: function(x, y) {
19667             clearTimeout(this.clickTimeout);
19668             if (this.dragCurrent) {
19669                 this.dragCurrent.b4StartDrag(x, y);
19670                 this.dragCurrent.startDrag(x, y);
19671             }
19672             this.dragThreshMet = true;
19673         },
19674
19675         /**
19676          * Internal function to handle the mouseup event.  Will be invoked
19677          * from the context of the document.
19678          * @method handleMouseUp
19679          * @param {Event} e the event
19680          * @private
19681          * @static
19682          */
19683         handleMouseUp: function(e) {
19684
19685             if(Roo.QuickTips){
19686                 Roo.QuickTips.enable();
19687             }
19688             if (! this.dragCurrent) {
19689                 return;
19690             }
19691
19692             clearTimeout(this.clickTimeout);
19693
19694             if (this.dragThreshMet) {
19695                 this.fireEvents(e, true);
19696             } else {
19697             }
19698
19699             this.stopDrag(e);
19700
19701             this.stopEvent(e);
19702         },
19703
19704         /**
19705          * Utility to stop event propagation and event default, if these
19706          * features are turned on.
19707          * @method stopEvent
19708          * @param {Event} e the event as returned by this.getEvent()
19709          * @static
19710          */
19711         stopEvent: function(e){
19712             if(this.stopPropagation) {
19713                 e.stopPropagation();
19714             }
19715
19716             if (this.preventDefault) {
19717                 e.preventDefault();
19718             }
19719         },
19720
19721         /**
19722          * Internal function to clean up event handlers after the drag
19723          * operation is complete
19724          * @method stopDrag
19725          * @param {Event} e the event
19726          * @private
19727          * @static
19728          */
19729         stopDrag: function(e) {
19730             // Fire the drag end event for the item that was dragged
19731             if (this.dragCurrent) {
19732                 if (this.dragThreshMet) {
19733                     this.dragCurrent.b4EndDrag(e);
19734                     this.dragCurrent.endDrag(e);
19735                 }
19736
19737                 this.dragCurrent.onMouseUp(e);
19738             }
19739
19740             this.dragCurrent = null;
19741             this.dragOvers = {};
19742         },
19743
19744         /**
19745          * Internal function to handle the mousemove event.  Will be invoked
19746          * from the context of the html element.
19747          *
19748          * @TODO figure out what we can do about mouse events lost when the
19749          * user drags objects beyond the window boundary.  Currently we can
19750          * detect this in internet explorer by verifying that the mouse is
19751          * down during the mousemove event.  Firefox doesn't give us the
19752          * button state on the mousemove event.
19753          * @method handleMouseMove
19754          * @param {Event} e the event
19755          * @private
19756          * @static
19757          */
19758         handleMouseMove: function(e) {
19759             if (! this.dragCurrent) {
19760                 return true;
19761             }
19762
19763             // var button = e.which || e.button;
19764
19765             // check for IE mouseup outside of page boundary
19766             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19767                 this.stopEvent(e);
19768                 return this.handleMouseUp(e);
19769             }
19770
19771             if (!this.dragThreshMet) {
19772                 var diffX = Math.abs(this.startX - e.getPageX());
19773                 var diffY = Math.abs(this.startY - e.getPageY());
19774                 if (diffX > this.clickPixelThresh ||
19775                             diffY > this.clickPixelThresh) {
19776                     this.startDrag(this.startX, this.startY);
19777                 }
19778             }
19779
19780             if (this.dragThreshMet) {
19781                 this.dragCurrent.b4Drag(e);
19782                 this.dragCurrent.onDrag(e);
19783                 if(!this.dragCurrent.moveOnly){
19784                     this.fireEvents(e, false);
19785                 }
19786             }
19787
19788             this.stopEvent(e);
19789
19790             return true;
19791         },
19792
19793         /**
19794          * Iterates over all of the DragDrop elements to find ones we are
19795          * hovering over or dropping on
19796          * @method fireEvents
19797          * @param {Event} e the event
19798          * @param {boolean} isDrop is this a drop op or a mouseover op?
19799          * @private
19800          * @static
19801          */
19802         fireEvents: function(e, isDrop) {
19803             var dc = this.dragCurrent;
19804
19805             // If the user did the mouse up outside of the window, we could
19806             // get here even though we have ended the drag.
19807             if (!dc || dc.isLocked()) {
19808                 return;
19809             }
19810
19811             var pt = e.getPoint();
19812
19813             // cache the previous dragOver array
19814             var oldOvers = [];
19815
19816             var outEvts   = [];
19817             var overEvts  = [];
19818             var dropEvts  = [];
19819             var enterEvts = [];
19820
19821             // Check to see if the object(s) we were hovering over is no longer
19822             // being hovered over so we can fire the onDragOut event
19823             for (var i in this.dragOvers) {
19824
19825                 var ddo = this.dragOvers[i];
19826
19827                 if (! this.isTypeOfDD(ddo)) {
19828                     continue;
19829                 }
19830
19831                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19832                     outEvts.push( ddo );
19833                 }
19834
19835                 oldOvers[i] = true;
19836                 delete this.dragOvers[i];
19837             }
19838
19839             for (var sGroup in dc.groups) {
19840
19841                 if ("string" != typeof sGroup) {
19842                     continue;
19843                 }
19844
19845                 for (i in this.ids[sGroup]) {
19846                     var oDD = this.ids[sGroup][i];
19847                     if (! this.isTypeOfDD(oDD)) {
19848                         continue;
19849                     }
19850
19851                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19852                         if (this.isOverTarget(pt, oDD, this.mode)) {
19853                             // look for drop interactions
19854                             if (isDrop) {
19855                                 dropEvts.push( oDD );
19856                             // look for drag enter and drag over interactions
19857                             } else {
19858
19859                                 // initial drag over: dragEnter fires
19860                                 if (!oldOvers[oDD.id]) {
19861                                     enterEvts.push( oDD );
19862                                 // subsequent drag overs: dragOver fires
19863                                 } else {
19864                                     overEvts.push( oDD );
19865                                 }
19866
19867                                 this.dragOvers[oDD.id] = oDD;
19868                             }
19869                         }
19870                     }
19871                 }
19872             }
19873
19874             if (this.mode) {
19875                 if (outEvts.length) {
19876                     dc.b4DragOut(e, outEvts);
19877                     dc.onDragOut(e, outEvts);
19878                 }
19879
19880                 if (enterEvts.length) {
19881                     dc.onDragEnter(e, enterEvts);
19882                 }
19883
19884                 if (overEvts.length) {
19885                     dc.b4DragOver(e, overEvts);
19886                     dc.onDragOver(e, overEvts);
19887                 }
19888
19889                 if (dropEvts.length) {
19890                     dc.b4DragDrop(e, dropEvts);
19891                     dc.onDragDrop(e, dropEvts);
19892                 }
19893
19894             } else {
19895                 // fire dragout events
19896                 var len = 0;
19897                 for (i=0, len=outEvts.length; i<len; ++i) {
19898                     dc.b4DragOut(e, outEvts[i].id);
19899                     dc.onDragOut(e, outEvts[i].id);
19900                 }
19901
19902                 // fire enter events
19903                 for (i=0,len=enterEvts.length; i<len; ++i) {
19904                     // dc.b4DragEnter(e, oDD.id);
19905                     dc.onDragEnter(e, enterEvts[i].id);
19906                 }
19907
19908                 // fire over events
19909                 for (i=0,len=overEvts.length; i<len; ++i) {
19910                     dc.b4DragOver(e, overEvts[i].id);
19911                     dc.onDragOver(e, overEvts[i].id);
19912                 }
19913
19914                 // fire drop events
19915                 for (i=0, len=dropEvts.length; i<len; ++i) {
19916                     dc.b4DragDrop(e, dropEvts[i].id);
19917                     dc.onDragDrop(e, dropEvts[i].id);
19918                 }
19919
19920             }
19921
19922             // notify about a drop that did not find a target
19923             if (isDrop && !dropEvts.length) {
19924                 dc.onInvalidDrop(e);
19925             }
19926
19927         },
19928
19929         /**
19930          * Helper function for getting the best match from the list of drag
19931          * and drop objects returned by the drag and drop events when we are
19932          * in INTERSECT mode.  It returns either the first object that the
19933          * cursor is over, or the object that has the greatest overlap with
19934          * the dragged element.
19935          * @method getBestMatch
19936          * @param  {DragDrop[]} dds The array of drag and drop objects
19937          * targeted
19938          * @return {DragDrop}       The best single match
19939          * @static
19940          */
19941         getBestMatch: function(dds) {
19942             var winner = null;
19943             // Return null if the input is not what we expect
19944             //if (!dds || !dds.length || dds.length == 0) {
19945                // winner = null;
19946             // If there is only one item, it wins
19947             //} else if (dds.length == 1) {
19948
19949             var len = dds.length;
19950
19951             if (len == 1) {
19952                 winner = dds[0];
19953             } else {
19954                 // Loop through the targeted items
19955                 for (var i=0; i<len; ++i) {
19956                     var dd = dds[i];
19957                     // If the cursor is over the object, it wins.  If the
19958                     // cursor is over multiple matches, the first one we come
19959                     // to wins.
19960                     if (dd.cursorIsOver) {
19961                         winner = dd;
19962                         break;
19963                     // Otherwise the object with the most overlap wins
19964                     } else {
19965                         if (!winner ||
19966                             winner.overlap.getArea() < dd.overlap.getArea()) {
19967                             winner = dd;
19968                         }
19969                     }
19970                 }
19971             }
19972
19973             return winner;
19974         },
19975
19976         /**
19977          * Refreshes the cache of the top-left and bottom-right points of the
19978          * drag and drop objects in the specified group(s).  This is in the
19979          * format that is stored in the drag and drop instance, so typical
19980          * usage is:
19981          * <code>
19982          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19983          * </code>
19984          * Alternatively:
19985          * <code>
19986          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19987          * </code>
19988          * @TODO this really should be an indexed array.  Alternatively this
19989          * method could accept both.
19990          * @method refreshCache
19991          * @param {Object} groups an associative array of groups to refresh
19992          * @static
19993          */
19994         refreshCache: function(groups) {
19995             for (var sGroup in groups) {
19996                 if ("string" != typeof sGroup) {
19997                     continue;
19998                 }
19999                 for (var i in this.ids[sGroup]) {
20000                     var oDD = this.ids[sGroup][i];
20001
20002                     if (this.isTypeOfDD(oDD)) {
20003                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20004                         var loc = this.getLocation(oDD);
20005                         if (loc) {
20006                             this.locationCache[oDD.id] = loc;
20007                         } else {
20008                             delete this.locationCache[oDD.id];
20009                             // this will unregister the drag and drop object if
20010                             // the element is not in a usable state
20011                             // oDD.unreg();
20012                         }
20013                     }
20014                 }
20015             }
20016         },
20017
20018         /**
20019          * This checks to make sure an element exists and is in the DOM.  The
20020          * main purpose is to handle cases where innerHTML is used to remove
20021          * drag and drop objects from the DOM.  IE provides an 'unspecified
20022          * error' when trying to access the offsetParent of such an element
20023          * @method verifyEl
20024          * @param {HTMLElement} el the element to check
20025          * @return {boolean} true if the element looks usable
20026          * @static
20027          */
20028         verifyEl: function(el) {
20029             if (el) {
20030                 var parent;
20031                 if(Roo.isIE){
20032                     try{
20033                         parent = el.offsetParent;
20034                     }catch(e){}
20035                 }else{
20036                     parent = el.offsetParent;
20037                 }
20038                 if (parent) {
20039                     return true;
20040                 }
20041             }
20042
20043             return false;
20044         },
20045
20046         /**
20047          * Returns a Region object containing the drag and drop element's position
20048          * and size, including the padding configured for it
20049          * @method getLocation
20050          * @param {DragDrop} oDD the drag and drop object to get the
20051          *                       location for
20052          * @return {Roo.lib.Region} a Region object representing the total area
20053          *                             the element occupies, including any padding
20054          *                             the instance is configured for.
20055          * @static
20056          */
20057         getLocation: function(oDD) {
20058             if (! this.isTypeOfDD(oDD)) {
20059                 return null;
20060             }
20061
20062             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20063
20064             try {
20065                 pos= Roo.lib.Dom.getXY(el);
20066             } catch (e) { }
20067
20068             if (!pos) {
20069                 return null;
20070             }
20071
20072             x1 = pos[0];
20073             x2 = x1 + el.offsetWidth;
20074             y1 = pos[1];
20075             y2 = y1 + el.offsetHeight;
20076
20077             t = y1 - oDD.padding[0];
20078             r = x2 + oDD.padding[1];
20079             b = y2 + oDD.padding[2];
20080             l = x1 - oDD.padding[3];
20081
20082             return new Roo.lib.Region( t, r, b, l );
20083         },
20084
20085         /**
20086          * Checks the cursor location to see if it over the target
20087          * @method isOverTarget
20088          * @param {Roo.lib.Point} pt The point to evaluate
20089          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20090          * @return {boolean} true if the mouse is over the target
20091          * @private
20092          * @static
20093          */
20094         isOverTarget: function(pt, oTarget, intersect) {
20095             // use cache if available
20096             var loc = this.locationCache[oTarget.id];
20097             if (!loc || !this.useCache) {
20098                 loc = this.getLocation(oTarget);
20099                 this.locationCache[oTarget.id] = loc;
20100
20101             }
20102
20103             if (!loc) {
20104                 return false;
20105             }
20106
20107             oTarget.cursorIsOver = loc.contains( pt );
20108
20109             // DragDrop is using this as a sanity check for the initial mousedown
20110             // in this case we are done.  In POINT mode, if the drag obj has no
20111             // contraints, we are also done. Otherwise we need to evaluate the
20112             // location of the target as related to the actual location of the
20113             // dragged element.
20114             var dc = this.dragCurrent;
20115             if (!dc || !dc.getTargetCoord ||
20116                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20117                 return oTarget.cursorIsOver;
20118             }
20119
20120             oTarget.overlap = null;
20121
20122             // Get the current location of the drag element, this is the
20123             // location of the mouse event less the delta that represents
20124             // where the original mousedown happened on the element.  We
20125             // need to consider constraints and ticks as well.
20126             var pos = dc.getTargetCoord(pt.x, pt.y);
20127
20128             var el = dc.getDragEl();
20129             var curRegion = new Roo.lib.Region( pos.y,
20130                                                    pos.x + el.offsetWidth,
20131                                                    pos.y + el.offsetHeight,
20132                                                    pos.x );
20133
20134             var overlap = curRegion.intersect(loc);
20135
20136             if (overlap) {
20137                 oTarget.overlap = overlap;
20138                 return (intersect) ? true : oTarget.cursorIsOver;
20139             } else {
20140                 return false;
20141             }
20142         },
20143
20144         /**
20145          * unload event handler
20146          * @method _onUnload
20147          * @private
20148          * @static
20149          */
20150         _onUnload: function(e, me) {
20151             Roo.dd.DragDropMgr.unregAll();
20152         },
20153
20154         /**
20155          * Cleans up the drag and drop events and objects.
20156          * @method unregAll
20157          * @private
20158          * @static
20159          */
20160         unregAll: function() {
20161
20162             if (this.dragCurrent) {
20163                 this.stopDrag();
20164                 this.dragCurrent = null;
20165             }
20166
20167             this._execOnAll("unreg", []);
20168
20169             for (i in this.elementCache) {
20170                 delete this.elementCache[i];
20171             }
20172
20173             this.elementCache = {};
20174             this.ids = {};
20175         },
20176
20177         /**
20178          * A cache of DOM elements
20179          * @property elementCache
20180          * @private
20181          * @static
20182          */
20183         elementCache: {},
20184
20185         /**
20186          * Get the wrapper for the DOM element specified
20187          * @method getElWrapper
20188          * @param {String} id the id of the element to get
20189          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20190          * @private
20191          * @deprecated This wrapper isn't that useful
20192          * @static
20193          */
20194         getElWrapper: function(id) {
20195             var oWrapper = this.elementCache[id];
20196             if (!oWrapper || !oWrapper.el) {
20197                 oWrapper = this.elementCache[id] =
20198                     new this.ElementWrapper(Roo.getDom(id));
20199             }
20200             return oWrapper;
20201         },
20202
20203         /**
20204          * Returns the actual DOM element
20205          * @method getElement
20206          * @param {String} id the id of the elment to get
20207          * @return {Object} The element
20208          * @deprecated use Roo.getDom instead
20209          * @static
20210          */
20211         getElement: function(id) {
20212             return Roo.getDom(id);
20213         },
20214
20215         /**
20216          * Returns the style property for the DOM element (i.e.,
20217          * document.getElById(id).style)
20218          * @method getCss
20219          * @param {String} id the id of the elment to get
20220          * @return {Object} The style property of the element
20221          * @deprecated use Roo.getDom instead
20222          * @static
20223          */
20224         getCss: function(id) {
20225             var el = Roo.getDom(id);
20226             return (el) ? el.style : null;
20227         },
20228
20229         /**
20230          * Inner class for cached elements
20231          * @class DragDropMgr.ElementWrapper
20232          * @for DragDropMgr
20233          * @private
20234          * @deprecated
20235          */
20236         ElementWrapper: function(el) {
20237                 /**
20238                  * The element
20239                  * @property el
20240                  */
20241                 this.el = el || null;
20242                 /**
20243                  * The element id
20244                  * @property id
20245                  */
20246                 this.id = this.el && el.id;
20247                 /**
20248                  * A reference to the style property
20249                  * @property css
20250                  */
20251                 this.css = this.el && el.style;
20252             },
20253
20254         /**
20255          * Returns the X position of an html element
20256          * @method getPosX
20257          * @param el the element for which to get the position
20258          * @return {int} the X coordinate
20259          * @for DragDropMgr
20260          * @deprecated use Roo.lib.Dom.getX instead
20261          * @static
20262          */
20263         getPosX: function(el) {
20264             return Roo.lib.Dom.getX(el);
20265         },
20266
20267         /**
20268          * Returns the Y position of an html element
20269          * @method getPosY
20270          * @param el the element for which to get the position
20271          * @return {int} the Y coordinate
20272          * @deprecated use Roo.lib.Dom.getY instead
20273          * @static
20274          */
20275         getPosY: function(el) {
20276             return Roo.lib.Dom.getY(el);
20277         },
20278
20279         /**
20280          * Swap two nodes.  In IE, we use the native method, for others we
20281          * emulate the IE behavior
20282          * @method swapNode
20283          * @param n1 the first node to swap
20284          * @param n2 the other node to swap
20285          * @static
20286          */
20287         swapNode: function(n1, n2) {
20288             if (n1.swapNode) {
20289                 n1.swapNode(n2);
20290             } else {
20291                 var p = n2.parentNode;
20292                 var s = n2.nextSibling;
20293
20294                 if (s == n1) {
20295                     p.insertBefore(n1, n2);
20296                 } else if (n2 == n1.nextSibling) {
20297                     p.insertBefore(n2, n1);
20298                 } else {
20299                     n1.parentNode.replaceChild(n2, n1);
20300                     p.insertBefore(n1, s);
20301                 }
20302             }
20303         },
20304
20305         /**
20306          * Returns the current scroll position
20307          * @method getScroll
20308          * @private
20309          * @static
20310          */
20311         getScroll: function () {
20312             var t, l, dde=document.documentElement, db=document.body;
20313             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20314                 t = dde.scrollTop;
20315                 l = dde.scrollLeft;
20316             } else if (db) {
20317                 t = db.scrollTop;
20318                 l = db.scrollLeft;
20319             } else {
20320
20321             }
20322             return { top: t, left: l };
20323         },
20324
20325         /**
20326          * Returns the specified element style property
20327          * @method getStyle
20328          * @param {HTMLElement} el          the element
20329          * @param {string}      styleProp   the style property
20330          * @return {string} The value of the style property
20331          * @deprecated use Roo.lib.Dom.getStyle
20332          * @static
20333          */
20334         getStyle: function(el, styleProp) {
20335             return Roo.fly(el).getStyle(styleProp);
20336         },
20337
20338         /**
20339          * Gets the scrollTop
20340          * @method getScrollTop
20341          * @return {int} the document's scrollTop
20342          * @static
20343          */
20344         getScrollTop: function () { return this.getScroll().top; },
20345
20346         /**
20347          * Gets the scrollLeft
20348          * @method getScrollLeft
20349          * @return {int} the document's scrollTop
20350          * @static
20351          */
20352         getScrollLeft: function () { return this.getScroll().left; },
20353
20354         /**
20355          * Sets the x/y position of an element to the location of the
20356          * target element.
20357          * @method moveToEl
20358          * @param {HTMLElement} moveEl      The element to move
20359          * @param {HTMLElement} targetEl    The position reference element
20360          * @static
20361          */
20362         moveToEl: function (moveEl, targetEl) {
20363             var aCoord = Roo.lib.Dom.getXY(targetEl);
20364             Roo.lib.Dom.setXY(moveEl, aCoord);
20365         },
20366
20367         /**
20368          * Numeric array sort function
20369          * @method numericSort
20370          * @static
20371          */
20372         numericSort: function(a, b) { return (a - b); },
20373
20374         /**
20375          * Internal counter
20376          * @property _timeoutCount
20377          * @private
20378          * @static
20379          */
20380         _timeoutCount: 0,
20381
20382         /**
20383          * Trying to make the load order less important.  Without this we get
20384          * an error if this file is loaded before the Event Utility.
20385          * @method _addListeners
20386          * @private
20387          * @static
20388          */
20389         _addListeners: function() {
20390             var DDM = Roo.dd.DDM;
20391             if ( Roo.lib.Event && document ) {
20392                 DDM._onLoad();
20393             } else {
20394                 if (DDM._timeoutCount > 2000) {
20395                 } else {
20396                     setTimeout(DDM._addListeners, 10);
20397                     if (document && document.body) {
20398                         DDM._timeoutCount += 1;
20399                     }
20400                 }
20401             }
20402         },
20403
20404         /**
20405          * Recursively searches the immediate parent and all child nodes for
20406          * the handle element in order to determine wheter or not it was
20407          * clicked.
20408          * @method handleWasClicked
20409          * @param node the html element to inspect
20410          * @static
20411          */
20412         handleWasClicked: function(node, id) {
20413             if (this.isHandle(id, node.id)) {
20414                 return true;
20415             } else {
20416                 // check to see if this is a text node child of the one we want
20417                 var p = node.parentNode;
20418
20419                 while (p) {
20420                     if (this.isHandle(id, p.id)) {
20421                         return true;
20422                     } else {
20423                         p = p.parentNode;
20424                     }
20425                 }
20426             }
20427
20428             return false;
20429         }
20430
20431     };
20432
20433 }();
20434
20435 // shorter alias, save a few bytes
20436 Roo.dd.DDM = Roo.dd.DragDropMgr;
20437 Roo.dd.DDM._addListeners();
20438
20439 }/*
20440  * Based on:
20441  * Ext JS Library 1.1.1
20442  * Copyright(c) 2006-2007, Ext JS, LLC.
20443  *
20444  * Originally Released Under LGPL - original licence link has changed is not relivant.
20445  *
20446  * Fork - LGPL
20447  * <script type="text/javascript">
20448  */
20449
20450 /**
20451  * @class Roo.dd.DD
20452  * A DragDrop implementation where the linked element follows the
20453  * mouse cursor during a drag.
20454  * @extends Roo.dd.DragDrop
20455  * @constructor
20456  * @param {String} id the id of the linked element
20457  * @param {String} sGroup the group of related DragDrop items
20458  * @param {object} config an object containing configurable attributes
20459  *                Valid properties for DD:
20460  *                    scroll
20461  */
20462 Roo.dd.DD = function(id, sGroup, config) {
20463     if (id) {
20464         this.init(id, sGroup, config);
20465     }
20466 };
20467
20468 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20469
20470     /**
20471      * When set to true, the utility automatically tries to scroll the browser
20472      * window wehn a drag and drop element is dragged near the viewport boundary.
20473      * Defaults to true.
20474      * @property scroll
20475      * @type boolean
20476      */
20477     scroll: true,
20478
20479     /**
20480      * Sets the pointer offset to the distance between the linked element's top
20481      * left corner and the location the element was clicked
20482      * @method autoOffset
20483      * @param {int} iPageX the X coordinate of the click
20484      * @param {int} iPageY the Y coordinate of the click
20485      */
20486     autoOffset: function(iPageX, iPageY) {
20487         var x = iPageX - this.startPageX;
20488         var y = iPageY - this.startPageY;
20489         this.setDelta(x, y);
20490     },
20491
20492     /**
20493      * Sets the pointer offset.  You can call this directly to force the
20494      * offset to be in a particular location (e.g., pass in 0,0 to set it
20495      * to the center of the object)
20496      * @method setDelta
20497      * @param {int} iDeltaX the distance from the left
20498      * @param {int} iDeltaY the distance from the top
20499      */
20500     setDelta: function(iDeltaX, iDeltaY) {
20501         this.deltaX = iDeltaX;
20502         this.deltaY = iDeltaY;
20503     },
20504
20505     /**
20506      * Sets the drag element to the location of the mousedown or click event,
20507      * maintaining the cursor location relative to the location on the element
20508      * that was clicked.  Override this if you want to place the element in a
20509      * location other than where the cursor is.
20510      * @method setDragElPos
20511      * @param {int} iPageX the X coordinate of the mousedown or drag event
20512      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20513      */
20514     setDragElPos: function(iPageX, iPageY) {
20515         // the first time we do this, we are going to check to make sure
20516         // the element has css positioning
20517
20518         var el = this.getDragEl();
20519         this.alignElWithMouse(el, iPageX, iPageY);
20520     },
20521
20522     /**
20523      * Sets the element to the location of the mousedown or click event,
20524      * maintaining the cursor location relative to the location on the element
20525      * that was clicked.  Override this if you want to place the element in a
20526      * location other than where the cursor is.
20527      * @method alignElWithMouse
20528      * @param {HTMLElement} el the element to move
20529      * @param {int} iPageX the X coordinate of the mousedown or drag event
20530      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20531      */
20532     alignElWithMouse: function(el, iPageX, iPageY) {
20533         var oCoord = this.getTargetCoord(iPageX, iPageY);
20534         var fly = el.dom ? el : Roo.fly(el);
20535         if (!this.deltaSetXY) {
20536             var aCoord = [oCoord.x, oCoord.y];
20537             fly.setXY(aCoord);
20538             var newLeft = fly.getLeft(true);
20539             var newTop  = fly.getTop(true);
20540             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20541         } else {
20542             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20543         }
20544
20545         this.cachePosition(oCoord.x, oCoord.y);
20546         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20547         return oCoord;
20548     },
20549
20550     /**
20551      * Saves the most recent position so that we can reset the constraints and
20552      * tick marks on-demand.  We need to know this so that we can calculate the
20553      * number of pixels the element is offset from its original position.
20554      * @method cachePosition
20555      * @param iPageX the current x position (optional, this just makes it so we
20556      * don't have to look it up again)
20557      * @param iPageY the current y position (optional, this just makes it so we
20558      * don't have to look it up again)
20559      */
20560     cachePosition: function(iPageX, iPageY) {
20561         if (iPageX) {
20562             this.lastPageX = iPageX;
20563             this.lastPageY = iPageY;
20564         } else {
20565             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20566             this.lastPageX = aCoord[0];
20567             this.lastPageY = aCoord[1];
20568         }
20569     },
20570
20571     /**
20572      * Auto-scroll the window if the dragged object has been moved beyond the
20573      * visible window boundary.
20574      * @method autoScroll
20575      * @param {int} x the drag element's x position
20576      * @param {int} y the drag element's y position
20577      * @param {int} h the height of the drag element
20578      * @param {int} w the width of the drag element
20579      * @private
20580      */
20581     autoScroll: function(x, y, h, w) {
20582
20583         if (this.scroll) {
20584             // The client height
20585             var clientH = Roo.lib.Dom.getViewWidth();
20586
20587             // The client width
20588             var clientW = Roo.lib.Dom.getViewHeight();
20589
20590             // The amt scrolled down
20591             var st = this.DDM.getScrollTop();
20592
20593             // The amt scrolled right
20594             var sl = this.DDM.getScrollLeft();
20595
20596             // Location of the bottom of the element
20597             var bot = h + y;
20598
20599             // Location of the right of the element
20600             var right = w + x;
20601
20602             // The distance from the cursor to the bottom of the visible area,
20603             // adjusted so that we don't scroll if the cursor is beyond the
20604             // element drag constraints
20605             var toBot = (clientH + st - y - this.deltaY);
20606
20607             // The distance from the cursor to the right of the visible area
20608             var toRight = (clientW + sl - x - this.deltaX);
20609
20610
20611             // How close to the edge the cursor must be before we scroll
20612             // var thresh = (document.all) ? 100 : 40;
20613             var thresh = 40;
20614
20615             // How many pixels to scroll per autoscroll op.  This helps to reduce
20616             // clunky scrolling. IE is more sensitive about this ... it needs this
20617             // value to be higher.
20618             var scrAmt = (document.all) ? 80 : 30;
20619
20620             // Scroll down if we are near the bottom of the visible page and the
20621             // obj extends below the crease
20622             if ( bot > clientH && toBot < thresh ) {
20623                 window.scrollTo(sl, st + scrAmt);
20624             }
20625
20626             // Scroll up if the window is scrolled down and the top of the object
20627             // goes above the top border
20628             if ( y < st && st > 0 && y - st < thresh ) {
20629                 window.scrollTo(sl, st - scrAmt);
20630             }
20631
20632             // Scroll right if the obj is beyond the right border and the cursor is
20633             // near the border.
20634             if ( right > clientW && toRight < thresh ) {
20635                 window.scrollTo(sl + scrAmt, st);
20636             }
20637
20638             // Scroll left if the window has been scrolled to the right and the obj
20639             // extends past the left border
20640             if ( x < sl && sl > 0 && x - sl < thresh ) {
20641                 window.scrollTo(sl - scrAmt, st);
20642             }
20643         }
20644     },
20645
20646     /**
20647      * Finds the location the element should be placed if we want to move
20648      * it to where the mouse location less the click offset would place us.
20649      * @method getTargetCoord
20650      * @param {int} iPageX the X coordinate of the click
20651      * @param {int} iPageY the Y coordinate of the click
20652      * @return an object that contains the coordinates (Object.x and Object.y)
20653      * @private
20654      */
20655     getTargetCoord: function(iPageX, iPageY) {
20656
20657
20658         var x = iPageX - this.deltaX;
20659         var y = iPageY - this.deltaY;
20660
20661         if (this.constrainX) {
20662             if (x < this.minX) { x = this.minX; }
20663             if (x > this.maxX) { x = this.maxX; }
20664         }
20665
20666         if (this.constrainY) {
20667             if (y < this.minY) { y = this.minY; }
20668             if (y > this.maxY) { y = this.maxY; }
20669         }
20670
20671         x = this.getTick(x, this.xTicks);
20672         y = this.getTick(y, this.yTicks);
20673
20674
20675         return {x:x, y:y};
20676     },
20677
20678     /*
20679      * Sets up config options specific to this class. Overrides
20680      * Roo.dd.DragDrop, but all versions of this method through the
20681      * inheritance chain are called
20682      */
20683     applyConfig: function() {
20684         Roo.dd.DD.superclass.applyConfig.call(this);
20685         this.scroll = (this.config.scroll !== false);
20686     },
20687
20688     /*
20689      * Event that fires prior to the onMouseDown event.  Overrides
20690      * Roo.dd.DragDrop.
20691      */
20692     b4MouseDown: function(e) {
20693         // this.resetConstraints();
20694         this.autoOffset(e.getPageX(),
20695                             e.getPageY());
20696     },
20697
20698     /*
20699      * Event that fires prior to the onDrag event.  Overrides
20700      * Roo.dd.DragDrop.
20701      */
20702     b4Drag: function(e) {
20703         this.setDragElPos(e.getPageX(),
20704                             e.getPageY());
20705     },
20706
20707     toString: function() {
20708         return ("DD " + this.id);
20709     }
20710
20711     //////////////////////////////////////////////////////////////////////////
20712     // Debugging ygDragDrop events that can be overridden
20713     //////////////////////////////////////////////////////////////////////////
20714     /*
20715     startDrag: function(x, y) {
20716     },
20717
20718     onDrag: function(e) {
20719     },
20720
20721     onDragEnter: function(e, id) {
20722     },
20723
20724     onDragOver: function(e, id) {
20725     },
20726
20727     onDragOut: function(e, id) {
20728     },
20729
20730     onDragDrop: function(e, id) {
20731     },
20732
20733     endDrag: function(e) {
20734     }
20735
20736     */
20737
20738 });/*
20739  * Based on:
20740  * Ext JS Library 1.1.1
20741  * Copyright(c) 2006-2007, Ext JS, LLC.
20742  *
20743  * Originally Released Under LGPL - original licence link has changed is not relivant.
20744  *
20745  * Fork - LGPL
20746  * <script type="text/javascript">
20747  */
20748
20749 /**
20750  * @class Roo.dd.DDProxy
20751  * A DragDrop implementation that inserts an empty, bordered div into
20752  * the document that follows the cursor during drag operations.  At the time of
20753  * the click, the frame div is resized to the dimensions of the linked html
20754  * element, and moved to the exact location of the linked element.
20755  *
20756  * References to the "frame" element refer to the single proxy element that
20757  * was created to be dragged in place of all DDProxy elements on the
20758  * page.
20759  *
20760  * @extends Roo.dd.DD
20761  * @constructor
20762  * @param {String} id the id of the linked html element
20763  * @param {String} sGroup the group of related DragDrop objects
20764  * @param {object} config an object containing configurable attributes
20765  *                Valid properties for DDProxy in addition to those in DragDrop:
20766  *                   resizeFrame, centerFrame, dragElId
20767  */
20768 Roo.dd.DDProxy = function(id, sGroup, config) {
20769     if (id) {
20770         this.init(id, sGroup, config);
20771         this.initFrame();
20772     }
20773 };
20774
20775 /**
20776  * The default drag frame div id
20777  * @property Roo.dd.DDProxy.dragElId
20778  * @type String
20779  * @static
20780  */
20781 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20782
20783 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20784
20785     /**
20786      * By default we resize the drag frame to be the same size as the element
20787      * we want to drag (this is to get the frame effect).  We can turn it off
20788      * if we want a different behavior.
20789      * @property resizeFrame
20790      * @type boolean
20791      */
20792     resizeFrame: true,
20793
20794     /**
20795      * By default the frame is positioned exactly where the drag element is, so
20796      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20797      * you do not have constraints on the obj is to have the drag frame centered
20798      * around the cursor.  Set centerFrame to true for this effect.
20799      * @property centerFrame
20800      * @type boolean
20801      */
20802     centerFrame: false,
20803
20804     /**
20805      * Creates the proxy element if it does not yet exist
20806      * @method createFrame
20807      */
20808     createFrame: function() {
20809         var self = this;
20810         var body = document.body;
20811
20812         if (!body || !body.firstChild) {
20813             setTimeout( function() { self.createFrame(); }, 50 );
20814             return;
20815         }
20816
20817         var div = this.getDragEl();
20818
20819         if (!div) {
20820             div    = document.createElement("div");
20821             div.id = this.dragElId;
20822             var s  = div.style;
20823
20824             s.position   = "absolute";
20825             s.visibility = "hidden";
20826             s.cursor     = "move";
20827             s.border     = "2px solid #aaa";
20828             s.zIndex     = 999;
20829
20830             // appendChild can blow up IE if invoked prior to the window load event
20831             // while rendering a table.  It is possible there are other scenarios
20832             // that would cause this to happen as well.
20833             body.insertBefore(div, body.firstChild);
20834         }
20835     },
20836
20837     /**
20838      * Initialization for the drag frame element.  Must be called in the
20839      * constructor of all subclasses
20840      * @method initFrame
20841      */
20842     initFrame: function() {
20843         this.createFrame();
20844     },
20845
20846     applyConfig: function() {
20847         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20848
20849         this.resizeFrame = (this.config.resizeFrame !== false);
20850         this.centerFrame = (this.config.centerFrame);
20851         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20852     },
20853
20854     /**
20855      * Resizes the drag frame to the dimensions of the clicked object, positions
20856      * it over the object, and finally displays it
20857      * @method showFrame
20858      * @param {int} iPageX X click position
20859      * @param {int} iPageY Y click position
20860      * @private
20861      */
20862     showFrame: function(iPageX, iPageY) {
20863         var el = this.getEl();
20864         var dragEl = this.getDragEl();
20865         var s = dragEl.style;
20866
20867         this._resizeProxy();
20868
20869         if (this.centerFrame) {
20870             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20871                            Math.round(parseInt(s.height, 10)/2) );
20872         }
20873
20874         this.setDragElPos(iPageX, iPageY);
20875
20876         Roo.fly(dragEl).show();
20877     },
20878
20879     /**
20880      * The proxy is automatically resized to the dimensions of the linked
20881      * element when a drag is initiated, unless resizeFrame is set to false
20882      * @method _resizeProxy
20883      * @private
20884      */
20885     _resizeProxy: function() {
20886         if (this.resizeFrame) {
20887             var el = this.getEl();
20888             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20889         }
20890     },
20891
20892     // overrides Roo.dd.DragDrop
20893     b4MouseDown: function(e) {
20894         var x = e.getPageX();
20895         var y = e.getPageY();
20896         this.autoOffset(x, y);
20897         this.setDragElPos(x, y);
20898     },
20899
20900     // overrides Roo.dd.DragDrop
20901     b4StartDrag: function(x, y) {
20902         // show the drag frame
20903         this.showFrame(x, y);
20904     },
20905
20906     // overrides Roo.dd.DragDrop
20907     b4EndDrag: function(e) {
20908         Roo.fly(this.getDragEl()).hide();
20909     },
20910
20911     // overrides Roo.dd.DragDrop
20912     // By default we try to move the element to the last location of the frame.
20913     // This is so that the default behavior mirrors that of Roo.dd.DD.
20914     endDrag: function(e) {
20915
20916         var lel = this.getEl();
20917         var del = this.getDragEl();
20918
20919         // Show the drag frame briefly so we can get its position
20920         del.style.visibility = "";
20921
20922         this.beforeMove();
20923         // Hide the linked element before the move to get around a Safari
20924         // rendering bug.
20925         lel.style.visibility = "hidden";
20926         Roo.dd.DDM.moveToEl(lel, del);
20927         del.style.visibility = "hidden";
20928         lel.style.visibility = "";
20929
20930         this.afterDrag();
20931     },
20932
20933     beforeMove : function(){
20934
20935     },
20936
20937     afterDrag : function(){
20938
20939     },
20940
20941     toString: function() {
20942         return ("DDProxy " + this.id);
20943     }
20944
20945 });
20946 /*
20947  * Based on:
20948  * Ext JS Library 1.1.1
20949  * Copyright(c) 2006-2007, Ext JS, LLC.
20950  *
20951  * Originally Released Under LGPL - original licence link has changed is not relivant.
20952  *
20953  * Fork - LGPL
20954  * <script type="text/javascript">
20955  */
20956
20957  /**
20958  * @class Roo.dd.DDTarget
20959  * A DragDrop implementation that does not move, but can be a drop
20960  * target.  You would get the same result by simply omitting implementation
20961  * for the event callbacks, but this way we reduce the processing cost of the
20962  * event listener and the callbacks.
20963  * @extends Roo.dd.DragDrop
20964  * @constructor
20965  * @param {String} id the id of the element that is a drop target
20966  * @param {String} sGroup the group of related DragDrop objects
20967  * @param {object} config an object containing configurable attributes
20968  *                 Valid properties for DDTarget in addition to those in
20969  *                 DragDrop:
20970  *                    none
20971  */
20972 Roo.dd.DDTarget = function(id, sGroup, config) {
20973     if (id) {
20974         this.initTarget(id, sGroup, config);
20975     }
20976     if (config.listeners || config.events) { 
20977        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20978             listeners : config.listeners || {}, 
20979             events : config.events || {} 
20980         });    
20981     }
20982 };
20983
20984 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20985 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20986     toString: function() {
20987         return ("DDTarget " + this.id);
20988     }
20989 });
20990 /*
20991  * Based on:
20992  * Ext JS Library 1.1.1
20993  * Copyright(c) 2006-2007, Ext JS, LLC.
20994  *
20995  * Originally Released Under LGPL - original licence link has changed is not relivant.
20996  *
20997  * Fork - LGPL
20998  * <script type="text/javascript">
20999  */
21000  
21001
21002 /**
21003  * @class Roo.dd.ScrollManager
21004  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21005  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21006  * @singleton
21007  */
21008 Roo.dd.ScrollManager = function(){
21009     var ddm = Roo.dd.DragDropMgr;
21010     var els = {};
21011     var dragEl = null;
21012     var proc = {};
21013     
21014     
21015     
21016     var onStop = function(e){
21017         dragEl = null;
21018         clearProc();
21019     };
21020     
21021     var triggerRefresh = function(){
21022         if(ddm.dragCurrent){
21023              ddm.refreshCache(ddm.dragCurrent.groups);
21024         }
21025     };
21026     
21027     var doScroll = function(){
21028         if(ddm.dragCurrent){
21029             var dds = Roo.dd.ScrollManager;
21030             if(!dds.animate){
21031                 if(proc.el.scroll(proc.dir, dds.increment)){
21032                     triggerRefresh();
21033                 }
21034             }else{
21035                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21036             }
21037         }
21038     };
21039     
21040     var clearProc = function(){
21041         if(proc.id){
21042             clearInterval(proc.id);
21043         }
21044         proc.id = 0;
21045         proc.el = null;
21046         proc.dir = "";
21047     };
21048     
21049     var startProc = function(el, dir){
21050          Roo.log('scroll startproc');
21051         clearProc();
21052         proc.el = el;
21053         proc.dir = dir;
21054         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21055     };
21056     
21057     var onFire = function(e, isDrop){
21058        
21059         if(isDrop || !ddm.dragCurrent){ return; }
21060         var dds = Roo.dd.ScrollManager;
21061         if(!dragEl || dragEl != ddm.dragCurrent){
21062             dragEl = ddm.dragCurrent;
21063             // refresh regions on drag start
21064             dds.refreshCache();
21065         }
21066         
21067         var xy = Roo.lib.Event.getXY(e);
21068         var pt = new Roo.lib.Point(xy[0], xy[1]);
21069         for(var id in els){
21070             var el = els[id], r = el._region;
21071             if(r && r.contains(pt) && el.isScrollable()){
21072                 if(r.bottom - pt.y <= dds.thresh){
21073                     if(proc.el != el){
21074                         startProc(el, "down");
21075                     }
21076                     return;
21077                 }else if(r.right - pt.x <= dds.thresh){
21078                     if(proc.el != el){
21079                         startProc(el, "left");
21080                     }
21081                     return;
21082                 }else if(pt.y - r.top <= dds.thresh){
21083                     if(proc.el != el){
21084                         startProc(el, "up");
21085                     }
21086                     return;
21087                 }else if(pt.x - r.left <= dds.thresh){
21088                     if(proc.el != el){
21089                         startProc(el, "right");
21090                     }
21091                     return;
21092                 }
21093             }
21094         }
21095         clearProc();
21096     };
21097     
21098     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21099     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21100     
21101     return {
21102         /**
21103          * Registers new overflow element(s) to auto scroll
21104          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21105          */
21106         register : function(el){
21107             if(el instanceof Array){
21108                 for(var i = 0, len = el.length; i < len; i++) {
21109                         this.register(el[i]);
21110                 }
21111             }else{
21112                 el = Roo.get(el);
21113                 els[el.id] = el;
21114             }
21115             Roo.dd.ScrollManager.els = els;
21116         },
21117         
21118         /**
21119          * Unregisters overflow element(s) so they are no longer scrolled
21120          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21121          */
21122         unregister : function(el){
21123             if(el instanceof Array){
21124                 for(var i = 0, len = el.length; i < len; i++) {
21125                         this.unregister(el[i]);
21126                 }
21127             }else{
21128                 el = Roo.get(el);
21129                 delete els[el.id];
21130             }
21131         },
21132         
21133         /**
21134          * The number of pixels from the edge of a container the pointer needs to be to 
21135          * trigger scrolling (defaults to 25)
21136          * @type Number
21137          */
21138         thresh : 25,
21139         
21140         /**
21141          * The number of pixels to scroll in each scroll increment (defaults to 50)
21142          * @type Number
21143          */
21144         increment : 100,
21145         
21146         /**
21147          * The frequency of scrolls in milliseconds (defaults to 500)
21148          * @type Number
21149          */
21150         frequency : 500,
21151         
21152         /**
21153          * True to animate the scroll (defaults to true)
21154          * @type Boolean
21155          */
21156         animate: true,
21157         
21158         /**
21159          * The animation duration in seconds - 
21160          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21161          * @type Number
21162          */
21163         animDuration: .4,
21164         
21165         /**
21166          * Manually trigger a cache refresh.
21167          */
21168         refreshCache : function(){
21169             for(var id in els){
21170                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21171                     els[id]._region = els[id].getRegion();
21172                 }
21173             }
21174         }
21175     };
21176 }();/*
21177  * Based on:
21178  * Ext JS Library 1.1.1
21179  * Copyright(c) 2006-2007, Ext JS, LLC.
21180  *
21181  * Originally Released Under LGPL - original licence link has changed is not relivant.
21182  *
21183  * Fork - LGPL
21184  * <script type="text/javascript">
21185  */
21186  
21187
21188 /**
21189  * @class Roo.dd.Registry
21190  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21191  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21192  * @singleton
21193  */
21194 Roo.dd.Registry = function(){
21195     var elements = {}; 
21196     var handles = {}; 
21197     var autoIdSeed = 0;
21198
21199     var getId = function(el, autogen){
21200         if(typeof el == "string"){
21201             return el;
21202         }
21203         var id = el.id;
21204         if(!id && autogen !== false){
21205             id = "roodd-" + (++autoIdSeed);
21206             el.id = id;
21207         }
21208         return id;
21209     };
21210     
21211     return {
21212     /**
21213      * Register a drag drop element
21214      * @param {String|HTMLElement} element The id or DOM node to register
21215      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21216      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21217      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21218      * populated in the data object (if applicable):
21219      * <pre>
21220 Value      Description<br />
21221 ---------  ------------------------------------------<br />
21222 handles    Array of DOM nodes that trigger dragging<br />
21223            for the element being registered<br />
21224 isHandle   True if the element passed in triggers<br />
21225            dragging itself, else false
21226 </pre>
21227      */
21228         register : function(el, data){
21229             data = data || {};
21230             if(typeof el == "string"){
21231                 el = document.getElementById(el);
21232             }
21233             data.ddel = el;
21234             elements[getId(el)] = data;
21235             if(data.isHandle !== false){
21236                 handles[data.ddel.id] = data;
21237             }
21238             if(data.handles){
21239                 var hs = data.handles;
21240                 for(var i = 0, len = hs.length; i < len; i++){
21241                         handles[getId(hs[i])] = data;
21242                 }
21243             }
21244         },
21245
21246     /**
21247      * Unregister a drag drop element
21248      * @param {String|HTMLElement}  element The id or DOM node to unregister
21249      */
21250         unregister : function(el){
21251             var id = getId(el, false);
21252             var data = elements[id];
21253             if(data){
21254                 delete elements[id];
21255                 if(data.handles){
21256                     var hs = data.handles;
21257                     for(var i = 0, len = hs.length; i < len; i++){
21258                         delete handles[getId(hs[i], false)];
21259                     }
21260                 }
21261             }
21262         },
21263
21264     /**
21265      * Returns the handle registered for a DOM Node by id
21266      * @param {String|HTMLElement} id The DOM node or id to look up
21267      * @return {Object} handle The custom handle data
21268      */
21269         getHandle : function(id){
21270             if(typeof id != "string"){ // must be element?
21271                 id = id.id;
21272             }
21273             return handles[id];
21274         },
21275
21276     /**
21277      * Returns the handle that is registered for the DOM node that is the target of the event
21278      * @param {Event} e The event
21279      * @return {Object} handle The custom handle data
21280      */
21281         getHandleFromEvent : function(e){
21282             var t = Roo.lib.Event.getTarget(e);
21283             return t ? handles[t.id] : null;
21284         },
21285
21286     /**
21287      * Returns a custom data object that is registered for a DOM node by id
21288      * @param {String|HTMLElement} id The DOM node or id to look up
21289      * @return {Object} data The custom data
21290      */
21291         getTarget : function(id){
21292             if(typeof id != "string"){ // must be element?
21293                 id = id.id;
21294             }
21295             return elements[id];
21296         },
21297
21298     /**
21299      * Returns a custom data object that is registered for the DOM node that is the target of the event
21300      * @param {Event} e The event
21301      * @return {Object} data The custom data
21302      */
21303         getTargetFromEvent : function(e){
21304             var t = Roo.lib.Event.getTarget(e);
21305             return t ? elements[t.id] || handles[t.id] : null;
21306         }
21307     };
21308 }();/*
21309  * Based on:
21310  * Ext JS Library 1.1.1
21311  * Copyright(c) 2006-2007, Ext JS, LLC.
21312  *
21313  * Originally Released Under LGPL - original licence link has changed is not relivant.
21314  *
21315  * Fork - LGPL
21316  * <script type="text/javascript">
21317  */
21318  
21319
21320 /**
21321  * @class Roo.dd.StatusProxy
21322  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21323  * default drag proxy used by all Roo.dd components.
21324  * @constructor
21325  * @param {Object} config
21326  */
21327 Roo.dd.StatusProxy = function(config){
21328     Roo.apply(this, config);
21329     this.id = this.id || Roo.id();
21330     this.el = new Roo.Layer({
21331         dh: {
21332             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21333                 {tag: "div", cls: "x-dd-drop-icon"},
21334                 {tag: "div", cls: "x-dd-drag-ghost"}
21335             ]
21336         }, 
21337         shadow: !config || config.shadow !== false
21338     });
21339     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21340     this.dropStatus = this.dropNotAllowed;
21341 };
21342
21343 Roo.dd.StatusProxy.prototype = {
21344     /**
21345      * @cfg {String} dropAllowed
21346      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21347      */
21348     dropAllowed : "x-dd-drop-ok",
21349     /**
21350      * @cfg {String} dropNotAllowed
21351      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21352      */
21353     dropNotAllowed : "x-dd-drop-nodrop",
21354
21355     /**
21356      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21357      * over the current target element.
21358      * @param {String} cssClass The css class for the new drop status indicator image
21359      */
21360     setStatus : function(cssClass){
21361         cssClass = cssClass || this.dropNotAllowed;
21362         if(this.dropStatus != cssClass){
21363             this.el.replaceClass(this.dropStatus, cssClass);
21364             this.dropStatus = cssClass;
21365         }
21366     },
21367
21368     /**
21369      * Resets the status indicator to the default dropNotAllowed value
21370      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21371      */
21372     reset : function(clearGhost){
21373         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21374         this.dropStatus = this.dropNotAllowed;
21375         if(clearGhost){
21376             this.ghost.update("");
21377         }
21378     },
21379
21380     /**
21381      * Updates the contents of the ghost element
21382      * @param {String} html The html that will replace the current innerHTML of the ghost element
21383      */
21384     update : function(html){
21385         if(typeof html == "string"){
21386             this.ghost.update(html);
21387         }else{
21388             this.ghost.update("");
21389             html.style.margin = "0";
21390             this.ghost.dom.appendChild(html);
21391         }
21392         // ensure float = none set?? cant remember why though.
21393         var el = this.ghost.dom.firstChild;
21394                 if(el){
21395                         Roo.fly(el).setStyle('float', 'none');
21396                 }
21397     },
21398     
21399     /**
21400      * Returns the underlying proxy {@link Roo.Layer}
21401      * @return {Roo.Layer} el
21402     */
21403     getEl : function(){
21404         return this.el;
21405     },
21406
21407     /**
21408      * Returns the ghost element
21409      * @return {Roo.Element} el
21410      */
21411     getGhost : function(){
21412         return this.ghost;
21413     },
21414
21415     /**
21416      * Hides the proxy
21417      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21418      */
21419     hide : function(clear){
21420         this.el.hide();
21421         if(clear){
21422             this.reset(true);
21423         }
21424     },
21425
21426     /**
21427      * Stops the repair animation if it's currently running
21428      */
21429     stop : function(){
21430         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21431             this.anim.stop();
21432         }
21433     },
21434
21435     /**
21436      * Displays this proxy
21437      */
21438     show : function(){
21439         this.el.show();
21440     },
21441
21442     /**
21443      * Force the Layer to sync its shadow and shim positions to the element
21444      */
21445     sync : function(){
21446         this.el.sync();
21447     },
21448
21449     /**
21450      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21451      * invalid drop operation by the item being dragged.
21452      * @param {Array} xy The XY position of the element ([x, y])
21453      * @param {Function} callback The function to call after the repair is complete
21454      * @param {Object} scope The scope in which to execute the callback
21455      */
21456     repair : function(xy, callback, scope){
21457         this.callback = callback;
21458         this.scope = scope;
21459         if(xy && this.animRepair !== false){
21460             this.el.addClass("x-dd-drag-repair");
21461             this.el.hideUnders(true);
21462             this.anim = this.el.shift({
21463                 duration: this.repairDuration || .5,
21464                 easing: 'easeOut',
21465                 xy: xy,
21466                 stopFx: true,
21467                 callback: this.afterRepair,
21468                 scope: this
21469             });
21470         }else{
21471             this.afterRepair();
21472         }
21473     },
21474
21475     // private
21476     afterRepair : function(){
21477         this.hide(true);
21478         if(typeof this.callback == "function"){
21479             this.callback.call(this.scope || this);
21480         }
21481         this.callback = null;
21482         this.scope = null;
21483     }
21484 };/*
21485  * Based on:
21486  * Ext JS Library 1.1.1
21487  * Copyright(c) 2006-2007, Ext JS, LLC.
21488  *
21489  * Originally Released Under LGPL - original licence link has changed is not relivant.
21490  *
21491  * Fork - LGPL
21492  * <script type="text/javascript">
21493  */
21494
21495 /**
21496  * @class Roo.dd.DragSource
21497  * @extends Roo.dd.DDProxy
21498  * A simple class that provides the basic implementation needed to make any element draggable.
21499  * @constructor
21500  * @param {String/HTMLElement/Element} el The container element
21501  * @param {Object} config
21502  */
21503 Roo.dd.DragSource = function(el, config){
21504     this.el = Roo.get(el);
21505     this.dragData = {};
21506     
21507     Roo.apply(this, config);
21508     
21509     if(!this.proxy){
21510         this.proxy = new Roo.dd.StatusProxy();
21511     }
21512
21513     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21514           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21515     
21516     this.dragging = false;
21517 };
21518
21519 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21520     /**
21521      * @cfg {String} dropAllowed
21522      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21523      */
21524     dropAllowed : "x-dd-drop-ok",
21525     /**
21526      * @cfg {String} dropNotAllowed
21527      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21528      */
21529     dropNotAllowed : "x-dd-drop-nodrop",
21530
21531     /**
21532      * Returns the data object associated with this drag source
21533      * @return {Object} data An object containing arbitrary data
21534      */
21535     getDragData : function(e){
21536         return this.dragData;
21537     },
21538
21539     // private
21540     onDragEnter : function(e, id){
21541         var target = Roo.dd.DragDropMgr.getDDById(id);
21542         this.cachedTarget = target;
21543         if(this.beforeDragEnter(target, e, id) !== false){
21544             if(target.isNotifyTarget){
21545                 var status = target.notifyEnter(this, e, this.dragData);
21546                 this.proxy.setStatus(status);
21547             }else{
21548                 this.proxy.setStatus(this.dropAllowed);
21549             }
21550             
21551             if(this.afterDragEnter){
21552                 /**
21553                  * An empty function by default, but provided so that you can perform a custom action
21554                  * when the dragged item enters the drop target by providing an implementation.
21555                  * @param {Roo.dd.DragDrop} target The drop target
21556                  * @param {Event} e The event object
21557                  * @param {String} id The id of the dragged element
21558                  * @method afterDragEnter
21559                  */
21560                 this.afterDragEnter(target, e, id);
21561             }
21562         }
21563     },
21564
21565     /**
21566      * An empty function by default, but provided so that you can perform a custom action
21567      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21568      * @param {Roo.dd.DragDrop} target The drop target
21569      * @param {Event} e The event object
21570      * @param {String} id The id of the dragged element
21571      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21572      */
21573     beforeDragEnter : function(target, e, id){
21574         return true;
21575     },
21576
21577     // private
21578     alignElWithMouse: function() {
21579         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21580         this.proxy.sync();
21581     },
21582
21583     // private
21584     onDragOver : function(e, id){
21585         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21586         if(this.beforeDragOver(target, e, id) !== false){
21587             if(target.isNotifyTarget){
21588                 var status = target.notifyOver(this, e, this.dragData);
21589                 this.proxy.setStatus(status);
21590             }
21591
21592             if(this.afterDragOver){
21593                 /**
21594                  * An empty function by default, but provided so that you can perform a custom action
21595                  * while the dragged item is over the drop target by providing an implementation.
21596                  * @param {Roo.dd.DragDrop} target The drop target
21597                  * @param {Event} e The event object
21598                  * @param {String} id The id of the dragged element
21599                  * @method afterDragOver
21600                  */
21601                 this.afterDragOver(target, e, id);
21602             }
21603         }
21604     },
21605
21606     /**
21607      * An empty function by default, but provided so that you can perform a custom action
21608      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21609      * @param {Roo.dd.DragDrop} target The drop target
21610      * @param {Event} e The event object
21611      * @param {String} id The id of the dragged element
21612      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21613      */
21614     beforeDragOver : function(target, e, id){
21615         return true;
21616     },
21617
21618     // private
21619     onDragOut : function(e, id){
21620         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21621         if(this.beforeDragOut(target, e, id) !== false){
21622             if(target.isNotifyTarget){
21623                 target.notifyOut(this, e, this.dragData);
21624             }
21625             this.proxy.reset();
21626             if(this.afterDragOut){
21627                 /**
21628                  * An empty function by default, but provided so that you can perform a custom action
21629                  * after the dragged item is dragged out of the target without dropping.
21630                  * @param {Roo.dd.DragDrop} target The drop target
21631                  * @param {Event} e The event object
21632                  * @param {String} id The id of the dragged element
21633                  * @method afterDragOut
21634                  */
21635                 this.afterDragOut(target, e, id);
21636             }
21637         }
21638         this.cachedTarget = null;
21639     },
21640
21641     /**
21642      * An empty function by default, but provided so that you can perform a custom action before the dragged
21643      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21644      * @param {Roo.dd.DragDrop} target The drop target
21645      * @param {Event} e The event object
21646      * @param {String} id The id of the dragged element
21647      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21648      */
21649     beforeDragOut : function(target, e, id){
21650         return true;
21651     },
21652     
21653     // private
21654     onDragDrop : function(e, id){
21655         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21656         if(this.beforeDragDrop(target, e, id) !== false){
21657             if(target.isNotifyTarget){
21658                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21659                     this.onValidDrop(target, e, id);
21660                 }else{
21661                     this.onInvalidDrop(target, e, id);
21662                 }
21663             }else{
21664                 this.onValidDrop(target, e, id);
21665             }
21666             
21667             if(this.afterDragDrop){
21668                 /**
21669                  * An empty function by default, but provided so that you can perform a custom action
21670                  * after a valid drag drop has occurred by providing an implementation.
21671                  * @param {Roo.dd.DragDrop} target The drop target
21672                  * @param {Event} e The event object
21673                  * @param {String} id The id of the dropped element
21674                  * @method afterDragDrop
21675                  */
21676                 this.afterDragDrop(target, e, id);
21677             }
21678         }
21679         delete this.cachedTarget;
21680     },
21681
21682     /**
21683      * An empty function by default, but provided so that you can perform a custom action before the dragged
21684      * item is dropped onto the target and optionally cancel the onDragDrop.
21685      * @param {Roo.dd.DragDrop} target The drop target
21686      * @param {Event} e The event object
21687      * @param {String} id The id of the dragged element
21688      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21689      */
21690     beforeDragDrop : function(target, e, id){
21691         return true;
21692     },
21693
21694     // private
21695     onValidDrop : function(target, e, id){
21696         this.hideProxy();
21697         if(this.afterValidDrop){
21698             /**
21699              * An empty function by default, but provided so that you can perform a custom action
21700              * after a valid drop has occurred by providing an implementation.
21701              * @param {Object} target The target DD 
21702              * @param {Event} e The event object
21703              * @param {String} id The id of the dropped element
21704              * @method afterInvalidDrop
21705              */
21706             this.afterValidDrop(target, e, id);
21707         }
21708     },
21709
21710     // private
21711     getRepairXY : function(e, data){
21712         return this.el.getXY();  
21713     },
21714
21715     // private
21716     onInvalidDrop : function(target, e, id){
21717         this.beforeInvalidDrop(target, e, id);
21718         if(this.cachedTarget){
21719             if(this.cachedTarget.isNotifyTarget){
21720                 this.cachedTarget.notifyOut(this, e, this.dragData);
21721             }
21722             this.cacheTarget = null;
21723         }
21724         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21725
21726         if(this.afterInvalidDrop){
21727             /**
21728              * An empty function by default, but provided so that you can perform a custom action
21729              * after an invalid drop has occurred by providing an implementation.
21730              * @param {Event} e The event object
21731              * @param {String} id The id of the dropped element
21732              * @method afterInvalidDrop
21733              */
21734             this.afterInvalidDrop(e, id);
21735         }
21736     },
21737
21738     // private
21739     afterRepair : function(){
21740         if(Roo.enableFx){
21741             this.el.highlight(this.hlColor || "c3daf9");
21742         }
21743         this.dragging = false;
21744     },
21745
21746     /**
21747      * An empty function by default, but provided so that you can perform a custom action after an invalid
21748      * drop has occurred.
21749      * @param {Roo.dd.DragDrop} target The drop target
21750      * @param {Event} e The event object
21751      * @param {String} id The id of the dragged element
21752      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21753      */
21754     beforeInvalidDrop : function(target, e, id){
21755         return true;
21756     },
21757
21758     // private
21759     handleMouseDown : function(e){
21760         if(this.dragging) {
21761             return;
21762         }
21763         var data = this.getDragData(e);
21764         if(data && this.onBeforeDrag(data, e) !== false){
21765             this.dragData = data;
21766             this.proxy.stop();
21767             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21768         } 
21769     },
21770
21771     /**
21772      * An empty function by default, but provided so that you can perform a custom action before the initial
21773      * drag event begins and optionally cancel it.
21774      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21775      * @param {Event} e The event object
21776      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21777      */
21778     onBeforeDrag : function(data, e){
21779         return true;
21780     },
21781
21782     /**
21783      * An empty function by default, but provided so that you can perform a custom action once the initial
21784      * drag event has begun.  The drag cannot be canceled from this function.
21785      * @param {Number} x The x position of the click on the dragged object
21786      * @param {Number} y The y position of the click on the dragged object
21787      */
21788     onStartDrag : Roo.emptyFn,
21789
21790     // private - YUI override
21791     startDrag : function(x, y){
21792         this.proxy.reset();
21793         this.dragging = true;
21794         this.proxy.update("");
21795         this.onInitDrag(x, y);
21796         this.proxy.show();
21797     },
21798
21799     // private
21800     onInitDrag : function(x, y){
21801         var clone = this.el.dom.cloneNode(true);
21802         clone.id = Roo.id(); // prevent duplicate ids
21803         this.proxy.update(clone);
21804         this.onStartDrag(x, y);
21805         return true;
21806     },
21807
21808     /**
21809      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21810      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21811      */
21812     getProxy : function(){
21813         return this.proxy;  
21814     },
21815
21816     /**
21817      * Hides the drag source's {@link Roo.dd.StatusProxy}
21818      */
21819     hideProxy : function(){
21820         this.proxy.hide();  
21821         this.proxy.reset(true);
21822         this.dragging = false;
21823     },
21824
21825     // private
21826     triggerCacheRefresh : function(){
21827         Roo.dd.DDM.refreshCache(this.groups);
21828     },
21829
21830     // private - override to prevent hiding
21831     b4EndDrag: function(e) {
21832     },
21833
21834     // private - override to prevent moving
21835     endDrag : function(e){
21836         this.onEndDrag(this.dragData, e);
21837     },
21838
21839     // private
21840     onEndDrag : function(data, e){
21841     },
21842     
21843     // private - pin to cursor
21844     autoOffset : function(x, y) {
21845         this.setDelta(-12, -20);
21846     }    
21847 });/*
21848  * Based on:
21849  * Ext JS Library 1.1.1
21850  * Copyright(c) 2006-2007, Ext JS, LLC.
21851  *
21852  * Originally Released Under LGPL - original licence link has changed is not relivant.
21853  *
21854  * Fork - LGPL
21855  * <script type="text/javascript">
21856  */
21857
21858
21859 /**
21860  * @class Roo.dd.DropTarget
21861  * @extends Roo.dd.DDTarget
21862  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21863  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21864  * @constructor
21865  * @param {String/HTMLElement/Element} el The container element
21866  * @param {Object} config
21867  */
21868 Roo.dd.DropTarget = function(el, config){
21869     this.el = Roo.get(el);
21870     
21871     var listeners = false; ;
21872     if (config && config.listeners) {
21873         listeners= config.listeners;
21874         delete config.listeners;
21875     }
21876     Roo.apply(this, config);
21877     
21878     if(this.containerScroll){
21879         Roo.dd.ScrollManager.register(this.el);
21880     }
21881     this.addEvents( {
21882          /**
21883          * @scope Roo.dd.DropTarget
21884          */
21885          
21886          /**
21887          * @event enter
21888          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21889          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21890          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21891          * 
21892          * IMPORTANT : it should set this.overClass and this.dropAllowed
21893          * 
21894          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21895          * @param {Event} e The event
21896          * @param {Object} data An object containing arbitrary data supplied by the drag source
21897          */
21898         "enter" : true,
21899         
21900          /**
21901          * @event over
21902          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21903          * This method will be called on every mouse movement while the drag source is over the drop target.
21904          * This default implementation simply returns the dropAllowed config value.
21905          * 
21906          * IMPORTANT : it should set this.dropAllowed
21907          * 
21908          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21909          * @param {Event} e The event
21910          * @param {Object} data An object containing arbitrary data supplied by the drag source
21911          
21912          */
21913         "over" : true,
21914         /**
21915          * @event out
21916          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21917          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21918          * overClass (if any) from the drop element.
21919          * 
21920          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21921          * @param {Event} e The event
21922          * @param {Object} data An object containing arbitrary data supplied by the drag source
21923          */
21924          "out" : true,
21925          
21926         /**
21927          * @event drop
21928          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21929          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21930          * implementation that does something to process the drop event and returns true so that the drag source's
21931          * repair action does not run.
21932          * 
21933          * IMPORTANT : it should set this.success
21934          * 
21935          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21936          * @param {Event} e The event
21937          * @param {Object} data An object containing arbitrary data supplied by the drag source
21938         */
21939          "drop" : true
21940     });
21941             
21942      
21943     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21944         this.el.dom, 
21945         this.ddGroup || this.group,
21946         {
21947             isTarget: true,
21948             listeners : listeners || {} 
21949            
21950         
21951         }
21952     );
21953
21954 };
21955
21956 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21957     /**
21958      * @cfg {String} overClass
21959      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21960      */
21961      /**
21962      * @cfg {String} ddGroup
21963      * The drag drop group to handle drop events for
21964      */
21965      
21966     /**
21967      * @cfg {String} dropAllowed
21968      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21969      */
21970     dropAllowed : "x-dd-drop-ok",
21971     /**
21972      * @cfg {String} dropNotAllowed
21973      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21974      */
21975     dropNotAllowed : "x-dd-drop-nodrop",
21976     /**
21977      * @cfg {boolean} success
21978      * set this after drop listener.. 
21979      */
21980     success : false,
21981     /**
21982      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21983      * if the drop point is valid for over/enter..
21984      */
21985     valid : false,
21986     // private
21987     isTarget : true,
21988
21989     // private
21990     isNotifyTarget : true,
21991     
21992     /**
21993      * @hide
21994      */
21995     notifyEnter : function(dd, e, data)
21996     {
21997         this.valid = true;
21998         this.fireEvent('enter', dd, e, data);
21999         if(this.overClass){
22000             this.el.addClass(this.overClass);
22001         }
22002         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22003             this.valid ? this.dropAllowed : this.dropNotAllowed
22004         );
22005     },
22006
22007     /**
22008      * @hide
22009      */
22010     notifyOver : function(dd, e, data)
22011     {
22012         this.valid = true;
22013         this.fireEvent('over', dd, e, data);
22014         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22015             this.valid ? this.dropAllowed : this.dropNotAllowed
22016         );
22017     },
22018
22019     /**
22020      * @hide
22021      */
22022     notifyOut : function(dd, e, data)
22023     {
22024         this.fireEvent('out', dd, e, data);
22025         if(this.overClass){
22026             this.el.removeClass(this.overClass);
22027         }
22028     },
22029
22030     /**
22031      * @hide
22032      */
22033     notifyDrop : function(dd, e, data)
22034     {
22035         this.success = false;
22036         this.fireEvent('drop', dd, e, data);
22037         return this.success;
22038     }
22039 });/*
22040  * Based on:
22041  * Ext JS Library 1.1.1
22042  * Copyright(c) 2006-2007, Ext JS, LLC.
22043  *
22044  * Originally Released Under LGPL - original licence link has changed is not relivant.
22045  *
22046  * Fork - LGPL
22047  * <script type="text/javascript">
22048  */
22049
22050
22051 /**
22052  * @class Roo.dd.DragZone
22053  * @extends Roo.dd.DragSource
22054  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22055  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22056  * @constructor
22057  * @param {String/HTMLElement/Element} el The container element
22058  * @param {Object} config
22059  */
22060 Roo.dd.DragZone = function(el, config){
22061     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22062     if(this.containerScroll){
22063         Roo.dd.ScrollManager.register(this.el);
22064     }
22065 };
22066
22067 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22068     /**
22069      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22070      * for auto scrolling during drag operations.
22071      */
22072     /**
22073      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22074      * method after a failed drop (defaults to "c3daf9" - light blue)
22075      */
22076
22077     /**
22078      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22079      * for a valid target to drag based on the mouse down. Override this method
22080      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22081      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22082      * @param {EventObject} e The mouse down event
22083      * @return {Object} The dragData
22084      */
22085     getDragData : function(e){
22086         return Roo.dd.Registry.getHandleFromEvent(e);
22087     },
22088     
22089     /**
22090      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22091      * this.dragData.ddel
22092      * @param {Number} x The x position of the click on the dragged object
22093      * @param {Number} y The y position of the click on the dragged object
22094      * @return {Boolean} true to continue the drag, false to cancel
22095      */
22096     onInitDrag : function(x, y){
22097         this.proxy.update(this.dragData.ddel.cloneNode(true));
22098         this.onStartDrag(x, y);
22099         return true;
22100     },
22101     
22102     /**
22103      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22104      */
22105     afterRepair : function(){
22106         if(Roo.enableFx){
22107             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22108         }
22109         this.dragging = false;
22110     },
22111
22112     /**
22113      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22114      * the XY of this.dragData.ddel
22115      * @param {EventObject} e The mouse up event
22116      * @return {Array} The xy location (e.g. [100, 200])
22117      */
22118     getRepairXY : function(e){
22119         return Roo.Element.fly(this.dragData.ddel).getXY();  
22120     }
22121 });/*
22122  * Based on:
22123  * Ext JS Library 1.1.1
22124  * Copyright(c) 2006-2007, Ext JS, LLC.
22125  *
22126  * Originally Released Under LGPL - original licence link has changed is not relivant.
22127  *
22128  * Fork - LGPL
22129  * <script type="text/javascript">
22130  */
22131 /**
22132  * @class Roo.dd.DropZone
22133  * @extends Roo.dd.DropTarget
22134  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22135  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22136  * @constructor
22137  * @param {String/HTMLElement/Element} el The container element
22138  * @param {Object} config
22139  */
22140 Roo.dd.DropZone = function(el, config){
22141     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22142 };
22143
22144 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22145     /**
22146      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22147      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22148      * provide your own custom lookup.
22149      * @param {Event} e The event
22150      * @return {Object} data The custom data
22151      */
22152     getTargetFromEvent : function(e){
22153         return Roo.dd.Registry.getTargetFromEvent(e);
22154     },
22155
22156     /**
22157      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22158      * that it has registered.  This method has no default implementation and should be overridden to provide
22159      * node-specific processing if necessary.
22160      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22161      * {@link #getTargetFromEvent} for this node)
22162      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22163      * @param {Event} e The event
22164      * @param {Object} data An object containing arbitrary data supplied by the drag source
22165      */
22166     onNodeEnter : function(n, dd, e, data){
22167         
22168     },
22169
22170     /**
22171      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22172      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22173      * overridden to provide the proper feedback.
22174      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22175      * {@link #getTargetFromEvent} for this node)
22176      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22177      * @param {Event} e The event
22178      * @param {Object} data An object containing arbitrary data supplied by the drag source
22179      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22180      * underlying {@link Roo.dd.StatusProxy} can be updated
22181      */
22182     onNodeOver : function(n, dd, e, data){
22183         return this.dropAllowed;
22184     },
22185
22186     /**
22187      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22188      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22189      * node-specific processing if necessary.
22190      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22191      * {@link #getTargetFromEvent} for this node)
22192      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22193      * @param {Event} e The event
22194      * @param {Object} data An object containing arbitrary data supplied by the drag source
22195      */
22196     onNodeOut : function(n, dd, e, data){
22197         
22198     },
22199
22200     /**
22201      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22202      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22203      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22204      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22205      * {@link #getTargetFromEvent} for this node)
22206      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22207      * @param {Event} e The event
22208      * @param {Object} data An object containing arbitrary data supplied by the drag source
22209      * @return {Boolean} True if the drop was valid, else false
22210      */
22211     onNodeDrop : function(n, dd, e, data){
22212         return false;
22213     },
22214
22215     /**
22216      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22217      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22218      * it should be overridden to provide the proper feedback if necessary.
22219      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22220      * @param {Event} e The event
22221      * @param {Object} data An object containing arbitrary data supplied by the drag source
22222      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22223      * underlying {@link Roo.dd.StatusProxy} can be updated
22224      */
22225     onContainerOver : function(dd, e, data){
22226         return this.dropNotAllowed;
22227     },
22228
22229     /**
22230      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22231      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22232      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22233      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22234      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22235      * @param {Event} e The event
22236      * @param {Object} data An object containing arbitrary data supplied by the drag source
22237      * @return {Boolean} True if the drop was valid, else false
22238      */
22239     onContainerDrop : function(dd, e, data){
22240         return false;
22241     },
22242
22243     /**
22244      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22245      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22246      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22247      * you should override this method and provide a custom implementation.
22248      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22249      * @param {Event} e The event
22250      * @param {Object} data An object containing arbitrary data supplied by the drag source
22251      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22252      * underlying {@link Roo.dd.StatusProxy} can be updated
22253      */
22254     notifyEnter : function(dd, e, data){
22255         return this.dropNotAllowed;
22256     },
22257
22258     /**
22259      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22260      * This method will be called on every mouse movement while the drag source is over the drop zone.
22261      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22262      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22263      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22264      * registered node, it will call {@link #onContainerOver}.
22265      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22266      * @param {Event} e The event
22267      * @param {Object} data An object containing arbitrary data supplied by the drag source
22268      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22269      * underlying {@link Roo.dd.StatusProxy} can be updated
22270      */
22271     notifyOver : function(dd, e, data){
22272         var n = this.getTargetFromEvent(e);
22273         if(!n){ // not over valid drop target
22274             if(this.lastOverNode){
22275                 this.onNodeOut(this.lastOverNode, dd, e, data);
22276                 this.lastOverNode = null;
22277             }
22278             return this.onContainerOver(dd, e, data);
22279         }
22280         if(this.lastOverNode != n){
22281             if(this.lastOverNode){
22282                 this.onNodeOut(this.lastOverNode, dd, e, data);
22283             }
22284             this.onNodeEnter(n, dd, e, data);
22285             this.lastOverNode = n;
22286         }
22287         return this.onNodeOver(n, dd, e, data);
22288     },
22289
22290     /**
22291      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22292      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22293      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22294      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22295      * @param {Event} e The event
22296      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22297      */
22298     notifyOut : function(dd, e, data){
22299         if(this.lastOverNode){
22300             this.onNodeOut(this.lastOverNode, dd, e, data);
22301             this.lastOverNode = null;
22302         }
22303     },
22304
22305     /**
22306      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22307      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22308      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22309      * otherwise it will call {@link #onContainerDrop}.
22310      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22311      * @param {Event} e The event
22312      * @param {Object} data An object containing arbitrary data supplied by the drag source
22313      * @return {Boolean} True if the drop was valid, else false
22314      */
22315     notifyDrop : function(dd, e, data){
22316         if(this.lastOverNode){
22317             this.onNodeOut(this.lastOverNode, dd, e, data);
22318             this.lastOverNode = null;
22319         }
22320         var n = this.getTargetFromEvent(e);
22321         return n ?
22322             this.onNodeDrop(n, dd, e, data) :
22323             this.onContainerDrop(dd, e, data);
22324     },
22325
22326     // private
22327     triggerCacheRefresh : function(){
22328         Roo.dd.DDM.refreshCache(this.groups);
22329     }  
22330 });