roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isGecko = !isSafari && ua.indexOf("gecko") > -1,
61         isBorderBox = isIE && !isStrict,
62         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64         isLinux = (ua.indexOf("linux") != -1),
65         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66         isIOS = /iphone|ipad/.test(ua),
67         isTouch =  (function() {
68             try {
69                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
70                     window.addEventListener('touchstart', function __set_has_touch__ () {
71                         Roo.isTouch = true;
72                         window.removeEventListener('touchstart', __set_has_touch__);
73                     });
74                     return false; // no touch on chrome!?
75                 }
76                 document.createEvent("TouchEvent");  
77                 return true;  
78             } catch (e) {  
79                 return false;  
80             } 
81             
82         })();
83     // remove css image flicker
84         if(isIE && !isIE7){
85         try{
86             document.execCommand("BackgroundImageCache", false, true);
87         }catch(e){}
88     }
89     
90     Roo.apply(Roo, {
91         /**
92          * True if the browser is in strict mode
93          * @type Boolean
94          */
95         isStrict : isStrict,
96         /**
97          * True if the page is running over SSL
98          * @type Boolean
99          */
100         isSecure : isSecure,
101         /**
102          * True when the document is fully initialized and ready for action
103          * @type Boolean
104          */
105         isReady : false,
106         /**
107          * Turn on debugging output (currently only the factory uses this)
108          * @type Boolean
109          */
110         
111         debug: false,
112
113         /**
114          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
115          * @type Boolean
116          */
117         enableGarbageCollector : true,
118
119         /**
120          * True to automatically purge event listeners after uncaching an element (defaults to false).
121          * Note: this only happens if enableGarbageCollector is true.
122          * @type Boolean
123          */
124         enableListenerCollection:false,
125
126         /**
127          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
128          * the IE insecure content warning (defaults to javascript:false).
129          * @type String
130          */
131         SSL_SECURE_URL : "javascript:false",
132
133         /**
134          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
135          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
136          * @type String
137          */
138         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
139
140         emptyFn : function(){},
141         
142         /**
143          * Copies all the properties of config to obj if they don't already exist.
144          * @param {Object} obj The receiver of the properties
145          * @param {Object} config The source of the properties
146          * @return {Object} returns obj
147          */
148         applyIf : function(o, c){
149             if(o && c){
150                 for(var p in c){
151                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
152                 }
153             }
154             return o;
155         },
156
157         /**
158          * Applies event listeners to elements by selectors when the document is ready.
159          * The event name is specified with an @ suffix.
160 <pre><code>
161 Roo.addBehaviors({
162    // add a listener for click on all anchors in element with id foo
163    '#foo a@click' : function(e, t){
164        // do something
165    },
166
167    // add the same listener to multiple selectors (separated by comma BEFORE the @)
168    '#foo a, #bar span.some-class@mouseover' : function(){
169        // do something
170    }
171 });
172 </code></pre>
173          * @param {Object} obj The list of behaviors to apply
174          */
175         addBehaviors : function(o){
176             if(!Roo.isReady){
177                 Roo.onReady(function(){
178                     Roo.addBehaviors(o);
179                 });
180                 return;
181             }
182             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
183             for(var b in o){
184                 var parts = b.split('@');
185                 if(parts[1]){ // for Object prototype breakers
186                     var s = parts[0];
187                     if(!cache[s]){
188                         cache[s] = Roo.select(s);
189                     }
190                     cache[s].on(parts[1], o[b]);
191                 }
192             }
193             cache = null;
194         },
195
196         /**
197          * Generates unique ids. If the element already has an id, it is unchanged
198          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
199          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
200          * @return {String} The generated Id.
201          */
202         id : function(el, prefix){
203             prefix = prefix || "roo-gen";
204             el = Roo.getDom(el);
205             var id = prefix + (++idSeed);
206             return el ? (el.id ? el.id : (el.id = id)) : id;
207         },
208          
209        
210         /**
211          * Extends one class with another class and optionally overrides members with the passed literal. This class
212          * also adds the function "override()" to the class that can be used to override
213          * members on an instance.
214          * @param {Object} subclass The class inheriting the functionality
215          * @param {Object} superclass The class being extended
216          * @param {Object} overrides (optional) A literal with members
217          * @method extend
218          */
219         extend : function(){
220             // inline overrides
221             var io = function(o){
222                 for(var m in o){
223                     this[m] = o[m];
224                 }
225             };
226             return function(sb, sp, overrides){
227                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
228                     overrides = sp;
229                     sp = sb;
230                     sb = function(){sp.apply(this, arguments);};
231                 }
232                 var F = function(){}, sbp, spp = sp.prototype;
233                 F.prototype = spp;
234                 sbp = sb.prototype = new F();
235                 sbp.constructor=sb;
236                 sb.superclass=spp;
237                 
238                 if(spp.constructor == Object.prototype.constructor){
239                     spp.constructor=sp;
240                    
241                 }
242                 
243                 sb.override = function(o){
244                     Roo.override(sb, o);
245                 };
246                 sbp.override = io;
247                 Roo.override(sb, overrides);
248                 return sb;
249             };
250         }(),
251
252         /**
253          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
254          * Usage:<pre><code>
255 Roo.override(MyClass, {
256     newMethod1: function(){
257         // etc.
258     },
259     newMethod2: function(foo){
260         // etc.
261     }
262 });
263  </code></pre>
264          * @param {Object} origclass The class to override
265          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
266          * containing one or more methods.
267          * @method override
268          */
269         override : function(origclass, overrides){
270             if(overrides){
271                 var p = origclass.prototype;
272                 for(var method in overrides){
273                     p[method] = overrides[method];
274                 }
275             }
276         },
277         /**
278          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
279          * <pre><code>
280 Roo.namespace('Company', 'Company.data');
281 Company.Widget = function() { ... }
282 Company.data.CustomStore = function(config) { ... }
283 </code></pre>
284          * @param {String} namespace1
285          * @param {String} namespace2
286          * @param {String} etc
287          * @method namespace
288          */
289         namespace : function(){
290             var a=arguments, o=null, i, j, d, rt;
291             for (i=0; i<a.length; ++i) {
292                 d=a[i].split(".");
293                 rt = d[0];
294                 /** eval:var:o */
295                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
296                 for (j=1; j<d.length; ++j) {
297                     o[d[j]]=o[d[j]] || {};
298                     o=o[d[j]];
299                 }
300             }
301         },
302         /**
303          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
304          * <pre><code>
305 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
306 Roo.factory(conf, Roo.data);
307 </code></pre>
308          * @param {String} classname
309          * @param {String} namespace (optional)
310          * @method factory
311          */
312          
313         factory : function(c, ns)
314         {
315             // no xtype, no ns or c.xns - or forced off by c.xns
316             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
317                 return c;
318             }
319             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
320             if (c.constructor == ns[c.xtype]) {// already created...
321                 return c;
322             }
323             if (ns[c.xtype]) {
324                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
325                 var ret = new ns[c.xtype](c);
326                 ret.xns = false;
327                 return ret;
328             }
329             c.xns = false; // prevent recursion..
330             return c;
331         },
332          /**
333          * Logs to console if it can.
334          *
335          * @param {String|Object} string
336          * @method log
337          */
338         log : function(s)
339         {
340             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
341                 return; // alerT?
342             }
343             console.log(s);
344             
345         },
346         /**
347          * 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.
348          * @param {Object} o
349          * @return {String}
350          */
351         urlEncode : function(o){
352             if(!o){
353                 return "";
354             }
355             var buf = [];
356             for(var key in o){
357                 var ov = o[key], k = Roo.encodeURIComponent(key);
358                 var type = typeof ov;
359                 if(type == 'undefined'){
360                     buf.push(k, "=&");
361                 }else if(type != "function" && type != "object"){
362                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
363                 }else if(ov instanceof Array){
364                     if (ov.length) {
365                             for(var i = 0, len = ov.length; i < len; i++) {
366                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
367                             }
368                         } else {
369                             buf.push(k, "=&");
370                         }
371                 }
372             }
373             buf.pop();
374             return buf.join("");
375         },
376          /**
377          * Safe version of encodeURIComponent
378          * @param {String} data 
379          * @return {String} 
380          */
381         
382         encodeURIComponent : function (data)
383         {
384             try {
385                 return encodeURIComponent(data);
386             } catch(e) {} // should be an uri encode error.
387             
388             if (data == '' || data == null){
389                return '';
390             }
391             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
392             function nibble_to_hex(nibble){
393                 var chars = '0123456789ABCDEF';
394                 return chars.charAt(nibble);
395             }
396             data = data.toString();
397             var buffer = '';
398             for(var i=0; i<data.length; i++){
399                 var c = data.charCodeAt(i);
400                 var bs = new Array();
401                 if (c > 0x10000){
402                         // 4 bytes
403                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
404                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
405                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
406                     bs[3] = 0x80 | (c & 0x3F);
407                 }else if (c > 0x800){
408                          // 3 bytes
409                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
410                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
411                     bs[2] = 0x80 | (c & 0x3F);
412                 }else if (c > 0x80){
413                        // 2 bytes
414                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
415                     bs[1] = 0x80 | (c & 0x3F);
416                 }else{
417                         // 1 byte
418                     bs[0] = c;
419                 }
420                 for(var j=0; j<bs.length; j++){
421                     var b = bs[j];
422                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
423                             + nibble_to_hex(b &0x0F);
424                     buffer += '%'+hex;
425                }
426             }
427             return buffer;    
428              
429         },
430
431         /**
432          * 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]}.
433          * @param {String} string
434          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
435          * @return {Object} A literal with members
436          */
437         urlDecode : function(string, overwrite){
438             if(!string || !string.length){
439                 return {};
440             }
441             var obj = {};
442             var pairs = string.split('&');
443             var pair, name, value;
444             for(var i = 0, len = pairs.length; i < len; i++){
445                 pair = pairs[i].split('=');
446                 name = decodeURIComponent(pair[0]);
447                 value = decodeURIComponent(pair[1]);
448                 if(overwrite !== true){
449                     if(typeof obj[name] == "undefined"){
450                         obj[name] = value;
451                     }else if(typeof obj[name] == "string"){
452                         obj[name] = [obj[name]];
453                         obj[name].push(value);
454                     }else{
455                         obj[name].push(value);
456                     }
457                 }else{
458                     obj[name] = value;
459                 }
460             }
461             return obj;
462         },
463
464         /**
465          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
466          * passed array is not really an array, your function is called once with it.
467          * The supplied function is called with (Object item, Number index, Array allItems).
468          * @param {Array/NodeList/Mixed} array
469          * @param {Function} fn
470          * @param {Object} scope
471          */
472         each : function(array, fn, scope){
473             if(typeof array.length == "undefined" || typeof array == "string"){
474                 array = [array];
475             }
476             for(var i = 0, len = array.length; i < len; i++){
477                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
478             }
479         },
480
481         // deprecated
482         combine : function(){
483             var as = arguments, l = as.length, r = [];
484             for(var i = 0; i < l; i++){
485                 var a = as[i];
486                 if(a instanceof Array){
487                     r = r.concat(a);
488                 }else if(a.length !== undefined && !a.substr){
489                     r = r.concat(Array.prototype.slice.call(a, 0));
490                 }else{
491                     r.push(a);
492                 }
493             }
494             return r;
495         },
496
497         /**
498          * Escapes the passed string for use in a regular expression
499          * @param {String} str
500          * @return {String}
501          */
502         escapeRe : function(s) {
503             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
504         },
505
506         // internal
507         callback : function(cb, scope, args, delay){
508             if(typeof cb == "function"){
509                 if(delay){
510                     cb.defer(delay, scope, args || []);
511                 }else{
512                     cb.apply(scope, args || []);
513                 }
514             }
515         },
516
517         /**
518          * Return the dom node for the passed string (id), dom node, or Roo.Element
519          * @param {String/HTMLElement/Roo.Element} el
520          * @return HTMLElement
521          */
522         getDom : function(el){
523             if(!el){
524                 return null;
525             }
526             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
527         },
528
529         /**
530         * Shorthand for {@link Roo.ComponentMgr#get}
531         * @param {String} id
532         * @return Roo.Component
533         */
534         getCmp : function(id){
535             return Roo.ComponentMgr.get(id);
536         },
537          
538         num : function(v, defaultValue){
539             if(typeof v != 'number'){
540                 return defaultValue;
541             }
542             return v;
543         },
544
545         destroy : function(){
546             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
547                 var as = a[i];
548                 if(as){
549                     if(as.dom){
550                         as.removeAllListeners();
551                         as.remove();
552                         continue;
553                     }
554                     if(typeof as.purgeListeners == 'function'){
555                         as.purgeListeners();
556                     }
557                     if(typeof as.destroy == 'function'){
558                         as.destroy();
559                     }
560                 }
561             }
562         },
563
564         // inpired by a similar function in mootools library
565         /**
566          * Returns the type of object that is passed in. If the object passed in is null or undefined it
567          * return false otherwise it returns one of the following values:<ul>
568          * <li><b>string</b>: If the object passed is a string</li>
569          * <li><b>number</b>: If the object passed is a number</li>
570          * <li><b>boolean</b>: If the object passed is a boolean value</li>
571          * <li><b>function</b>: If the object passed is a function reference</li>
572          * <li><b>object</b>: If the object passed is an object</li>
573          * <li><b>array</b>: If the object passed is an array</li>
574          * <li><b>regexp</b>: If the object passed is a regular expression</li>
575          * <li><b>element</b>: If the object passed is a DOM Element</li>
576          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
577          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
578          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
579          * @param {Mixed} object
580          * @return {String}
581          */
582         type : function(o){
583             if(o === undefined || o === null){
584                 return false;
585             }
586             if(o.htmlElement){
587                 return 'element';
588             }
589             var t = typeof o;
590             if(t == 'object' && o.nodeName) {
591                 switch(o.nodeType) {
592                     case 1: return 'element';
593                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
594                 }
595             }
596             if(t == 'object' || t == 'function') {
597                 switch(o.constructor) {
598                     case Array: return 'array';
599                     case RegExp: return 'regexp';
600                 }
601                 if(typeof o.length == 'number' && typeof o.item == 'function') {
602                     return 'nodelist';
603                 }
604             }
605             return t;
606         },
607
608         /**
609          * Returns true if the passed value is null, undefined or an empty string (optional).
610          * @param {Mixed} value The value to test
611          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
612          * @return {Boolean}
613          */
614         isEmpty : function(v, allowBlank){
615             return v === null || v === undefined || (!allowBlank ? v === '' : false);
616         },
617         
618         /** @type Boolean */
619         isOpera : isOpera,
620         /** @type Boolean */
621         isSafari : isSafari,
622         /** @type Boolean */
623         isFirefox : isFirefox,
624         /** @type Boolean */
625         isIE : isIE,
626         /** @type Boolean */
627         isIE7 : isIE7,
628         /** @type Boolean */
629         isIE11 : isIE11,
630         /** @type Boolean */
631         isGecko : isGecko,
632         /** @type Boolean */
633         isBorderBox : isBorderBox,
634         /** @type Boolean */
635         isWindows : isWindows,
636         /** @type Boolean */
637         isLinux : isLinux,
638         /** @type Boolean */
639         isMac : isMac,
640         /** @type Boolean */
641         isIOS : isIOS,
642         /** @type Boolean */
643         isTouch : isTouch,
644
645         /**
646          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
647          * you may want to set this to true.
648          * @type Boolean
649          */
650         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
651         
652         
653                 
654         /**
655          * Selects a single element as a Roo Element
656          * This is about as close as you can get to jQuery's $('do crazy stuff')
657          * @param {String} selector The selector/xpath query
658          * @param {Node} root (optional) The start of the query (defaults to document).
659          * @return {Roo.Element}
660          */
661         selectNode : function(selector, root) 
662         {
663             var node = Roo.DomQuery.selectNode(selector,root);
664             return node ? Roo.get(node) : new Roo.Element(false);
665         }
666         
667     });
668
669
670 })();
671
672 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
673                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
674                 "Roo.app", "Roo.ux",
675                 "Roo.bootstrap",
676                 "Roo.bootstrap.dash");
677 /*
678  * Based on:
679  * Ext JS Library 1.1.1
680  * Copyright(c) 2006-2007, Ext JS, LLC.
681  *
682  * Originally Released Under LGPL - original licence link has changed is not relivant.
683  *
684  * Fork - LGPL
685  * <script type="text/javascript">
686  */
687
688 (function() {    
689     // wrappedn so fnCleanup is not in global scope...
690     if(Roo.isIE) {
691         function fnCleanUp() {
692             var p = Function.prototype;
693             delete p.createSequence;
694             delete p.defer;
695             delete p.createDelegate;
696             delete p.createCallback;
697             delete p.createInterceptor;
698
699             window.detachEvent("onunload", fnCleanUp);
700         }
701         window.attachEvent("onunload", fnCleanUp);
702     }
703 })();
704
705
706 /**
707  * @class Function
708  * These functions are available on every Function object (any JavaScript function).
709  */
710 Roo.apply(Function.prototype, {
711      /**
712      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
713      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
714      * Will create a function that is bound to those 2 args.
715      * @return {Function} The new function
716     */
717     createCallback : function(/*args...*/){
718         // make args available, in function below
719         var args = arguments;
720         var method = this;
721         return function() {
722             return method.apply(window, args);
723         };
724     },
725
726     /**
727      * Creates a delegate (callback) that sets the scope to obj.
728      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
729      * Will create a function that is automatically scoped to this.
730      * @param {Object} obj (optional) The object for which the scope is set
731      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
732      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
733      *                                             if a number the args are inserted at the specified position
734      * @return {Function} The new function
735      */
736     createDelegate : function(obj, args, appendArgs){
737         var method = this;
738         return function() {
739             var callArgs = args || arguments;
740             if(appendArgs === true){
741                 callArgs = Array.prototype.slice.call(arguments, 0);
742                 callArgs = callArgs.concat(args);
743             }else if(typeof appendArgs == "number"){
744                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
745                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
746                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
747             }
748             return method.apply(obj || window, callArgs);
749         };
750     },
751
752     /**
753      * Calls this function after the number of millseconds specified.
754      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
755      * @param {Object} obj (optional) The object for which the scope is set
756      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
757      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
758      *                                             if a number the args are inserted at the specified position
759      * @return {Number} The timeout id that can be used with clearTimeout
760      */
761     defer : function(millis, obj, args, appendArgs){
762         var fn = this.createDelegate(obj, args, appendArgs);
763         if(millis){
764             return setTimeout(fn, millis);
765         }
766         fn();
767         return 0;
768     },
769     /**
770      * Create a combined function call sequence of the original function + the passed function.
771      * The resulting function returns the results of the original function.
772      * The passed fcn is called with the parameters of the original function
773      * @param {Function} fcn The function to sequence
774      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
775      * @return {Function} The new function
776      */
777     createSequence : function(fcn, scope){
778         if(typeof fcn != "function"){
779             return this;
780         }
781         var method = this;
782         return function() {
783             var retval = method.apply(this || window, arguments);
784             fcn.apply(scope || this || window, arguments);
785             return retval;
786         };
787     },
788
789     /**
790      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
791      * The resulting function returns the results of the original function.
792      * The passed fcn is called with the parameters of the original function.
793      * @addon
794      * @param {Function} fcn The function to call before the original
795      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
796      * @return {Function} The new function
797      */
798     createInterceptor : function(fcn, scope){
799         if(typeof fcn != "function"){
800             return this;
801         }
802         var method = this;
803         return function() {
804             fcn.target = this;
805             fcn.method = method;
806             if(fcn.apply(scope || this || window, arguments) === false){
807                 return;
808             }
809             return method.apply(this || window, arguments);
810         };
811     }
812 });
813 /*
814  * Based on:
815  * Ext JS Library 1.1.1
816  * Copyright(c) 2006-2007, Ext JS, LLC.
817  *
818  * Originally Released Under LGPL - original licence link has changed is not relivant.
819  *
820  * Fork - LGPL
821  * <script type="text/javascript">
822  */
823
824 Roo.applyIf(String, {
825     
826     /** @scope String */
827     
828     /**
829      * Escapes the passed string for ' and \
830      * @param {String} string The string to escape
831      * @return {String} The escaped string
832      * @static
833      */
834     escape : function(string) {
835         return string.replace(/('|\\)/g, "\\$1");
836     },
837
838     /**
839      * Pads the left side of a string with a specified character.  This is especially useful
840      * for normalizing number and date strings.  Example usage:
841      * <pre><code>
842 var s = String.leftPad('123', 5, '0');
843 // s now contains the string: '00123'
844 </code></pre>
845      * @param {String} string The original string
846      * @param {Number} size The total length of the output string
847      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
848      * @return {String} The padded string
849      * @static
850      */
851     leftPad : function (val, size, ch) {
852         var result = new String(val);
853         if(ch === null || ch === undefined || ch === '') {
854             ch = " ";
855         }
856         while (result.length < size) {
857             result = ch + result;
858         }
859         return result;
860     },
861
862     /**
863      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
864      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
865      * <pre><code>
866 var cls = 'my-class', text = 'Some text';
867 var s = String.format('<div class="{0}">{1}</div>', cls, text);
868 // s now contains the string: '<div class="my-class">Some text</div>'
869 </code></pre>
870      * @param {String} string The tokenized string to be formatted
871      * @param {String} value1 The value to replace token {0}
872      * @param {String} value2 Etc...
873      * @return {String} The formatted string
874      * @static
875      */
876     format : function(format){
877         var args = Array.prototype.slice.call(arguments, 1);
878         return format.replace(/\{(\d+)\}/g, function(m, i){
879             return Roo.util.Format.htmlEncode(args[i]);
880         });
881     }
882 });
883
884 /**
885  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
886  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
887  * they are already different, the first value passed in is returned.  Note that this method returns the new value
888  * but does not change the current string.
889  * <pre><code>
890 // alternate sort directions
891 sort = sort.toggle('ASC', 'DESC');
892
893 // instead of conditional logic:
894 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
895 </code></pre>
896  * @param {String} value The value to compare to the current string
897  * @param {String} other The new value to use if the string already equals the first value passed in
898  * @return {String} The new value
899  */
900  
901 String.prototype.toggle = function(value, other){
902     return this == value ? other : value;
903 };/*
904  * Based on:
905  * Ext JS Library 1.1.1
906  * Copyright(c) 2006-2007, Ext JS, LLC.
907  *
908  * Originally Released Under LGPL - original licence link has changed is not relivant.
909  *
910  * Fork - LGPL
911  * <script type="text/javascript">
912  */
913
914  /**
915  * @class Number
916  */
917 Roo.applyIf(Number.prototype, {
918     /**
919      * Checks whether or not the current number is within a desired range.  If the number is already within the
920      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
921      * exceeded.  Note that this method returns the constrained value but does not change the current number.
922      * @param {Number} min The minimum number in the range
923      * @param {Number} max The maximum number in the range
924      * @return {Number} The constrained value if outside the range, otherwise the current value
925      */
926     constrain : function(min, max){
927         return Math.min(Math.max(this, min), max);
928     }
929 });/*
930  * Based on:
931  * Ext JS Library 1.1.1
932  * Copyright(c) 2006-2007, Ext JS, LLC.
933  *
934  * Originally Released Under LGPL - original licence link has changed is not relivant.
935  *
936  * Fork - LGPL
937  * <script type="text/javascript">
938  */
939  /**
940  * @class Array
941  */
942 Roo.applyIf(Array.prototype, {
943     /**
944      * 
945      * Checks whether or not the specified object exists in the array.
946      * @param {Object} o The object to check for
947      * @return {Number} The index of o in the array (or -1 if it is not found)
948      */
949     indexOf : function(o){
950        for (var i = 0, len = this.length; i < len; i++){
951               if(this[i] == o) { return i; }
952        }
953            return -1;
954     },
955
956     /**
957      * Removes the specified object from the array.  If the object is not found nothing happens.
958      * @param {Object} o The object to remove
959      */
960     remove : function(o){
961        var index = this.indexOf(o);
962        if(index != -1){
963            this.splice(index, 1);
964        }
965     },
966     /**
967      * Map (JS 1.6 compatibility)
968      * @param {Function} function  to call
969      */
970     map : function(fun )
971     {
972         var len = this.length >>> 0;
973         if (typeof fun != "function") {
974             throw new TypeError();
975         }
976         var res = new Array(len);
977         var thisp = arguments[1];
978         for (var i = 0; i < len; i++)
979         {
980             if (i in this) {
981                 res[i] = fun.call(thisp, this[i], i, this);
982             }
983         }
984
985         return res;
986     }
987     
988 });
989
990
991  
992 /*
993  * Based on:
994  * Ext JS Library 1.1.1
995  * Copyright(c) 2006-2007, Ext JS, LLC.
996  *
997  * Originally Released Under LGPL - original licence link has changed is not relivant.
998  *
999  * Fork - LGPL
1000  * <script type="text/javascript">
1001  */
1002
1003 /**
1004  * @class Date
1005  *
1006  * The date parsing and format syntax is a subset of
1007  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1008  * supported will provide results equivalent to their PHP versions.
1009  *
1010  * Following is the list of all currently supported formats:
1011  *<pre>
1012 Sample date:
1013 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1014
1015 Format  Output      Description
1016 ------  ----------  --------------------------------------------------------------
1017   d      10         Day of the month, 2 digits with leading zeros
1018   D      Wed        A textual representation of a day, three letters
1019   j      10         Day of the month without leading zeros
1020   l      Wednesday  A full textual representation of the day of the week
1021   S      th         English ordinal day of month suffix, 2 chars (use with j)
1022   w      3          Numeric representation of the day of the week
1023   z      9          The julian date, or day of the year (0-365)
1024   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1025   F      January    A full textual representation of the month
1026   m      01         Numeric representation of a month, with leading zeros
1027   M      Jan        Month name abbreviation, three letters
1028   n      1          Numeric representation of a month, without leading zeros
1029   t      31         Number of days in the given month
1030   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1031   Y      2007       A full numeric representation of a year, 4 digits
1032   y      07         A two digit representation of a year
1033   a      pm         Lowercase Ante meridiem and Post meridiem
1034   A      PM         Uppercase Ante meridiem and Post meridiem
1035   g      3          12-hour format of an hour without leading zeros
1036   G      15         24-hour format of an hour without leading zeros
1037   h      03         12-hour format of an hour with leading zeros
1038   H      15         24-hour format of an hour with leading zeros
1039   i      05         Minutes with leading zeros
1040   s      01         Seconds, with leading zeros
1041   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1042   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1043   T      CST        Timezone setting of the machine running the code
1044   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1045 </pre>
1046  *
1047  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1048  * <pre><code>
1049 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1050 document.write(dt.format('Y-m-d'));                         //2007-01-10
1051 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1052 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
1053  </code></pre>
1054  *
1055  * Here are some standard date/time patterns that you might find helpful.  They
1056  * are not part of the source of Date.js, but to use them you can simply copy this
1057  * block of code into any script that is included after Date.js and they will also become
1058  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1059  * <pre><code>
1060 Date.patterns = {
1061     ISO8601Long:"Y-m-d H:i:s",
1062     ISO8601Short:"Y-m-d",
1063     ShortDate: "n/j/Y",
1064     LongDate: "l, F d, Y",
1065     FullDateTime: "l, F d, Y g:i:s A",
1066     MonthDay: "F d",
1067     ShortTime: "g:i A",
1068     LongTime: "g:i:s A",
1069     SortableDateTime: "Y-m-d\\TH:i:s",
1070     UniversalSortableDateTime: "Y-m-d H:i:sO",
1071     YearMonth: "F, Y"
1072 };
1073 </code></pre>
1074  *
1075  * Example usage:
1076  * <pre><code>
1077 var dt = new Date();
1078 document.write(dt.format(Date.patterns.ShortDate));
1079  </code></pre>
1080  */
1081
1082 /*
1083  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1084  * They generate precompiled functions from date formats instead of parsing and
1085  * processing the pattern every time you format a date.  These functions are available
1086  * on every Date object (any javascript function).
1087  *
1088  * The original article and download are here:
1089  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1090  *
1091  */
1092  
1093  
1094  // was in core
1095 /**
1096  Returns the number of milliseconds between this date and date
1097  @param {Date} date (optional) Defaults to now
1098  @return {Number} The diff in milliseconds
1099  @member Date getElapsed
1100  */
1101 Date.prototype.getElapsed = function(date) {
1102         return Math.abs((date || new Date()).getTime()-this.getTime());
1103 };
1104 // was in date file..
1105
1106
1107 // private
1108 Date.parseFunctions = {count:0};
1109 // private
1110 Date.parseRegexes = [];
1111 // private
1112 Date.formatFunctions = {count:0};
1113
1114 // private
1115 Date.prototype.dateFormat = function(format) {
1116     if (Date.formatFunctions[format] == null) {
1117         Date.createNewFormat(format);
1118     }
1119     var func = Date.formatFunctions[format];
1120     return this[func]();
1121 };
1122
1123
1124 /**
1125  * Formats a date given the supplied format string
1126  * @param {String} format The format string
1127  * @return {String} The formatted date
1128  * @method
1129  */
1130 Date.prototype.format = Date.prototype.dateFormat;
1131
1132 // private
1133 Date.createNewFormat = function(format) {
1134     var funcName = "format" + Date.formatFunctions.count++;
1135     Date.formatFunctions[format] = funcName;
1136     var code = "Date.prototype." + funcName + " = function(){return ";
1137     var special = false;
1138     var ch = '';
1139     for (var i = 0; i < format.length; ++i) {
1140         ch = format.charAt(i);
1141         if (!special && ch == "\\") {
1142             special = true;
1143         }
1144         else if (special) {
1145             special = false;
1146             code += "'" + String.escape(ch) + "' + ";
1147         }
1148         else {
1149             code += Date.getFormatCode(ch);
1150         }
1151     }
1152     /** eval:var:zzzzzzzzzzzzz */
1153     eval(code.substring(0, code.length - 3) + ";}");
1154 };
1155
1156 // private
1157 Date.getFormatCode = function(character) {
1158     switch (character) {
1159     case "d":
1160         return "String.leftPad(this.getDate(), 2, '0') + ";
1161     case "D":
1162         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1163     case "j":
1164         return "this.getDate() + ";
1165     case "l":
1166         return "Date.dayNames[this.getDay()] + ";
1167     case "S":
1168         return "this.getSuffix() + ";
1169     case "w":
1170         return "this.getDay() + ";
1171     case "z":
1172         return "this.getDayOfYear() + ";
1173     case "W":
1174         return "this.getWeekOfYear() + ";
1175     case "F":
1176         return "Date.monthNames[this.getMonth()] + ";
1177     case "m":
1178         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1179     case "M":
1180         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1181     case "n":
1182         return "(this.getMonth() + 1) + ";
1183     case "t":
1184         return "this.getDaysInMonth() + ";
1185     case "L":
1186         return "(this.isLeapYear() ? 1 : 0) + ";
1187     case "Y":
1188         return "this.getFullYear() + ";
1189     case "y":
1190         return "('' + this.getFullYear()).substring(2, 4) + ";
1191     case "a":
1192         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1193     case "A":
1194         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1195     case "g":
1196         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1197     case "G":
1198         return "this.getHours() + ";
1199     case "h":
1200         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1201     case "H":
1202         return "String.leftPad(this.getHours(), 2, '0') + ";
1203     case "i":
1204         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1205     case "s":
1206         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1207     case "O":
1208         return "this.getGMTOffset() + ";
1209     case "P":
1210         return "this.getGMTColonOffset() + ";
1211     case "T":
1212         return "this.getTimezone() + ";
1213     case "Z":
1214         return "(this.getTimezoneOffset() * -60) + ";
1215     default:
1216         return "'" + String.escape(character) + "' + ";
1217     }
1218 };
1219
1220 /**
1221  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1222  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1223  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1224  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1225  * string or the parse operation will fail.
1226  * Example Usage:
1227 <pre><code>
1228 //dt = Fri May 25 2007 (current date)
1229 var dt = new Date();
1230
1231 //dt = Thu May 25 2006 (today's month/day in 2006)
1232 dt = Date.parseDate("2006", "Y");
1233
1234 //dt = Sun Jan 15 2006 (all date parts specified)
1235 dt = Date.parseDate("2006-1-15", "Y-m-d");
1236
1237 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1238 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1239 </code></pre>
1240  * @param {String} input The unparsed date as a string
1241  * @param {String} format The format the date is in
1242  * @return {Date} The parsed date
1243  * @static
1244  */
1245 Date.parseDate = function(input, format) {
1246     if (Date.parseFunctions[format] == null) {
1247         Date.createParser(format);
1248     }
1249     var func = Date.parseFunctions[format];
1250     return Date[func](input);
1251 };
1252 /**
1253  * @private
1254  */
1255
1256 Date.createParser = function(format) {
1257     var funcName = "parse" + Date.parseFunctions.count++;
1258     var regexNum = Date.parseRegexes.length;
1259     var currentGroup = 1;
1260     Date.parseFunctions[format] = funcName;
1261
1262     var code = "Date." + funcName + " = function(input){\n"
1263         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1264         + "var d = new Date();\n"
1265         + "y = d.getFullYear();\n"
1266         + "m = d.getMonth();\n"
1267         + "d = d.getDate();\n"
1268         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1269         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1270         + "if (results && results.length > 0) {";
1271     var regex = "";
1272
1273     var special = false;
1274     var ch = '';
1275     for (var i = 0; i < format.length; ++i) {
1276         ch = format.charAt(i);
1277         if (!special && ch == "\\") {
1278             special = true;
1279         }
1280         else if (special) {
1281             special = false;
1282             regex += String.escape(ch);
1283         }
1284         else {
1285             var obj = Date.formatCodeToRegex(ch, currentGroup);
1286             currentGroup += obj.g;
1287             regex += obj.s;
1288             if (obj.g && obj.c) {
1289                 code += obj.c;
1290             }
1291         }
1292     }
1293
1294     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1295         + "{v = new Date(y, m, d, h, i, s);}\n"
1296         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1297         + "{v = new Date(y, m, d, h, i);}\n"
1298         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1299         + "{v = new Date(y, m, d, h);}\n"
1300         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1301         + "{v = new Date(y, m, d);}\n"
1302         + "else if (y >= 0 && m >= 0)\n"
1303         + "{v = new Date(y, m);}\n"
1304         + "else if (y >= 0)\n"
1305         + "{v = new Date(y);}\n"
1306         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1307         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1308         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1309         + ";}";
1310
1311     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1312     /** eval:var:zzzzzzzzzzzzz */
1313     eval(code);
1314 };
1315
1316 // private
1317 Date.formatCodeToRegex = function(character, currentGroup) {
1318     switch (character) {
1319     case "D":
1320         return {g:0,
1321         c:null,
1322         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1323     case "j":
1324         return {g:1,
1325             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1326             s:"(\\d{1,2})"}; // day of month without leading zeroes
1327     case "d":
1328         return {g:1,
1329             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1330             s:"(\\d{2})"}; // day of month with leading zeroes
1331     case "l":
1332         return {g:0,
1333             c:null,
1334             s:"(?:" + Date.dayNames.join("|") + ")"};
1335     case "S":
1336         return {g:0,
1337             c:null,
1338             s:"(?:st|nd|rd|th)"};
1339     case "w":
1340         return {g:0,
1341             c:null,
1342             s:"\\d"};
1343     case "z":
1344         return {g:0,
1345             c:null,
1346             s:"(?:\\d{1,3})"};
1347     case "W":
1348         return {g:0,
1349             c:null,
1350             s:"(?:\\d{2})"};
1351     case "F":
1352         return {g:1,
1353             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1354             s:"(" + Date.monthNames.join("|") + ")"};
1355     case "M":
1356         return {g:1,
1357             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1358             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1359     case "n":
1360         return {g:1,
1361             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1362             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1363     case "m":
1364         return {g:1,
1365             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1366             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1367     case "t":
1368         return {g:0,
1369             c:null,
1370             s:"\\d{1,2}"};
1371     case "L":
1372         return {g:0,
1373             c:null,
1374             s:"(?:1|0)"};
1375     case "Y":
1376         return {g:1,
1377             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1378             s:"(\\d{4})"};
1379     case "y":
1380         return {g:1,
1381             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1382                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1383             s:"(\\d{1,2})"};
1384     case "a":
1385         return {g:1,
1386             c:"if (results[" + currentGroup + "] == 'am') {\n"
1387                 + "if (h == 12) { h = 0; }\n"
1388                 + "} else { if (h < 12) { h += 12; }}",
1389             s:"(am|pm)"};
1390     case "A":
1391         return {g:1,
1392             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1393                 + "if (h == 12) { h = 0; }\n"
1394                 + "} else { if (h < 12) { h += 12; }}",
1395             s:"(AM|PM)"};
1396     case "g":
1397     case "G":
1398         return {g:1,
1399             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1400             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1401     case "h":
1402     case "H":
1403         return {g:1,
1404             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1405             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1406     case "i":
1407         return {g:1,
1408             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1409             s:"(\\d{2})"};
1410     case "s":
1411         return {g:1,
1412             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1413             s:"(\\d{2})"};
1414     case "O":
1415         return {g:1,
1416             c:[
1417                 "o = results[", currentGroup, "];\n",
1418                 "var sn = o.substring(0,1);\n", // get + / - sign
1419                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1420                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1421                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1422                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1423             ].join(""),
1424             s:"([+\-]\\d{2,4})"};
1425     
1426     
1427     case "P":
1428         return {g:1,
1429                 c:[
1430                    "o = results[", currentGroup, "];\n",
1431                    "var sn = o.substring(0,1);\n",
1432                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1433                    "var mn = o.substring(4,6) % 60;\n",
1434                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1435                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1436             ].join(""),
1437             s:"([+\-]\\d{4})"};
1438     case "T":
1439         return {g:0,
1440             c:null,
1441             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1442     case "Z":
1443         return {g:1,
1444             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1445                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1446             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1447     default:
1448         return {g:0,
1449             c:null,
1450             s:String.escape(character)};
1451     }
1452 };
1453
1454 /**
1455  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1456  * @return {String} The abbreviated timezone name (e.g. 'CST')
1457  */
1458 Date.prototype.getTimezone = function() {
1459     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1460 };
1461
1462 /**
1463  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1464  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1465  */
1466 Date.prototype.getGMTOffset = function() {
1467     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1468         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1469         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1470 };
1471
1472 /**
1473  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1474  * @return {String} 2-characters representing hours and 2-characters representing minutes
1475  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1476  */
1477 Date.prototype.getGMTColonOffset = function() {
1478         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1479                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1480                 + ":"
1481                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1482 }
1483
1484 /**
1485  * Get the numeric day number of the year, adjusted for leap year.
1486  * @return {Number} 0 through 364 (365 in leap years)
1487  */
1488 Date.prototype.getDayOfYear = function() {
1489     var num = 0;
1490     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1491     for (var i = 0; i < this.getMonth(); ++i) {
1492         num += Date.daysInMonth[i];
1493     }
1494     return num + this.getDate() - 1;
1495 };
1496
1497 /**
1498  * Get the string representation of the numeric week number of the year
1499  * (equivalent to the format specifier 'W').
1500  * @return {String} '00' through '52'
1501  */
1502 Date.prototype.getWeekOfYear = function() {
1503     // Skip to Thursday of this week
1504     var now = this.getDayOfYear() + (4 - this.getDay());
1505     // Find the first Thursday of the year
1506     var jan1 = new Date(this.getFullYear(), 0, 1);
1507     var then = (7 - jan1.getDay() + 4);
1508     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1509 };
1510
1511 /**
1512  * Whether or not the current date is in a leap year.
1513  * @return {Boolean} True if the current date is in a leap year, else false
1514  */
1515 Date.prototype.isLeapYear = function() {
1516     var year = this.getFullYear();
1517     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1518 };
1519
1520 /**
1521  * Get the first day of the current month, adjusted for leap year.  The returned value
1522  * is the numeric day index within the week (0-6) which can be used in conjunction with
1523  * the {@link #monthNames} array to retrieve the textual day name.
1524  * Example:
1525  *<pre><code>
1526 var dt = new Date('1/10/2007');
1527 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1528 </code></pre>
1529  * @return {Number} The day number (0-6)
1530  */
1531 Date.prototype.getFirstDayOfMonth = function() {
1532     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1533     return (day < 0) ? (day + 7) : day;
1534 };
1535
1536 /**
1537  * Get the last day of the current month, adjusted for leap year.  The returned value
1538  * is the numeric day index within the week (0-6) which can be used in conjunction with
1539  * the {@link #monthNames} array to retrieve the textual day name.
1540  * Example:
1541  *<pre><code>
1542 var dt = new Date('1/10/2007');
1543 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1544 </code></pre>
1545  * @return {Number} The day number (0-6)
1546  */
1547 Date.prototype.getLastDayOfMonth = function() {
1548     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1549     return (day < 0) ? (day + 7) : day;
1550 };
1551
1552
1553 /**
1554  * Get the first date of this date's month
1555  * @return {Date}
1556  */
1557 Date.prototype.getFirstDateOfMonth = function() {
1558     return new Date(this.getFullYear(), this.getMonth(), 1);
1559 };
1560
1561 /**
1562  * Get the last date of this date's month
1563  * @return {Date}
1564  */
1565 Date.prototype.getLastDateOfMonth = function() {
1566     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1567 };
1568 /**
1569  * Get the number of days in the current month, adjusted for leap year.
1570  * @return {Number} The number of days in the month
1571  */
1572 Date.prototype.getDaysInMonth = function() {
1573     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1574     return Date.daysInMonth[this.getMonth()];
1575 };
1576
1577 /**
1578  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1579  * @return {String} 'st, 'nd', 'rd' or 'th'
1580  */
1581 Date.prototype.getSuffix = function() {
1582     switch (this.getDate()) {
1583         case 1:
1584         case 21:
1585         case 31:
1586             return "st";
1587         case 2:
1588         case 22:
1589             return "nd";
1590         case 3:
1591         case 23:
1592             return "rd";
1593         default:
1594             return "th";
1595     }
1596 };
1597
1598 // private
1599 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1600
1601 /**
1602  * An array of textual month names.
1603  * Override these values for international dates, for example...
1604  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1605  * @type Array
1606  * @static
1607  */
1608 Date.monthNames =
1609    ["January",
1610     "February",
1611     "March",
1612     "April",
1613     "May",
1614     "June",
1615     "July",
1616     "August",
1617     "September",
1618     "October",
1619     "November",
1620     "December"];
1621
1622 /**
1623  * An array of textual day names.
1624  * Override these values for international dates, for example...
1625  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1626  * @type Array
1627  * @static
1628  */
1629 Date.dayNames =
1630    ["Sunday",
1631     "Monday",
1632     "Tuesday",
1633     "Wednesday",
1634     "Thursday",
1635     "Friday",
1636     "Saturday"];
1637
1638 // private
1639 Date.y2kYear = 50;
1640 // private
1641 Date.monthNumbers = {
1642     Jan:0,
1643     Feb:1,
1644     Mar:2,
1645     Apr:3,
1646     May:4,
1647     Jun:5,
1648     Jul:6,
1649     Aug:7,
1650     Sep:8,
1651     Oct:9,
1652     Nov:10,
1653     Dec:11};
1654
1655 /**
1656  * Creates and returns a new Date instance with the exact same date value as the called instance.
1657  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1658  * variable will also be changed.  When the intention is to create a new variable that will not
1659  * modify the original instance, you should create a clone.
1660  *
1661  * Example of correctly cloning a date:
1662  * <pre><code>
1663 //wrong way:
1664 var orig = new Date('10/1/2006');
1665 var copy = orig;
1666 copy.setDate(5);
1667 document.write(orig);  //returns 'Thu Oct 05 2006'!
1668
1669 //correct way:
1670 var orig = new Date('10/1/2006');
1671 var copy = orig.clone();
1672 copy.setDate(5);
1673 document.write(orig);  //returns 'Thu Oct 01 2006'
1674 </code></pre>
1675  * @return {Date} The new Date instance
1676  */
1677 Date.prototype.clone = function() {
1678         return new Date(this.getTime());
1679 };
1680
1681 /**
1682  * Clears any time information from this date
1683  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1684  @return {Date} this or the clone
1685  */
1686 Date.prototype.clearTime = function(clone){
1687     if(clone){
1688         return this.clone().clearTime();
1689     }
1690     this.setHours(0);
1691     this.setMinutes(0);
1692     this.setSeconds(0);
1693     this.setMilliseconds(0);
1694     return this;
1695 };
1696
1697 // private
1698 // safari setMonth is broken -- check that this is only donw once...
1699 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1700     Date.brokenSetMonth = Date.prototype.setMonth;
1701         Date.prototype.setMonth = function(num){
1702                 if(num <= -1){
1703                         var n = Math.ceil(-num);
1704                         var back_year = Math.ceil(n/12);
1705                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1706                         this.setFullYear(this.getFullYear() - back_year);
1707                         return Date.brokenSetMonth.call(this, month);
1708                 } else {
1709                         return Date.brokenSetMonth.apply(this, arguments);
1710                 }
1711         };
1712 }
1713
1714 /** Date interval constant 
1715 * @static 
1716 * @type String */
1717 Date.MILLI = "ms";
1718 /** Date interval constant 
1719 * @static 
1720 * @type String */
1721 Date.SECOND = "s";
1722 /** Date interval constant 
1723 * @static 
1724 * @type String */
1725 Date.MINUTE = "mi";
1726 /** Date interval constant 
1727 * @static 
1728 * @type String */
1729 Date.HOUR = "h";
1730 /** Date interval constant 
1731 * @static 
1732 * @type String */
1733 Date.DAY = "d";
1734 /** Date interval constant 
1735 * @static 
1736 * @type String */
1737 Date.MONTH = "mo";
1738 /** Date interval constant 
1739 * @static 
1740 * @type String */
1741 Date.YEAR = "y";
1742
1743 /**
1744  * Provides a convenient method of performing basic date arithmetic.  This method
1745  * does not modify the Date instance being called - it creates and returns
1746  * a new Date instance containing the resulting date value.
1747  *
1748  * Examples:
1749  * <pre><code>
1750 //Basic usage:
1751 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1752 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1753
1754 //Negative values will subtract correctly:
1755 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1756 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1757
1758 //You can even chain several calls together in one line!
1759 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1760 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1761  </code></pre>
1762  *
1763  * @param {String} interval   A valid date interval enum value
1764  * @param {Number} value      The amount to add to the current date
1765  * @return {Date} The new Date instance
1766  */
1767 Date.prototype.add = function(interval, value){
1768   var d = this.clone();
1769   if (!interval || value === 0) { return d; }
1770   switch(interval.toLowerCase()){
1771     case Date.MILLI:
1772       d.setMilliseconds(this.getMilliseconds() + value);
1773       break;
1774     case Date.SECOND:
1775       d.setSeconds(this.getSeconds() + value);
1776       break;
1777     case Date.MINUTE:
1778       d.setMinutes(this.getMinutes() + value);
1779       break;
1780     case Date.HOUR:
1781       d.setHours(this.getHours() + value);
1782       break;
1783     case Date.DAY:
1784       d.setDate(this.getDate() + value);
1785       break;
1786     case Date.MONTH:
1787       var day = this.getDate();
1788       if(day > 28){
1789           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1790       }
1791       d.setDate(day);
1792       d.setMonth(this.getMonth() + value);
1793       break;
1794     case Date.YEAR:
1795       d.setFullYear(this.getFullYear() + value);
1796       break;
1797   }
1798   return d;
1799 };
1800 /*
1801  * Based on:
1802  * Ext JS Library 1.1.1
1803  * Copyright(c) 2006-2007, Ext JS, LLC.
1804  *
1805  * Originally Released Under LGPL - original licence link has changed is not relivant.
1806  *
1807  * Fork - LGPL
1808  * <script type="text/javascript">
1809  */
1810
1811 /**
1812  * @class Roo.lib.Dom
1813  * @static
1814  * 
1815  * Dom utils (from YIU afaik)
1816  * 
1817  **/
1818 Roo.lib.Dom = {
1819     /**
1820      * Get the view width
1821      * @param {Boolean} full True will get the full document, otherwise it's the view width
1822      * @return {Number} The width
1823      */
1824      
1825     getViewWidth : function(full) {
1826         return full ? this.getDocumentWidth() : this.getViewportWidth();
1827     },
1828     /**
1829      * Get the view height
1830      * @param {Boolean} full True will get the full document, otherwise it's the view height
1831      * @return {Number} The height
1832      */
1833     getViewHeight : function(full) {
1834         return full ? this.getDocumentHeight() : this.getViewportHeight();
1835     },
1836
1837     getDocumentHeight: function() {
1838         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1839         return Math.max(scrollHeight, this.getViewportHeight());
1840     },
1841
1842     getDocumentWidth: function() {
1843         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1844         return Math.max(scrollWidth, this.getViewportWidth());
1845     },
1846
1847     getViewportHeight: function() {
1848         var height = self.innerHeight;
1849         var mode = document.compatMode;
1850
1851         if ((mode || Roo.isIE) && !Roo.isOpera) {
1852             height = (mode == "CSS1Compat") ?
1853                      document.documentElement.clientHeight :
1854                      document.body.clientHeight;
1855         }
1856
1857         return height;
1858     },
1859
1860     getViewportWidth: function() {
1861         var width = self.innerWidth;
1862         var mode = document.compatMode;
1863
1864         if (mode || Roo.isIE) {
1865             width = (mode == "CSS1Compat") ?
1866                     document.documentElement.clientWidth :
1867                     document.body.clientWidth;
1868         }
1869         return width;
1870     },
1871
1872     isAncestor : function(p, c) {
1873         p = Roo.getDom(p);
1874         c = Roo.getDom(c);
1875         if (!p || !c) {
1876             return false;
1877         }
1878
1879         if (p.contains && !Roo.isSafari) {
1880             return p.contains(c);
1881         } else if (p.compareDocumentPosition) {
1882             return !!(p.compareDocumentPosition(c) & 16);
1883         } else {
1884             var parent = c.parentNode;
1885             while (parent) {
1886                 if (parent == p) {
1887                     return true;
1888                 }
1889                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1890                     return false;
1891                 }
1892                 parent = parent.parentNode;
1893             }
1894             return false;
1895         }
1896     },
1897
1898     getRegion : function(el) {
1899         return Roo.lib.Region.getRegion(el);
1900     },
1901
1902     getY : function(el) {
1903         return this.getXY(el)[1];
1904     },
1905
1906     getX : function(el) {
1907         return this.getXY(el)[0];
1908     },
1909
1910     getXY : function(el) {
1911         var p, pe, b, scroll, bd = document.body;
1912         el = Roo.getDom(el);
1913         var fly = Roo.lib.AnimBase.fly;
1914         if (el.getBoundingClientRect) {
1915             b = el.getBoundingClientRect();
1916             scroll = fly(document).getScroll();
1917             return [b.left + scroll.left, b.top + scroll.top];
1918         }
1919         var x = 0, y = 0;
1920
1921         p = el;
1922
1923         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1924
1925         while (p) {
1926
1927             x += p.offsetLeft;
1928             y += p.offsetTop;
1929
1930             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1931                 hasAbsolute = true;
1932             }
1933
1934             if (Roo.isGecko) {
1935                 pe = fly(p);
1936
1937                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1938                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1939
1940
1941                 x += bl;
1942                 y += bt;
1943
1944
1945                 if (p != el && pe.getStyle('overflow') != 'visible') {
1946                     x += bl;
1947                     y += bt;
1948                 }
1949             }
1950             p = p.offsetParent;
1951         }
1952
1953         if (Roo.isSafari && hasAbsolute) {
1954             x -= bd.offsetLeft;
1955             y -= bd.offsetTop;
1956         }
1957
1958         if (Roo.isGecko && !hasAbsolute) {
1959             var dbd = fly(bd);
1960             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1961             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1962         }
1963
1964         p = el.parentNode;
1965         while (p && p != bd) {
1966             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1967                 x -= p.scrollLeft;
1968                 y -= p.scrollTop;
1969             }
1970             p = p.parentNode;
1971         }
1972         return [x, y];
1973     },
1974  
1975   
1976
1977
1978     setXY : function(el, xy) {
1979         el = Roo.fly(el, '_setXY');
1980         el.position();
1981         var pts = el.translatePoints(xy);
1982         if (xy[0] !== false) {
1983             el.dom.style.left = pts.left + "px";
1984         }
1985         if (xy[1] !== false) {
1986             el.dom.style.top = pts.top + "px";
1987         }
1988     },
1989
1990     setX : function(el, x) {
1991         this.setXY(el, [x, false]);
1992     },
1993
1994     setY : function(el, y) {
1995         this.setXY(el, [false, y]);
1996     }
1997 };
1998 /*
1999  * Portions of this file are based on pieces of Yahoo User Interface Library
2000  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2001  * YUI licensed under the BSD License:
2002  * http://developer.yahoo.net/yui/license.txt
2003  * <script type="text/javascript">
2004  *
2005  */
2006
2007 Roo.lib.Event = function() {
2008     var loadComplete = false;
2009     var listeners = [];
2010     var unloadListeners = [];
2011     var retryCount = 0;
2012     var onAvailStack = [];
2013     var counter = 0;
2014     var lastError = null;
2015
2016     return {
2017         POLL_RETRYS: 200,
2018         POLL_INTERVAL: 20,
2019         EL: 0,
2020         TYPE: 1,
2021         FN: 2,
2022         WFN: 3,
2023         OBJ: 3,
2024         ADJ_SCOPE: 4,
2025         _interval: null,
2026
2027         startInterval: function() {
2028             if (!this._interval) {
2029                 var self = this;
2030                 var callback = function() {
2031                     self._tryPreloadAttach();
2032                 };
2033                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2034
2035             }
2036         },
2037
2038         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2039             onAvailStack.push({ id:         p_id,
2040                 fn:         p_fn,
2041                 obj:        p_obj,
2042                 override:   p_override,
2043                 checkReady: false    });
2044
2045             retryCount = this.POLL_RETRYS;
2046             this.startInterval();
2047         },
2048
2049
2050         addListener: function(el, eventName, fn) {
2051             el = Roo.getDom(el);
2052             if (!el || !fn) {
2053                 return false;
2054             }
2055
2056             if ("unload" == eventName) {
2057                 unloadListeners[unloadListeners.length] =
2058                 [el, eventName, fn];
2059                 return true;
2060             }
2061
2062             var wrappedFn = function(e) {
2063                 return fn(Roo.lib.Event.getEvent(e));
2064             };
2065
2066             var li = [el, eventName, fn, wrappedFn];
2067
2068             var index = listeners.length;
2069             listeners[index] = li;
2070
2071             this.doAdd(el, eventName, wrappedFn, false);
2072             return true;
2073
2074         },
2075
2076
2077         removeListener: function(el, eventName, fn) {
2078             var i, len;
2079
2080             el = Roo.getDom(el);
2081
2082             if(!fn) {
2083                 return this.purgeElement(el, false, eventName);
2084             }
2085
2086
2087             if ("unload" == eventName) {
2088
2089                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2090                     var li = unloadListeners[i];
2091                     if (li &&
2092                         li[0] == el &&
2093                         li[1] == eventName &&
2094                         li[2] == fn) {
2095                         unloadListeners.splice(i, 1);
2096                         return true;
2097                     }
2098                 }
2099
2100                 return false;
2101             }
2102
2103             var cacheItem = null;
2104
2105
2106             var index = arguments[3];
2107
2108             if ("undefined" == typeof index) {
2109                 index = this._getCacheIndex(el, eventName, fn);
2110             }
2111
2112             if (index >= 0) {
2113                 cacheItem = listeners[index];
2114             }
2115
2116             if (!el || !cacheItem) {
2117                 return false;
2118             }
2119
2120             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2121
2122             delete listeners[index][this.WFN];
2123             delete listeners[index][this.FN];
2124             listeners.splice(index, 1);
2125
2126             return true;
2127
2128         },
2129
2130
2131         getTarget: function(ev, resolveTextNode) {
2132             ev = ev.browserEvent || ev;
2133             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2134             var t = ev.target || ev.srcElement;
2135             return this.resolveTextNode(t);
2136         },
2137
2138
2139         resolveTextNode: function(node) {
2140             if (Roo.isSafari && node && 3 == node.nodeType) {
2141                 return node.parentNode;
2142             } else {
2143                 return node;
2144             }
2145         },
2146
2147
2148         getPageX: function(ev) {
2149             ev = ev.browserEvent || ev;
2150             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2151             var x = ev.pageX;
2152             if (!x && 0 !== x) {
2153                 x = ev.clientX || 0;
2154
2155                 if (Roo.isIE) {
2156                     x += this.getScroll()[1];
2157                 }
2158             }
2159
2160             return x;
2161         },
2162
2163
2164         getPageY: function(ev) {
2165             ev = ev.browserEvent || ev;
2166             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2167             var y = ev.pageY;
2168             if (!y && 0 !== y) {
2169                 y = ev.clientY || 0;
2170
2171                 if (Roo.isIE) {
2172                     y += this.getScroll()[0];
2173                 }
2174             }
2175
2176
2177             return y;
2178         },
2179
2180
2181         getXY: function(ev) {
2182             ev = ev.browserEvent || ev;
2183             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2184             return [this.getPageX(ev), this.getPageY(ev)];
2185         },
2186
2187
2188         getRelatedTarget: function(ev) {
2189             ev = ev.browserEvent || ev;
2190             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2191             var t = ev.relatedTarget;
2192             if (!t) {
2193                 if (ev.type == "mouseout") {
2194                     t = ev.toElement;
2195                 } else if (ev.type == "mouseover") {
2196                     t = ev.fromElement;
2197                 }
2198             }
2199
2200             return this.resolveTextNode(t);
2201         },
2202
2203
2204         getTime: function(ev) {
2205             ev = ev.browserEvent || ev;
2206             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2207             if (!ev.time) {
2208                 var t = new Date().getTime();
2209                 try {
2210                     ev.time = t;
2211                 } catch(ex) {
2212                     this.lastError = ex;
2213                     return t;
2214                 }
2215             }
2216
2217             return ev.time;
2218         },
2219
2220
2221         stopEvent: function(ev) {
2222             this.stopPropagation(ev);
2223             this.preventDefault(ev);
2224         },
2225
2226
2227         stopPropagation: function(ev) {
2228             ev = ev.browserEvent || ev;
2229             if (ev.stopPropagation) {
2230                 ev.stopPropagation();
2231             } else {
2232                 ev.cancelBubble = true;
2233             }
2234         },
2235
2236
2237         preventDefault: function(ev) {
2238             ev = ev.browserEvent || ev;
2239             if(ev.preventDefault) {
2240                 ev.preventDefault();
2241             } else {
2242                 ev.returnValue = false;
2243             }
2244         },
2245
2246
2247         getEvent: function(e) {
2248             var ev = e || window.event;
2249             if (!ev) {
2250                 var c = this.getEvent.caller;
2251                 while (c) {
2252                     ev = c.arguments[0];
2253                     if (ev && Event == ev.constructor) {
2254                         break;
2255                     }
2256                     c = c.caller;
2257                 }
2258             }
2259             return ev;
2260         },
2261
2262
2263         getCharCode: function(ev) {
2264             ev = ev.browserEvent || ev;
2265             return ev.charCode || ev.keyCode || 0;
2266         },
2267
2268
2269         _getCacheIndex: function(el, eventName, fn) {
2270             for (var i = 0,len = listeners.length; i < len; ++i) {
2271                 var li = listeners[i];
2272                 if (li &&
2273                     li[this.FN] == fn &&
2274                     li[this.EL] == el &&
2275                     li[this.TYPE] == eventName) {
2276                     return i;
2277                 }
2278             }
2279
2280             return -1;
2281         },
2282
2283
2284         elCache: {},
2285
2286
2287         getEl: function(id) {
2288             return document.getElementById(id);
2289         },
2290
2291
2292         clearCache: function() {
2293         },
2294
2295
2296         _load: function(e) {
2297             loadComplete = true;
2298             var EU = Roo.lib.Event;
2299
2300
2301             if (Roo.isIE) {
2302                 EU.doRemove(window, "load", EU._load);
2303             }
2304         },
2305
2306
2307         _tryPreloadAttach: function() {
2308
2309             if (this.locked) {
2310                 return false;
2311             }
2312
2313             this.locked = true;
2314
2315
2316             var tryAgain = !loadComplete;
2317             if (!tryAgain) {
2318                 tryAgain = (retryCount > 0);
2319             }
2320
2321
2322             var notAvail = [];
2323             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2324                 var item = onAvailStack[i];
2325                 if (item) {
2326                     var el = this.getEl(item.id);
2327
2328                     if (el) {
2329                         if (!item.checkReady ||
2330                             loadComplete ||
2331                             el.nextSibling ||
2332                             (document && document.body)) {
2333
2334                             var scope = el;
2335                             if (item.override) {
2336                                 if (item.override === true) {
2337                                     scope = item.obj;
2338                                 } else {
2339                                     scope = item.override;
2340                                 }
2341                             }
2342                             item.fn.call(scope, item.obj);
2343                             onAvailStack[i] = null;
2344                         }
2345                     } else {
2346                         notAvail.push(item);
2347                     }
2348                 }
2349             }
2350
2351             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2352
2353             if (tryAgain) {
2354
2355                 this.startInterval();
2356             } else {
2357                 clearInterval(this._interval);
2358                 this._interval = null;
2359             }
2360
2361             this.locked = false;
2362
2363             return true;
2364
2365         },
2366
2367
2368         purgeElement: function(el, recurse, eventName) {
2369             var elListeners = this.getListeners(el, eventName);
2370             if (elListeners) {
2371                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2372                     var l = elListeners[i];
2373                     this.removeListener(el, l.type, l.fn);
2374                 }
2375             }
2376
2377             if (recurse && el && el.childNodes) {
2378                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2379                     this.purgeElement(el.childNodes[i], recurse, eventName);
2380                 }
2381             }
2382         },
2383
2384
2385         getListeners: function(el, eventName) {
2386             var results = [], searchLists;
2387             if (!eventName) {
2388                 searchLists = [listeners, unloadListeners];
2389             } else if (eventName == "unload") {
2390                 searchLists = [unloadListeners];
2391             } else {
2392                 searchLists = [listeners];
2393             }
2394
2395             for (var j = 0; j < searchLists.length; ++j) {
2396                 var searchList = searchLists[j];
2397                 if (searchList && searchList.length > 0) {
2398                     for (var i = 0,len = searchList.length; i < len; ++i) {
2399                         var l = searchList[i];
2400                         if (l && l[this.EL] === el &&
2401                             (!eventName || eventName === l[this.TYPE])) {
2402                             results.push({
2403                                 type:   l[this.TYPE],
2404                                 fn:     l[this.FN],
2405                                 obj:    l[this.OBJ],
2406                                 adjust: l[this.ADJ_SCOPE],
2407                                 index:  i
2408                             });
2409                         }
2410                     }
2411                 }
2412             }
2413
2414             return (results.length) ? results : null;
2415         },
2416
2417
2418         _unload: function(e) {
2419
2420             var EU = Roo.lib.Event, i, j, l, len, index;
2421
2422             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2423                 l = unloadListeners[i];
2424                 if (l) {
2425                     var scope = window;
2426                     if (l[EU.ADJ_SCOPE]) {
2427                         if (l[EU.ADJ_SCOPE] === true) {
2428                             scope = l[EU.OBJ];
2429                         } else {
2430                             scope = l[EU.ADJ_SCOPE];
2431                         }
2432                     }
2433                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2434                     unloadListeners[i] = null;
2435                     l = null;
2436                     scope = null;
2437                 }
2438             }
2439
2440             unloadListeners = null;
2441
2442             if (listeners && listeners.length > 0) {
2443                 j = listeners.length;
2444                 while (j) {
2445                     index = j - 1;
2446                     l = listeners[index];
2447                     if (l) {
2448                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2449                                 l[EU.FN], index);
2450                     }
2451                     j = j - 1;
2452                 }
2453                 l = null;
2454
2455                 EU.clearCache();
2456             }
2457
2458             EU.doRemove(window, "unload", EU._unload);
2459
2460         },
2461
2462
2463         getScroll: function() {
2464             var dd = document.documentElement, db = document.body;
2465             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2466                 return [dd.scrollTop, dd.scrollLeft];
2467             } else if (db) {
2468                 return [db.scrollTop, db.scrollLeft];
2469             } else {
2470                 return [0, 0];
2471             }
2472         },
2473
2474
2475         doAdd: function () {
2476             if (window.addEventListener) {
2477                 return function(el, eventName, fn, capture) {
2478                     el.addEventListener(eventName, fn, (capture));
2479                 };
2480             } else if (window.attachEvent) {
2481                 return function(el, eventName, fn, capture) {
2482                     el.attachEvent("on" + eventName, fn);
2483                 };
2484             } else {
2485                 return function() {
2486                 };
2487             }
2488         }(),
2489
2490
2491         doRemove: function() {
2492             if (window.removeEventListener) {
2493                 return function (el, eventName, fn, capture) {
2494                     el.removeEventListener(eventName, fn, (capture));
2495                 };
2496             } else if (window.detachEvent) {
2497                 return function (el, eventName, fn) {
2498                     el.detachEvent("on" + eventName, fn);
2499                 };
2500             } else {
2501                 return function() {
2502                 };
2503             }
2504         }()
2505     };
2506     
2507 }();
2508 (function() {     
2509    
2510     var E = Roo.lib.Event;
2511     E.on = E.addListener;
2512     E.un = E.removeListener;
2513
2514     if (document && document.body) {
2515         E._load();
2516     } else {
2517         E.doAdd(window, "load", E._load);
2518     }
2519     E.doAdd(window, "unload", E._unload);
2520     E._tryPreloadAttach();
2521 })();
2522
2523 /*
2524  * Portions of this file are based on pieces of Yahoo User Interface Library
2525  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2526  * YUI licensed under the BSD License:
2527  * http://developer.yahoo.net/yui/license.txt
2528  * <script type="text/javascript">
2529  *
2530  */
2531
2532 (function() {
2533     /**
2534      * @class Roo.lib.Ajax
2535      *
2536      */
2537     Roo.lib.Ajax = {
2538         /**
2539          * @static 
2540          */
2541         request : function(method, uri, cb, data, options) {
2542             if(options){
2543                 var hs = options.headers;
2544                 if(hs){
2545                     for(var h in hs){
2546                         if(hs.hasOwnProperty(h)){
2547                             this.initHeader(h, hs[h], false);
2548                         }
2549                     }
2550                 }
2551                 if(options.xmlData){
2552                     this.initHeader('Content-Type', 'text/xml', false);
2553                     method = 'POST';
2554                     data = options.xmlData;
2555                 }
2556             }
2557
2558             return this.asyncRequest(method, uri, cb, data);
2559         },
2560
2561         serializeForm : function(form) {
2562             if(typeof form == 'string') {
2563                 form = (document.getElementById(form) || document.forms[form]);
2564             }
2565
2566             var el, name, val, disabled, data = '', hasSubmit = false;
2567             for (var i = 0; i < form.elements.length; i++) {
2568                 el = form.elements[i];
2569                 disabled = form.elements[i].disabled;
2570                 name = form.elements[i].name;
2571                 val = form.elements[i].value;
2572
2573                 if (!disabled && name){
2574                     switch (el.type)
2575                             {
2576                         case 'select-one':
2577                         case 'select-multiple':
2578                             for (var j = 0; j < el.options.length; j++) {
2579                                 if (el.options[j].selected) {
2580                                     if (Roo.isIE) {
2581                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2582                                     }
2583                                     else {
2584                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2585                                     }
2586                                 }
2587                             }
2588                             break;
2589                         case 'radio':
2590                         case 'checkbox':
2591                             if (el.checked) {
2592                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2593                             }
2594                             break;
2595                         case 'file':
2596
2597                         case undefined:
2598
2599                         case 'reset':
2600
2601                         case 'button':
2602
2603                             break;
2604                         case 'submit':
2605                             if(hasSubmit == false) {
2606                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2607                                 hasSubmit = true;
2608                             }
2609                             break;
2610                         default:
2611                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2612                             break;
2613                     }
2614                 }
2615             }
2616             data = data.substr(0, data.length - 1);
2617             return data;
2618         },
2619
2620         headers:{},
2621
2622         hasHeaders:false,
2623
2624         useDefaultHeader:true,
2625
2626         defaultPostHeader:'application/x-www-form-urlencoded',
2627
2628         useDefaultXhrHeader:true,
2629
2630         defaultXhrHeader:'XMLHttpRequest',
2631
2632         hasDefaultHeaders:true,
2633
2634         defaultHeaders:{},
2635
2636         poll:{},
2637
2638         timeout:{},
2639
2640         pollInterval:50,
2641
2642         transactionId:0,
2643
2644         setProgId:function(id)
2645         {
2646             this.activeX.unshift(id);
2647         },
2648
2649         setDefaultPostHeader:function(b)
2650         {
2651             this.useDefaultHeader = b;
2652         },
2653
2654         setDefaultXhrHeader:function(b)
2655         {
2656             this.useDefaultXhrHeader = b;
2657         },
2658
2659         setPollingInterval:function(i)
2660         {
2661             if (typeof i == 'number' && isFinite(i)) {
2662                 this.pollInterval = i;
2663             }
2664         },
2665
2666         createXhrObject:function(transactionId)
2667         {
2668             var obj,http;
2669             try
2670             {
2671
2672                 http = new XMLHttpRequest();
2673
2674                 obj = { conn:http, tId:transactionId };
2675             }
2676             catch(e)
2677             {
2678                 for (var i = 0; i < this.activeX.length; ++i) {
2679                     try
2680                     {
2681
2682                         http = new ActiveXObject(this.activeX[i]);
2683
2684                         obj = { conn:http, tId:transactionId };
2685                         break;
2686                     }
2687                     catch(e) {
2688                     }
2689                 }
2690             }
2691             finally
2692             {
2693                 return obj;
2694             }
2695         },
2696
2697         getConnectionObject:function()
2698         {
2699             var o;
2700             var tId = this.transactionId;
2701
2702             try
2703             {
2704                 o = this.createXhrObject(tId);
2705                 if (o) {
2706                     this.transactionId++;
2707                 }
2708             }
2709             catch(e) {
2710             }
2711             finally
2712             {
2713                 return o;
2714             }
2715         },
2716
2717         asyncRequest:function(method, uri, callback, postData)
2718         {
2719             var o = this.getConnectionObject();
2720
2721             if (!o) {
2722                 return null;
2723             }
2724             else {
2725                 o.conn.open(method, uri, true);
2726
2727                 if (this.useDefaultXhrHeader) {
2728                     if (!this.defaultHeaders['X-Requested-With']) {
2729                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2730                     }
2731                 }
2732
2733                 if(postData && this.useDefaultHeader){
2734                     this.initHeader('Content-Type', this.defaultPostHeader);
2735                 }
2736
2737                  if (this.hasDefaultHeaders || this.hasHeaders) {
2738                     this.setHeader(o);
2739                 }
2740
2741                 this.handleReadyState(o, callback);
2742                 o.conn.send(postData || null);
2743
2744                 return o;
2745             }
2746         },
2747
2748         handleReadyState:function(o, callback)
2749         {
2750             var oConn = this;
2751
2752             if (callback && callback.timeout) {
2753                 
2754                 this.timeout[o.tId] = window.setTimeout(function() {
2755                     oConn.abort(o, callback, true);
2756                 }, callback.timeout);
2757             }
2758
2759             this.poll[o.tId] = window.setInterval(
2760                     function() {
2761                         if (o.conn && o.conn.readyState == 4) {
2762                             window.clearInterval(oConn.poll[o.tId]);
2763                             delete oConn.poll[o.tId];
2764
2765                             if(callback && callback.timeout) {
2766                                 window.clearTimeout(oConn.timeout[o.tId]);
2767                                 delete oConn.timeout[o.tId];
2768                             }
2769
2770                             oConn.handleTransactionResponse(o, callback);
2771                         }
2772                     }
2773                     , this.pollInterval);
2774         },
2775
2776         handleTransactionResponse:function(o, callback, isAbort)
2777         {
2778
2779             if (!callback) {
2780                 this.releaseObject(o);
2781                 return;
2782             }
2783
2784             var httpStatus, responseObject;
2785
2786             try
2787             {
2788                 if (o.conn.status !== undefined && o.conn.status != 0) {
2789                     httpStatus = o.conn.status;
2790                 }
2791                 else {
2792                     httpStatus = 13030;
2793                 }
2794             }
2795             catch(e) {
2796
2797
2798                 httpStatus = 13030;
2799             }
2800
2801             if (httpStatus >= 200 && httpStatus < 300) {
2802                 responseObject = this.createResponseObject(o, callback.argument);
2803                 if (callback.success) {
2804                     if (!callback.scope) {
2805                         callback.success(responseObject);
2806                     }
2807                     else {
2808
2809
2810                         callback.success.apply(callback.scope, [responseObject]);
2811                     }
2812                 }
2813             }
2814             else {
2815                 switch (httpStatus) {
2816
2817                     case 12002:
2818                     case 12029:
2819                     case 12030:
2820                     case 12031:
2821                     case 12152:
2822                     case 13030:
2823                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2824                         if (callback.failure) {
2825                             if (!callback.scope) {
2826                                 callback.failure(responseObject);
2827                             }
2828                             else {
2829                                 callback.failure.apply(callback.scope, [responseObject]);
2830                             }
2831                         }
2832                         break;
2833                     default:
2834                         responseObject = this.createResponseObject(o, callback.argument);
2835                         if (callback.failure) {
2836                             if (!callback.scope) {
2837                                 callback.failure(responseObject);
2838                             }
2839                             else {
2840                                 callback.failure.apply(callback.scope, [responseObject]);
2841                             }
2842                         }
2843                 }
2844             }
2845
2846             this.releaseObject(o);
2847             responseObject = null;
2848         },
2849
2850         createResponseObject:function(o, callbackArg)
2851         {
2852             var obj = {};
2853             var headerObj = {};
2854
2855             try
2856             {
2857                 var headerStr = o.conn.getAllResponseHeaders();
2858                 var header = headerStr.split('\n');
2859                 for (var i = 0; i < header.length; i++) {
2860                     var delimitPos = header[i].indexOf(':');
2861                     if (delimitPos != -1) {
2862                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2863                     }
2864                 }
2865             }
2866             catch(e) {
2867             }
2868
2869             obj.tId = o.tId;
2870             obj.status = o.conn.status;
2871             obj.statusText = o.conn.statusText;
2872             obj.getResponseHeader = headerObj;
2873             obj.getAllResponseHeaders = headerStr;
2874             obj.responseText = o.conn.responseText;
2875             obj.responseXML = o.conn.responseXML;
2876
2877             if (typeof callbackArg !== undefined) {
2878                 obj.argument = callbackArg;
2879             }
2880
2881             return obj;
2882         },
2883
2884         createExceptionObject:function(tId, callbackArg, isAbort)
2885         {
2886             var COMM_CODE = 0;
2887             var COMM_ERROR = 'communication failure';
2888             var ABORT_CODE = -1;
2889             var ABORT_ERROR = 'transaction aborted';
2890
2891             var obj = {};
2892
2893             obj.tId = tId;
2894             if (isAbort) {
2895                 obj.status = ABORT_CODE;
2896                 obj.statusText = ABORT_ERROR;
2897             }
2898             else {
2899                 obj.status = COMM_CODE;
2900                 obj.statusText = COMM_ERROR;
2901             }
2902
2903             if (callbackArg) {
2904                 obj.argument = callbackArg;
2905             }
2906
2907             return obj;
2908         },
2909
2910         initHeader:function(label, value, isDefault)
2911         {
2912             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2913
2914             if (headerObj[label] === undefined) {
2915                 headerObj[label] = value;
2916             }
2917             else {
2918
2919
2920                 headerObj[label] = value + "," + headerObj[label];
2921             }
2922
2923             if (isDefault) {
2924                 this.hasDefaultHeaders = true;
2925             }
2926             else {
2927                 this.hasHeaders = true;
2928             }
2929         },
2930
2931
2932         setHeader:function(o)
2933         {
2934             if (this.hasDefaultHeaders) {
2935                 for (var prop in this.defaultHeaders) {
2936                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2937                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2938                     }
2939                 }
2940             }
2941
2942             if (this.hasHeaders) {
2943                 for (var prop in this.headers) {
2944                     if (this.headers.hasOwnProperty(prop)) {
2945                         o.conn.setRequestHeader(prop, this.headers[prop]);
2946                     }
2947                 }
2948                 this.headers = {};
2949                 this.hasHeaders = false;
2950             }
2951         },
2952
2953         resetDefaultHeaders:function() {
2954             delete this.defaultHeaders;
2955             this.defaultHeaders = {};
2956             this.hasDefaultHeaders = false;
2957         },
2958
2959         abort:function(o, callback, isTimeout)
2960         {
2961             if(this.isCallInProgress(o)) {
2962                 o.conn.abort();
2963                 window.clearInterval(this.poll[o.tId]);
2964                 delete this.poll[o.tId];
2965                 if (isTimeout) {
2966                     delete this.timeout[o.tId];
2967                 }
2968
2969                 this.handleTransactionResponse(o, callback, true);
2970
2971                 return true;
2972             }
2973             else {
2974                 return false;
2975             }
2976         },
2977
2978
2979         isCallInProgress:function(o)
2980         {
2981             if (o && o.conn) {
2982                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2983             }
2984             else {
2985
2986                 return false;
2987             }
2988         },
2989
2990
2991         releaseObject:function(o)
2992         {
2993
2994             o.conn = null;
2995
2996             o = null;
2997         },
2998
2999         activeX:[
3000         'MSXML2.XMLHTTP.3.0',
3001         'MSXML2.XMLHTTP',
3002         'Microsoft.XMLHTTP'
3003         ]
3004
3005
3006     };
3007 })();/*
3008  * Portions of this file are based on pieces of Yahoo User Interface Library
3009  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3010  * YUI licensed under the BSD License:
3011  * http://developer.yahoo.net/yui/license.txt
3012  * <script type="text/javascript">
3013  *
3014  */
3015
3016 Roo.lib.Region = function(t, r, b, l) {
3017     this.top = t;
3018     this[1] = t;
3019     this.right = r;
3020     this.bottom = b;
3021     this.left = l;
3022     this[0] = l;
3023 };
3024
3025
3026 Roo.lib.Region.prototype = {
3027     contains : function(region) {
3028         return ( region.left >= this.left &&
3029                  region.right <= this.right &&
3030                  region.top >= this.top &&
3031                  region.bottom <= this.bottom    );
3032
3033     },
3034
3035     getArea : function() {
3036         return ( (this.bottom - this.top) * (this.right - this.left) );
3037     },
3038
3039     intersect : function(region) {
3040         var t = Math.max(this.top, region.top);
3041         var r = Math.min(this.right, region.right);
3042         var b = Math.min(this.bottom, region.bottom);
3043         var l = Math.max(this.left, region.left);
3044
3045         if (b >= t && r >= l) {
3046             return new Roo.lib.Region(t, r, b, l);
3047         } else {
3048             return null;
3049         }
3050     },
3051     union : function(region) {
3052         var t = Math.min(this.top, region.top);
3053         var r = Math.max(this.right, region.right);
3054         var b = Math.max(this.bottom, region.bottom);
3055         var l = Math.min(this.left, region.left);
3056
3057         return new Roo.lib.Region(t, r, b, l);
3058     },
3059
3060     adjust : function(t, l, b, r) {
3061         this.top += t;
3062         this.left += l;
3063         this.right += r;
3064         this.bottom += b;
3065         return this;
3066     }
3067 };
3068
3069 Roo.lib.Region.getRegion = function(el) {
3070     var p = Roo.lib.Dom.getXY(el);
3071
3072     var t = p[1];
3073     var r = p[0] + el.offsetWidth;
3074     var b = p[1] + el.offsetHeight;
3075     var l = p[0];
3076
3077     return new Roo.lib.Region(t, r, b, l);
3078 };
3079 /*
3080  * Portions of this file are based on pieces of Yahoo User Interface Library
3081  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3082  * YUI licensed under the BSD License:
3083  * http://developer.yahoo.net/yui/license.txt
3084  * <script type="text/javascript">
3085  *
3086  */
3087 //@@dep Roo.lib.Region
3088
3089
3090 Roo.lib.Point = function(x, y) {
3091     if (x instanceof Array) {
3092         y = x[1];
3093         x = x[0];
3094     }
3095     this.x = this.right = this.left = this[0] = x;
3096     this.y = this.top = this.bottom = this[1] = y;
3097 };
3098
3099 Roo.lib.Point.prototype = new Roo.lib.Region();
3100 /*
3101  * Portions of this file are based on pieces of Yahoo User Interface Library
3102  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3103  * YUI licensed under the BSD License:
3104  * http://developer.yahoo.net/yui/license.txt
3105  * <script type="text/javascript">
3106  *
3107  */
3108  
3109 (function() {   
3110
3111     Roo.lib.Anim = {
3112         scroll : function(el, args, duration, easing, cb, scope) {
3113             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3114         },
3115
3116         motion : function(el, args, duration, easing, cb, scope) {
3117             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3118         },
3119
3120         color : function(el, args, duration, easing, cb, scope) {
3121             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3122         },
3123
3124         run : function(el, args, duration, easing, cb, scope, type) {
3125             type = type || Roo.lib.AnimBase;
3126             if (typeof easing == "string") {
3127                 easing = Roo.lib.Easing[easing];
3128             }
3129             var anim = new type(el, args, duration, easing);
3130             anim.animateX(function() {
3131                 Roo.callback(cb, scope);
3132             });
3133             return anim;
3134         }
3135     };
3136 })();/*
3137  * Portions of this file are based on pieces of Yahoo User Interface Library
3138  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3139  * YUI licensed under the BSD License:
3140  * http://developer.yahoo.net/yui/license.txt
3141  * <script type="text/javascript">
3142  *
3143  */
3144
3145 (function() {    
3146     var libFlyweight;
3147     
3148     function fly(el) {
3149         if (!libFlyweight) {
3150             libFlyweight = new Roo.Element.Flyweight();
3151         }
3152         libFlyweight.dom = el;
3153         return libFlyweight;
3154     }
3155
3156     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3157     
3158    
3159     
3160     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3161         if (el) {
3162             this.init(el, attributes, duration, method);
3163         }
3164     };
3165
3166     Roo.lib.AnimBase.fly = fly;
3167     
3168     
3169     
3170     Roo.lib.AnimBase.prototype = {
3171
3172         toString: function() {
3173             var el = this.getEl();
3174             var id = el.id || el.tagName;
3175             return ("Anim " + id);
3176         },
3177
3178         patterns: {
3179             noNegatives:        /width|height|opacity|padding/i,
3180             offsetAttribute:  /^((width|height)|(top|left))$/,
3181             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3182             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3183         },
3184
3185
3186         doMethod: function(attr, start, end) {
3187             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3188         },
3189
3190
3191         setAttribute: function(attr, val, unit) {
3192             if (this.patterns.noNegatives.test(attr)) {
3193                 val = (val > 0) ? val : 0;
3194             }
3195
3196             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3197         },
3198
3199
3200         getAttribute: function(attr) {
3201             var el = this.getEl();
3202             var val = fly(el).getStyle(attr);
3203
3204             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3205                 return parseFloat(val);
3206             }
3207
3208             var a = this.patterns.offsetAttribute.exec(attr) || [];
3209             var pos = !!( a[3] );
3210             var box = !!( a[2] );
3211
3212
3213             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3214                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3215             } else {
3216                 val = 0;
3217             }
3218
3219             return val;
3220         },
3221
3222
3223         getDefaultUnit: function(attr) {
3224             if (this.patterns.defaultUnit.test(attr)) {
3225                 return 'px';
3226             }
3227
3228             return '';
3229         },
3230
3231         animateX : function(callback, scope) {
3232             var f = function() {
3233                 this.onComplete.removeListener(f);
3234                 if (typeof callback == "function") {
3235                     callback.call(scope || this, this);
3236                 }
3237             };
3238             this.onComplete.addListener(f, this);
3239             this.animate();
3240         },
3241
3242
3243         setRuntimeAttribute: function(attr) {
3244             var start;
3245             var end;
3246             var attributes = this.attributes;
3247
3248             this.runtimeAttributes[attr] = {};
3249
3250             var isset = function(prop) {
3251                 return (typeof prop !== 'undefined');
3252             };
3253
3254             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3255                 return false;
3256             }
3257
3258             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3259
3260
3261             if (isset(attributes[attr]['to'])) {
3262                 end = attributes[attr]['to'];
3263             } else if (isset(attributes[attr]['by'])) {
3264                 if (start.constructor == Array) {
3265                     end = [];
3266                     for (var i = 0, len = start.length; i < len; ++i) {
3267                         end[i] = start[i] + attributes[attr]['by'][i];
3268                     }
3269                 } else {
3270                     end = start + attributes[attr]['by'];
3271                 }
3272             }
3273
3274             this.runtimeAttributes[attr].start = start;
3275             this.runtimeAttributes[attr].end = end;
3276
3277
3278             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3279         },
3280
3281
3282         init: function(el, attributes, duration, method) {
3283
3284             var isAnimated = false;
3285
3286
3287             var startTime = null;
3288
3289
3290             var actualFrames = 0;
3291
3292
3293             el = Roo.getDom(el);
3294
3295
3296             this.attributes = attributes || {};
3297
3298
3299             this.duration = duration || 1;
3300
3301
3302             this.method = method || Roo.lib.Easing.easeNone;
3303
3304
3305             this.useSeconds = true;
3306
3307
3308             this.currentFrame = 0;
3309
3310
3311             this.totalFrames = Roo.lib.AnimMgr.fps;
3312
3313
3314             this.getEl = function() {
3315                 return el;
3316             };
3317
3318
3319             this.isAnimated = function() {
3320                 return isAnimated;
3321             };
3322
3323
3324             this.getStartTime = function() {
3325                 return startTime;
3326             };
3327
3328             this.runtimeAttributes = {};
3329
3330
3331             this.animate = function() {
3332                 if (this.isAnimated()) {
3333                     return false;
3334                 }
3335
3336                 this.currentFrame = 0;
3337
3338                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3339
3340                 Roo.lib.AnimMgr.registerElement(this);
3341             };
3342
3343
3344             this.stop = function(finish) {
3345                 if (finish) {
3346                     this.currentFrame = this.totalFrames;
3347                     this._onTween.fire();
3348                 }
3349                 Roo.lib.AnimMgr.stop(this);
3350             };
3351
3352             var onStart = function() {
3353                 this.onStart.fire();
3354
3355                 this.runtimeAttributes = {};
3356                 for (var attr in this.attributes) {
3357                     this.setRuntimeAttribute(attr);
3358                 }
3359
3360                 isAnimated = true;
3361                 actualFrames = 0;
3362                 startTime = new Date();
3363             };
3364
3365
3366             var onTween = function() {
3367                 var data = {
3368                     duration: new Date() - this.getStartTime(),
3369                     currentFrame: this.currentFrame
3370                 };
3371
3372                 data.toString = function() {
3373                     return (
3374                             'duration: ' + data.duration +
3375                             ', currentFrame: ' + data.currentFrame
3376                             );
3377                 };
3378
3379                 this.onTween.fire(data);
3380
3381                 var runtimeAttributes = this.runtimeAttributes;
3382
3383                 for (var attr in runtimeAttributes) {
3384                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3385                 }
3386
3387                 actualFrames += 1;
3388             };
3389
3390             var onComplete = function() {
3391                 var actual_duration = (new Date() - startTime) / 1000 ;
3392
3393                 var data = {
3394                     duration: actual_duration,
3395                     frames: actualFrames,
3396                     fps: actualFrames / actual_duration
3397                 };
3398
3399                 data.toString = function() {
3400                     return (
3401                             'duration: ' + data.duration +
3402                             ', frames: ' + data.frames +
3403                             ', fps: ' + data.fps
3404                             );
3405                 };
3406
3407                 isAnimated = false;
3408                 actualFrames = 0;
3409                 this.onComplete.fire(data);
3410             };
3411
3412
3413             this._onStart = new Roo.util.Event(this);
3414             this.onStart = new Roo.util.Event(this);
3415             this.onTween = new Roo.util.Event(this);
3416             this._onTween = new Roo.util.Event(this);
3417             this.onComplete = new Roo.util.Event(this);
3418             this._onComplete = new Roo.util.Event(this);
3419             this._onStart.addListener(onStart);
3420             this._onTween.addListener(onTween);
3421             this._onComplete.addListener(onComplete);
3422         }
3423     };
3424 })();
3425 /*
3426  * Portions of this file are based on pieces of Yahoo User Interface Library
3427  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3428  * YUI licensed under the BSD License:
3429  * http://developer.yahoo.net/yui/license.txt
3430  * <script type="text/javascript">
3431  *
3432  */
3433
3434 Roo.lib.AnimMgr = new function() {
3435
3436     var thread = null;
3437
3438
3439     var queue = [];
3440
3441
3442     var tweenCount = 0;
3443
3444
3445     this.fps = 1000;
3446
3447
3448     this.delay = 1;
3449
3450
3451     this.registerElement = function(tween) {
3452         queue[queue.length] = tween;
3453         tweenCount += 1;
3454         tween._onStart.fire();
3455         this.start();
3456     };
3457
3458
3459     this.unRegister = function(tween, index) {
3460         tween._onComplete.fire();
3461         index = index || getIndex(tween);
3462         if (index != -1) {
3463             queue.splice(index, 1);
3464         }
3465
3466         tweenCount -= 1;
3467         if (tweenCount <= 0) {
3468             this.stop();
3469         }
3470     };
3471
3472
3473     this.start = function() {
3474         if (thread === null) {
3475             thread = setInterval(this.run, this.delay);
3476         }
3477     };
3478
3479
3480     this.stop = function(tween) {
3481         if (!tween) {
3482             clearInterval(thread);
3483
3484             for (var i = 0, len = queue.length; i < len; ++i) {
3485                 if (queue[0].isAnimated()) {
3486                     this.unRegister(queue[0], 0);
3487                 }
3488             }
3489
3490             queue = [];
3491             thread = null;
3492             tweenCount = 0;
3493         }
3494         else {
3495             this.unRegister(tween);
3496         }
3497     };
3498
3499
3500     this.run = function() {
3501         for (var i = 0, len = queue.length; i < len; ++i) {
3502             var tween = queue[i];
3503             if (!tween || !tween.isAnimated()) {
3504                 continue;
3505             }
3506
3507             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3508             {
3509                 tween.currentFrame += 1;
3510
3511                 if (tween.useSeconds) {
3512                     correctFrame(tween);
3513                 }
3514                 tween._onTween.fire();
3515             }
3516             else {
3517                 Roo.lib.AnimMgr.stop(tween, i);
3518             }
3519         }
3520     };
3521
3522     var getIndex = function(anim) {
3523         for (var i = 0, len = queue.length; i < len; ++i) {
3524             if (queue[i] == anim) {
3525                 return i;
3526             }
3527         }
3528         return -1;
3529     };
3530
3531
3532     var correctFrame = function(tween) {
3533         var frames = tween.totalFrames;
3534         var frame = tween.currentFrame;
3535         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3536         var elapsed = (new Date() - tween.getStartTime());
3537         var tweak = 0;
3538
3539         if (elapsed < tween.duration * 1000) {
3540             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3541         } else {
3542             tweak = frames - (frame + 1);
3543         }
3544         if (tweak > 0 && isFinite(tweak)) {
3545             if (tween.currentFrame + tweak >= frames) {
3546                 tweak = frames - (frame + 1);
3547             }
3548
3549             tween.currentFrame += tweak;
3550         }
3551     };
3552 };
3553
3554     /*
3555  * Portions of this file are based on pieces of Yahoo User Interface Library
3556  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3557  * YUI licensed under the BSD License:
3558  * http://developer.yahoo.net/yui/license.txt
3559  * <script type="text/javascript">
3560  *
3561  */
3562 Roo.lib.Bezier = new function() {
3563
3564         this.getPosition = function(points, t) {
3565             var n = points.length;
3566             var tmp = [];
3567
3568             for (var i = 0; i < n; ++i) {
3569                 tmp[i] = [points[i][0], points[i][1]];
3570             }
3571
3572             for (var j = 1; j < n; ++j) {
3573                 for (i = 0; i < n - j; ++i) {
3574                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3575                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3576                 }
3577             }
3578
3579             return [ tmp[0][0], tmp[0][1] ];
3580
3581         };
3582     };/*
3583  * Portions of this file are based on pieces of Yahoo User Interface Library
3584  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3585  * YUI licensed under the BSD License:
3586  * http://developer.yahoo.net/yui/license.txt
3587  * <script type="text/javascript">
3588  *
3589  */
3590 (function() {
3591
3592     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3593         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3594     };
3595
3596     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3597
3598     var fly = Roo.lib.AnimBase.fly;
3599     var Y = Roo.lib;
3600     var superclass = Y.ColorAnim.superclass;
3601     var proto = Y.ColorAnim.prototype;
3602
3603     proto.toString = function() {
3604         var el = this.getEl();
3605         var id = el.id || el.tagName;
3606         return ("ColorAnim " + id);
3607     };
3608
3609     proto.patterns.color = /color$/i;
3610     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3611     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3612     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3613     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3614
3615
3616     proto.parseColor = function(s) {
3617         if (s.length == 3) {
3618             return s;
3619         }
3620
3621         var c = this.patterns.hex.exec(s);
3622         if (c && c.length == 4) {
3623             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3624         }
3625
3626         c = this.patterns.rgb.exec(s);
3627         if (c && c.length == 4) {
3628             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3629         }
3630
3631         c = this.patterns.hex3.exec(s);
3632         if (c && c.length == 4) {
3633             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3634         }
3635
3636         return null;
3637     };
3638     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3639     proto.getAttribute = function(attr) {
3640         var el = this.getEl();
3641         if (this.patterns.color.test(attr)) {
3642             var val = fly(el).getStyle(attr);
3643
3644             if (this.patterns.transparent.test(val)) {
3645                 var parent = el.parentNode;
3646                 val = fly(parent).getStyle(attr);
3647
3648                 while (parent && this.patterns.transparent.test(val)) {
3649                     parent = parent.parentNode;
3650                     val = fly(parent).getStyle(attr);
3651                     if (parent.tagName.toUpperCase() == 'HTML') {
3652                         val = '#fff';
3653                     }
3654                 }
3655             }
3656         } else {
3657             val = superclass.getAttribute.call(this, attr);
3658         }
3659
3660         return val;
3661     };
3662     proto.getAttribute = function(attr) {
3663         var el = this.getEl();
3664         if (this.patterns.color.test(attr)) {
3665             var val = fly(el).getStyle(attr);
3666
3667             if (this.patterns.transparent.test(val)) {
3668                 var parent = el.parentNode;
3669                 val = fly(parent).getStyle(attr);
3670
3671                 while (parent && this.patterns.transparent.test(val)) {
3672                     parent = parent.parentNode;
3673                     val = fly(parent).getStyle(attr);
3674                     if (parent.tagName.toUpperCase() == 'HTML') {
3675                         val = '#fff';
3676                     }
3677                 }
3678             }
3679         } else {
3680             val = superclass.getAttribute.call(this, attr);
3681         }
3682
3683         return val;
3684     };
3685
3686     proto.doMethod = function(attr, start, end) {
3687         var val;
3688
3689         if (this.patterns.color.test(attr)) {
3690             val = [];
3691             for (var i = 0, len = start.length; i < len; ++i) {
3692                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3693             }
3694
3695             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3696         }
3697         else {
3698             val = superclass.doMethod.call(this, attr, start, end);
3699         }
3700
3701         return val;
3702     };
3703
3704     proto.setRuntimeAttribute = function(attr) {
3705         superclass.setRuntimeAttribute.call(this, attr);
3706
3707         if (this.patterns.color.test(attr)) {
3708             var attributes = this.attributes;
3709             var start = this.parseColor(this.runtimeAttributes[attr].start);
3710             var end = this.parseColor(this.runtimeAttributes[attr].end);
3711
3712             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3713                 end = this.parseColor(attributes[attr].by);
3714
3715                 for (var i = 0, len = start.length; i < len; ++i) {
3716                     end[i] = start[i] + end[i];
3717                 }
3718             }
3719
3720             this.runtimeAttributes[attr].start = start;
3721             this.runtimeAttributes[attr].end = end;
3722         }
3723     };
3724 })();
3725
3726 /*
3727  * Portions of this file are based on pieces of Yahoo User Interface Library
3728  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3729  * YUI licensed under the BSD License:
3730  * http://developer.yahoo.net/yui/license.txt
3731  * <script type="text/javascript">
3732  *
3733  */
3734 Roo.lib.Easing = {
3735
3736
3737     easeNone: function (t, b, c, d) {
3738         return c * t / d + b;
3739     },
3740
3741
3742     easeIn: function (t, b, c, d) {
3743         return c * (t /= d) * t + b;
3744     },
3745
3746
3747     easeOut: function (t, b, c, d) {
3748         return -c * (t /= d) * (t - 2) + b;
3749     },
3750
3751
3752     easeBoth: function (t, b, c, d) {
3753         if ((t /= d / 2) < 1) {
3754             return c / 2 * t * t + b;
3755         }
3756
3757         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3758     },
3759
3760
3761     easeInStrong: function (t, b, c, d) {
3762         return c * (t /= d) * t * t * t + b;
3763     },
3764
3765
3766     easeOutStrong: function (t, b, c, d) {
3767         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3768     },
3769
3770
3771     easeBothStrong: function (t, b, c, d) {
3772         if ((t /= d / 2) < 1) {
3773             return c / 2 * t * t * t * t + b;
3774         }
3775
3776         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3777     },
3778
3779
3780
3781     elasticIn: function (t, b, c, d, a, p) {
3782         if (t == 0) {
3783             return b;
3784         }
3785         if ((t /= d) == 1) {
3786             return b + c;
3787         }
3788         if (!p) {
3789             p = d * .3;
3790         }
3791
3792         if (!a || a < Math.abs(c)) {
3793             a = c;
3794             var s = p / 4;
3795         }
3796         else {
3797             var s = p / (2 * Math.PI) * Math.asin(c / a);
3798         }
3799
3800         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3801     },
3802
3803
3804     elasticOut: function (t, b, c, d, a, p) {
3805         if (t == 0) {
3806             return b;
3807         }
3808         if ((t /= d) == 1) {
3809             return b + c;
3810         }
3811         if (!p) {
3812             p = d * .3;
3813         }
3814
3815         if (!a || a < Math.abs(c)) {
3816             a = c;
3817             var s = p / 4;
3818         }
3819         else {
3820             var s = p / (2 * Math.PI) * Math.asin(c / a);
3821         }
3822
3823         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3824     },
3825
3826
3827     elasticBoth: function (t, b, c, d, a, p) {
3828         if (t == 0) {
3829             return b;
3830         }
3831
3832         if ((t /= d / 2) == 2) {
3833             return b + c;
3834         }
3835
3836         if (!p) {
3837             p = d * (.3 * 1.5);
3838         }
3839
3840         if (!a || a < Math.abs(c)) {
3841             a = c;
3842             var s = p / 4;
3843         }
3844         else {
3845             var s = p / (2 * Math.PI) * Math.asin(c / a);
3846         }
3847
3848         if (t < 1) {
3849             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3850                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3851         }
3852         return a * Math.pow(2, -10 * (t -= 1)) *
3853                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3854     },
3855
3856
3857
3858     backIn: function (t, b, c, d, s) {
3859         if (typeof s == 'undefined') {
3860             s = 1.70158;
3861         }
3862         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3863     },
3864
3865
3866     backOut: function (t, b, c, d, s) {
3867         if (typeof s == 'undefined') {
3868             s = 1.70158;
3869         }
3870         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3871     },
3872
3873
3874     backBoth: function (t, b, c, d, s) {
3875         if (typeof s == 'undefined') {
3876             s = 1.70158;
3877         }
3878
3879         if ((t /= d / 2 ) < 1) {
3880             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3881         }
3882         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3883     },
3884
3885
3886     bounceIn: function (t, b, c, d) {
3887         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3888     },
3889
3890
3891     bounceOut: function (t, b, c, d) {
3892         if ((t /= d) < (1 / 2.75)) {
3893             return c * (7.5625 * t * t) + b;
3894         } else if (t < (2 / 2.75)) {
3895             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3896         } else if (t < (2.5 / 2.75)) {
3897             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3898         }
3899         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3900     },
3901
3902
3903     bounceBoth: function (t, b, c, d) {
3904         if (t < d / 2) {
3905             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3906         }
3907         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3908     }
3909 };/*
3910  * Portions of this file are based on pieces of Yahoo User Interface Library
3911  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3912  * YUI licensed under the BSD License:
3913  * http://developer.yahoo.net/yui/license.txt
3914  * <script type="text/javascript">
3915  *
3916  */
3917     (function() {
3918         Roo.lib.Motion = function(el, attributes, duration, method) {
3919             if (el) {
3920                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3921             }
3922         };
3923
3924         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3925
3926
3927         var Y = Roo.lib;
3928         var superclass = Y.Motion.superclass;
3929         var proto = Y.Motion.prototype;
3930
3931         proto.toString = function() {
3932             var el = this.getEl();
3933             var id = el.id || el.tagName;
3934             return ("Motion " + id);
3935         };
3936
3937         proto.patterns.points = /^points$/i;
3938
3939         proto.setAttribute = function(attr, val, unit) {
3940             if (this.patterns.points.test(attr)) {
3941                 unit = unit || 'px';
3942                 superclass.setAttribute.call(this, 'left', val[0], unit);
3943                 superclass.setAttribute.call(this, 'top', val[1], unit);
3944             } else {
3945                 superclass.setAttribute.call(this, attr, val, unit);
3946             }
3947         };
3948
3949         proto.getAttribute = function(attr) {
3950             if (this.patterns.points.test(attr)) {
3951                 var val = [
3952                         superclass.getAttribute.call(this, 'left'),
3953                         superclass.getAttribute.call(this, 'top')
3954                         ];
3955             } else {
3956                 val = superclass.getAttribute.call(this, attr);
3957             }
3958
3959             return val;
3960         };
3961
3962         proto.doMethod = function(attr, start, end) {
3963             var val = null;
3964
3965             if (this.patterns.points.test(attr)) {
3966                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3967                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3968             } else {
3969                 val = superclass.doMethod.call(this, attr, start, end);
3970             }
3971             return val;
3972         };
3973
3974         proto.setRuntimeAttribute = function(attr) {
3975             if (this.patterns.points.test(attr)) {
3976                 var el = this.getEl();
3977                 var attributes = this.attributes;
3978                 var start;
3979                 var control = attributes['points']['control'] || [];
3980                 var end;
3981                 var i, len;
3982
3983                 if (control.length > 0 && !(control[0] instanceof Array)) {
3984                     control = [control];
3985                 } else {
3986                     var tmp = [];
3987                     for (i = 0,len = control.length; i < len; ++i) {
3988                         tmp[i] = control[i];
3989                     }
3990                     control = tmp;
3991                 }
3992
3993                 Roo.fly(el).position();
3994
3995                 if (isset(attributes['points']['from'])) {
3996                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3997                 }
3998                 else {
3999                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4000                 }
4001
4002                 start = this.getAttribute('points');
4003
4004
4005                 if (isset(attributes['points']['to'])) {
4006                     end = translateValues.call(this, attributes['points']['to'], start);
4007
4008                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4009                     for (i = 0,len = control.length; i < len; ++i) {
4010                         control[i] = translateValues.call(this, control[i], start);
4011                     }
4012
4013
4014                 } else if (isset(attributes['points']['by'])) {
4015                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4016
4017                     for (i = 0,len = control.length; i < len; ++i) {
4018                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4019                     }
4020                 }
4021
4022                 this.runtimeAttributes[attr] = [start];
4023
4024                 if (control.length > 0) {
4025                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4026                 }
4027
4028                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4029             }
4030             else {
4031                 superclass.setRuntimeAttribute.call(this, attr);
4032             }
4033         };
4034
4035         var translateValues = function(val, start) {
4036             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4037             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4038
4039             return val;
4040         };
4041
4042         var isset = function(prop) {
4043             return (typeof prop !== 'undefined');
4044         };
4045     })();
4046 /*
4047  * Portions of this file are based on pieces of Yahoo User Interface Library
4048  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4049  * YUI licensed under the BSD License:
4050  * http://developer.yahoo.net/yui/license.txt
4051  * <script type="text/javascript">
4052  *
4053  */
4054     (function() {
4055         Roo.lib.Scroll = function(el, attributes, duration, method) {
4056             if (el) {
4057                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4058             }
4059         };
4060
4061         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4062
4063
4064         var Y = Roo.lib;
4065         var superclass = Y.Scroll.superclass;
4066         var proto = Y.Scroll.prototype;
4067
4068         proto.toString = function() {
4069             var el = this.getEl();
4070             var id = el.id || el.tagName;
4071             return ("Scroll " + id);
4072         };
4073
4074         proto.doMethod = function(attr, start, end) {
4075             var val = null;
4076
4077             if (attr == 'scroll') {
4078                 val = [
4079                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4080                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4081                         ];
4082
4083             } else {
4084                 val = superclass.doMethod.call(this, attr, start, end);
4085             }
4086             return val;
4087         };
4088
4089         proto.getAttribute = function(attr) {
4090             var val = null;
4091             var el = this.getEl();
4092
4093             if (attr == 'scroll') {
4094                 val = [ el.scrollLeft, el.scrollTop ];
4095             } else {
4096                 val = superclass.getAttribute.call(this, attr);
4097             }
4098
4099             return val;
4100         };
4101
4102         proto.setAttribute = function(attr, val, unit) {
4103             var el = this.getEl();
4104
4105             if (attr == 'scroll') {
4106                 el.scrollLeft = val[0];
4107                 el.scrollTop = val[1];
4108             } else {
4109                 superclass.setAttribute.call(this, attr, val, unit);
4110             }
4111         };
4112     })();
4113 /*
4114  * Based on:
4115  * Ext JS Library 1.1.1
4116  * Copyright(c) 2006-2007, Ext JS, LLC.
4117  *
4118  * Originally Released Under LGPL - original licence link has changed is not relivant.
4119  *
4120  * Fork - LGPL
4121  * <script type="text/javascript">
4122  */
4123
4124
4125 // nasty IE9 hack - what a pile of crap that is..
4126
4127  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4128     Range.prototype.createContextualFragment = function (html) {
4129         var doc = window.document;
4130         var container = doc.createElement("div");
4131         container.innerHTML = html;
4132         var frag = doc.createDocumentFragment(), n;
4133         while ((n = container.firstChild)) {
4134             frag.appendChild(n);
4135         }
4136         return frag;
4137     };
4138 }
4139
4140 /**
4141  * @class Roo.DomHelper
4142  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4143  * 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>.
4144  * @singleton
4145  */
4146 Roo.DomHelper = function(){
4147     var tempTableEl = null;
4148     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4149     var tableRe = /^table|tbody|tr|td$/i;
4150     var xmlns = {};
4151     // build as innerHTML where available
4152     /** @ignore */
4153     var createHtml = function(o){
4154         if(typeof o == 'string'){
4155             return o;
4156         }
4157         var b = "";
4158         if(!o.tag){
4159             o.tag = "div";
4160         }
4161         b += "<" + o.tag;
4162         for(var attr in o){
4163             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4164             if(attr == "style"){
4165                 var s = o["style"];
4166                 if(typeof s == "function"){
4167                     s = s.call();
4168                 }
4169                 if(typeof s == "string"){
4170                     b += ' style="' + s + '"';
4171                 }else if(typeof s == "object"){
4172                     b += ' style="';
4173                     for(var key in s){
4174                         if(typeof s[key] != "function"){
4175                             b += key + ":" + s[key] + ";";
4176                         }
4177                     }
4178                     b += '"';
4179                 }
4180             }else{
4181                 if(attr == "cls"){
4182                     b += ' class="' + o["cls"] + '"';
4183                 }else if(attr == "htmlFor"){
4184                     b += ' for="' + o["htmlFor"] + '"';
4185                 }else{
4186                     b += " " + attr + '="' + o[attr] + '"';
4187                 }
4188             }
4189         }
4190         if(emptyTags.test(o.tag)){
4191             b += "/>";
4192         }else{
4193             b += ">";
4194             var cn = o.children || o.cn;
4195             if(cn){
4196                 //http://bugs.kde.org/show_bug.cgi?id=71506
4197                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198                     for(var i = 0, len = cn.length; i < len; i++) {
4199                         b += createHtml(cn[i], b);
4200                     }
4201                 }else{
4202                     b += createHtml(cn, b);
4203                 }
4204             }
4205             if(o.html){
4206                 b += o.html;
4207             }
4208             b += "</" + o.tag + ">";
4209         }
4210         return b;
4211     };
4212
4213     // build as dom
4214     /** @ignore */
4215     var createDom = function(o, parentNode){
4216          
4217         // defininition craeted..
4218         var ns = false;
4219         if (o.ns && o.ns != 'html') {
4220                
4221             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4222                 xmlns[o.ns] = o.xmlns;
4223                 ns = o.xmlns;
4224             }
4225             if (typeof(xmlns[o.ns]) == 'undefined') {
4226                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4227             }
4228             ns = xmlns[o.ns];
4229         }
4230         
4231         
4232         if (typeof(o) == 'string') {
4233             return parentNode.appendChild(document.createTextNode(o));
4234         }
4235         o.tag = o.tag || div;
4236         if (o.ns && Roo.isIE) {
4237             ns = false;
4238             o.tag = o.ns + ':' + o.tag;
4239             
4240         }
4241         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4242         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4243         for(var attr in o){
4244             
4245             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4246                     attr == "style" || typeof o[attr] == "function") { continue; }
4247                     
4248             if(attr=="cls" && Roo.isIE){
4249                 el.className = o["cls"];
4250             }else{
4251                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4252                 else { 
4253                     el[attr] = o[attr];
4254                 }
4255             }
4256         }
4257         Roo.DomHelper.applyStyles(el, o.style);
4258         var cn = o.children || o.cn;
4259         if(cn){
4260             //http://bugs.kde.org/show_bug.cgi?id=71506
4261              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4262                 for(var i = 0, len = cn.length; i < len; i++) {
4263                     createDom(cn[i], el);
4264                 }
4265             }else{
4266                 createDom(cn, el);
4267             }
4268         }
4269         if(o.html){
4270             el.innerHTML = o.html;
4271         }
4272         if(parentNode){
4273            parentNode.appendChild(el);
4274         }
4275         return el;
4276     };
4277
4278     var ieTable = function(depth, s, h, e){
4279         tempTableEl.innerHTML = [s, h, e].join('');
4280         var i = -1, el = tempTableEl;
4281         while(++i < depth){
4282             el = el.firstChild;
4283         }
4284         return el;
4285     };
4286
4287     // kill repeat to save bytes
4288     var ts = '<table>',
4289         te = '</table>',
4290         tbs = ts+'<tbody>',
4291         tbe = '</tbody>'+te,
4292         trs = tbs + '<tr>',
4293         tre = '</tr>'+tbe;
4294
4295     /**
4296      * @ignore
4297      * Nasty code for IE's broken table implementation
4298      */
4299     var insertIntoTable = function(tag, where, el, html){
4300         if(!tempTableEl){
4301             tempTableEl = document.createElement('div');
4302         }
4303         var node;
4304         var before = null;
4305         if(tag == 'td'){
4306             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4307                 return;
4308             }
4309             if(where == 'beforebegin'){
4310                 before = el;
4311                 el = el.parentNode;
4312             } else{
4313                 before = el.nextSibling;
4314                 el = el.parentNode;
4315             }
4316             node = ieTable(4, trs, html, tre);
4317         }
4318         else if(tag == 'tr'){
4319             if(where == 'beforebegin'){
4320                 before = el;
4321                 el = el.parentNode;
4322                 node = ieTable(3, tbs, html, tbe);
4323             } else if(where == 'afterend'){
4324                 before = el.nextSibling;
4325                 el = el.parentNode;
4326                 node = ieTable(3, tbs, html, tbe);
4327             } else{ // INTO a TR
4328                 if(where == 'afterbegin'){
4329                     before = el.firstChild;
4330                 }
4331                 node = ieTable(4, trs, html, tre);
4332             }
4333         } else if(tag == 'tbody'){
4334             if(where == 'beforebegin'){
4335                 before = el;
4336                 el = el.parentNode;
4337                 node = ieTable(2, ts, html, te);
4338             } else if(where == 'afterend'){
4339                 before = el.nextSibling;
4340                 el = el.parentNode;
4341                 node = ieTable(2, ts, html, te);
4342             } else{
4343                 if(where == 'afterbegin'){
4344                     before = el.firstChild;
4345                 }
4346                 node = ieTable(3, tbs, html, tbe);
4347             }
4348         } else{ // TABLE
4349             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4350                 return;
4351             }
4352             if(where == 'afterbegin'){
4353                 before = el.firstChild;
4354             }
4355             node = ieTable(2, ts, html, te);
4356         }
4357         el.insertBefore(node, before);
4358         return node;
4359     };
4360
4361     return {
4362     /** True to force the use of DOM instead of html fragments @type Boolean */
4363     useDom : false,
4364
4365     /**
4366      * Returns the markup for the passed Element(s) config
4367      * @param {Object} o The Dom object spec (and children)
4368      * @return {String}
4369      */
4370     markup : function(o){
4371         return createHtml(o);
4372     },
4373
4374     /**
4375      * Applies a style specification to an element
4376      * @param {String/HTMLElement} el The element to apply styles to
4377      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4378      * a function which returns such a specification.
4379      */
4380     applyStyles : function(el, styles){
4381         if(styles){
4382            el = Roo.fly(el);
4383            if(typeof styles == "string"){
4384                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4385                var matches;
4386                while ((matches = re.exec(styles)) != null){
4387                    el.setStyle(matches[1], matches[2]);
4388                }
4389            }else if (typeof styles == "object"){
4390                for (var style in styles){
4391                   el.setStyle(style, styles[style]);
4392                }
4393            }else if (typeof styles == "function"){
4394                 Roo.DomHelper.applyStyles(el, styles.call());
4395            }
4396         }
4397     },
4398
4399     /**
4400      * Inserts an HTML fragment into the Dom
4401      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4402      * @param {HTMLElement} el The context element
4403      * @param {String} html The HTML fragmenet
4404      * @return {HTMLElement} The new node
4405      */
4406     insertHtml : function(where, el, html){
4407         where = where.toLowerCase();
4408         if(el.insertAdjacentHTML){
4409             if(tableRe.test(el.tagName)){
4410                 var rs;
4411                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4412                     return rs;
4413                 }
4414             }
4415             switch(where){
4416                 case "beforebegin":
4417                     el.insertAdjacentHTML('BeforeBegin', html);
4418                     return el.previousSibling;
4419                 case "afterbegin":
4420                     el.insertAdjacentHTML('AfterBegin', html);
4421                     return el.firstChild;
4422                 case "beforeend":
4423                     el.insertAdjacentHTML('BeforeEnd', html);
4424                     return el.lastChild;
4425                 case "afterend":
4426                     el.insertAdjacentHTML('AfterEnd', html);
4427                     return el.nextSibling;
4428             }
4429             throw 'Illegal insertion point -> "' + where + '"';
4430         }
4431         var range = el.ownerDocument.createRange();
4432         var frag;
4433         switch(where){
4434              case "beforebegin":
4435                 range.setStartBefore(el);
4436                 frag = range.createContextualFragment(html);
4437                 el.parentNode.insertBefore(frag, el);
4438                 return el.previousSibling;
4439              case "afterbegin":
4440                 if(el.firstChild){
4441                     range.setStartBefore(el.firstChild);
4442                     frag = range.createContextualFragment(html);
4443                     el.insertBefore(frag, el.firstChild);
4444                     return el.firstChild;
4445                 }else{
4446                     el.innerHTML = html;
4447                     return el.firstChild;
4448                 }
4449             case "beforeend":
4450                 if(el.lastChild){
4451                     range.setStartAfter(el.lastChild);
4452                     frag = range.createContextualFragment(html);
4453                     el.appendChild(frag);
4454                     return el.lastChild;
4455                 }else{
4456                     el.innerHTML = html;
4457                     return el.lastChild;
4458                 }
4459             case "afterend":
4460                 range.setStartAfter(el);
4461                 frag = range.createContextualFragment(html);
4462                 el.parentNode.insertBefore(frag, el.nextSibling);
4463                 return el.nextSibling;
4464             }
4465             throw 'Illegal insertion point -> "' + where + '"';
4466     },
4467
4468     /**
4469      * Creates new Dom element(s) and inserts them before el
4470      * @param {String/HTMLElement/Element} el The context element
4471      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4472      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4473      * @return {HTMLElement/Roo.Element} The new node
4474      */
4475     insertBefore : function(el, o, returnElement){
4476         return this.doInsert(el, o, returnElement, "beforeBegin");
4477     },
4478
4479     /**
4480      * Creates new Dom element(s) and inserts them after el
4481      * @param {String/HTMLElement/Element} el The context element
4482      * @param {Object} o The Dom object spec (and children)
4483      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4484      * @return {HTMLElement/Roo.Element} The new node
4485      */
4486     insertAfter : function(el, o, returnElement){
4487         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4488     },
4489
4490     /**
4491      * Creates new Dom element(s) and inserts them as the first child of el
4492      * @param {String/HTMLElement/Element} el The context element
4493      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4494      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4495      * @return {HTMLElement/Roo.Element} The new node
4496      */
4497     insertFirst : function(el, o, returnElement){
4498         return this.doInsert(el, o, returnElement, "afterBegin");
4499     },
4500
4501     // private
4502     doInsert : function(el, o, returnElement, pos, sibling){
4503         el = Roo.getDom(el);
4504         var newNode;
4505         if(this.useDom || o.ns){
4506             newNode = createDom(o, null);
4507             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4508         }else{
4509             var html = createHtml(o);
4510             newNode = this.insertHtml(pos, el, html);
4511         }
4512         return returnElement ? Roo.get(newNode, true) : newNode;
4513     },
4514
4515     /**
4516      * Creates new Dom element(s) and appends them to el
4517      * @param {String/HTMLElement/Element} el The context element
4518      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4519      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4520      * @return {HTMLElement/Roo.Element} The new node
4521      */
4522     append : function(el, o, returnElement){
4523         el = Roo.getDom(el);
4524         var newNode;
4525         if(this.useDom || o.ns){
4526             newNode = createDom(o, null);
4527             el.appendChild(newNode);
4528         }else{
4529             var html = createHtml(o);
4530             newNode = this.insertHtml("beforeEnd", el, html);
4531         }
4532         return returnElement ? Roo.get(newNode, true) : newNode;
4533     },
4534
4535     /**
4536      * Creates new Dom element(s) and overwrites the contents of el with them
4537      * @param {String/HTMLElement/Element} el The context element
4538      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4539      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4540      * @return {HTMLElement/Roo.Element} The new node
4541      */
4542     overwrite : function(el, o, returnElement){
4543         el = Roo.getDom(el);
4544         if (o.ns) {
4545           
4546             while (el.childNodes.length) {
4547                 el.removeChild(el.firstChild);
4548             }
4549             createDom(o, el);
4550         } else {
4551             el.innerHTML = createHtml(o);   
4552         }
4553         
4554         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4555     },
4556
4557     /**
4558      * Creates a new Roo.DomHelper.Template from the Dom object spec
4559      * @param {Object} o The Dom object spec (and children)
4560      * @return {Roo.DomHelper.Template} The new template
4561      */
4562     createTemplate : function(o){
4563         var html = createHtml(o);
4564         return new Roo.Template(html);
4565     }
4566     };
4567 }();
4568 /*
4569  * Based on:
4570  * Ext JS Library 1.1.1
4571  * Copyright(c) 2006-2007, Ext JS, LLC.
4572  *
4573  * Originally Released Under LGPL - original licence link has changed is not relivant.
4574  *
4575  * Fork - LGPL
4576  * <script type="text/javascript">
4577  */
4578  
4579 /**
4580 * @class Roo.Template
4581 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4582 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4583 * Usage:
4584 <pre><code>
4585 var t = new Roo.Template({
4586     html :  '&lt;div name="{id}"&gt;' + 
4587         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4588         '&lt;/div&gt;',
4589     myformat: function (value, allValues) {
4590         return 'XX' + value;
4591     }
4592 });
4593 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4594 </code></pre>
4595 * For more information see this blog post with examples:
4596 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4597      - Create Elements using DOM, HTML fragments and Templates</a>. 
4598 * @constructor
4599 * @param {Object} cfg - Configuration object.
4600 */
4601 Roo.Template = function(cfg){
4602     // BC!
4603     if(cfg instanceof Array){
4604         cfg = cfg.join("");
4605     }else if(arguments.length > 1){
4606         cfg = Array.prototype.join.call(arguments, "");
4607     }
4608     
4609     
4610     if (typeof(cfg) == 'object') {
4611         Roo.apply(this,cfg)
4612     } else {
4613         // bc
4614         this.html = cfg;
4615     }
4616     if (this.url) {
4617         this.load();
4618     }
4619     
4620 };
4621 Roo.Template.prototype = {
4622     
4623     /**
4624      * @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..
4625      *                    it should be fixed so that template is observable...
4626      */
4627     url : false,
4628     /**
4629      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4630      */
4631     html : '',
4632     /**
4633      * Returns an HTML fragment of this template with the specified values applied.
4634      * @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'})
4635      * @return {String} The HTML fragment
4636      */
4637     applyTemplate : function(values){
4638         try {
4639            
4640             if(this.compiled){
4641                 return this.compiled(values);
4642             }
4643             var useF = this.disableFormats !== true;
4644             var fm = Roo.util.Format, tpl = this;
4645             var fn = function(m, name, format, args){
4646                 if(format && useF){
4647                     if(format.substr(0, 5) == "this."){
4648                         return tpl.call(format.substr(5), values[name], values);
4649                     }else{
4650                         if(args){
4651                             // quoted values are required for strings in compiled templates, 
4652                             // but for non compiled we need to strip them
4653                             // quoted reversed for jsmin
4654                             var re = /^\s*['"](.*)["']\s*$/;
4655                             args = args.split(',');
4656                             for(var i = 0, len = args.length; i < len; i++){
4657                                 args[i] = args[i].replace(re, "$1");
4658                             }
4659                             args = [values[name]].concat(args);
4660                         }else{
4661                             args = [values[name]];
4662                         }
4663                         return fm[format].apply(fm, args);
4664                     }
4665                 }else{
4666                     return values[name] !== undefined ? values[name] : "";
4667                 }
4668             };
4669             return this.html.replace(this.re, fn);
4670         } catch (e) {
4671             Roo.log(e);
4672             throw e;
4673         }
4674          
4675     },
4676     
4677     loading : false,
4678       
4679     load : function ()
4680     {
4681          
4682         if (this.loading) {
4683             return;
4684         }
4685         var _t = this;
4686         
4687         this.loading = true;
4688         this.compiled = false;
4689         
4690         var cx = new Roo.data.Connection();
4691         cx.request({
4692             url : this.url,
4693             method : 'GET',
4694             success : function (response) {
4695                 _t.loading = false;
4696                 _t.html = response.responseText;
4697                 _t.url = false;
4698                 _t.compile();
4699              },
4700             failure : function(response) {
4701                 Roo.log("Template failed to load from " + _t.url);
4702                 _t.loading = false;
4703             }
4704         });
4705     },
4706
4707     /**
4708      * Sets the HTML used as the template and optionally compiles it.
4709      * @param {String} html
4710      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4711      * @return {Roo.Template} this
4712      */
4713     set : function(html, compile){
4714         this.html = html;
4715         this.compiled = null;
4716         if(compile){
4717             this.compile();
4718         }
4719         return this;
4720     },
4721     
4722     /**
4723      * True to disable format functions (defaults to false)
4724      * @type Boolean
4725      */
4726     disableFormats : false,
4727     
4728     /**
4729     * The regular expression used to match template variables 
4730     * @type RegExp
4731     * @property 
4732     */
4733     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4734     
4735     /**
4736      * Compiles the template into an internal function, eliminating the RegEx overhead.
4737      * @return {Roo.Template} this
4738      */
4739     compile : function(){
4740         var fm = Roo.util.Format;
4741         var useF = this.disableFormats !== true;
4742         var sep = Roo.isGecko ? "+" : ",";
4743         var fn = function(m, name, format, args){
4744             if(format && useF){
4745                 args = args ? ',' + args : "";
4746                 if(format.substr(0, 5) != "this."){
4747                     format = "fm." + format + '(';
4748                 }else{
4749                     format = 'this.call("'+ format.substr(5) + '", ';
4750                     args = ", values";
4751                 }
4752             }else{
4753                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4754             }
4755             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4756         };
4757         var body;
4758         // branched to use + in gecko and [].join() in others
4759         if(Roo.isGecko){
4760             body = "this.compiled = function(values){ return '" +
4761                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4762                     "';};";
4763         }else{
4764             body = ["this.compiled = function(values){ return ['"];
4765             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4766             body.push("'].join('');};");
4767             body = body.join('');
4768         }
4769         /**
4770          * eval:var:values
4771          * eval:var:fm
4772          */
4773         eval(body);
4774         return this;
4775     },
4776     
4777     // private function used to call members
4778     call : function(fnName, value, allValues){
4779         return this[fnName](value, allValues);
4780     },
4781     
4782     /**
4783      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4784      * @param {String/HTMLElement/Roo.Element} el The context element
4785      * @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'})
4786      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4787      * @return {HTMLElement/Roo.Element} The new node or Element
4788      */
4789     insertFirst: function(el, values, returnElement){
4790         return this.doInsert('afterBegin', el, values, returnElement);
4791     },
4792
4793     /**
4794      * Applies the supplied values to the template and inserts the new node(s) before el.
4795      * @param {String/HTMLElement/Roo.Element} el The context element
4796      * @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'})
4797      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4798      * @return {HTMLElement/Roo.Element} The new node or Element
4799      */
4800     insertBefore: function(el, values, returnElement){
4801         return this.doInsert('beforeBegin', el, values, returnElement);
4802     },
4803
4804     /**
4805      * Applies the supplied values to the template and inserts the new node(s) after el.
4806      * @param {String/HTMLElement/Roo.Element} el The context element
4807      * @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'})
4808      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4809      * @return {HTMLElement/Roo.Element} The new node or Element
4810      */
4811     insertAfter : function(el, values, returnElement){
4812         return this.doInsert('afterEnd', el, values, returnElement);
4813     },
4814     
4815     /**
4816      * Applies the supplied values to the template and appends the new node(s) to el.
4817      * @param {String/HTMLElement/Roo.Element} el The context element
4818      * @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'})
4819      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4820      * @return {HTMLElement/Roo.Element} The new node or Element
4821      */
4822     append : function(el, values, returnElement){
4823         return this.doInsert('beforeEnd', el, values, returnElement);
4824     },
4825
4826     doInsert : function(where, el, values, returnEl){
4827         el = Roo.getDom(el);
4828         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4829         return returnEl ? Roo.get(newNode, true) : newNode;
4830     },
4831
4832     /**
4833      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4834      * @param {String/HTMLElement/Roo.Element} el The context element
4835      * @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'})
4836      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4837      * @return {HTMLElement/Roo.Element} The new node or Element
4838      */
4839     overwrite : function(el, values, returnElement){
4840         el = Roo.getDom(el);
4841         el.innerHTML = this.applyTemplate(values);
4842         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4843     }
4844 };
4845 /**
4846  * Alias for {@link #applyTemplate}
4847  * @method
4848  */
4849 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4850
4851 // backwards compat
4852 Roo.DomHelper.Template = Roo.Template;
4853
4854 /**
4855  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4856  * @param {String/HTMLElement} el A DOM element or its id
4857  * @returns {Roo.Template} The created template
4858  * @static
4859  */
4860 Roo.Template.from = function(el){
4861     el = Roo.getDom(el);
4862     return new Roo.Template(el.value || el.innerHTML);
4863 };/*
4864  * Based on:
4865  * Ext JS Library 1.1.1
4866  * Copyright(c) 2006-2007, Ext JS, LLC.
4867  *
4868  * Originally Released Under LGPL - original licence link has changed is not relivant.
4869  *
4870  * Fork - LGPL
4871  * <script type="text/javascript">
4872  */
4873  
4874
4875 /*
4876  * This is code is also distributed under MIT license for use
4877  * with jQuery and prototype JavaScript libraries.
4878  */
4879 /**
4880  * @class Roo.DomQuery
4881 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).
4882 <p>
4883 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>
4884
4885 <p>
4886 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.
4887 </p>
4888 <h4>Element Selectors:</h4>
4889 <ul class="list">
4890     <li> <b>*</b> any element</li>
4891     <li> <b>E</b> an element with the tag E</li>
4892     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4893     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4894     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4895     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4896 </ul>
4897 <h4>Attribute Selectors:</h4>
4898 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4899 <ul class="list">
4900     <li> <b>E[foo]</b> has an attribute "foo"</li>
4901     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4902     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4903     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4904     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4905     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4906     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4907 </ul>
4908 <h4>Pseudo Classes:</h4>
4909 <ul class="list">
4910     <li> <b>E:first-child</b> E is the first child of its parent</li>
4911     <li> <b>E:last-child</b> E is the last child of its parent</li>
4912     <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>
4913     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4914     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4915     <li> <b>E:only-child</b> E is the only child of its parent</li>
4916     <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>
4917     <li> <b>E:first</b> the first E in the resultset</li>
4918     <li> <b>E:last</b> the last E in the resultset</li>
4919     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4920     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4921     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4922     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4923     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4924     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4925     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4926     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4927     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4928 </ul>
4929 <h4>CSS Value Selectors:</h4>
4930 <ul class="list">
4931     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4932     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4933     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4934     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4935     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4936     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4937 </ul>
4938  * @singleton
4939  */
4940 Roo.DomQuery = function(){
4941     var cache = {}, simpleCache = {}, valueCache = {};
4942     var nonSpace = /\S/;
4943     var trimRe = /^\s+|\s+$/g;
4944     var tplRe = /\{(\d+)\}/g;
4945     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4946     var tagTokenRe = /^(#)?([\w-\*]+)/;
4947     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4948
4949     function child(p, index){
4950         var i = 0;
4951         var n = p.firstChild;
4952         while(n){
4953             if(n.nodeType == 1){
4954                if(++i == index){
4955                    return n;
4956                }
4957             }
4958             n = n.nextSibling;
4959         }
4960         return null;
4961     };
4962
4963     function next(n){
4964         while((n = n.nextSibling) && n.nodeType != 1);
4965         return n;
4966     };
4967
4968     function prev(n){
4969         while((n = n.previousSibling) && n.nodeType != 1);
4970         return n;
4971     };
4972
4973     function children(d){
4974         var n = d.firstChild, ni = -1;
4975             while(n){
4976                 var nx = n.nextSibling;
4977                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4978                     d.removeChild(n);
4979                 }else{
4980                     n.nodeIndex = ++ni;
4981                 }
4982                 n = nx;
4983             }
4984             return this;
4985         };
4986
4987     function byClassName(c, a, v){
4988         if(!v){
4989             return c;
4990         }
4991         var r = [], ri = -1, cn;
4992         for(var i = 0, ci; ci = c[i]; i++){
4993             if((' '+ci.className+' ').indexOf(v) != -1){
4994                 r[++ri] = ci;
4995             }
4996         }
4997         return r;
4998     };
4999
5000     function attrValue(n, attr){
5001         if(!n.tagName && typeof n.length != "undefined"){
5002             n = n[0];
5003         }
5004         if(!n){
5005             return null;
5006         }
5007         if(attr == "for"){
5008             return n.htmlFor;
5009         }
5010         if(attr == "class" || attr == "className"){
5011             return n.className;
5012         }
5013         return n.getAttribute(attr) || n[attr];
5014
5015     };
5016
5017     function getNodes(ns, mode, tagName){
5018         var result = [], ri = -1, cs;
5019         if(!ns){
5020             return result;
5021         }
5022         tagName = tagName || "*";
5023         if(typeof ns.getElementsByTagName != "undefined"){
5024             ns = [ns];
5025         }
5026         if(!mode){
5027             for(var i = 0, ni; ni = ns[i]; i++){
5028                 cs = ni.getElementsByTagName(tagName);
5029                 for(var j = 0, ci; ci = cs[j]; j++){
5030                     result[++ri] = ci;
5031                 }
5032             }
5033         }else if(mode == "/" || mode == ">"){
5034             var utag = tagName.toUpperCase();
5035             for(var i = 0, ni, cn; ni = ns[i]; i++){
5036                 cn = ni.children || ni.childNodes;
5037                 for(var j = 0, cj; cj = cn[j]; j++){
5038                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5039                         result[++ri] = cj;
5040                     }
5041                 }
5042             }
5043         }else if(mode == "+"){
5044             var utag = tagName.toUpperCase();
5045             for(var i = 0, n; n = ns[i]; i++){
5046                 while((n = n.nextSibling) && n.nodeType != 1);
5047                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5048                     result[++ri] = n;
5049                 }
5050             }
5051         }else if(mode == "~"){
5052             for(var i = 0, n; n = ns[i]; i++){
5053                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5054                 if(n){
5055                     result[++ri] = n;
5056                 }
5057             }
5058         }
5059         return result;
5060     };
5061
5062     function concat(a, b){
5063         if(b.slice){
5064             return a.concat(b);
5065         }
5066         for(var i = 0, l = b.length; i < l; i++){
5067             a[a.length] = b[i];
5068         }
5069         return a;
5070     }
5071
5072     function byTag(cs, tagName){
5073         if(cs.tagName || cs == document){
5074             cs = [cs];
5075         }
5076         if(!tagName){
5077             return cs;
5078         }
5079         var r = [], ri = -1;
5080         tagName = tagName.toLowerCase();
5081         for(var i = 0, ci; ci = cs[i]; i++){
5082             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5083                 r[++ri] = ci;
5084             }
5085         }
5086         return r;
5087     };
5088
5089     function byId(cs, attr, id){
5090         if(cs.tagName || cs == document){
5091             cs = [cs];
5092         }
5093         if(!id){
5094             return cs;
5095         }
5096         var r = [], ri = -1;
5097         for(var i = 0,ci; ci = cs[i]; i++){
5098             if(ci && ci.id == id){
5099                 r[++ri] = ci;
5100                 return r;
5101             }
5102         }
5103         return r;
5104     };
5105
5106     function byAttribute(cs, attr, value, op, custom){
5107         var r = [], ri = -1, st = custom=="{";
5108         var f = Roo.DomQuery.operators[op];
5109         for(var i = 0, ci; ci = cs[i]; i++){
5110             var a;
5111             if(st){
5112                 a = Roo.DomQuery.getStyle(ci, attr);
5113             }
5114             else if(attr == "class" || attr == "className"){
5115                 a = ci.className;
5116             }else if(attr == "for"){
5117                 a = ci.htmlFor;
5118             }else if(attr == "href"){
5119                 a = ci.getAttribute("href", 2);
5120             }else{
5121                 a = ci.getAttribute(attr);
5122             }
5123             if((f && f(a, value)) || (!f && a)){
5124                 r[++ri] = ci;
5125             }
5126         }
5127         return r;
5128     };
5129
5130     function byPseudo(cs, name, value){
5131         return Roo.DomQuery.pseudos[name](cs, value);
5132     };
5133
5134     // This is for IE MSXML which does not support expandos.
5135     // IE runs the same speed using setAttribute, however FF slows way down
5136     // and Safari completely fails so they need to continue to use expandos.
5137     var isIE = window.ActiveXObject ? true : false;
5138
5139     // this eval is stop the compressor from
5140     // renaming the variable to something shorter
5141     
5142     /** eval:var:batch */
5143     var batch = 30803; 
5144
5145     var key = 30803;
5146
5147     function nodupIEXml(cs){
5148         var d = ++key;
5149         cs[0].setAttribute("_nodup", d);
5150         var r = [cs[0]];
5151         for(var i = 1, len = cs.length; i < len; i++){
5152             var c = cs[i];
5153             if(!c.getAttribute("_nodup") != d){
5154                 c.setAttribute("_nodup", d);
5155                 r[r.length] = c;
5156             }
5157         }
5158         for(var i = 0, len = cs.length; i < len; i++){
5159             cs[i].removeAttribute("_nodup");
5160         }
5161         return r;
5162     }
5163
5164     function nodup(cs){
5165         if(!cs){
5166             return [];
5167         }
5168         var len = cs.length, c, i, r = cs, cj, ri = -1;
5169         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5170             return cs;
5171         }
5172         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5173             return nodupIEXml(cs);
5174         }
5175         var d = ++key;
5176         cs[0]._nodup = d;
5177         for(i = 1; c = cs[i]; i++){
5178             if(c._nodup != d){
5179                 c._nodup = d;
5180             }else{
5181                 r = [];
5182                 for(var j = 0; j < i; j++){
5183                     r[++ri] = cs[j];
5184                 }
5185                 for(j = i+1; cj = cs[j]; j++){
5186                     if(cj._nodup != d){
5187                         cj._nodup = d;
5188                         r[++ri] = cj;
5189                     }
5190                 }
5191                 return r;
5192             }
5193         }
5194         return r;
5195     }
5196
5197     function quickDiffIEXml(c1, c2){
5198         var d = ++key;
5199         for(var i = 0, len = c1.length; i < len; i++){
5200             c1[i].setAttribute("_qdiff", d);
5201         }
5202         var r = [];
5203         for(var i = 0, len = c2.length; i < len; i++){
5204             if(c2[i].getAttribute("_qdiff") != d){
5205                 r[r.length] = c2[i];
5206             }
5207         }
5208         for(var i = 0, len = c1.length; i < len; i++){
5209            c1[i].removeAttribute("_qdiff");
5210         }
5211         return r;
5212     }
5213
5214     function quickDiff(c1, c2){
5215         var len1 = c1.length;
5216         if(!len1){
5217             return c2;
5218         }
5219         if(isIE && c1[0].selectSingleNode){
5220             return quickDiffIEXml(c1, c2);
5221         }
5222         var d = ++key;
5223         for(var i = 0; i < len1; i++){
5224             c1[i]._qdiff = d;
5225         }
5226         var r = [];
5227         for(var i = 0, len = c2.length; i < len; i++){
5228             if(c2[i]._qdiff != d){
5229                 r[r.length] = c2[i];
5230             }
5231         }
5232         return r;
5233     }
5234
5235     function quickId(ns, mode, root, id){
5236         if(ns == root){
5237            var d = root.ownerDocument || root;
5238            return d.getElementById(id);
5239         }
5240         ns = getNodes(ns, mode, "*");
5241         return byId(ns, null, id);
5242     }
5243
5244     return {
5245         getStyle : function(el, name){
5246             return Roo.fly(el).getStyle(name);
5247         },
5248         /**
5249          * Compiles a selector/xpath query into a reusable function. The returned function
5250          * takes one parameter "root" (optional), which is the context node from where the query should start.
5251          * @param {String} selector The selector/xpath query
5252          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5253          * @return {Function}
5254          */
5255         compile : function(path, type){
5256             type = type || "select";
5257             
5258             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5259             var q = path, mode, lq;
5260             var tk = Roo.DomQuery.matchers;
5261             var tklen = tk.length;
5262             var mm;
5263
5264             // accept leading mode switch
5265             var lmode = q.match(modeRe);
5266             if(lmode && lmode[1]){
5267                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5268                 q = q.replace(lmode[1], "");
5269             }
5270             // strip leading slashes
5271             while(path.substr(0, 1)=="/"){
5272                 path = path.substr(1);
5273             }
5274
5275             while(q && lq != q){
5276                 lq = q;
5277                 var tm = q.match(tagTokenRe);
5278                 if(type == "select"){
5279                     if(tm){
5280                         if(tm[1] == "#"){
5281                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5282                         }else{
5283                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5284                         }
5285                         q = q.replace(tm[0], "");
5286                     }else if(q.substr(0, 1) != '@'){
5287                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5288                     }
5289                 }else{
5290                     if(tm){
5291                         if(tm[1] == "#"){
5292                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5293                         }else{
5294                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5295                         }
5296                         q = q.replace(tm[0], "");
5297                     }
5298                 }
5299                 while(!(mm = q.match(modeRe))){
5300                     var matched = false;
5301                     for(var j = 0; j < tklen; j++){
5302                         var t = tk[j];
5303                         var m = q.match(t.re);
5304                         if(m){
5305                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5306                                                     return m[i];
5307                                                 });
5308                             q = q.replace(m[0], "");
5309                             matched = true;
5310                             break;
5311                         }
5312                     }
5313                     // prevent infinite loop on bad selector
5314                     if(!matched){
5315                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5316                     }
5317                 }
5318                 if(mm[1]){
5319                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5320                     q = q.replace(mm[1], "");
5321                 }
5322             }
5323             fn[fn.length] = "return nodup(n);\n}";
5324             
5325              /** 
5326               * list of variables that need from compression as they are used by eval.
5327              *  eval:var:batch 
5328              *  eval:var:nodup
5329              *  eval:var:byTag
5330              *  eval:var:ById
5331              *  eval:var:getNodes
5332              *  eval:var:quickId
5333              *  eval:var:mode
5334              *  eval:var:root
5335              *  eval:var:n
5336              *  eval:var:byClassName
5337              *  eval:var:byPseudo
5338              *  eval:var:byAttribute
5339              *  eval:var:attrValue
5340              * 
5341              **/ 
5342             eval(fn.join(""));
5343             return f;
5344         },
5345
5346         /**
5347          * Selects a group of elements.
5348          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5349          * @param {Node} root (optional) The start of the query (defaults to document).
5350          * @return {Array}
5351          */
5352         select : function(path, root, type){
5353             if(!root || root == document){
5354                 root = document;
5355             }
5356             if(typeof root == "string"){
5357                 root = document.getElementById(root);
5358             }
5359             var paths = path.split(",");
5360             var results = [];
5361             for(var i = 0, len = paths.length; i < len; i++){
5362                 var p = paths[i].replace(trimRe, "");
5363                 if(!cache[p]){
5364                     cache[p] = Roo.DomQuery.compile(p);
5365                     if(!cache[p]){
5366                         throw p + " is not a valid selector";
5367                     }
5368                 }
5369                 var result = cache[p](root);
5370                 if(result && result != document){
5371                     results = results.concat(result);
5372                 }
5373             }
5374             if(paths.length > 1){
5375                 return nodup(results);
5376             }
5377             return results;
5378         },
5379
5380         /**
5381          * Selects a single element.
5382          * @param {String} selector The selector/xpath query
5383          * @param {Node} root (optional) The start of the query (defaults to document).
5384          * @return {Element}
5385          */
5386         selectNode : function(path, root){
5387             return Roo.DomQuery.select(path, root)[0];
5388         },
5389
5390         /**
5391          * Selects the value of a node, optionally replacing null with the defaultValue.
5392          * @param {String} selector The selector/xpath query
5393          * @param {Node} root (optional) The start of the query (defaults to document).
5394          * @param {String} defaultValue
5395          */
5396         selectValue : function(path, root, defaultValue){
5397             path = path.replace(trimRe, "");
5398             if(!valueCache[path]){
5399                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5400             }
5401             var n = valueCache[path](root);
5402             n = n[0] ? n[0] : n;
5403             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5404             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5405         },
5406
5407         /**
5408          * Selects the value of a node, parsing integers and floats.
5409          * @param {String} selector The selector/xpath query
5410          * @param {Node} root (optional) The start of the query (defaults to document).
5411          * @param {Number} defaultValue
5412          * @return {Number}
5413          */
5414         selectNumber : function(path, root, defaultValue){
5415             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5416             return parseFloat(v);
5417         },
5418
5419         /**
5420          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5421          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5422          * @param {String} selector The simple selector to test
5423          * @return {Boolean}
5424          */
5425         is : function(el, ss){
5426             if(typeof el == "string"){
5427                 el = document.getElementById(el);
5428             }
5429             var isArray = (el instanceof Array);
5430             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5431             return isArray ? (result.length == el.length) : (result.length > 0);
5432         },
5433
5434         /**
5435          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5436          * @param {Array} el An array of elements to filter
5437          * @param {String} selector The simple selector to test
5438          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5439          * the selector instead of the ones that match
5440          * @return {Array}
5441          */
5442         filter : function(els, ss, nonMatches){
5443             ss = ss.replace(trimRe, "");
5444             if(!simpleCache[ss]){
5445                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5446             }
5447             var result = simpleCache[ss](els);
5448             return nonMatches ? quickDiff(result, els) : result;
5449         },
5450
5451         /**
5452          * Collection of matching regular expressions and code snippets.
5453          */
5454         matchers : [{
5455                 re: /^\.([\w-]+)/,
5456                 select: 'n = byClassName(n, null, " {1} ");'
5457             }, {
5458                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5459                 select: 'n = byPseudo(n, "{1}", "{2}");'
5460             },{
5461                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5462                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5463             }, {
5464                 re: /^#([\w-]+)/,
5465                 select: 'n = byId(n, null, "{1}");'
5466             },{
5467                 re: /^@([\w-]+)/,
5468                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5469             }
5470         ],
5471
5472         /**
5473          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5474          * 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;.
5475          */
5476         operators : {
5477             "=" : function(a, v){
5478                 return a == v;
5479             },
5480             "!=" : function(a, v){
5481                 return a != v;
5482             },
5483             "^=" : function(a, v){
5484                 return a && a.substr(0, v.length) == v;
5485             },
5486             "$=" : function(a, v){
5487                 return a && a.substr(a.length-v.length) == v;
5488             },
5489             "*=" : function(a, v){
5490                 return a && a.indexOf(v) !== -1;
5491             },
5492             "%=" : function(a, v){
5493                 return (a % v) == 0;
5494             },
5495             "|=" : function(a, v){
5496                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5497             },
5498             "~=" : function(a, v){
5499                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5500             }
5501         },
5502
5503         /**
5504          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5505          * and the argument (if any) supplied in the selector.
5506          */
5507         pseudos : {
5508             "first-child" : function(c){
5509                 var r = [], ri = -1, n;
5510                 for(var i = 0, ci; ci = n = c[i]; i++){
5511                     while((n = n.previousSibling) && n.nodeType != 1);
5512                     if(!n){
5513                         r[++ri] = ci;
5514                     }
5515                 }
5516                 return r;
5517             },
5518
5519             "last-child" : function(c){
5520                 var r = [], ri = -1, n;
5521                 for(var i = 0, ci; ci = n = c[i]; i++){
5522                     while((n = n.nextSibling) && n.nodeType != 1);
5523                     if(!n){
5524                         r[++ri] = ci;
5525                     }
5526                 }
5527                 return r;
5528             },
5529
5530             "nth-child" : function(c, a) {
5531                 var r = [], ri = -1;
5532                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5533                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5534                 for(var i = 0, n; n = c[i]; i++){
5535                     var pn = n.parentNode;
5536                     if (batch != pn._batch) {
5537                         var j = 0;
5538                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5539                             if(cn.nodeType == 1){
5540                                cn.nodeIndex = ++j;
5541                             }
5542                         }
5543                         pn._batch = batch;
5544                     }
5545                     if (f == 1) {
5546                         if (l == 0 || n.nodeIndex == l){
5547                             r[++ri] = n;
5548                         }
5549                     } else if ((n.nodeIndex + l) % f == 0){
5550                         r[++ri] = n;
5551                     }
5552                 }
5553
5554                 return r;
5555             },
5556
5557             "only-child" : function(c){
5558                 var r = [], ri = -1;;
5559                 for(var i = 0, ci; ci = c[i]; i++){
5560                     if(!prev(ci) && !next(ci)){
5561                         r[++ri] = ci;
5562                     }
5563                 }
5564                 return r;
5565             },
5566
5567             "empty" : function(c){
5568                 var r = [], ri = -1;
5569                 for(var i = 0, ci; ci = c[i]; i++){
5570                     var cns = ci.childNodes, j = 0, cn, empty = true;
5571                     while(cn = cns[j]){
5572                         ++j;
5573                         if(cn.nodeType == 1 || cn.nodeType == 3){
5574                             empty = false;
5575                             break;
5576                         }
5577                     }
5578                     if(empty){
5579                         r[++ri] = ci;
5580                     }
5581                 }
5582                 return r;
5583             },
5584
5585             "contains" : function(c, v){
5586                 var r = [], ri = -1;
5587                 for(var i = 0, ci; ci = c[i]; i++){
5588                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5589                         r[++ri] = ci;
5590                     }
5591                 }
5592                 return r;
5593             },
5594
5595             "nodeValue" : function(c, v){
5596                 var r = [], ri = -1;
5597                 for(var i = 0, ci; ci = c[i]; i++){
5598                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5599                         r[++ri] = ci;
5600                     }
5601                 }
5602                 return r;
5603             },
5604
5605             "checked" : function(c){
5606                 var r = [], ri = -1;
5607                 for(var i = 0, ci; ci = c[i]; i++){
5608                     if(ci.checked == true){
5609                         r[++ri] = ci;
5610                     }
5611                 }
5612                 return r;
5613             },
5614
5615             "not" : function(c, ss){
5616                 return Roo.DomQuery.filter(c, ss, true);
5617             },
5618
5619             "odd" : function(c){
5620                 return this["nth-child"](c, "odd");
5621             },
5622
5623             "even" : function(c){
5624                 return this["nth-child"](c, "even");
5625             },
5626
5627             "nth" : function(c, a){
5628                 return c[a-1] || [];
5629             },
5630
5631             "first" : function(c){
5632                 return c[0] || [];
5633             },
5634
5635             "last" : function(c){
5636                 return c[c.length-1] || [];
5637             },
5638
5639             "has" : function(c, ss){
5640                 var s = Roo.DomQuery.select;
5641                 var r = [], ri = -1;
5642                 for(var i = 0, ci; ci = c[i]; i++){
5643                     if(s(ss, ci).length > 0){
5644                         r[++ri] = ci;
5645                     }
5646                 }
5647                 return r;
5648             },
5649
5650             "next" : function(c, ss){
5651                 var is = Roo.DomQuery.is;
5652                 var r = [], ri = -1;
5653                 for(var i = 0, ci; ci = c[i]; i++){
5654                     var n = next(ci);
5655                     if(n && is(n, ss)){
5656                         r[++ri] = ci;
5657                     }
5658                 }
5659                 return r;
5660             },
5661
5662             "prev" : function(c, ss){
5663                 var is = Roo.DomQuery.is;
5664                 var r = [], ri = -1;
5665                 for(var i = 0, ci; ci = c[i]; i++){
5666                     var n = prev(ci);
5667                     if(n && is(n, ss)){
5668                         r[++ri] = ci;
5669                     }
5670                 }
5671                 return r;
5672             }
5673         }
5674     };
5675 }();
5676
5677 /**
5678  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5679  * @param {String} path The selector/xpath query
5680  * @param {Node} root (optional) The start of the query (defaults to document).
5681  * @return {Array}
5682  * @member Roo
5683  * @method query
5684  */
5685 Roo.query = Roo.DomQuery.select;
5686 /*
5687  * Based on:
5688  * Ext JS Library 1.1.1
5689  * Copyright(c) 2006-2007, Ext JS, LLC.
5690  *
5691  * Originally Released Under LGPL - original licence link has changed is not relivant.
5692  *
5693  * Fork - LGPL
5694  * <script type="text/javascript">
5695  */
5696
5697 /**
5698  * @class Roo.util.Observable
5699  * Base class that provides a common interface for publishing events. Subclasses are expected to
5700  * to have a property "events" with all the events defined.<br>
5701  * For example:
5702  * <pre><code>
5703  Employee = function(name){
5704     this.name = name;
5705     this.addEvents({
5706         "fired" : true,
5707         "quit" : true
5708     });
5709  }
5710  Roo.extend(Employee, Roo.util.Observable);
5711 </code></pre>
5712  * @param {Object} config properties to use (incuding events / listeners)
5713  */
5714
5715 Roo.util.Observable = function(cfg){
5716     
5717     cfg = cfg|| {};
5718     this.addEvents(cfg.events || {});
5719     if (cfg.events) {
5720         delete cfg.events; // make sure
5721     }
5722      
5723     Roo.apply(this, cfg);
5724     
5725     if(this.listeners){
5726         this.on(this.listeners);
5727         delete this.listeners;
5728     }
5729 };
5730 Roo.util.Observable.prototype = {
5731     /** 
5732  * @cfg {Object} listeners  list of events and functions to call for this object, 
5733  * For example :
5734  * <pre><code>
5735     listeners :  { 
5736        'click' : function(e) {
5737            ..... 
5738         } ,
5739         .... 
5740     } 
5741   </code></pre>
5742  */
5743     
5744     
5745     /**
5746      * Fires the specified event with the passed parameters (minus the event name).
5747      * @param {String} eventName
5748      * @param {Object...} args Variable number of parameters are passed to handlers
5749      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5750      */
5751     fireEvent : function(){
5752         var ce = this.events[arguments[0].toLowerCase()];
5753         if(typeof ce == "object"){
5754             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5755         }else{
5756             return true;
5757         }
5758     },
5759
5760     // private
5761     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5762
5763     /**
5764      * Appends an event handler to this component
5765      * @param {String}   eventName The type of event to listen for
5766      * @param {Function} handler The method the event invokes
5767      * @param {Object}   scope (optional) The scope in which to execute the handler
5768      * function. The handler function's "this" context.
5769      * @param {Object}   options (optional) An object containing handler configuration
5770      * properties. This may contain any of the following properties:<ul>
5771      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5772      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5773      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5774      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5775      * by the specified number of milliseconds. If the event fires again within that time, the original
5776      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5777      * </ul><br>
5778      * <p>
5779      * <b>Combining Options</b><br>
5780      * Using the options argument, it is possible to combine different types of listeners:<br>
5781      * <br>
5782      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5783                 <pre><code>
5784                 el.on('click', this.onClick, this, {
5785                         single: true,
5786                 delay: 100,
5787                 forumId: 4
5788                 });
5789                 </code></pre>
5790      * <p>
5791      * <b>Attaching multiple handlers in 1 call</b><br>
5792      * The method also allows for a single argument to be passed which is a config object containing properties
5793      * which specify multiple handlers.
5794      * <pre><code>
5795                 el.on({
5796                         'click': {
5797                         fn: this.onClick,
5798                         scope: this,
5799                         delay: 100
5800                 }, 
5801                 'mouseover': {
5802                         fn: this.onMouseOver,
5803                         scope: this
5804                 },
5805                 'mouseout': {
5806                         fn: this.onMouseOut,
5807                         scope: this
5808                 }
5809                 });
5810                 </code></pre>
5811      * <p>
5812      * Or a shorthand syntax which passes the same scope object to all handlers:
5813         <pre><code>
5814                 el.on({
5815                         'click': this.onClick,
5816                 'mouseover': this.onMouseOver,
5817                 'mouseout': this.onMouseOut,
5818                 scope: this
5819                 });
5820                 </code></pre>
5821      */
5822     addListener : function(eventName, fn, scope, o){
5823         if(typeof eventName == "object"){
5824             o = eventName;
5825             for(var e in o){
5826                 if(this.filterOptRe.test(e)){
5827                     continue;
5828                 }
5829                 if(typeof o[e] == "function"){
5830                     // shared options
5831                     this.addListener(e, o[e], o.scope,  o);
5832                 }else{
5833                     // individual options
5834                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5835                 }
5836             }
5837             return;
5838         }
5839         o = (!o || typeof o == "boolean") ? {} : o;
5840         eventName = eventName.toLowerCase();
5841         var ce = this.events[eventName] || true;
5842         if(typeof ce == "boolean"){
5843             ce = new Roo.util.Event(this, eventName);
5844             this.events[eventName] = ce;
5845         }
5846         ce.addListener(fn, scope, o);
5847     },
5848
5849     /**
5850      * Removes a listener
5851      * @param {String}   eventName     The type of event to listen for
5852      * @param {Function} handler        The handler to remove
5853      * @param {Object}   scope  (optional) The scope (this object) for the handler
5854      */
5855     removeListener : function(eventName, fn, scope){
5856         var ce = this.events[eventName.toLowerCase()];
5857         if(typeof ce == "object"){
5858             ce.removeListener(fn, scope);
5859         }
5860     },
5861
5862     /**
5863      * Removes all listeners for this object
5864      */
5865     purgeListeners : function(){
5866         for(var evt in this.events){
5867             if(typeof this.events[evt] == "object"){
5868                  this.events[evt].clearListeners();
5869             }
5870         }
5871     },
5872
5873     relayEvents : function(o, events){
5874         var createHandler = function(ename){
5875             return function(){
5876                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5877             };
5878         };
5879         for(var i = 0, len = events.length; i < len; i++){
5880             var ename = events[i];
5881             if(!this.events[ename]){ this.events[ename] = true; };
5882             o.on(ename, createHandler(ename), this);
5883         }
5884     },
5885
5886     /**
5887      * Used to define events on this Observable
5888      * @param {Object} object The object with the events defined
5889      */
5890     addEvents : function(o){
5891         if(!this.events){
5892             this.events = {};
5893         }
5894         Roo.applyIf(this.events, o);
5895     },
5896
5897     /**
5898      * Checks to see if this object has any listeners for a specified event
5899      * @param {String} eventName The name of the event to check for
5900      * @return {Boolean} True if the event is being listened for, else false
5901      */
5902     hasListener : function(eventName){
5903         var e = this.events[eventName];
5904         return typeof e == "object" && e.listeners.length > 0;
5905     }
5906 };
5907 /**
5908  * Appends an event handler to this element (shorthand for addListener)
5909  * @param {String}   eventName     The type of event to listen for
5910  * @param {Function} handler        The method the event invokes
5911  * @param {Object}   scope (optional) The scope in which to execute the handler
5912  * function. The handler function's "this" context.
5913  * @param {Object}   options  (optional)
5914  * @method
5915  */
5916 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5917 /**
5918  * Removes a listener (shorthand for removeListener)
5919  * @param {String}   eventName     The type of event to listen for
5920  * @param {Function} handler        The handler to remove
5921  * @param {Object}   scope  (optional) The scope (this object) for the handler
5922  * @method
5923  */
5924 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5925
5926 /**
5927  * Starts capture on the specified Observable. All events will be passed
5928  * to the supplied function with the event name + standard signature of the event
5929  * <b>before</b> the event is fired. If the supplied function returns false,
5930  * the event will not fire.
5931  * @param {Observable} o The Observable to capture
5932  * @param {Function} fn The function to call
5933  * @param {Object} scope (optional) The scope (this object) for the fn
5934  * @static
5935  */
5936 Roo.util.Observable.capture = function(o, fn, scope){
5937     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5938 };
5939
5940 /**
5941  * Removes <b>all</b> added captures from the Observable.
5942  * @param {Observable} o The Observable to release
5943  * @static
5944  */
5945 Roo.util.Observable.releaseCapture = function(o){
5946     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5947 };
5948
5949 (function(){
5950
5951     var createBuffered = function(h, o, scope){
5952         var task = new Roo.util.DelayedTask();
5953         return function(){
5954             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5955         };
5956     };
5957
5958     var createSingle = function(h, e, fn, scope){
5959         return function(){
5960             e.removeListener(fn, scope);
5961             return h.apply(scope, arguments);
5962         };
5963     };
5964
5965     var createDelayed = function(h, o, scope){
5966         return function(){
5967             var args = Array.prototype.slice.call(arguments, 0);
5968             setTimeout(function(){
5969                 h.apply(scope, args);
5970             }, o.delay || 10);
5971         };
5972     };
5973
5974     Roo.util.Event = function(obj, name){
5975         this.name = name;
5976         this.obj = obj;
5977         this.listeners = [];
5978     };
5979
5980     Roo.util.Event.prototype = {
5981         addListener : function(fn, scope, options){
5982             var o = options || {};
5983             scope = scope || this.obj;
5984             if(!this.isListening(fn, scope)){
5985                 var l = {fn: fn, scope: scope, options: o};
5986                 var h = fn;
5987                 if(o.delay){
5988                     h = createDelayed(h, o, scope);
5989                 }
5990                 if(o.single){
5991                     h = createSingle(h, this, fn, scope);
5992                 }
5993                 if(o.buffer){
5994                     h = createBuffered(h, o, scope);
5995                 }
5996                 l.fireFn = h;
5997                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5998                     this.listeners.push(l);
5999                 }else{
6000                     this.listeners = this.listeners.slice(0);
6001                     this.listeners.push(l);
6002                 }
6003             }
6004         },
6005
6006         findListener : function(fn, scope){
6007             scope = scope || this.obj;
6008             var ls = this.listeners;
6009             for(var i = 0, len = ls.length; i < len; i++){
6010                 var l = ls[i];
6011                 if(l.fn == fn && l.scope == scope){
6012                     return i;
6013                 }
6014             }
6015             return -1;
6016         },
6017
6018         isListening : function(fn, scope){
6019             return this.findListener(fn, scope) != -1;
6020         },
6021
6022         removeListener : function(fn, scope){
6023             var index;
6024             if((index = this.findListener(fn, scope)) != -1){
6025                 if(!this.firing){
6026                     this.listeners.splice(index, 1);
6027                 }else{
6028                     this.listeners = this.listeners.slice(0);
6029                     this.listeners.splice(index, 1);
6030                 }
6031                 return true;
6032             }
6033             return false;
6034         },
6035
6036         clearListeners : function(){
6037             this.listeners = [];
6038         },
6039
6040         fire : function(){
6041             var ls = this.listeners, scope, len = ls.length;
6042             if(len > 0){
6043                 this.firing = true;
6044                 var args = Array.prototype.slice.call(arguments, 0);
6045                 for(var i = 0; i < len; i++){
6046                     var l = ls[i];
6047                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6048                         this.firing = false;
6049                         return false;
6050                     }
6051                 }
6052                 this.firing = false;
6053             }
6054             return true;
6055         }
6056     };
6057 })();/*
6058  * RooJS Library 
6059  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6060  *
6061  * Licence LGPL 
6062  *
6063  */
6064  
6065 /**
6066  * @class Roo.Document
6067  * @extends Roo.util.Observable
6068  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6069  * 
6070  * @param {Object} config the methods and properties of the 'base' class for the application.
6071  * 
6072  *  Generic Page handler - implement this to start your app..
6073  * 
6074  * eg.
6075  *  MyProject = new Roo.Document({
6076         events : {
6077             'load' : true // your events..
6078         },
6079         listeners : {
6080             'ready' : function() {
6081                 // fired on Roo.onReady()
6082             }
6083         }
6084  * 
6085  */
6086 Roo.Document = function(cfg) {
6087      
6088     this.addEvents({ 
6089         'ready' : true
6090     });
6091     Roo.util.Observable.call(this,cfg);
6092     
6093     var _this = this;
6094     
6095     Roo.onReady(function() {
6096         _this.fireEvent('ready');
6097     },null,false);
6098     
6099     
6100 }
6101
6102 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6103  * Based on:
6104  * Ext JS Library 1.1.1
6105  * Copyright(c) 2006-2007, Ext JS, LLC.
6106  *
6107  * Originally Released Under LGPL - original licence link has changed is not relivant.
6108  *
6109  * Fork - LGPL
6110  * <script type="text/javascript">
6111  */
6112
6113 /**
6114  * @class Roo.EventManager
6115  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6116  * several useful events directly.
6117  * See {@link Roo.EventObject} for more details on normalized event objects.
6118  * @singleton
6119  */
6120 Roo.EventManager = function(){
6121     var docReadyEvent, docReadyProcId, docReadyState = false;
6122     var resizeEvent, resizeTask, textEvent, textSize;
6123     var E = Roo.lib.Event;
6124     var D = Roo.lib.Dom;
6125
6126     
6127     
6128
6129     var fireDocReady = function(){
6130         if(!docReadyState){
6131             docReadyState = true;
6132             Roo.isReady = true;
6133             if(docReadyProcId){
6134                 clearInterval(docReadyProcId);
6135             }
6136             if(Roo.isGecko || Roo.isOpera) {
6137                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6138             }
6139             if(Roo.isIE){
6140                 var defer = document.getElementById("ie-deferred-loader");
6141                 if(defer){
6142                     defer.onreadystatechange = null;
6143                     defer.parentNode.removeChild(defer);
6144                 }
6145             }
6146             if(docReadyEvent){
6147                 docReadyEvent.fire();
6148                 docReadyEvent.clearListeners();
6149             }
6150         }
6151     };
6152     
6153     var initDocReady = function(){
6154         docReadyEvent = new Roo.util.Event();
6155         if(Roo.isGecko || Roo.isOpera) {
6156             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6157         }else if(Roo.isIE){
6158             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6159             var defer = document.getElementById("ie-deferred-loader");
6160             defer.onreadystatechange = function(){
6161                 if(this.readyState == "complete"){
6162                     fireDocReady();
6163                 }
6164             };
6165         }else if(Roo.isSafari){ 
6166             docReadyProcId = setInterval(function(){
6167                 var rs = document.readyState;
6168                 if(rs == "complete") {
6169                     fireDocReady();     
6170                  }
6171             }, 10);
6172         }
6173         // no matter what, make sure it fires on load
6174         E.on(window, "load", fireDocReady);
6175     };
6176
6177     var createBuffered = function(h, o){
6178         var task = new Roo.util.DelayedTask(h);
6179         return function(e){
6180             // create new event object impl so new events don't wipe out properties
6181             e = new Roo.EventObjectImpl(e);
6182             task.delay(o.buffer, h, null, [e]);
6183         };
6184     };
6185
6186     var createSingle = function(h, el, ename, fn){
6187         return function(e){
6188             Roo.EventManager.removeListener(el, ename, fn);
6189             h(e);
6190         };
6191     };
6192
6193     var createDelayed = function(h, o){
6194         return function(e){
6195             // create new event object impl so new events don't wipe out properties
6196             e = new Roo.EventObjectImpl(e);
6197             setTimeout(function(){
6198                 h(e);
6199             }, o.delay || 10);
6200         };
6201     };
6202     var transitionEndVal = false;
6203     
6204     var transitionEnd = function()
6205     {
6206         if (transitionEndVal) {
6207             return transitionEndVal;
6208         }
6209         var el = document.createElement('div');
6210
6211         var transEndEventNames = {
6212             WebkitTransition : 'webkitTransitionEnd',
6213             MozTransition    : 'transitionend',
6214             OTransition      : 'oTransitionEnd otransitionend',
6215             transition       : 'transitionend'
6216         };
6217     
6218         for (var name in transEndEventNames) {
6219             if (el.style[name] !== undefined) {
6220                 transitionEndVal = transEndEventNames[name];
6221                 return  transitionEndVal ;
6222             }
6223         }
6224     }
6225     
6226
6227     var listen = function(element, ename, opt, fn, scope){
6228         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6229         fn = fn || o.fn; scope = scope || o.scope;
6230         var el = Roo.getDom(element);
6231         
6232         
6233         if(!el){
6234             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6235         }
6236         
6237         if (ename == 'transitionend') {
6238             ename = transitionEnd();
6239         }
6240         var h = function(e){
6241             e = Roo.EventObject.setEvent(e);
6242             var t;
6243             if(o.delegate){
6244                 t = e.getTarget(o.delegate, el);
6245                 if(!t){
6246                     return;
6247                 }
6248             }else{
6249                 t = e.target;
6250             }
6251             if(o.stopEvent === true){
6252                 e.stopEvent();
6253             }
6254             if(o.preventDefault === true){
6255                e.preventDefault();
6256             }
6257             if(o.stopPropagation === true){
6258                 e.stopPropagation();
6259             }
6260
6261             if(o.normalized === false){
6262                 e = e.browserEvent;
6263             }
6264
6265             fn.call(scope || el, e, t, o);
6266         };
6267         if(o.delay){
6268             h = createDelayed(h, o);
6269         }
6270         if(o.single){
6271             h = createSingle(h, el, ename, fn);
6272         }
6273         if(o.buffer){
6274             h = createBuffered(h, o);
6275         }
6276         fn._handlers = fn._handlers || [];
6277         
6278         
6279         fn._handlers.push([Roo.id(el), ename, h]);
6280         
6281         
6282          
6283         E.on(el, ename, h);
6284         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6285             el.addEventListener("DOMMouseScroll", h, false);
6286             E.on(window, 'unload', function(){
6287                 el.removeEventListener("DOMMouseScroll", h, false);
6288             });
6289         }
6290         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6291             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6292         }
6293         return h;
6294     };
6295
6296     var stopListening = function(el, ename, fn){
6297         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6298         if(hds){
6299             for(var i = 0, len = hds.length; i < len; i++){
6300                 var h = hds[i];
6301                 if(h[0] == id && h[1] == ename){
6302                     hd = h[2];
6303                     hds.splice(i, 1);
6304                     break;
6305                 }
6306             }
6307         }
6308         E.un(el, ename, hd);
6309         el = Roo.getDom(el);
6310         if(ename == "mousewheel" && el.addEventListener){
6311             el.removeEventListener("DOMMouseScroll", hd, false);
6312         }
6313         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6314             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6315         }
6316     };
6317
6318     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6319     
6320     var pub = {
6321         
6322         
6323         /** 
6324          * Fix for doc tools
6325          * @scope Roo.EventManager
6326          */
6327         
6328         
6329         /** 
6330          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6331          * object with a Roo.EventObject
6332          * @param {Function} fn        The method the event invokes
6333          * @param {Object}   scope    An object that becomes the scope of the handler
6334          * @param {boolean}  override If true, the obj passed in becomes
6335          *                             the execution scope of the listener
6336          * @return {Function} The wrapped function
6337          * @deprecated
6338          */
6339         wrap : function(fn, scope, override){
6340             return function(e){
6341                 Roo.EventObject.setEvent(e);
6342                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6343             };
6344         },
6345         
6346         /**
6347      * Appends an event handler to an element (shorthand for addListener)
6348      * @param {String/HTMLElement}   element        The html element or id to assign the
6349      * @param {String}   eventName The type of event to listen for
6350      * @param {Function} handler The method the event invokes
6351      * @param {Object}   scope (optional) The scope in which to execute the handler
6352      * function. The handler function's "this" context.
6353      * @param {Object}   options (optional) An object containing handler configuration
6354      * properties. This may contain any of the following properties:<ul>
6355      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6356      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6357      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6358      * <li>preventDefault {Boolean} True to prevent the default action</li>
6359      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6360      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6361      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6362      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6363      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6364      * by the specified number of milliseconds. If the event fires again within that time, the original
6365      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6366      * </ul><br>
6367      * <p>
6368      * <b>Combining Options</b><br>
6369      * Using the options argument, it is possible to combine different types of listeners:<br>
6370      * <br>
6371      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6372      * Code:<pre><code>
6373 el.on('click', this.onClick, this, {
6374     single: true,
6375     delay: 100,
6376     stopEvent : true,
6377     forumId: 4
6378 });</code></pre>
6379      * <p>
6380      * <b>Attaching multiple handlers in 1 call</b><br>
6381       * The method also allows for a single argument to be passed which is a config object containing properties
6382      * which specify multiple handlers.
6383      * <p>
6384      * Code:<pre><code>
6385 el.on({
6386     'click' : {
6387         fn: this.onClick
6388         scope: this,
6389         delay: 100
6390     },
6391     'mouseover' : {
6392         fn: this.onMouseOver
6393         scope: this
6394     },
6395     'mouseout' : {
6396         fn: this.onMouseOut
6397         scope: this
6398     }
6399 });</code></pre>
6400      * <p>
6401      * Or a shorthand syntax:<br>
6402      * Code:<pre><code>
6403 el.on({
6404     'click' : this.onClick,
6405     'mouseover' : this.onMouseOver,
6406     'mouseout' : this.onMouseOut
6407     scope: this
6408 });</code></pre>
6409      */
6410         addListener : function(element, eventName, fn, scope, options){
6411             if(typeof eventName == "object"){
6412                 var o = eventName;
6413                 for(var e in o){
6414                     if(propRe.test(e)){
6415                         continue;
6416                     }
6417                     if(typeof o[e] == "function"){
6418                         // shared options
6419                         listen(element, e, o, o[e], o.scope);
6420                     }else{
6421                         // individual options
6422                         listen(element, e, o[e]);
6423                     }
6424                 }
6425                 return;
6426             }
6427             return listen(element, eventName, options, fn, scope);
6428         },
6429         
6430         /**
6431          * Removes an event handler
6432          *
6433          * @param {String/HTMLElement}   element        The id or html element to remove the 
6434          *                             event from
6435          * @param {String}   eventName     The type of event
6436          * @param {Function} fn
6437          * @return {Boolean} True if a listener was actually removed
6438          */
6439         removeListener : function(element, eventName, fn){
6440             return stopListening(element, eventName, fn);
6441         },
6442         
6443         /**
6444          * Fires when the document is ready (before onload and before images are loaded). Can be 
6445          * accessed shorthanded Roo.onReady().
6446          * @param {Function} fn        The method the event invokes
6447          * @param {Object}   scope    An  object that becomes the scope of the handler
6448          * @param {boolean}  options
6449          */
6450         onDocumentReady : function(fn, scope, options){
6451             if(docReadyState){ // if it already fired
6452                 docReadyEvent.addListener(fn, scope, options);
6453                 docReadyEvent.fire();
6454                 docReadyEvent.clearListeners();
6455                 return;
6456             }
6457             if(!docReadyEvent){
6458                 initDocReady();
6459             }
6460             docReadyEvent.addListener(fn, scope, options);
6461         },
6462         
6463         /**
6464          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6465          * @param {Function} fn        The method the event invokes
6466          * @param {Object}   scope    An object that becomes the scope of the handler
6467          * @param {boolean}  options
6468          */
6469         onWindowResize : function(fn, scope, options){
6470             if(!resizeEvent){
6471                 resizeEvent = new Roo.util.Event();
6472                 resizeTask = new Roo.util.DelayedTask(function(){
6473                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6474                 });
6475                 E.on(window, "resize", function(){
6476                     if(Roo.isIE){
6477                         resizeTask.delay(50);
6478                     }else{
6479                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6480                     }
6481                 });
6482             }
6483             resizeEvent.addListener(fn, scope, options);
6484         },
6485
6486         /**
6487          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6488          * @param {Function} fn        The method the event invokes
6489          * @param {Object}   scope    An object that becomes the scope of the handler
6490          * @param {boolean}  options
6491          */
6492         onTextResize : function(fn, scope, options){
6493             if(!textEvent){
6494                 textEvent = new Roo.util.Event();
6495                 var textEl = new Roo.Element(document.createElement('div'));
6496                 textEl.dom.className = 'x-text-resize';
6497                 textEl.dom.innerHTML = 'X';
6498                 textEl.appendTo(document.body);
6499                 textSize = textEl.dom.offsetHeight;
6500                 setInterval(function(){
6501                     if(textEl.dom.offsetHeight != textSize){
6502                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6503                     }
6504                 }, this.textResizeInterval);
6505             }
6506             textEvent.addListener(fn, scope, options);
6507         },
6508
6509         /**
6510          * Removes the passed window resize listener.
6511          * @param {Function} fn        The method the event invokes
6512          * @param {Object}   scope    The scope of handler
6513          */
6514         removeResizeListener : function(fn, scope){
6515             if(resizeEvent){
6516                 resizeEvent.removeListener(fn, scope);
6517             }
6518         },
6519
6520         // private
6521         fireResize : function(){
6522             if(resizeEvent){
6523                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6524             }   
6525         },
6526         /**
6527          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6528          */
6529         ieDeferSrc : false,
6530         /**
6531          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6532          */
6533         textResizeInterval : 50
6534     };
6535     
6536     /**
6537      * Fix for doc tools
6538      * @scopeAlias pub=Roo.EventManager
6539      */
6540     
6541      /**
6542      * Appends an event handler to an element (shorthand for addListener)
6543      * @param {String/HTMLElement}   element        The html element or id to assign the
6544      * @param {String}   eventName The type of event to listen for
6545      * @param {Function} handler The method the event invokes
6546      * @param {Object}   scope (optional) The scope in which to execute the handler
6547      * function. The handler function's "this" context.
6548      * @param {Object}   options (optional) An object containing handler configuration
6549      * properties. This may contain any of the following properties:<ul>
6550      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6551      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6552      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6553      * <li>preventDefault {Boolean} True to prevent the default action</li>
6554      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6555      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6556      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6557      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6558      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6559      * by the specified number of milliseconds. If the event fires again within that time, the original
6560      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6561      * </ul><br>
6562      * <p>
6563      * <b>Combining Options</b><br>
6564      * Using the options argument, it is possible to combine different types of listeners:<br>
6565      * <br>
6566      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6567      * Code:<pre><code>
6568 el.on('click', this.onClick, this, {
6569     single: true,
6570     delay: 100,
6571     stopEvent : true,
6572     forumId: 4
6573 });</code></pre>
6574      * <p>
6575      * <b>Attaching multiple handlers in 1 call</b><br>
6576       * The method also allows for a single argument to be passed which is a config object containing properties
6577      * which specify multiple handlers.
6578      * <p>
6579      * Code:<pre><code>
6580 el.on({
6581     'click' : {
6582         fn: this.onClick
6583         scope: this,
6584         delay: 100
6585     },
6586     'mouseover' : {
6587         fn: this.onMouseOver
6588         scope: this
6589     },
6590     'mouseout' : {
6591         fn: this.onMouseOut
6592         scope: this
6593     }
6594 });</code></pre>
6595      * <p>
6596      * Or a shorthand syntax:<br>
6597      * Code:<pre><code>
6598 el.on({
6599     'click' : this.onClick,
6600     'mouseover' : this.onMouseOver,
6601     'mouseout' : this.onMouseOut
6602     scope: this
6603 });</code></pre>
6604      */
6605     pub.on = pub.addListener;
6606     pub.un = pub.removeListener;
6607
6608     pub.stoppedMouseDownEvent = new Roo.util.Event();
6609     return pub;
6610 }();
6611 /**
6612   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6613   * @param {Function} fn        The method the event invokes
6614   * @param {Object}   scope    An  object that becomes the scope of the handler
6615   * @param {boolean}  override If true, the obj passed in becomes
6616   *                             the execution scope of the listener
6617   * @member Roo
6618   * @method onReady
6619  */
6620 Roo.onReady = Roo.EventManager.onDocumentReady;
6621
6622 Roo.onReady(function(){
6623     var bd = Roo.get(document.body);
6624     if(!bd){ return; }
6625
6626     var cls = [
6627             Roo.isIE ? "roo-ie"
6628             : Roo.isGecko ? "roo-gecko"
6629             : Roo.isOpera ? "roo-opera"
6630             : Roo.isSafari ? "roo-safari" : ""];
6631
6632     if(Roo.isMac){
6633         cls.push("roo-mac");
6634     }
6635     if(Roo.isLinux){
6636         cls.push("roo-linux");
6637     }
6638     if(Roo.isIOS){
6639         cls.push("roo-ios");
6640     }
6641     if(Roo.isTouch){
6642         cls.push("roo-touch");
6643     }
6644     if(Roo.isBorderBox){
6645         cls.push('roo-border-box');
6646     }
6647     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6648         var p = bd.dom.parentNode;
6649         if(p){
6650             p.className += ' roo-strict';
6651         }
6652     }
6653     bd.addClass(cls.join(' '));
6654 });
6655
6656 /**
6657  * @class Roo.EventObject
6658  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6659  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6660  * Example:
6661  * <pre><code>
6662  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6663     e.preventDefault();
6664     var target = e.getTarget();
6665     ...
6666  }
6667  var myDiv = Roo.get("myDiv");
6668  myDiv.on("click", handleClick);
6669  //or
6670  Roo.EventManager.on("myDiv", 'click', handleClick);
6671  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6672  </code></pre>
6673  * @singleton
6674  */
6675 Roo.EventObject = function(){
6676     
6677     var E = Roo.lib.Event;
6678     
6679     // safari keypress events for special keys return bad keycodes
6680     var safariKeys = {
6681         63234 : 37, // left
6682         63235 : 39, // right
6683         63232 : 38, // up
6684         63233 : 40, // down
6685         63276 : 33, // page up
6686         63277 : 34, // page down
6687         63272 : 46, // delete
6688         63273 : 36, // home
6689         63275 : 35  // end
6690     };
6691
6692     // normalize button clicks
6693     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6694                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6695
6696     Roo.EventObjectImpl = function(e){
6697         if(e){
6698             this.setEvent(e.browserEvent || e);
6699         }
6700     };
6701     Roo.EventObjectImpl.prototype = {
6702         /**
6703          * Used to fix doc tools.
6704          * @scope Roo.EventObject.prototype
6705          */
6706             
6707
6708         
6709         
6710         /** The normal browser event */
6711         browserEvent : null,
6712         /** The button pressed in a mouse event */
6713         button : -1,
6714         /** True if the shift key was down during the event */
6715         shiftKey : false,
6716         /** True if the control key was down during the event */
6717         ctrlKey : false,
6718         /** True if the alt key was down during the event */
6719         altKey : false,
6720
6721         /** Key constant 
6722         * @type Number */
6723         BACKSPACE : 8,
6724         /** Key constant 
6725         * @type Number */
6726         TAB : 9,
6727         /** Key constant 
6728         * @type Number */
6729         RETURN : 13,
6730         /** Key constant 
6731         * @type Number */
6732         ENTER : 13,
6733         /** Key constant 
6734         * @type Number */
6735         SHIFT : 16,
6736         /** Key constant 
6737         * @type Number */
6738         CONTROL : 17,
6739         /** Key constant 
6740         * @type Number */
6741         ESC : 27,
6742         /** Key constant 
6743         * @type Number */
6744         SPACE : 32,
6745         /** Key constant 
6746         * @type Number */
6747         PAGEUP : 33,
6748         /** Key constant 
6749         * @type Number */
6750         PAGEDOWN : 34,
6751         /** Key constant 
6752         * @type Number */
6753         END : 35,
6754         /** Key constant 
6755         * @type Number */
6756         HOME : 36,
6757         /** Key constant 
6758         * @type Number */
6759         LEFT : 37,
6760         /** Key constant 
6761         * @type Number */
6762         UP : 38,
6763         /** Key constant 
6764         * @type Number */
6765         RIGHT : 39,
6766         /** Key constant 
6767         * @type Number */
6768         DOWN : 40,
6769         /** Key constant 
6770         * @type Number */
6771         DELETE : 46,
6772         /** Key constant 
6773         * @type Number */
6774         F5 : 116,
6775
6776            /** @private */
6777         setEvent : function(e){
6778             if(e == this || (e && e.browserEvent)){ // already wrapped
6779                 return e;
6780             }
6781             this.browserEvent = e;
6782             if(e){
6783                 // normalize buttons
6784                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6785                 if(e.type == 'click' && this.button == -1){
6786                     this.button = 0;
6787                 }
6788                 this.type = e.type;
6789                 this.shiftKey = e.shiftKey;
6790                 // mac metaKey behaves like ctrlKey
6791                 this.ctrlKey = e.ctrlKey || e.metaKey;
6792                 this.altKey = e.altKey;
6793                 // in getKey these will be normalized for the mac
6794                 this.keyCode = e.keyCode;
6795                 // keyup warnings on firefox.
6796                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6797                 // cache the target for the delayed and or buffered events
6798                 this.target = E.getTarget(e);
6799                 // same for XY
6800                 this.xy = E.getXY(e);
6801             }else{
6802                 this.button = -1;
6803                 this.shiftKey = false;
6804                 this.ctrlKey = false;
6805                 this.altKey = false;
6806                 this.keyCode = 0;
6807                 this.charCode =0;
6808                 this.target = null;
6809                 this.xy = [0, 0];
6810             }
6811             return this;
6812         },
6813
6814         /**
6815          * Stop the event (preventDefault and stopPropagation)
6816          */
6817         stopEvent : function(){
6818             if(this.browserEvent){
6819                 if(this.browserEvent.type == 'mousedown'){
6820                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6821                 }
6822                 E.stopEvent(this.browserEvent);
6823             }
6824         },
6825
6826         /**
6827          * Prevents the browsers default handling of the event.
6828          */
6829         preventDefault : function(){
6830             if(this.browserEvent){
6831                 E.preventDefault(this.browserEvent);
6832             }
6833         },
6834
6835         /** @private */
6836         isNavKeyPress : function(){
6837             var k = this.keyCode;
6838             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6839             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6840         },
6841
6842         isSpecialKey : function(){
6843             var k = this.keyCode;
6844             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6845             (k == 16) || (k == 17) ||
6846             (k >= 18 && k <= 20) ||
6847             (k >= 33 && k <= 35) ||
6848             (k >= 36 && k <= 39) ||
6849             (k >= 44 && k <= 45);
6850         },
6851         /**
6852          * Cancels bubbling of the event.
6853          */
6854         stopPropagation : function(){
6855             if(this.browserEvent){
6856                 if(this.type == 'mousedown'){
6857                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6858                 }
6859                 E.stopPropagation(this.browserEvent);
6860             }
6861         },
6862
6863         /**
6864          * Gets the key code for the event.
6865          * @return {Number}
6866          */
6867         getCharCode : function(){
6868             return this.charCode || this.keyCode;
6869         },
6870
6871         /**
6872          * Returns a normalized keyCode for the event.
6873          * @return {Number} The key code
6874          */
6875         getKey : function(){
6876             var k = this.keyCode || this.charCode;
6877             return Roo.isSafari ? (safariKeys[k] || k) : k;
6878         },
6879
6880         /**
6881          * Gets the x coordinate of the event.
6882          * @return {Number}
6883          */
6884         getPageX : function(){
6885             return this.xy[0];
6886         },
6887
6888         /**
6889          * Gets the y coordinate of the event.
6890          * @return {Number}
6891          */
6892         getPageY : function(){
6893             return this.xy[1];
6894         },
6895
6896         /**
6897          * Gets the time of the event.
6898          * @return {Number}
6899          */
6900         getTime : function(){
6901             if(this.browserEvent){
6902                 return E.getTime(this.browserEvent);
6903             }
6904             return null;
6905         },
6906
6907         /**
6908          * Gets the page coordinates of the event.
6909          * @return {Array} The xy values like [x, y]
6910          */
6911         getXY : function(){
6912             return this.xy;
6913         },
6914
6915         /**
6916          * Gets the target for the event.
6917          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6918          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6919                 search as a number or element (defaults to 10 || document.body)
6920          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6921          * @return {HTMLelement}
6922          */
6923         getTarget : function(selector, maxDepth, returnEl){
6924             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6925         },
6926         /**
6927          * Gets the related target.
6928          * @return {HTMLElement}
6929          */
6930         getRelatedTarget : function(){
6931             if(this.browserEvent){
6932                 return E.getRelatedTarget(this.browserEvent);
6933             }
6934             return null;
6935         },
6936
6937         /**
6938          * Normalizes mouse wheel delta across browsers
6939          * @return {Number} The delta
6940          */
6941         getWheelDelta : function(){
6942             var e = this.browserEvent;
6943             var delta = 0;
6944             if(e.wheelDelta){ /* IE/Opera. */
6945                 delta = e.wheelDelta/120;
6946             }else if(e.detail){ /* Mozilla case. */
6947                 delta = -e.detail/3;
6948             }
6949             return delta;
6950         },
6951
6952         /**
6953          * Returns true if the control, meta, shift or alt key was pressed during this event.
6954          * @return {Boolean}
6955          */
6956         hasModifier : function(){
6957             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6958         },
6959
6960         /**
6961          * Returns true if the target of this event equals el or is a child of el
6962          * @param {String/HTMLElement/Element} el
6963          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6964          * @return {Boolean}
6965          */
6966         within : function(el, related){
6967             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6968             return t && Roo.fly(el).contains(t);
6969         },
6970
6971         getPoint : function(){
6972             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6973         }
6974     };
6975
6976     return new Roo.EventObjectImpl();
6977 }();
6978             
6979     /*
6980  * Based on:
6981  * Ext JS Library 1.1.1
6982  * Copyright(c) 2006-2007, Ext JS, LLC.
6983  *
6984  * Originally Released Under LGPL - original licence link has changed is not relivant.
6985  *
6986  * Fork - LGPL
6987  * <script type="text/javascript">
6988  */
6989
6990  
6991 // was in Composite Element!??!?!
6992  
6993 (function(){
6994     var D = Roo.lib.Dom;
6995     var E = Roo.lib.Event;
6996     var A = Roo.lib.Anim;
6997
6998     // local style camelizing for speed
6999     var propCache = {};
7000     var camelRe = /(-[a-z])/gi;
7001     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7002     var view = document.defaultView;
7003
7004 /**
7005  * @class Roo.Element
7006  * Represents an Element in the DOM.<br><br>
7007  * Usage:<br>
7008 <pre><code>
7009 var el = Roo.get("my-div");
7010
7011 // or with getEl
7012 var el = getEl("my-div");
7013
7014 // or with a DOM element
7015 var el = Roo.get(myDivElement);
7016 </code></pre>
7017  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7018  * each call instead of constructing a new one.<br><br>
7019  * <b>Animations</b><br />
7020  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7021  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7022 <pre>
7023 Option    Default   Description
7024 --------- --------  ---------------------------------------------
7025 duration  .35       The duration of the animation in seconds
7026 easing    easeOut   The YUI easing method
7027 callback  none      A function to execute when the anim completes
7028 scope     this      The scope (this) of the callback function
7029 </pre>
7030 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7031 * manipulate the animation. Here's an example:
7032 <pre><code>
7033 var el = Roo.get("my-div");
7034
7035 // no animation
7036 el.setWidth(100);
7037
7038 // default animation
7039 el.setWidth(100, true);
7040
7041 // animation with some options set
7042 el.setWidth(100, {
7043     duration: 1,
7044     callback: this.foo,
7045     scope: this
7046 });
7047
7048 // using the "anim" property to get the Anim object
7049 var opt = {
7050     duration: 1,
7051     callback: this.foo,
7052     scope: this
7053 };
7054 el.setWidth(100, opt);
7055 ...
7056 if(opt.anim.isAnimated()){
7057     opt.anim.stop();
7058 }
7059 </code></pre>
7060 * <b> Composite (Collections of) Elements</b><br />
7061  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7062  * @constructor Create a new Element directly.
7063  * @param {String/HTMLElement} element
7064  * @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).
7065  */
7066     Roo.Element = function(element, forceNew){
7067         var dom = typeof element == "string" ?
7068                 document.getElementById(element) : element;
7069         if(!dom){ // invalid id/element
7070             return null;
7071         }
7072         var id = dom.id;
7073         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7074             return Roo.Element.cache[id];
7075         }
7076
7077         /**
7078          * The DOM element
7079          * @type HTMLElement
7080          */
7081         this.dom = dom;
7082
7083         /**
7084          * The DOM element ID
7085          * @type String
7086          */
7087         this.id = id || Roo.id(dom);
7088     };
7089
7090     var El = Roo.Element;
7091
7092     El.prototype = {
7093         /**
7094          * The element's default display mode  (defaults to "")
7095          * @type String
7096          */
7097         originalDisplay : "",
7098
7099         visibilityMode : 1,
7100         /**
7101          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7102          * @type String
7103          */
7104         defaultUnit : "px",
7105         
7106         /**
7107          * Sets the element's visibility mode. When setVisible() is called it
7108          * will use this to determine whether to set the visibility or the display property.
7109          * @param visMode Element.VISIBILITY or Element.DISPLAY
7110          * @return {Roo.Element} this
7111          */
7112         setVisibilityMode : function(visMode){
7113             this.visibilityMode = visMode;
7114             return this;
7115         },
7116         /**
7117          * Convenience method for setVisibilityMode(Element.DISPLAY)
7118          * @param {String} display (optional) What to set display to when visible
7119          * @return {Roo.Element} this
7120          */
7121         enableDisplayMode : function(display){
7122             this.setVisibilityMode(El.DISPLAY);
7123             if(typeof display != "undefined") { this.originalDisplay = display; }
7124             return this;
7125         },
7126
7127         /**
7128          * 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)
7129          * @param {String} selector The simple selector to test
7130          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7131                 search as a number or element (defaults to 10 || document.body)
7132          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7133          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7134          */
7135         findParent : function(simpleSelector, maxDepth, returnEl){
7136             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7137             maxDepth = maxDepth || 50;
7138             if(typeof maxDepth != "number"){
7139                 stopEl = Roo.getDom(maxDepth);
7140                 maxDepth = 10;
7141             }
7142             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7143                 if(dq.is(p, simpleSelector)){
7144                     return returnEl ? Roo.get(p) : p;
7145                 }
7146                 depth++;
7147                 p = p.parentNode;
7148             }
7149             return null;
7150         },
7151
7152
7153         /**
7154          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7155          * @param {String} selector The simple selector to test
7156          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7157                 search as a number or element (defaults to 10 || document.body)
7158          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7159          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7160          */
7161         findParentNode : function(simpleSelector, maxDepth, returnEl){
7162             var p = Roo.fly(this.dom.parentNode, '_internal');
7163             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7164         },
7165         
7166         /**
7167          * Looks at  the scrollable parent element
7168          */
7169         findScrollableParent : function(){
7170             
7171             var overflowRegex = /(auto|scroll)/;
7172             
7173             if(this.getStyle('position') === 'fixed'){
7174                 return Roo.get(document.body);
7175             }
7176             
7177             var excludeStaticParent = this.getStyle('position') === "absolute";
7178             
7179             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7180                 
7181                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7182                     continue;
7183                 }
7184                 
7185                 if (
7186                         parent.dom.nodeName.toLowerCase() == 'body' ||
7187                         overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))
7188                 ){
7189                     return parent;
7190                 }
7191             }
7192             
7193             return Roo.get(document.body);
7194         },
7195
7196         /**
7197          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7198          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7199          * @param {String} selector The simple selector to test
7200          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7201                 search as a number or element (defaults to 10 || document.body)
7202          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7203          */
7204         up : function(simpleSelector, maxDepth){
7205             return this.findParentNode(simpleSelector, maxDepth, true);
7206         },
7207
7208
7209
7210         /**
7211          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7212          * @param {String} selector The simple selector to test
7213          * @return {Boolean} True if this element matches the selector, else false
7214          */
7215         is : function(simpleSelector){
7216             return Roo.DomQuery.is(this.dom, simpleSelector);
7217         },
7218
7219         /**
7220          * Perform animation on this element.
7221          * @param {Object} args The YUI animation control args
7222          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7223          * @param {Function} onComplete (optional) Function to call when animation completes
7224          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7225          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7226          * @return {Roo.Element} this
7227          */
7228         animate : function(args, duration, onComplete, easing, animType){
7229             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7230             return this;
7231         },
7232
7233         /*
7234          * @private Internal animation call
7235          */
7236         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7237             animType = animType || 'run';
7238             opt = opt || {};
7239             var anim = Roo.lib.Anim[animType](
7240                 this.dom, args,
7241                 (opt.duration || defaultDur) || .35,
7242                 (opt.easing || defaultEase) || 'easeOut',
7243                 function(){
7244                     Roo.callback(cb, this);
7245                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7246                 },
7247                 this
7248             );
7249             opt.anim = anim;
7250             return anim;
7251         },
7252
7253         // private legacy anim prep
7254         preanim : function(a, i){
7255             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7256         },
7257
7258         /**
7259          * Removes worthless text nodes
7260          * @param {Boolean} forceReclean (optional) By default the element
7261          * keeps track if it has been cleaned already so
7262          * you can call this over and over. However, if you update the element and
7263          * need to force a reclean, you can pass true.
7264          */
7265         clean : function(forceReclean){
7266             if(this.isCleaned && forceReclean !== true){
7267                 return this;
7268             }
7269             var ns = /\S/;
7270             var d = this.dom, n = d.firstChild, ni = -1;
7271             while(n){
7272                 var nx = n.nextSibling;
7273                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7274                     d.removeChild(n);
7275                 }else{
7276                     n.nodeIndex = ++ni;
7277                 }
7278                 n = nx;
7279             }
7280             this.isCleaned = true;
7281             return this;
7282         },
7283
7284         // private
7285         calcOffsetsTo : function(el){
7286             el = Roo.get(el);
7287             var d = el.dom;
7288             var restorePos = false;
7289             if(el.getStyle('position') == 'static'){
7290                 el.position('relative');
7291                 restorePos = true;
7292             }
7293             var x = 0, y =0;
7294             var op = this.dom;
7295             while(op && op != d && op.tagName != 'HTML'){
7296                 x+= op.offsetLeft;
7297                 y+= op.offsetTop;
7298                 op = op.offsetParent;
7299             }
7300             if(restorePos){
7301                 el.position('static');
7302             }
7303             return [x, y];
7304         },
7305
7306         /**
7307          * Scrolls this element into view within the passed container.
7308          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7309          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7310          * @return {Roo.Element} this
7311          */
7312         scrollIntoView : function(container, hscroll){
7313             var c = Roo.getDom(container) || document.body;
7314             var el = this.dom;
7315
7316             var o = this.calcOffsetsTo(c),
7317                 l = o[0],
7318                 t = o[1],
7319                 b = t+el.offsetHeight,
7320                 r = l+el.offsetWidth;
7321
7322             var ch = c.clientHeight;
7323             var ct = parseInt(c.scrollTop, 10);
7324             var cl = parseInt(c.scrollLeft, 10);
7325             var cb = ct + ch;
7326             var cr = cl + c.clientWidth;
7327
7328             if(t < ct){
7329                 c.scrollTop = t;
7330             }else if(b > cb){
7331                 c.scrollTop = b-ch;
7332             }
7333
7334             if(hscroll !== false){
7335                 if(l < cl){
7336                     c.scrollLeft = l;
7337                 }else if(r > cr){
7338                     c.scrollLeft = r-c.clientWidth;
7339                 }
7340             }
7341             return this;
7342         },
7343
7344         // private
7345         scrollChildIntoView : function(child, hscroll){
7346             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7347         },
7348
7349         /**
7350          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7351          * the new height may not be available immediately.
7352          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7353          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7354          * @param {Function} onComplete (optional) Function to call when animation completes
7355          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7356          * @return {Roo.Element} this
7357          */
7358         autoHeight : function(animate, duration, onComplete, easing){
7359             var oldHeight = this.getHeight();
7360             this.clip();
7361             this.setHeight(1); // force clipping
7362             setTimeout(function(){
7363                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7364                 if(!animate){
7365                     this.setHeight(height);
7366                     this.unclip();
7367                     if(typeof onComplete == "function"){
7368                         onComplete();
7369                     }
7370                 }else{
7371                     this.setHeight(oldHeight); // restore original height
7372                     this.setHeight(height, animate, duration, function(){
7373                         this.unclip();
7374                         if(typeof onComplete == "function") { onComplete(); }
7375                     }.createDelegate(this), easing);
7376                 }
7377             }.createDelegate(this), 0);
7378             return this;
7379         },
7380
7381         /**
7382          * Returns true if this element is an ancestor of the passed element
7383          * @param {HTMLElement/String} el The element to check
7384          * @return {Boolean} True if this element is an ancestor of el, else false
7385          */
7386         contains : function(el){
7387             if(!el){return false;}
7388             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7389         },
7390
7391         /**
7392          * Checks whether the element is currently visible using both visibility and display properties.
7393          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7394          * @return {Boolean} True if the element is currently visible, else false
7395          */
7396         isVisible : function(deep) {
7397             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7398             if(deep !== true || !vis){
7399                 return vis;
7400             }
7401             var p = this.dom.parentNode;
7402             while(p && p.tagName.toLowerCase() != "body"){
7403                 if(!Roo.fly(p, '_isVisible').isVisible()){
7404                     return false;
7405                 }
7406                 p = p.parentNode;
7407             }
7408             return true;
7409         },
7410
7411         /**
7412          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7413          * @param {String} selector The CSS selector
7414          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7415          * @return {CompositeElement/CompositeElementLite} The composite element
7416          */
7417         select : function(selector, unique){
7418             return El.select(selector, unique, this.dom);
7419         },
7420
7421         /**
7422          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7423          * @param {String} selector The CSS selector
7424          * @return {Array} An array of the matched nodes
7425          */
7426         query : function(selector, unique){
7427             return Roo.DomQuery.select(selector, this.dom);
7428         },
7429
7430         /**
7431          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7432          * @param {String} selector The CSS selector
7433          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7434          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7435          */
7436         child : function(selector, returnDom){
7437             var n = Roo.DomQuery.selectNode(selector, this.dom);
7438             return returnDom ? n : Roo.get(n);
7439         },
7440
7441         /**
7442          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7443          * @param {String} selector The CSS selector
7444          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7445          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7446          */
7447         down : function(selector, returnDom){
7448             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7449             return returnDom ? n : Roo.get(n);
7450         },
7451
7452         /**
7453          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7454          * @param {String} group The group the DD object is member of
7455          * @param {Object} config The DD config object
7456          * @param {Object} overrides An object containing methods to override/implement on the DD object
7457          * @return {Roo.dd.DD} The DD object
7458          */
7459         initDD : function(group, config, overrides){
7460             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7461             return Roo.apply(dd, overrides);
7462         },
7463
7464         /**
7465          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7466          * @param {String} group The group the DDProxy object is member of
7467          * @param {Object} config The DDProxy config object
7468          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7469          * @return {Roo.dd.DDProxy} The DDProxy object
7470          */
7471         initDDProxy : function(group, config, overrides){
7472             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7473             return Roo.apply(dd, overrides);
7474         },
7475
7476         /**
7477          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7478          * @param {String} group The group the DDTarget object is member of
7479          * @param {Object} config The DDTarget config object
7480          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7481          * @return {Roo.dd.DDTarget} The DDTarget object
7482          */
7483         initDDTarget : function(group, config, overrides){
7484             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7485             return Roo.apply(dd, overrides);
7486         },
7487
7488         /**
7489          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7490          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7491          * @param {Boolean} visible Whether the element is visible
7492          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7493          * @return {Roo.Element} this
7494          */
7495          setVisible : function(visible, animate){
7496             if(!animate || !A){
7497                 if(this.visibilityMode == El.DISPLAY){
7498                     this.setDisplayed(visible);
7499                 }else{
7500                     this.fixDisplay();
7501                     this.dom.style.visibility = visible ? "visible" : "hidden";
7502                 }
7503             }else{
7504                 // closure for composites
7505                 var dom = this.dom;
7506                 var visMode = this.visibilityMode;
7507                 if(visible){
7508                     this.setOpacity(.01);
7509                     this.setVisible(true);
7510                 }
7511                 this.anim({opacity: { to: (visible?1:0) }},
7512                       this.preanim(arguments, 1),
7513                       null, .35, 'easeIn', function(){
7514                          if(!visible){
7515                              if(visMode == El.DISPLAY){
7516                                  dom.style.display = "none";
7517                              }else{
7518                                  dom.style.visibility = "hidden";
7519                              }
7520                              Roo.get(dom).setOpacity(1);
7521                          }
7522                      });
7523             }
7524             return this;
7525         },
7526
7527         /**
7528          * Returns true if display is not "none"
7529          * @return {Boolean}
7530          */
7531         isDisplayed : function() {
7532             return this.getStyle("display") != "none";
7533         },
7534
7535         /**
7536          * Toggles the element's visibility or display, depending on visibility mode.
7537          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7538          * @return {Roo.Element} this
7539          */
7540         toggle : function(animate){
7541             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7542             return this;
7543         },
7544
7545         /**
7546          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7547          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7548          * @return {Roo.Element} this
7549          */
7550         setDisplayed : function(value) {
7551             if(typeof value == "boolean"){
7552                value = value ? this.originalDisplay : "none";
7553             }
7554             this.setStyle("display", value);
7555             return this;
7556         },
7557
7558         /**
7559          * Tries to focus the element. Any exceptions are caught and ignored.
7560          * @return {Roo.Element} this
7561          */
7562         focus : function() {
7563             try{
7564                 this.dom.focus();
7565             }catch(e){}
7566             return this;
7567         },
7568
7569         /**
7570          * Tries to blur the element. Any exceptions are caught and ignored.
7571          * @return {Roo.Element} this
7572          */
7573         blur : function() {
7574             try{
7575                 this.dom.blur();
7576             }catch(e){}
7577             return this;
7578         },
7579
7580         /**
7581          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7582          * @param {String/Array} className The CSS class to add, or an array of classes
7583          * @return {Roo.Element} this
7584          */
7585         addClass : function(className){
7586             if(className instanceof Array){
7587                 for(var i = 0, len = className.length; i < len; i++) {
7588                     this.addClass(className[i]);
7589                 }
7590             }else{
7591                 if(className && !this.hasClass(className)){
7592                     this.dom.className = this.dom.className + " " + className;
7593                 }
7594             }
7595             return this;
7596         },
7597
7598         /**
7599          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7600          * @param {String/Array} className The CSS class to add, or an array of classes
7601          * @return {Roo.Element} this
7602          */
7603         radioClass : function(className){
7604             var siblings = this.dom.parentNode.childNodes;
7605             for(var i = 0; i < siblings.length; i++) {
7606                 var s = siblings[i];
7607                 if(s.nodeType == 1){
7608                     Roo.get(s).removeClass(className);
7609                 }
7610             }
7611             this.addClass(className);
7612             return this;
7613         },
7614
7615         /**
7616          * Removes one or more CSS classes from the element.
7617          * @param {String/Array} className The CSS class to remove, or an array of classes
7618          * @return {Roo.Element} this
7619          */
7620         removeClass : function(className){
7621             if(!className || !this.dom.className){
7622                 return this;
7623             }
7624             if(className instanceof Array){
7625                 for(var i = 0, len = className.length; i < len; i++) {
7626                     this.removeClass(className[i]);
7627                 }
7628             }else{
7629                 if(this.hasClass(className)){
7630                     var re = this.classReCache[className];
7631                     if (!re) {
7632                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7633                        this.classReCache[className] = re;
7634                     }
7635                     this.dom.className =
7636                         this.dom.className.replace(re, " ");
7637                 }
7638             }
7639             return this;
7640         },
7641
7642         // private
7643         classReCache: {},
7644
7645         /**
7646          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7647          * @param {String} className The CSS class to toggle
7648          * @return {Roo.Element} this
7649          */
7650         toggleClass : function(className){
7651             if(this.hasClass(className)){
7652                 this.removeClass(className);
7653             }else{
7654                 this.addClass(className);
7655             }
7656             return this;
7657         },
7658
7659         /**
7660          * Checks if the specified CSS class exists on this element's DOM node.
7661          * @param {String} className The CSS class to check for
7662          * @return {Boolean} True if the class exists, else false
7663          */
7664         hasClass : function(className){
7665             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7666         },
7667
7668         /**
7669          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7670          * @param {String} oldClassName The CSS class to replace
7671          * @param {String} newClassName The replacement CSS class
7672          * @return {Roo.Element} this
7673          */
7674         replaceClass : function(oldClassName, newClassName){
7675             this.removeClass(oldClassName);
7676             this.addClass(newClassName);
7677             return this;
7678         },
7679
7680         /**
7681          * Returns an object with properties matching the styles requested.
7682          * For example, el.getStyles('color', 'font-size', 'width') might return
7683          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7684          * @param {String} style1 A style name
7685          * @param {String} style2 A style name
7686          * @param {String} etc.
7687          * @return {Object} The style object
7688          */
7689         getStyles : function(){
7690             var a = arguments, len = a.length, r = {};
7691             for(var i = 0; i < len; i++){
7692                 r[a[i]] = this.getStyle(a[i]);
7693             }
7694             return r;
7695         },
7696
7697         /**
7698          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7699          * @param {String} property The style property whose value is returned.
7700          * @return {String} The current value of the style property for this element.
7701          */
7702         getStyle : function(){
7703             return view && view.getComputedStyle ?
7704                 function(prop){
7705                     var el = this.dom, v, cs, camel;
7706                     if(prop == 'float'){
7707                         prop = "cssFloat";
7708                     }
7709                     if(el.style && (v = el.style[prop])){
7710                         return v;
7711                     }
7712                     if(cs = view.getComputedStyle(el, "")){
7713                         if(!(camel = propCache[prop])){
7714                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7715                         }
7716                         return cs[camel];
7717                     }
7718                     return null;
7719                 } :
7720                 function(prop){
7721                     var el = this.dom, v, cs, camel;
7722                     if(prop == 'opacity'){
7723                         if(typeof el.style.filter == 'string'){
7724                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7725                             if(m){
7726                                 var fv = parseFloat(m[1]);
7727                                 if(!isNaN(fv)){
7728                                     return fv ? fv / 100 : 0;
7729                                 }
7730                             }
7731                         }
7732                         return 1;
7733                     }else if(prop == 'float'){
7734                         prop = "styleFloat";
7735                     }
7736                     if(!(camel = propCache[prop])){
7737                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7738                     }
7739                     if(v = el.style[camel]){
7740                         return v;
7741                     }
7742                     if(cs = el.currentStyle){
7743                         return cs[camel];
7744                     }
7745                     return null;
7746                 };
7747         }(),
7748
7749         /**
7750          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7751          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7752          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7753          * @return {Roo.Element} this
7754          */
7755         setStyle : function(prop, value){
7756             if(typeof prop == "string"){
7757                 
7758                 if (prop == 'float') {
7759                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7760                     return this;
7761                 }
7762                 
7763                 var camel;
7764                 if(!(camel = propCache[prop])){
7765                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7766                 }
7767                 
7768                 if(camel == 'opacity') {
7769                     this.setOpacity(value);
7770                 }else{
7771                     this.dom.style[camel] = value;
7772                 }
7773             }else{
7774                 for(var style in prop){
7775                     if(typeof prop[style] != "function"){
7776                        this.setStyle(style, prop[style]);
7777                     }
7778                 }
7779             }
7780             return this;
7781         },
7782
7783         /**
7784          * More flexible version of {@link #setStyle} for setting style properties.
7785          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7786          * a function which returns such a specification.
7787          * @return {Roo.Element} this
7788          */
7789         applyStyles : function(style){
7790             Roo.DomHelper.applyStyles(this.dom, style);
7791             return this;
7792         },
7793
7794         /**
7795           * 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).
7796           * @return {Number} The X position of the element
7797           */
7798         getX : function(){
7799             return D.getX(this.dom);
7800         },
7801
7802         /**
7803           * 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).
7804           * @return {Number} The Y position of the element
7805           */
7806         getY : function(){
7807             return D.getY(this.dom);
7808         },
7809
7810         /**
7811           * 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).
7812           * @return {Array} The XY position of the element
7813           */
7814         getXY : function(){
7815             return D.getXY(this.dom);
7816         },
7817
7818         /**
7819          * 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).
7820          * @param {Number} The X position of the element
7821          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7822          * @return {Roo.Element} this
7823          */
7824         setX : function(x, animate){
7825             if(!animate || !A){
7826                 D.setX(this.dom, x);
7827             }else{
7828                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7829             }
7830             return this;
7831         },
7832
7833         /**
7834          * 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).
7835          * @param {Number} The Y position of the element
7836          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7837          * @return {Roo.Element} this
7838          */
7839         setY : function(y, animate){
7840             if(!animate || !A){
7841                 D.setY(this.dom, y);
7842             }else{
7843                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7844             }
7845             return this;
7846         },
7847
7848         /**
7849          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7850          * @param {String} left The left CSS property value
7851          * @return {Roo.Element} this
7852          */
7853         setLeft : function(left){
7854             this.setStyle("left", this.addUnits(left));
7855             return this;
7856         },
7857
7858         /**
7859          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7860          * @param {String} top The top CSS property value
7861          * @return {Roo.Element} this
7862          */
7863         setTop : function(top){
7864             this.setStyle("top", this.addUnits(top));
7865             return this;
7866         },
7867
7868         /**
7869          * Sets the element's CSS right style.
7870          * @param {String} right The right CSS property value
7871          * @return {Roo.Element} this
7872          */
7873         setRight : function(right){
7874             this.setStyle("right", this.addUnits(right));
7875             return this;
7876         },
7877
7878         /**
7879          * Sets the element's CSS bottom style.
7880          * @param {String} bottom The bottom CSS property value
7881          * @return {Roo.Element} this
7882          */
7883         setBottom : function(bottom){
7884             this.setStyle("bottom", this.addUnits(bottom));
7885             return this;
7886         },
7887
7888         /**
7889          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7890          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7891          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7892          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7893          * @return {Roo.Element} this
7894          */
7895         setXY : function(pos, animate){
7896             if(!animate || !A){
7897                 D.setXY(this.dom, pos);
7898             }else{
7899                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7900             }
7901             return this;
7902         },
7903
7904         /**
7905          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7906          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7907          * @param {Number} x X value for new position (coordinates are page-based)
7908          * @param {Number} y Y value for new position (coordinates are page-based)
7909          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7910          * @return {Roo.Element} this
7911          */
7912         setLocation : function(x, y, animate){
7913             this.setXY([x, y], this.preanim(arguments, 2));
7914             return this;
7915         },
7916
7917         /**
7918          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7919          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7920          * @param {Number} x X value for new position (coordinates are page-based)
7921          * @param {Number} y Y value for new position (coordinates are page-based)
7922          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7923          * @return {Roo.Element} this
7924          */
7925         moveTo : function(x, y, animate){
7926             this.setXY([x, y], this.preanim(arguments, 2));
7927             return this;
7928         },
7929
7930         /**
7931          * Returns the region of the given element.
7932          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7933          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7934          */
7935         getRegion : function(){
7936             return D.getRegion(this.dom);
7937         },
7938
7939         /**
7940          * Returns the offset height of the element
7941          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7942          * @return {Number} The element's height
7943          */
7944         getHeight : function(contentHeight){
7945             var h = this.dom.offsetHeight || 0;
7946             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7947         },
7948
7949         /**
7950          * Returns the offset width of the element
7951          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7952          * @return {Number} The element's width
7953          */
7954         getWidth : function(contentWidth){
7955             var w = this.dom.offsetWidth || 0;
7956             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7957         },
7958
7959         /**
7960          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7961          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7962          * if a height has not been set using CSS.
7963          * @return {Number}
7964          */
7965         getComputedHeight : function(){
7966             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7967             if(!h){
7968                 h = parseInt(this.getStyle('height'), 10) || 0;
7969                 if(!this.isBorderBox()){
7970                     h += this.getFrameWidth('tb');
7971                 }
7972             }
7973             return h;
7974         },
7975
7976         /**
7977          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7978          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7979          * if a width has not been set using CSS.
7980          * @return {Number}
7981          */
7982         getComputedWidth : function(){
7983             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7984             if(!w){
7985                 w = parseInt(this.getStyle('width'), 10) || 0;
7986                 if(!this.isBorderBox()){
7987                     w += this.getFrameWidth('lr');
7988                 }
7989             }
7990             return w;
7991         },
7992
7993         /**
7994          * Returns the size of the element.
7995          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7996          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7997          */
7998         getSize : function(contentSize){
7999             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8000         },
8001
8002         /**
8003          * Returns the width and height of the viewport.
8004          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8005          */
8006         getViewSize : function(){
8007             var d = this.dom, doc = document, aw = 0, ah = 0;
8008             if(d == doc || d == doc.body){
8009                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8010             }else{
8011                 return {
8012                     width : d.clientWidth,
8013                     height: d.clientHeight
8014                 };
8015             }
8016         },
8017
8018         /**
8019          * Returns the value of the "value" attribute
8020          * @param {Boolean} asNumber true to parse the value as a number
8021          * @return {String/Number}
8022          */
8023         getValue : function(asNumber){
8024             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8025         },
8026
8027         // private
8028         adjustWidth : function(width){
8029             if(typeof width == "number"){
8030                 if(this.autoBoxAdjust && !this.isBorderBox()){
8031                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8032                 }
8033                 if(width < 0){
8034                     width = 0;
8035                 }
8036             }
8037             return width;
8038         },
8039
8040         // private
8041         adjustHeight : function(height){
8042             if(typeof height == "number"){
8043                if(this.autoBoxAdjust && !this.isBorderBox()){
8044                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8045                }
8046                if(height < 0){
8047                    height = 0;
8048                }
8049             }
8050             return height;
8051         },
8052
8053         /**
8054          * Set the width of the element
8055          * @param {Number} width The new width
8056          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8057          * @return {Roo.Element} this
8058          */
8059         setWidth : function(width, animate){
8060             width = this.adjustWidth(width);
8061             if(!animate || !A){
8062                 this.dom.style.width = this.addUnits(width);
8063             }else{
8064                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8065             }
8066             return this;
8067         },
8068
8069         /**
8070          * Set the height of the element
8071          * @param {Number} height The new height
8072          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8073          * @return {Roo.Element} this
8074          */
8075          setHeight : function(height, animate){
8076             height = this.adjustHeight(height);
8077             if(!animate || !A){
8078                 this.dom.style.height = this.addUnits(height);
8079             }else{
8080                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8081             }
8082             return this;
8083         },
8084
8085         /**
8086          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8087          * @param {Number} width The new width
8088          * @param {Number} height The new height
8089          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8090          * @return {Roo.Element} this
8091          */
8092          setSize : function(width, height, animate){
8093             if(typeof width == "object"){ // in case of object from getSize()
8094                 height = width.height; width = width.width;
8095             }
8096             width = this.adjustWidth(width); height = this.adjustHeight(height);
8097             if(!animate || !A){
8098                 this.dom.style.width = this.addUnits(width);
8099                 this.dom.style.height = this.addUnits(height);
8100             }else{
8101                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8102             }
8103             return this;
8104         },
8105
8106         /**
8107          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8108          * @param {Number} x X value for new position (coordinates are page-based)
8109          * @param {Number} y Y value for new position (coordinates are page-based)
8110          * @param {Number} width The new width
8111          * @param {Number} height The new height
8112          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8113          * @return {Roo.Element} this
8114          */
8115         setBounds : function(x, y, width, height, animate){
8116             if(!animate || !A){
8117                 this.setSize(width, height);
8118                 this.setLocation(x, y);
8119             }else{
8120                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8121                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8122                               this.preanim(arguments, 4), 'motion');
8123             }
8124             return this;
8125         },
8126
8127         /**
8128          * 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.
8129          * @param {Roo.lib.Region} region The region to fill
8130          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8131          * @return {Roo.Element} this
8132          */
8133         setRegion : function(region, animate){
8134             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8135             return this;
8136         },
8137
8138         /**
8139          * Appends an event handler
8140          *
8141          * @param {String}   eventName     The type of event to append
8142          * @param {Function} fn        The method the event invokes
8143          * @param {Object} scope       (optional) The scope (this object) of the fn
8144          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8145          */
8146         addListener : function(eventName, fn, scope, options){
8147             if (this.dom) {
8148                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8149             }
8150         },
8151
8152         /**
8153          * Removes an event handler from this element
8154          * @param {String} eventName the type of event to remove
8155          * @param {Function} fn the method the event invokes
8156          * @return {Roo.Element} this
8157          */
8158         removeListener : function(eventName, fn){
8159             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8160             return this;
8161         },
8162
8163         /**
8164          * Removes all previous added listeners from this element
8165          * @return {Roo.Element} this
8166          */
8167         removeAllListeners : function(){
8168             E.purgeElement(this.dom);
8169             return this;
8170         },
8171
8172         relayEvent : function(eventName, observable){
8173             this.on(eventName, function(e){
8174                 observable.fireEvent(eventName, e);
8175             });
8176         },
8177
8178         /**
8179          * Set the opacity of the element
8180          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8181          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8182          * @return {Roo.Element} this
8183          */
8184          setOpacity : function(opacity, animate){
8185             if(!animate || !A){
8186                 var s = this.dom.style;
8187                 if(Roo.isIE){
8188                     s.zoom = 1;
8189                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8190                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8191                 }else{
8192                     s.opacity = opacity;
8193                 }
8194             }else{
8195                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8196             }
8197             return this;
8198         },
8199
8200         /**
8201          * Gets the left X coordinate
8202          * @param {Boolean} local True to get the local css position instead of page coordinate
8203          * @return {Number}
8204          */
8205         getLeft : function(local){
8206             if(!local){
8207                 return this.getX();
8208             }else{
8209                 return parseInt(this.getStyle("left"), 10) || 0;
8210             }
8211         },
8212
8213         /**
8214          * Gets the right X coordinate of the element (element X position + element width)
8215          * @param {Boolean} local True to get the local css position instead of page coordinate
8216          * @return {Number}
8217          */
8218         getRight : function(local){
8219             if(!local){
8220                 return this.getX() + this.getWidth();
8221             }else{
8222                 return (this.getLeft(true) + this.getWidth()) || 0;
8223             }
8224         },
8225
8226         /**
8227          * Gets the top Y coordinate
8228          * @param {Boolean} local True to get the local css position instead of page coordinate
8229          * @return {Number}
8230          */
8231         getTop : function(local) {
8232             if(!local){
8233                 return this.getY();
8234             }else{
8235                 return parseInt(this.getStyle("top"), 10) || 0;
8236             }
8237         },
8238
8239         /**
8240          * Gets the bottom Y coordinate of the element (element Y position + element height)
8241          * @param {Boolean} local True to get the local css position instead of page coordinate
8242          * @return {Number}
8243          */
8244         getBottom : function(local){
8245             if(!local){
8246                 return this.getY() + this.getHeight();
8247             }else{
8248                 return (this.getTop(true) + this.getHeight()) || 0;
8249             }
8250         },
8251
8252         /**
8253         * Initializes positioning on this element. If a desired position is not passed, it will make the
8254         * the element positioned relative IF it is not already positioned.
8255         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8256         * @param {Number} zIndex (optional) The zIndex to apply
8257         * @param {Number} x (optional) Set the page X position
8258         * @param {Number} y (optional) Set the page Y position
8259         */
8260         position : function(pos, zIndex, x, y){
8261             if(!pos){
8262                if(this.getStyle('position') == 'static'){
8263                    this.setStyle('position', 'relative');
8264                }
8265             }else{
8266                 this.setStyle("position", pos);
8267             }
8268             if(zIndex){
8269                 this.setStyle("z-index", zIndex);
8270             }
8271             if(x !== undefined && y !== undefined){
8272                 this.setXY([x, y]);
8273             }else if(x !== undefined){
8274                 this.setX(x);
8275             }else if(y !== undefined){
8276                 this.setY(y);
8277             }
8278         },
8279
8280         /**
8281         * Clear positioning back to the default when the document was loaded
8282         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8283         * @return {Roo.Element} this
8284          */
8285         clearPositioning : function(value){
8286             value = value ||'';
8287             this.setStyle({
8288                 "left": value,
8289                 "right": value,
8290                 "top": value,
8291                 "bottom": value,
8292                 "z-index": "",
8293                 "position" : "static"
8294             });
8295             return this;
8296         },
8297
8298         /**
8299         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8300         * snapshot before performing an update and then restoring the element.
8301         * @return {Object}
8302         */
8303         getPositioning : function(){
8304             var l = this.getStyle("left");
8305             var t = this.getStyle("top");
8306             return {
8307                 "position" : this.getStyle("position"),
8308                 "left" : l,
8309                 "right" : l ? "" : this.getStyle("right"),
8310                 "top" : t,
8311                 "bottom" : t ? "" : this.getStyle("bottom"),
8312                 "z-index" : this.getStyle("z-index")
8313             };
8314         },
8315
8316         /**
8317          * Gets the width of the border(s) for the specified side(s)
8318          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8319          * passing lr would get the border (l)eft width + the border (r)ight width.
8320          * @return {Number} The width of the sides passed added together
8321          */
8322         getBorderWidth : function(side){
8323             return this.addStyles(side, El.borders);
8324         },
8325
8326         /**
8327          * Gets the width of the padding(s) for the specified side(s)
8328          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8329          * passing lr would get the padding (l)eft + the padding (r)ight.
8330          * @return {Number} The padding of the sides passed added together
8331          */
8332         getPadding : function(side){
8333             return this.addStyles(side, El.paddings);
8334         },
8335
8336         /**
8337         * Set positioning with an object returned by getPositioning().
8338         * @param {Object} posCfg
8339         * @return {Roo.Element} this
8340          */
8341         setPositioning : function(pc){
8342             this.applyStyles(pc);
8343             if(pc.right == "auto"){
8344                 this.dom.style.right = "";
8345             }
8346             if(pc.bottom == "auto"){
8347                 this.dom.style.bottom = "";
8348             }
8349             return this;
8350         },
8351
8352         // private
8353         fixDisplay : function(){
8354             if(this.getStyle("display") == "none"){
8355                 this.setStyle("visibility", "hidden");
8356                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8357                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8358                     this.setStyle("display", "block");
8359                 }
8360             }
8361         },
8362
8363         /**
8364          * Quick set left and top adding default units
8365          * @param {String} left The left CSS property value
8366          * @param {String} top The top CSS property value
8367          * @return {Roo.Element} this
8368          */
8369          setLeftTop : function(left, top){
8370             this.dom.style.left = this.addUnits(left);
8371             this.dom.style.top = this.addUnits(top);
8372             return this;
8373         },
8374
8375         /**
8376          * Move this element relative to its current position.
8377          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8378          * @param {Number} distance How far to move the element in pixels
8379          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8380          * @return {Roo.Element} this
8381          */
8382          move : function(direction, distance, animate){
8383             var xy = this.getXY();
8384             direction = direction.toLowerCase();
8385             switch(direction){
8386                 case "l":
8387                 case "left":
8388                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8389                     break;
8390                case "r":
8391                case "right":
8392                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8393                     break;
8394                case "t":
8395                case "top":
8396                case "up":
8397                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8398                     break;
8399                case "b":
8400                case "bottom":
8401                case "down":
8402                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8403                     break;
8404             }
8405             return this;
8406         },
8407
8408         /**
8409          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8410          * @return {Roo.Element} this
8411          */
8412         clip : function(){
8413             if(!this.isClipped){
8414                this.isClipped = true;
8415                this.originalClip = {
8416                    "o": this.getStyle("overflow"),
8417                    "x": this.getStyle("overflow-x"),
8418                    "y": this.getStyle("overflow-y")
8419                };
8420                this.setStyle("overflow", "hidden");
8421                this.setStyle("overflow-x", "hidden");
8422                this.setStyle("overflow-y", "hidden");
8423             }
8424             return this;
8425         },
8426
8427         /**
8428          *  Return clipping (overflow) to original clipping before clip() was called
8429          * @return {Roo.Element} this
8430          */
8431         unclip : function(){
8432             if(this.isClipped){
8433                 this.isClipped = false;
8434                 var o = this.originalClip;
8435                 if(o.o){this.setStyle("overflow", o.o);}
8436                 if(o.x){this.setStyle("overflow-x", o.x);}
8437                 if(o.y){this.setStyle("overflow-y", o.y);}
8438             }
8439             return this;
8440         },
8441
8442
8443         /**
8444          * Gets the x,y coordinates specified by the anchor position on the element.
8445          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8446          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8447          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8448          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8449          * @return {Array} [x, y] An array containing the element's x and y coordinates
8450          */
8451         getAnchorXY : function(anchor, local, s){
8452             //Passing a different size is useful for pre-calculating anchors,
8453             //especially for anchored animations that change the el size.
8454
8455             var w, h, vp = false;
8456             if(!s){
8457                 var d = this.dom;
8458                 if(d == document.body || d == document){
8459                     vp = true;
8460                     w = D.getViewWidth(); h = D.getViewHeight();
8461                 }else{
8462                     w = this.getWidth(); h = this.getHeight();
8463                 }
8464             }else{
8465                 w = s.width;  h = s.height;
8466             }
8467             var x = 0, y = 0, r = Math.round;
8468             switch((anchor || "tl").toLowerCase()){
8469                 case "c":
8470                     x = r(w*.5);
8471                     y = r(h*.5);
8472                 break;
8473                 case "t":
8474                     x = r(w*.5);
8475                     y = 0;
8476                 break;
8477                 case "l":
8478                     x = 0;
8479                     y = r(h*.5);
8480                 break;
8481                 case "r":
8482                     x = w;
8483                     y = r(h*.5);
8484                 break;
8485                 case "b":
8486                     x = r(w*.5);
8487                     y = h;
8488                 break;
8489                 case "tl":
8490                     x = 0;
8491                     y = 0;
8492                 break;
8493                 case "bl":
8494                     x = 0;
8495                     y = h;
8496                 break;
8497                 case "br":
8498                     x = w;
8499                     y = h;
8500                 break;
8501                 case "tr":
8502                     x = w;
8503                     y = 0;
8504                 break;
8505             }
8506             if(local === true){
8507                 return [x, y];
8508             }
8509             if(vp){
8510                 var sc = this.getScroll();
8511                 return [x + sc.left, y + sc.top];
8512             }
8513             //Add the element's offset xy
8514             var o = this.getXY();
8515             return [x+o[0], y+o[1]];
8516         },
8517
8518         /**
8519          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8520          * supported position values.
8521          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8522          * @param {String} position The position to align to.
8523          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8524          * @return {Array} [x, y]
8525          */
8526         getAlignToXY : function(el, p, o){
8527             el = Roo.get(el);
8528             var d = this.dom;
8529             if(!el.dom){
8530                 throw "Element.alignTo with an element that doesn't exist";
8531             }
8532             var c = false; //constrain to viewport
8533             var p1 = "", p2 = "";
8534             o = o || [0,0];
8535
8536             if(!p){
8537                 p = "tl-bl";
8538             }else if(p == "?"){
8539                 p = "tl-bl?";
8540             }else if(p.indexOf("-") == -1){
8541                 p = "tl-" + p;
8542             }
8543             p = p.toLowerCase();
8544             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8545             if(!m){
8546                throw "Element.alignTo with an invalid alignment " + p;
8547             }
8548             p1 = m[1]; p2 = m[2]; c = !!m[3];
8549
8550             //Subtract the aligned el's internal xy from the target's offset xy
8551             //plus custom offset to get the aligned el's new offset xy
8552             var a1 = this.getAnchorXY(p1, true);
8553             var a2 = el.getAnchorXY(p2, false);
8554             var x = a2[0] - a1[0] + o[0];
8555             var y = a2[1] - a1[1] + o[1];
8556             if(c){
8557                 //constrain the aligned el to viewport if necessary
8558                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8559                 // 5px of margin for ie
8560                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8561
8562                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8563                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8564                 //otherwise swap the aligned el to the opposite border of the target.
8565                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8566                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8567                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8568                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8569
8570                var doc = document;
8571                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8572                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8573
8574                if((x+w) > dw + scrollX){
8575                     x = swapX ? r.left-w : dw+scrollX-w;
8576                 }
8577                if(x < scrollX){
8578                    x = swapX ? r.right : scrollX;
8579                }
8580                if((y+h) > dh + scrollY){
8581                     y = swapY ? r.top-h : dh+scrollY-h;
8582                 }
8583                if (y < scrollY){
8584                    y = swapY ? r.bottom : scrollY;
8585                }
8586             }
8587             return [x,y];
8588         },
8589
8590         // private
8591         getConstrainToXY : function(){
8592             var os = {top:0, left:0, bottom:0, right: 0};
8593
8594             return function(el, local, offsets, proposedXY){
8595                 el = Roo.get(el);
8596                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8597
8598                 var vw, vh, vx = 0, vy = 0;
8599                 if(el.dom == document.body || el.dom == document){
8600                     vw = Roo.lib.Dom.getViewWidth();
8601                     vh = Roo.lib.Dom.getViewHeight();
8602                 }else{
8603                     vw = el.dom.clientWidth;
8604                     vh = el.dom.clientHeight;
8605                     if(!local){
8606                         var vxy = el.getXY();
8607                         vx = vxy[0];
8608                         vy = vxy[1];
8609                     }
8610                 }
8611
8612                 var s = el.getScroll();
8613
8614                 vx += offsets.left + s.left;
8615                 vy += offsets.top + s.top;
8616
8617                 vw -= offsets.right;
8618                 vh -= offsets.bottom;
8619
8620                 var vr = vx+vw;
8621                 var vb = vy+vh;
8622
8623                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8624                 var x = xy[0], y = xy[1];
8625                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8626
8627                 // only move it if it needs it
8628                 var moved = false;
8629
8630                 // first validate right/bottom
8631                 if((x + w) > vr){
8632                     x = vr - w;
8633                     moved = true;
8634                 }
8635                 if((y + h) > vb){
8636                     y = vb - h;
8637                     moved = true;
8638                 }
8639                 // then make sure top/left isn't negative
8640                 if(x < vx){
8641                     x = vx;
8642                     moved = true;
8643                 }
8644                 if(y < vy){
8645                     y = vy;
8646                     moved = true;
8647                 }
8648                 return moved ? [x, y] : false;
8649             };
8650         }(),
8651
8652         // private
8653         adjustForConstraints : function(xy, parent, offsets){
8654             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8655         },
8656
8657         /**
8658          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8659          * document it aligns it to the viewport.
8660          * The position parameter is optional, and can be specified in any one of the following formats:
8661          * <ul>
8662          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8663          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8664          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8665          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8666          *   <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
8667          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8668          * </ul>
8669          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8670          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8671          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8672          * that specified in order to enforce the viewport constraints.
8673          * Following are all of the supported anchor positions:
8674     <pre>
8675     Value  Description
8676     -----  -----------------------------
8677     tl     The top left corner (default)
8678     t      The center of the top edge
8679     tr     The top right corner
8680     l      The center of the left edge
8681     c      In the center of the element
8682     r      The center of the right edge
8683     bl     The bottom left corner
8684     b      The center of the bottom edge
8685     br     The bottom right corner
8686     </pre>
8687     Example Usage:
8688     <pre><code>
8689     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8690     el.alignTo("other-el");
8691
8692     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8693     el.alignTo("other-el", "tr?");
8694
8695     // align the bottom right corner of el with the center left edge of other-el
8696     el.alignTo("other-el", "br-l?");
8697
8698     // align the center of el with the bottom left corner of other-el and
8699     // adjust the x position by -6 pixels (and the y position by 0)
8700     el.alignTo("other-el", "c-bl", [-6, 0]);
8701     </code></pre>
8702          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8703          * @param {String} position The position to align to.
8704          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8705          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8706          * @return {Roo.Element} this
8707          */
8708         alignTo : function(element, position, offsets, animate){
8709             var xy = this.getAlignToXY(element, position, offsets);
8710             this.setXY(xy, this.preanim(arguments, 3));
8711             return this;
8712         },
8713
8714         /**
8715          * Anchors an element to another element and realigns it when the window is resized.
8716          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8717          * @param {String} position The position to align to.
8718          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8719          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8720          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8721          * is a number, it is used as the buffer delay (defaults to 50ms).
8722          * @param {Function} callback The function to call after the animation finishes
8723          * @return {Roo.Element} this
8724          */
8725         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8726             var action = function(){
8727                 this.alignTo(el, alignment, offsets, animate);
8728                 Roo.callback(callback, this);
8729             };
8730             Roo.EventManager.onWindowResize(action, this);
8731             var tm = typeof monitorScroll;
8732             if(tm != 'undefined'){
8733                 Roo.EventManager.on(window, 'scroll', action, this,
8734                     {buffer: tm == 'number' ? monitorScroll : 50});
8735             }
8736             action.call(this); // align immediately
8737             return this;
8738         },
8739         /**
8740          * Clears any opacity settings from this element. Required in some cases for IE.
8741          * @return {Roo.Element} this
8742          */
8743         clearOpacity : function(){
8744             if (window.ActiveXObject) {
8745                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8746                     this.dom.style.filter = "";
8747                 }
8748             } else {
8749                 this.dom.style.opacity = "";
8750                 this.dom.style["-moz-opacity"] = "";
8751                 this.dom.style["-khtml-opacity"] = "";
8752             }
8753             return this;
8754         },
8755
8756         /**
8757          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8758          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8759          * @return {Roo.Element} this
8760          */
8761         hide : function(animate){
8762             this.setVisible(false, this.preanim(arguments, 0));
8763             return this;
8764         },
8765
8766         /**
8767         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8768         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8769          * @return {Roo.Element} this
8770          */
8771         show : function(animate){
8772             this.setVisible(true, this.preanim(arguments, 0));
8773             return this;
8774         },
8775
8776         /**
8777          * @private Test if size has a unit, otherwise appends the default
8778          */
8779         addUnits : function(size){
8780             return Roo.Element.addUnits(size, this.defaultUnit);
8781         },
8782
8783         /**
8784          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8785          * @return {Roo.Element} this
8786          */
8787         beginMeasure : function(){
8788             var el = this.dom;
8789             if(el.offsetWidth || el.offsetHeight){
8790                 return this; // offsets work already
8791             }
8792             var changed = [];
8793             var p = this.dom, b = document.body; // start with this element
8794             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8795                 var pe = Roo.get(p);
8796                 if(pe.getStyle('display') == 'none'){
8797                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8798                     p.style.visibility = "hidden";
8799                     p.style.display = "block";
8800                 }
8801                 p = p.parentNode;
8802             }
8803             this._measureChanged = changed;
8804             return this;
8805
8806         },
8807
8808         /**
8809          * Restores displays to before beginMeasure was called
8810          * @return {Roo.Element} this
8811          */
8812         endMeasure : function(){
8813             var changed = this._measureChanged;
8814             if(changed){
8815                 for(var i = 0, len = changed.length; i < len; i++) {
8816                     var r = changed[i];
8817                     r.el.style.visibility = r.visibility;
8818                     r.el.style.display = "none";
8819                 }
8820                 this._measureChanged = null;
8821             }
8822             return this;
8823         },
8824
8825         /**
8826         * Update the innerHTML of this element, optionally searching for and processing scripts
8827         * @param {String} html The new HTML
8828         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8829         * @param {Function} callback For async script loading you can be noticed when the update completes
8830         * @return {Roo.Element} this
8831          */
8832         update : function(html, loadScripts, callback){
8833             if(typeof html == "undefined"){
8834                 html = "";
8835             }
8836             if(loadScripts !== true){
8837                 this.dom.innerHTML = html;
8838                 if(typeof callback == "function"){
8839                     callback();
8840                 }
8841                 return this;
8842             }
8843             var id = Roo.id();
8844             var dom = this.dom;
8845
8846             html += '<span id="' + id + '"></span>';
8847
8848             E.onAvailable(id, function(){
8849                 var hd = document.getElementsByTagName("head")[0];
8850                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8851                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8852                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8853
8854                 var match;
8855                 while(match = re.exec(html)){
8856                     var attrs = match[1];
8857                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8858                     if(srcMatch && srcMatch[2]){
8859                        var s = document.createElement("script");
8860                        s.src = srcMatch[2];
8861                        var typeMatch = attrs.match(typeRe);
8862                        if(typeMatch && typeMatch[2]){
8863                            s.type = typeMatch[2];
8864                        }
8865                        hd.appendChild(s);
8866                     }else if(match[2] && match[2].length > 0){
8867                         if(window.execScript) {
8868                            window.execScript(match[2]);
8869                         } else {
8870                             /**
8871                              * eval:var:id
8872                              * eval:var:dom
8873                              * eval:var:html
8874                              * 
8875                              */
8876                            window.eval(match[2]);
8877                         }
8878                     }
8879                 }
8880                 var el = document.getElementById(id);
8881                 if(el){el.parentNode.removeChild(el);}
8882                 if(typeof callback == "function"){
8883                     callback();
8884                 }
8885             });
8886             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8887             return this;
8888         },
8889
8890         /**
8891          * Direct access to the UpdateManager update() method (takes the same parameters).
8892          * @param {String/Function} url The url for this request or a function to call to get the url
8893          * @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}
8894          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8895          * @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.
8896          * @return {Roo.Element} this
8897          */
8898         load : function(){
8899             var um = this.getUpdateManager();
8900             um.update.apply(um, arguments);
8901             return this;
8902         },
8903
8904         /**
8905         * Gets this element's UpdateManager
8906         * @return {Roo.UpdateManager} The UpdateManager
8907         */
8908         getUpdateManager : function(){
8909             if(!this.updateManager){
8910                 this.updateManager = new Roo.UpdateManager(this);
8911             }
8912             return this.updateManager;
8913         },
8914
8915         /**
8916          * Disables text selection for this element (normalized across browsers)
8917          * @return {Roo.Element} this
8918          */
8919         unselectable : function(){
8920             this.dom.unselectable = "on";
8921             this.swallowEvent("selectstart", true);
8922             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8923             this.addClass("x-unselectable");
8924             return this;
8925         },
8926
8927         /**
8928         * Calculates the x, y to center this element on the screen
8929         * @return {Array} The x, y values [x, y]
8930         */
8931         getCenterXY : function(){
8932             return this.getAlignToXY(document, 'c-c');
8933         },
8934
8935         /**
8936         * Centers the Element in either the viewport, or another Element.
8937         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8938         */
8939         center : function(centerIn){
8940             this.alignTo(centerIn || document, 'c-c');
8941             return this;
8942         },
8943
8944         /**
8945          * Tests various css rules/browsers to determine if this element uses a border box
8946          * @return {Boolean}
8947          */
8948         isBorderBox : function(){
8949             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8950         },
8951
8952         /**
8953          * Return a box {x, y, width, height} that can be used to set another elements
8954          * size/location to match this element.
8955          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8956          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8957          * @return {Object} box An object in the format {x, y, width, height}
8958          */
8959         getBox : function(contentBox, local){
8960             var xy;
8961             if(!local){
8962                 xy = this.getXY();
8963             }else{
8964                 var left = parseInt(this.getStyle("left"), 10) || 0;
8965                 var top = parseInt(this.getStyle("top"), 10) || 0;
8966                 xy = [left, top];
8967             }
8968             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8969             if(!contentBox){
8970                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8971             }else{
8972                 var l = this.getBorderWidth("l")+this.getPadding("l");
8973                 var r = this.getBorderWidth("r")+this.getPadding("r");
8974                 var t = this.getBorderWidth("t")+this.getPadding("t");
8975                 var b = this.getBorderWidth("b")+this.getPadding("b");
8976                 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)};
8977             }
8978             bx.right = bx.x + bx.width;
8979             bx.bottom = bx.y + bx.height;
8980             return bx;
8981         },
8982
8983         /**
8984          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8985          for more information about the sides.
8986          * @param {String} sides
8987          * @return {Number}
8988          */
8989         getFrameWidth : function(sides, onlyContentBox){
8990             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8991         },
8992
8993         /**
8994          * 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.
8995          * @param {Object} box The box to fill {x, y, width, height}
8996          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8997          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8998          * @return {Roo.Element} this
8999          */
9000         setBox : function(box, adjust, animate){
9001             var w = box.width, h = box.height;
9002             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9003                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9004                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9005             }
9006             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9007             return this;
9008         },
9009
9010         /**
9011          * Forces the browser to repaint this element
9012          * @return {Roo.Element} this
9013          */
9014          repaint : function(){
9015             var dom = this.dom;
9016             this.addClass("x-repaint");
9017             setTimeout(function(){
9018                 Roo.get(dom).removeClass("x-repaint");
9019             }, 1);
9020             return this;
9021         },
9022
9023         /**
9024          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9025          * then it returns the calculated width of the sides (see getPadding)
9026          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9027          * @return {Object/Number}
9028          */
9029         getMargins : function(side){
9030             if(!side){
9031                 return {
9032                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9033                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9034                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9035                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9036                 };
9037             }else{
9038                 return this.addStyles(side, El.margins);
9039              }
9040         },
9041
9042         // private
9043         addStyles : function(sides, styles){
9044             var val = 0, v, w;
9045             for(var i = 0, len = sides.length; i < len; i++){
9046                 v = this.getStyle(styles[sides.charAt(i)]);
9047                 if(v){
9048                      w = parseInt(v, 10);
9049                      if(w){ val += w; }
9050                 }
9051             }
9052             return val;
9053         },
9054
9055         /**
9056          * Creates a proxy element of this element
9057          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9058          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9059          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9060          * @return {Roo.Element} The new proxy element
9061          */
9062         createProxy : function(config, renderTo, matchBox){
9063             if(renderTo){
9064                 renderTo = Roo.getDom(renderTo);
9065             }else{
9066                 renderTo = document.body;
9067             }
9068             config = typeof config == "object" ?
9069                 config : {tag : "div", cls: config};
9070             var proxy = Roo.DomHelper.append(renderTo, config, true);
9071             if(matchBox){
9072                proxy.setBox(this.getBox());
9073             }
9074             return proxy;
9075         },
9076
9077         /**
9078          * Puts a mask over this element to disable user interaction. Requires core.css.
9079          * This method can only be applied to elements which accept child nodes.
9080          * @param {String} msg (optional) A message to display in the mask
9081          * @param {String} msgCls (optional) A css class to apply to the msg element
9082          * @return {Element} The mask  element
9083          */
9084         mask : function(msg, msgCls)
9085         {
9086             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9087                 this.setStyle("position", "relative");
9088             }
9089             if(!this._mask){
9090                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9091             }
9092             this.addClass("x-masked");
9093             this._mask.setDisplayed(true);
9094             
9095             // we wander
9096             var z = 0;
9097             var dom = this.dom;
9098             while (dom && dom.style) {
9099                 if (!isNaN(parseInt(dom.style.zIndex))) {
9100                     z = Math.max(z, parseInt(dom.style.zIndex));
9101                 }
9102                 dom = dom.parentNode;
9103             }
9104             // if we are masking the body - then it hides everything..
9105             if (this.dom == document.body) {
9106                 z = 1000000;
9107                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9108                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9109             }
9110            
9111             if(typeof msg == 'string'){
9112                 if(!this._maskMsg){
9113                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9114                 }
9115                 var mm = this._maskMsg;
9116                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9117                 if (mm.dom.firstChild) { // weird IE issue?
9118                     mm.dom.firstChild.innerHTML = msg;
9119                 }
9120                 mm.setDisplayed(true);
9121                 mm.center(this);
9122                 mm.setStyle('z-index', z + 102);
9123             }
9124             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9125                 this._mask.setHeight(this.getHeight());
9126             }
9127             this._mask.setStyle('z-index', z + 100);
9128             
9129             return this._mask;
9130         },
9131
9132         /**
9133          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9134          * it is cached for reuse.
9135          */
9136         unmask : function(removeEl){
9137             if(this._mask){
9138                 if(removeEl === true){
9139                     this._mask.remove();
9140                     delete this._mask;
9141                     if(this._maskMsg){
9142                         this._maskMsg.remove();
9143                         delete this._maskMsg;
9144                     }
9145                 }else{
9146                     this._mask.setDisplayed(false);
9147                     if(this._maskMsg){
9148                         this._maskMsg.setDisplayed(false);
9149                     }
9150                 }
9151             }
9152             this.removeClass("x-masked");
9153         },
9154
9155         /**
9156          * Returns true if this element is masked
9157          * @return {Boolean}
9158          */
9159         isMasked : function(){
9160             return this._mask && this._mask.isVisible();
9161         },
9162
9163         /**
9164          * Creates an iframe shim for this element to keep selects and other windowed objects from
9165          * showing through.
9166          * @return {Roo.Element} The new shim element
9167          */
9168         createShim : function(){
9169             var el = document.createElement('iframe');
9170             el.frameBorder = 'no';
9171             el.className = 'roo-shim';
9172             if(Roo.isIE && Roo.isSecure){
9173                 el.src = Roo.SSL_SECURE_URL;
9174             }
9175             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9176             shim.autoBoxAdjust = false;
9177             return shim;
9178         },
9179
9180         /**
9181          * Removes this element from the DOM and deletes it from the cache
9182          */
9183         remove : function(){
9184             if(this.dom.parentNode){
9185                 this.dom.parentNode.removeChild(this.dom);
9186             }
9187             delete El.cache[this.dom.id];
9188         },
9189
9190         /**
9191          * Sets up event handlers to add and remove a css class when the mouse is over this element
9192          * @param {String} className
9193          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9194          * mouseout events for children elements
9195          * @return {Roo.Element} this
9196          */
9197         addClassOnOver : function(className, preventFlicker){
9198             this.on("mouseover", function(){
9199                 Roo.fly(this, '_internal').addClass(className);
9200             }, this.dom);
9201             var removeFn = function(e){
9202                 if(preventFlicker !== true || !e.within(this, true)){
9203                     Roo.fly(this, '_internal').removeClass(className);
9204                 }
9205             };
9206             this.on("mouseout", removeFn, this.dom);
9207             return this;
9208         },
9209
9210         /**
9211          * Sets up event handlers to add and remove a css class when this element has the focus
9212          * @param {String} className
9213          * @return {Roo.Element} this
9214          */
9215         addClassOnFocus : function(className){
9216             this.on("focus", function(){
9217                 Roo.fly(this, '_internal').addClass(className);
9218             }, this.dom);
9219             this.on("blur", function(){
9220                 Roo.fly(this, '_internal').removeClass(className);
9221             }, this.dom);
9222             return this;
9223         },
9224         /**
9225          * 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)
9226          * @param {String} className
9227          * @return {Roo.Element} this
9228          */
9229         addClassOnClick : function(className){
9230             var dom = this.dom;
9231             this.on("mousedown", function(){
9232                 Roo.fly(dom, '_internal').addClass(className);
9233                 var d = Roo.get(document);
9234                 var fn = function(){
9235                     Roo.fly(dom, '_internal').removeClass(className);
9236                     d.removeListener("mouseup", fn);
9237                 };
9238                 d.on("mouseup", fn);
9239             });
9240             return this;
9241         },
9242
9243         /**
9244          * Stops the specified event from bubbling and optionally prevents the default action
9245          * @param {String} eventName
9246          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9247          * @return {Roo.Element} this
9248          */
9249         swallowEvent : function(eventName, preventDefault){
9250             var fn = function(e){
9251                 e.stopPropagation();
9252                 if(preventDefault){
9253                     e.preventDefault();
9254                 }
9255             };
9256             if(eventName instanceof Array){
9257                 for(var i = 0, len = eventName.length; i < len; i++){
9258                      this.on(eventName[i], fn);
9259                 }
9260                 return this;
9261             }
9262             this.on(eventName, fn);
9263             return this;
9264         },
9265
9266         /**
9267          * @private
9268          */
9269       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9270
9271         /**
9272          * Sizes this element to its parent element's dimensions performing
9273          * neccessary box adjustments.
9274          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9275          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9276          * @return {Roo.Element} this
9277          */
9278         fitToParent : function(monitorResize, targetParent) {
9279           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9280           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9281           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9282             return;
9283           }
9284           var p = Roo.get(targetParent || this.dom.parentNode);
9285           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9286           if (monitorResize === true) {
9287             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9288             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9289           }
9290           return this;
9291         },
9292
9293         /**
9294          * Gets the next sibling, skipping text nodes
9295          * @return {HTMLElement} The next sibling or null
9296          */
9297         getNextSibling : function(){
9298             var n = this.dom.nextSibling;
9299             while(n && n.nodeType != 1){
9300                 n = n.nextSibling;
9301             }
9302             return n;
9303         },
9304
9305         /**
9306          * Gets the previous sibling, skipping text nodes
9307          * @return {HTMLElement} The previous sibling or null
9308          */
9309         getPrevSibling : function(){
9310             var n = this.dom.previousSibling;
9311             while(n && n.nodeType != 1){
9312                 n = n.previousSibling;
9313             }
9314             return n;
9315         },
9316
9317
9318         /**
9319          * Appends the passed element(s) to this element
9320          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9321          * @return {Roo.Element} this
9322          */
9323         appendChild: function(el){
9324             el = Roo.get(el);
9325             el.appendTo(this);
9326             return this;
9327         },
9328
9329         /**
9330          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9331          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9332          * automatically generated with the specified attributes.
9333          * @param {HTMLElement} insertBefore (optional) a child element of this element
9334          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9335          * @return {Roo.Element} The new child element
9336          */
9337         createChild: function(config, insertBefore, returnDom){
9338             config = config || {tag:'div'};
9339             if(insertBefore){
9340                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9341             }
9342             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9343         },
9344
9345         /**
9346          * Appends this element to the passed element
9347          * @param {String/HTMLElement/Element} el The new parent element
9348          * @return {Roo.Element} this
9349          */
9350         appendTo: function(el){
9351             el = Roo.getDom(el);
9352             el.appendChild(this.dom);
9353             return this;
9354         },
9355
9356         /**
9357          * Inserts this element before the passed element in the DOM
9358          * @param {String/HTMLElement/Element} el The element to insert before
9359          * @return {Roo.Element} this
9360          */
9361         insertBefore: function(el){
9362             el = Roo.getDom(el);
9363             el.parentNode.insertBefore(this.dom, el);
9364             return this;
9365         },
9366
9367         /**
9368          * Inserts this element after the passed element in the DOM
9369          * @param {String/HTMLElement/Element} el The element to insert after
9370          * @return {Roo.Element} this
9371          */
9372         insertAfter: function(el){
9373             el = Roo.getDom(el);
9374             el.parentNode.insertBefore(this.dom, el.nextSibling);
9375             return this;
9376         },
9377
9378         /**
9379          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9380          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9381          * @return {Roo.Element} The new child
9382          */
9383         insertFirst: function(el, returnDom){
9384             el = el || {};
9385             if(typeof el == 'object' && !el.nodeType){ // dh config
9386                 return this.createChild(el, this.dom.firstChild, returnDom);
9387             }else{
9388                 el = Roo.getDom(el);
9389                 this.dom.insertBefore(el, this.dom.firstChild);
9390                 return !returnDom ? Roo.get(el) : el;
9391             }
9392         },
9393
9394         /**
9395          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9396          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9397          * @param {String} where (optional) 'before' or 'after' defaults to before
9398          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9399          * @return {Roo.Element} the inserted Element
9400          */
9401         insertSibling: function(el, where, returnDom){
9402             where = where ? where.toLowerCase() : 'before';
9403             el = el || {};
9404             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9405
9406             if(typeof el == 'object' && !el.nodeType){ // dh config
9407                 if(where == 'after' && !this.dom.nextSibling){
9408                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9409                 }else{
9410                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9411                 }
9412
9413             }else{
9414                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9415                             where == 'before' ? this.dom : this.dom.nextSibling);
9416                 if(!returnDom){
9417                     rt = Roo.get(rt);
9418                 }
9419             }
9420             return rt;
9421         },
9422
9423         /**
9424          * Creates and wraps this element with another element
9425          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9426          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9427          * @return {HTMLElement/Element} The newly created wrapper element
9428          */
9429         wrap: function(config, returnDom){
9430             if(!config){
9431                 config = {tag: "div"};
9432             }
9433             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9434             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9435             return newEl;
9436         },
9437
9438         /**
9439          * Replaces the passed element with this element
9440          * @param {String/HTMLElement/Element} el The element to replace
9441          * @return {Roo.Element} this
9442          */
9443         replace: function(el){
9444             el = Roo.get(el);
9445             this.insertBefore(el);
9446             el.remove();
9447             return this;
9448         },
9449
9450         /**
9451          * Inserts an html fragment into this element
9452          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9453          * @param {String} html The HTML fragment
9454          * @param {Boolean} returnEl True to return an Roo.Element
9455          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9456          */
9457         insertHtml : function(where, html, returnEl){
9458             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9459             return returnEl ? Roo.get(el) : el;
9460         },
9461
9462         /**
9463          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9464          * @param {Object} o The object with the attributes
9465          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9466          * @return {Roo.Element} this
9467          */
9468         set : function(o, useSet){
9469             var el = this.dom;
9470             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9471             for(var attr in o){
9472                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9473                 if(attr=="cls"){
9474                     el.className = o["cls"];
9475                 }else{
9476                     if(useSet) {
9477                         el.setAttribute(attr, o[attr]);
9478                     } else {
9479                         el[attr] = o[attr];
9480                     }
9481                 }
9482             }
9483             if(o.style){
9484                 Roo.DomHelper.applyStyles(el, o.style);
9485             }
9486             return this;
9487         },
9488
9489         /**
9490          * Convenience method for constructing a KeyMap
9491          * @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:
9492          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9493          * @param {Function} fn The function to call
9494          * @param {Object} scope (optional) The scope of the function
9495          * @return {Roo.KeyMap} The KeyMap created
9496          */
9497         addKeyListener : function(key, fn, scope){
9498             var config;
9499             if(typeof key != "object" || key instanceof Array){
9500                 config = {
9501                     key: key,
9502                     fn: fn,
9503                     scope: scope
9504                 };
9505             }else{
9506                 config = {
9507                     key : key.key,
9508                     shift : key.shift,
9509                     ctrl : key.ctrl,
9510                     alt : key.alt,
9511                     fn: fn,
9512                     scope: scope
9513                 };
9514             }
9515             return new Roo.KeyMap(this, config);
9516         },
9517
9518         /**
9519          * Creates a KeyMap for this element
9520          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9521          * @return {Roo.KeyMap} The KeyMap created
9522          */
9523         addKeyMap : function(config){
9524             return new Roo.KeyMap(this, config);
9525         },
9526
9527         /**
9528          * Returns true if this element is scrollable.
9529          * @return {Boolean}
9530          */
9531          isScrollable : function(){
9532             var dom = this.dom;
9533             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9534         },
9535
9536         /**
9537          * 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().
9538          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9539          * @param {Number} value The new scroll value
9540          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9541          * @return {Element} this
9542          */
9543
9544         scrollTo : function(side, value, animate){
9545             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9546             if(!animate || !A){
9547                 this.dom[prop] = value;
9548             }else{
9549                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9550                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9551             }
9552             return this;
9553         },
9554
9555         /**
9556          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9557          * within this element's scrollable range.
9558          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9559          * @param {Number} distance How far to scroll the element in pixels
9560          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9561          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9562          * was scrolled as far as it could go.
9563          */
9564          scroll : function(direction, distance, animate){
9565              if(!this.isScrollable()){
9566                  return;
9567              }
9568              var el = this.dom;
9569              var l = el.scrollLeft, t = el.scrollTop;
9570              var w = el.scrollWidth, h = el.scrollHeight;
9571              var cw = el.clientWidth, ch = el.clientHeight;
9572              direction = direction.toLowerCase();
9573              var scrolled = false;
9574              var a = this.preanim(arguments, 2);
9575              switch(direction){
9576                  case "l":
9577                  case "left":
9578                      if(w - l > cw){
9579                          var v = Math.min(l + distance, w-cw);
9580                          this.scrollTo("left", v, a);
9581                          scrolled = true;
9582                      }
9583                      break;
9584                 case "r":
9585                 case "right":
9586                      if(l > 0){
9587                          var v = Math.max(l - distance, 0);
9588                          this.scrollTo("left", v, a);
9589                          scrolled = true;
9590                      }
9591                      break;
9592                 case "t":
9593                 case "top":
9594                 case "up":
9595                      if(t > 0){
9596                          var v = Math.max(t - distance, 0);
9597                          this.scrollTo("top", v, a);
9598                          scrolled = true;
9599                      }
9600                      break;
9601                 case "b":
9602                 case "bottom":
9603                 case "down":
9604                      if(h - t > ch){
9605                          var v = Math.min(t + distance, h-ch);
9606                          this.scrollTo("top", v, a);
9607                          scrolled = true;
9608                      }
9609                      break;
9610              }
9611              return scrolled;
9612         },
9613
9614         /**
9615          * Translates the passed page coordinates into left/top css values for this element
9616          * @param {Number/Array} x The page x or an array containing [x, y]
9617          * @param {Number} y The page y
9618          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9619          */
9620         translatePoints : function(x, y){
9621             if(typeof x == 'object' || x instanceof Array){
9622                 y = x[1]; x = x[0];
9623             }
9624             var p = this.getStyle('position');
9625             var o = this.getXY();
9626
9627             var l = parseInt(this.getStyle('left'), 10);
9628             var t = parseInt(this.getStyle('top'), 10);
9629
9630             if(isNaN(l)){
9631                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9632             }
9633             if(isNaN(t)){
9634                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9635             }
9636
9637             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9638         },
9639
9640         /**
9641          * Returns the current scroll position of the element.
9642          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9643          */
9644         getScroll : function(){
9645             var d = this.dom, doc = document;
9646             if(d == doc || d == doc.body){
9647                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9648                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9649                 return {left: l, top: t};
9650             }else{
9651                 return {left: d.scrollLeft, top: d.scrollTop};
9652             }
9653         },
9654
9655         /**
9656          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9657          * are convert to standard 6 digit hex color.
9658          * @param {String} attr The css attribute
9659          * @param {String} defaultValue The default value to use when a valid color isn't found
9660          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9661          * YUI color anims.
9662          */
9663         getColor : function(attr, defaultValue, prefix){
9664             var v = this.getStyle(attr);
9665             if(!v || v == "transparent" || v == "inherit") {
9666                 return defaultValue;
9667             }
9668             var color = typeof prefix == "undefined" ? "#" : prefix;
9669             if(v.substr(0, 4) == "rgb("){
9670                 var rvs = v.slice(4, v.length -1).split(",");
9671                 for(var i = 0; i < 3; i++){
9672                     var h = parseInt(rvs[i]).toString(16);
9673                     if(h < 16){
9674                         h = "0" + h;
9675                     }
9676                     color += h;
9677                 }
9678             } else {
9679                 if(v.substr(0, 1) == "#"){
9680                     if(v.length == 4) {
9681                         for(var i = 1; i < 4; i++){
9682                             var c = v.charAt(i);
9683                             color +=  c + c;
9684                         }
9685                     }else if(v.length == 7){
9686                         color += v.substr(1);
9687                     }
9688                 }
9689             }
9690             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9691         },
9692
9693         /**
9694          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9695          * gradient background, rounded corners and a 4-way shadow.
9696          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9697          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9698          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9699          * @return {Roo.Element} this
9700          */
9701         boxWrap : function(cls){
9702             cls = cls || 'x-box';
9703             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9704             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9705             return el;
9706         },
9707
9708         /**
9709          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9710          * @param {String} namespace The namespace in which to look for the attribute
9711          * @param {String} name The attribute name
9712          * @return {String} The attribute value
9713          */
9714         getAttributeNS : Roo.isIE ? function(ns, name){
9715             var d = this.dom;
9716             var type = typeof d[ns+":"+name];
9717             if(type != 'undefined' && type != 'unknown'){
9718                 return d[ns+":"+name];
9719             }
9720             return d[name];
9721         } : function(ns, name){
9722             var d = this.dom;
9723             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9724         },
9725         
9726         
9727         /**
9728          * Sets or Returns the value the dom attribute value
9729          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9730          * @param {String} value (optional) The value to set the attribute to
9731          * @return {String} The attribute value
9732          */
9733         attr : function(name){
9734             if (arguments.length > 1) {
9735                 this.dom.setAttribute(name, arguments[1]);
9736                 return arguments[1];
9737             }
9738             if (typeof(name) == 'object') {
9739                 for(var i in name) {
9740                     this.attr(i, name[i]);
9741                 }
9742                 return name;
9743             }
9744             
9745             
9746             if (!this.dom.hasAttribute(name)) {
9747                 return undefined;
9748             }
9749             return this.dom.getAttribute(name);
9750         }
9751         
9752         
9753         
9754     };
9755
9756     var ep = El.prototype;
9757
9758     /**
9759      * Appends an event handler (Shorthand for addListener)
9760      * @param {String}   eventName     The type of event to append
9761      * @param {Function} fn        The method the event invokes
9762      * @param {Object} scope       (optional) The scope (this object) of the fn
9763      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9764      * @method
9765      */
9766     ep.on = ep.addListener;
9767         // backwards compat
9768     ep.mon = ep.addListener;
9769
9770     /**
9771      * Removes an event handler from this element (shorthand for removeListener)
9772      * @param {String} eventName the type of event to remove
9773      * @param {Function} fn the method the event invokes
9774      * @return {Roo.Element} this
9775      * @method
9776      */
9777     ep.un = ep.removeListener;
9778
9779     /**
9780      * true to automatically adjust width and height settings for box-model issues (default to true)
9781      */
9782     ep.autoBoxAdjust = true;
9783
9784     // private
9785     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9786
9787     // private
9788     El.addUnits = function(v, defaultUnit){
9789         if(v === "" || v == "auto"){
9790             return v;
9791         }
9792         if(v === undefined){
9793             return '';
9794         }
9795         if(typeof v == "number" || !El.unitPattern.test(v)){
9796             return v + (defaultUnit || 'px');
9797         }
9798         return v;
9799     };
9800
9801     // special markup used throughout Roo when box wrapping elements
9802     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>';
9803     /**
9804      * Visibility mode constant - Use visibility to hide element
9805      * @static
9806      * @type Number
9807      */
9808     El.VISIBILITY = 1;
9809     /**
9810      * Visibility mode constant - Use display to hide element
9811      * @static
9812      * @type Number
9813      */
9814     El.DISPLAY = 2;
9815
9816     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9817     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9818     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9819
9820
9821
9822     /**
9823      * @private
9824      */
9825     El.cache = {};
9826
9827     var docEl;
9828
9829     /**
9830      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9831      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9832      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9833      * @return {Element} The Element object
9834      * @static
9835      */
9836     El.get = function(el){
9837         var ex, elm, id;
9838         if(!el){ return null; }
9839         if(typeof el == "string"){ // element id
9840             if(!(elm = document.getElementById(el))){
9841                 return null;
9842             }
9843             if(ex = El.cache[el]){
9844                 ex.dom = elm;
9845             }else{
9846                 ex = El.cache[el] = new El(elm);
9847             }
9848             return ex;
9849         }else if(el.tagName){ // dom element
9850             if(!(id = el.id)){
9851                 id = Roo.id(el);
9852             }
9853             if(ex = El.cache[id]){
9854                 ex.dom = el;
9855             }else{
9856                 ex = El.cache[id] = new El(el);
9857             }
9858             return ex;
9859         }else if(el instanceof El){
9860             if(el != docEl){
9861                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9862                                                               // catch case where it hasn't been appended
9863                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9864             }
9865             return el;
9866         }else if(el.isComposite){
9867             return el;
9868         }else if(el instanceof Array){
9869             return El.select(el);
9870         }else if(el == document){
9871             // create a bogus element object representing the document object
9872             if(!docEl){
9873                 var f = function(){};
9874                 f.prototype = El.prototype;
9875                 docEl = new f();
9876                 docEl.dom = document;
9877             }
9878             return docEl;
9879         }
9880         return null;
9881     };
9882
9883     // private
9884     El.uncache = function(el){
9885         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9886             if(a[i]){
9887                 delete El.cache[a[i].id || a[i]];
9888             }
9889         }
9890     };
9891
9892     // private
9893     // Garbage collection - uncache elements/purge listeners on orphaned elements
9894     // so we don't hold a reference and cause the browser to retain them
9895     El.garbageCollect = function(){
9896         if(!Roo.enableGarbageCollector){
9897             clearInterval(El.collectorThread);
9898             return;
9899         }
9900         for(var eid in El.cache){
9901             var el = El.cache[eid], d = el.dom;
9902             // -------------------------------------------------------
9903             // Determining what is garbage:
9904             // -------------------------------------------------------
9905             // !d
9906             // dom node is null, definitely garbage
9907             // -------------------------------------------------------
9908             // !d.parentNode
9909             // no parentNode == direct orphan, definitely garbage
9910             // -------------------------------------------------------
9911             // !d.offsetParent && !document.getElementById(eid)
9912             // display none elements have no offsetParent so we will
9913             // also try to look it up by it's id. However, check
9914             // offsetParent first so we don't do unneeded lookups.
9915             // This enables collection of elements that are not orphans
9916             // directly, but somewhere up the line they have an orphan
9917             // parent.
9918             // -------------------------------------------------------
9919             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9920                 delete El.cache[eid];
9921                 if(d && Roo.enableListenerCollection){
9922                     E.purgeElement(d);
9923                 }
9924             }
9925         }
9926     }
9927     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9928
9929
9930     // dom is optional
9931     El.Flyweight = function(dom){
9932         this.dom = dom;
9933     };
9934     El.Flyweight.prototype = El.prototype;
9935
9936     El._flyweights = {};
9937     /**
9938      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9939      * the dom node can be overwritten by other code.
9940      * @param {String/HTMLElement} el The dom node or id
9941      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9942      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9943      * @static
9944      * @return {Element} The shared Element object
9945      */
9946     El.fly = function(el, named){
9947         named = named || '_global';
9948         el = Roo.getDom(el);
9949         if(!el){
9950             return null;
9951         }
9952         if(!El._flyweights[named]){
9953             El._flyweights[named] = new El.Flyweight();
9954         }
9955         El._flyweights[named].dom = el;
9956         return El._flyweights[named];
9957     };
9958
9959     /**
9960      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9961      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9962      * Shorthand of {@link Roo.Element#get}
9963      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9964      * @return {Element} The Element object
9965      * @member Roo
9966      * @method get
9967      */
9968     Roo.get = El.get;
9969     /**
9970      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9971      * the dom node can be overwritten by other code.
9972      * Shorthand of {@link Roo.Element#fly}
9973      * @param {String/HTMLElement} el The dom node or id
9974      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9975      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9976      * @static
9977      * @return {Element} The shared Element object
9978      * @member Roo
9979      * @method fly
9980      */
9981     Roo.fly = El.fly;
9982
9983     // speedy lookup for elements never to box adjust
9984     var noBoxAdjust = Roo.isStrict ? {
9985         select:1
9986     } : {
9987         input:1, select:1, textarea:1
9988     };
9989     if(Roo.isIE || Roo.isGecko){
9990         noBoxAdjust['button'] = 1;
9991     }
9992
9993
9994     Roo.EventManager.on(window, 'unload', function(){
9995         delete El.cache;
9996         delete El._flyweights;
9997     });
9998 })();
9999
10000
10001
10002
10003 if(Roo.DomQuery){
10004     Roo.Element.selectorFunction = Roo.DomQuery.select;
10005 }
10006
10007 Roo.Element.select = function(selector, unique, root){
10008     var els;
10009     if(typeof selector == "string"){
10010         els = Roo.Element.selectorFunction(selector, root);
10011     }else if(selector.length !== undefined){
10012         els = selector;
10013     }else{
10014         throw "Invalid selector";
10015     }
10016     if(unique === true){
10017         return new Roo.CompositeElement(els);
10018     }else{
10019         return new Roo.CompositeElementLite(els);
10020     }
10021 };
10022 /**
10023  * Selects elements based on the passed CSS selector to enable working on them as 1.
10024  * @param {String/Array} selector The CSS selector or an array of elements
10025  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10026  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10027  * @return {CompositeElementLite/CompositeElement}
10028  * @member Roo
10029  * @method select
10030  */
10031 Roo.select = Roo.Element.select;
10032
10033
10034
10035
10036
10037
10038
10039
10040
10041
10042
10043
10044
10045
10046 /*
10047  * Based on:
10048  * Ext JS Library 1.1.1
10049  * Copyright(c) 2006-2007, Ext JS, LLC.
10050  *
10051  * Originally Released Under LGPL - original licence link has changed is not relivant.
10052  *
10053  * Fork - LGPL
10054  * <script type="text/javascript">
10055  */
10056
10057
10058
10059 //Notifies Element that fx methods are available
10060 Roo.enableFx = true;
10061
10062 /**
10063  * @class Roo.Fx
10064  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10065  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10066  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10067  * Element effects to work.</p><br/>
10068  *
10069  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10070  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10071  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10072  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10073  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10074  * expected results and should be done with care.</p><br/>
10075  *
10076  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10077  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10078 <pre>
10079 Value  Description
10080 -----  -----------------------------
10081 tl     The top left corner
10082 t      The center of the top edge
10083 tr     The top right corner
10084 l      The center of the left edge
10085 r      The center of the right edge
10086 bl     The bottom left corner
10087 b      The center of the bottom edge
10088 br     The bottom right corner
10089 </pre>
10090  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10091  * below are common options that can be passed to any Fx method.</b>
10092  * @cfg {Function} callback A function called when the effect is finished
10093  * @cfg {Object} scope The scope of the effect function
10094  * @cfg {String} easing A valid Easing value for the effect
10095  * @cfg {String} afterCls A css class to apply after the effect
10096  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10097  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10098  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10099  * effects that end with the element being visually hidden, ignored otherwise)
10100  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10101  * a function which returns such a specification that will be applied to the Element after the effect finishes
10102  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10103  * @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
10104  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10105  */
10106 Roo.Fx = {
10107         /**
10108          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10109          * origin for the slide effect.  This function automatically handles wrapping the element with
10110          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10111          * Usage:
10112          *<pre><code>
10113 // default: slide the element in from the top
10114 el.slideIn();
10115
10116 // custom: slide the element in from the right with a 2-second duration
10117 el.slideIn('r', { duration: 2 });
10118
10119 // common config options shown with default values
10120 el.slideIn('t', {
10121     easing: 'easeOut',
10122     duration: .5
10123 });
10124 </code></pre>
10125          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10126          * @param {Object} options (optional) Object literal with any of the Fx config options
10127          * @return {Roo.Element} The Element
10128          */
10129     slideIn : function(anchor, o){
10130         var el = this.getFxEl();
10131         o = o || {};
10132
10133         el.queueFx(o, function(){
10134
10135             anchor = anchor || "t";
10136
10137             // fix display to visibility
10138             this.fixDisplay();
10139
10140             // restore values after effect
10141             var r = this.getFxRestore();
10142             var b = this.getBox();
10143             // fixed size for slide
10144             this.setSize(b);
10145
10146             // wrap if needed
10147             var wrap = this.fxWrap(r.pos, o, "hidden");
10148
10149             var st = this.dom.style;
10150             st.visibility = "visible";
10151             st.position = "absolute";
10152
10153             // clear out temp styles after slide and unwrap
10154             var after = function(){
10155                 el.fxUnwrap(wrap, r.pos, o);
10156                 st.width = r.width;
10157                 st.height = r.height;
10158                 el.afterFx(o);
10159             };
10160             // time to calc the positions
10161             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10162
10163             switch(anchor.toLowerCase()){
10164                 case "t":
10165                     wrap.setSize(b.width, 0);
10166                     st.left = st.bottom = "0";
10167                     a = {height: bh};
10168                 break;
10169                 case "l":
10170                     wrap.setSize(0, b.height);
10171                     st.right = st.top = "0";
10172                     a = {width: bw};
10173                 break;
10174                 case "r":
10175                     wrap.setSize(0, b.height);
10176                     wrap.setX(b.right);
10177                     st.left = st.top = "0";
10178                     a = {width: bw, points: pt};
10179                 break;
10180                 case "b":
10181                     wrap.setSize(b.width, 0);
10182                     wrap.setY(b.bottom);
10183                     st.left = st.top = "0";
10184                     a = {height: bh, points: pt};
10185                 break;
10186                 case "tl":
10187                     wrap.setSize(0, 0);
10188                     st.right = st.bottom = "0";
10189                     a = {width: bw, height: bh};
10190                 break;
10191                 case "bl":
10192                     wrap.setSize(0, 0);
10193                     wrap.setY(b.y+b.height);
10194                     st.right = st.top = "0";
10195                     a = {width: bw, height: bh, points: pt};
10196                 break;
10197                 case "br":
10198                     wrap.setSize(0, 0);
10199                     wrap.setXY([b.right, b.bottom]);
10200                     st.left = st.top = "0";
10201                     a = {width: bw, height: bh, points: pt};
10202                 break;
10203                 case "tr":
10204                     wrap.setSize(0, 0);
10205                     wrap.setX(b.x+b.width);
10206                     st.left = st.bottom = "0";
10207                     a = {width: bw, height: bh, points: pt};
10208                 break;
10209             }
10210             this.dom.style.visibility = "visible";
10211             wrap.show();
10212
10213             arguments.callee.anim = wrap.fxanim(a,
10214                 o,
10215                 'motion',
10216                 .5,
10217                 'easeOut', after);
10218         });
10219         return this;
10220     },
10221     
10222         /**
10223          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10224          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10225          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10226          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10227          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10228          * Usage:
10229          *<pre><code>
10230 // default: slide the element out to the top
10231 el.slideOut();
10232
10233 // custom: slide the element out to the right with a 2-second duration
10234 el.slideOut('r', { duration: 2 });
10235
10236 // common config options shown with default values
10237 el.slideOut('t', {
10238     easing: 'easeOut',
10239     duration: .5,
10240     remove: false,
10241     useDisplay: false
10242 });
10243 </code></pre>
10244          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10245          * @param {Object} options (optional) Object literal with any of the Fx config options
10246          * @return {Roo.Element} The Element
10247          */
10248     slideOut : function(anchor, o){
10249         var el = this.getFxEl();
10250         o = o || {};
10251
10252         el.queueFx(o, function(){
10253
10254             anchor = anchor || "t";
10255
10256             // restore values after effect
10257             var r = this.getFxRestore();
10258             
10259             var b = this.getBox();
10260             // fixed size for slide
10261             this.setSize(b);
10262
10263             // wrap if needed
10264             var wrap = this.fxWrap(r.pos, o, "visible");
10265
10266             var st = this.dom.style;
10267             st.visibility = "visible";
10268             st.position = "absolute";
10269
10270             wrap.setSize(b);
10271
10272             var after = function(){
10273                 if(o.useDisplay){
10274                     el.setDisplayed(false);
10275                 }else{
10276                     el.hide();
10277                 }
10278
10279                 el.fxUnwrap(wrap, r.pos, o);
10280
10281                 st.width = r.width;
10282                 st.height = r.height;
10283
10284                 el.afterFx(o);
10285             };
10286
10287             var a, zero = {to: 0};
10288             switch(anchor.toLowerCase()){
10289                 case "t":
10290                     st.left = st.bottom = "0";
10291                     a = {height: zero};
10292                 break;
10293                 case "l":
10294                     st.right = st.top = "0";
10295                     a = {width: zero};
10296                 break;
10297                 case "r":
10298                     st.left = st.top = "0";
10299                     a = {width: zero, points: {to:[b.right, b.y]}};
10300                 break;
10301                 case "b":
10302                     st.left = st.top = "0";
10303                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10304                 break;
10305                 case "tl":
10306                     st.right = st.bottom = "0";
10307                     a = {width: zero, height: zero};
10308                 break;
10309                 case "bl":
10310                     st.right = st.top = "0";
10311                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10312                 break;
10313                 case "br":
10314                     st.left = st.top = "0";
10315                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10316                 break;
10317                 case "tr":
10318                     st.left = st.bottom = "0";
10319                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10320                 break;
10321             }
10322
10323             arguments.callee.anim = wrap.fxanim(a,
10324                 o,
10325                 'motion',
10326                 .5,
10327                 "easeOut", after);
10328         });
10329         return this;
10330     },
10331
10332         /**
10333          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10334          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10335          * The element must be removed from the DOM using the 'remove' config option if desired.
10336          * Usage:
10337          *<pre><code>
10338 // default
10339 el.puff();
10340
10341 // common config options shown with default values
10342 el.puff({
10343     easing: 'easeOut',
10344     duration: .5,
10345     remove: false,
10346     useDisplay: false
10347 });
10348 </code></pre>
10349          * @param {Object} options (optional) Object literal with any of the Fx config options
10350          * @return {Roo.Element} The Element
10351          */
10352     puff : function(o){
10353         var el = this.getFxEl();
10354         o = o || {};
10355
10356         el.queueFx(o, function(){
10357             this.clearOpacity();
10358             this.show();
10359
10360             // restore values after effect
10361             var r = this.getFxRestore();
10362             var st = this.dom.style;
10363
10364             var after = function(){
10365                 if(o.useDisplay){
10366                     el.setDisplayed(false);
10367                 }else{
10368                     el.hide();
10369                 }
10370
10371                 el.clearOpacity();
10372
10373                 el.setPositioning(r.pos);
10374                 st.width = r.width;
10375                 st.height = r.height;
10376                 st.fontSize = '';
10377                 el.afterFx(o);
10378             };
10379
10380             var width = this.getWidth();
10381             var height = this.getHeight();
10382
10383             arguments.callee.anim = this.fxanim({
10384                     width : {to: this.adjustWidth(width * 2)},
10385                     height : {to: this.adjustHeight(height * 2)},
10386                     points : {by: [-(width * .5), -(height * .5)]},
10387                     opacity : {to: 0},
10388                     fontSize: {to:200, unit: "%"}
10389                 },
10390                 o,
10391                 'motion',
10392                 .5,
10393                 "easeOut", after);
10394         });
10395         return this;
10396     },
10397
10398         /**
10399          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10400          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10401          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10402          * Usage:
10403          *<pre><code>
10404 // default
10405 el.switchOff();
10406
10407 // all config options shown with default values
10408 el.switchOff({
10409     easing: 'easeIn',
10410     duration: .3,
10411     remove: false,
10412     useDisplay: false
10413 });
10414 </code></pre>
10415          * @param {Object} options (optional) Object literal with any of the Fx config options
10416          * @return {Roo.Element} The Element
10417          */
10418     switchOff : function(o){
10419         var el = this.getFxEl();
10420         o = o || {};
10421
10422         el.queueFx(o, function(){
10423             this.clearOpacity();
10424             this.clip();
10425
10426             // restore values after effect
10427             var r = this.getFxRestore();
10428             var st = this.dom.style;
10429
10430             var after = function(){
10431                 if(o.useDisplay){
10432                     el.setDisplayed(false);
10433                 }else{
10434                     el.hide();
10435                 }
10436
10437                 el.clearOpacity();
10438                 el.setPositioning(r.pos);
10439                 st.width = r.width;
10440                 st.height = r.height;
10441
10442                 el.afterFx(o);
10443             };
10444
10445             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10446                 this.clearOpacity();
10447                 (function(){
10448                     this.fxanim({
10449                         height:{to:1},
10450                         points:{by:[0, this.getHeight() * .5]}
10451                     }, o, 'motion', 0.3, 'easeIn', after);
10452                 }).defer(100, this);
10453             });
10454         });
10455         return this;
10456     },
10457
10458     /**
10459      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10460      * changed using the "attr" config option) and then fading back to the original color. If no original
10461      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10462      * Usage:
10463 <pre><code>
10464 // default: highlight background to yellow
10465 el.highlight();
10466
10467 // custom: highlight foreground text to blue for 2 seconds
10468 el.highlight("0000ff", { attr: 'color', duration: 2 });
10469
10470 // common config options shown with default values
10471 el.highlight("ffff9c", {
10472     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10473     endColor: (current color) or "ffffff",
10474     easing: 'easeIn',
10475     duration: 1
10476 });
10477 </code></pre>
10478      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10479      * @param {Object} options (optional) Object literal with any of the Fx config options
10480      * @return {Roo.Element} The Element
10481      */ 
10482     highlight : function(color, o){
10483         var el = this.getFxEl();
10484         o = o || {};
10485
10486         el.queueFx(o, function(){
10487             color = color || "ffff9c";
10488             attr = o.attr || "backgroundColor";
10489
10490             this.clearOpacity();
10491             this.show();
10492
10493             var origColor = this.getColor(attr);
10494             var restoreColor = this.dom.style[attr];
10495             endColor = (o.endColor || origColor) || "ffffff";
10496
10497             var after = function(){
10498                 el.dom.style[attr] = restoreColor;
10499                 el.afterFx(o);
10500             };
10501
10502             var a = {};
10503             a[attr] = {from: color, to: endColor};
10504             arguments.callee.anim = this.fxanim(a,
10505                 o,
10506                 'color',
10507                 1,
10508                 'easeIn', after);
10509         });
10510         return this;
10511     },
10512
10513    /**
10514     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10515     * Usage:
10516 <pre><code>
10517 // default: a single light blue ripple
10518 el.frame();
10519
10520 // custom: 3 red ripples lasting 3 seconds total
10521 el.frame("ff0000", 3, { duration: 3 });
10522
10523 // common config options shown with default values
10524 el.frame("C3DAF9", 1, {
10525     duration: 1 //duration of entire animation (not each individual ripple)
10526     // Note: Easing is not configurable and will be ignored if included
10527 });
10528 </code></pre>
10529     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10530     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10531     * @param {Object} options (optional) Object literal with any of the Fx config options
10532     * @return {Roo.Element} The Element
10533     */
10534     frame : function(color, count, o){
10535         var el = this.getFxEl();
10536         o = o || {};
10537
10538         el.queueFx(o, function(){
10539             color = color || "#C3DAF9";
10540             if(color.length == 6){
10541                 color = "#" + color;
10542             }
10543             count = count || 1;
10544             duration = o.duration || 1;
10545             this.show();
10546
10547             var b = this.getBox();
10548             var animFn = function(){
10549                 var proxy = this.createProxy({
10550
10551                      style:{
10552                         visbility:"hidden",
10553                         position:"absolute",
10554                         "z-index":"35000", // yee haw
10555                         border:"0px solid " + color
10556                      }
10557                   });
10558                 var scale = Roo.isBorderBox ? 2 : 1;
10559                 proxy.animate({
10560                     top:{from:b.y, to:b.y - 20},
10561                     left:{from:b.x, to:b.x - 20},
10562                     borderWidth:{from:0, to:10},
10563                     opacity:{from:1, to:0},
10564                     height:{from:b.height, to:(b.height + (20*scale))},
10565                     width:{from:b.width, to:(b.width + (20*scale))}
10566                 }, duration, function(){
10567                     proxy.remove();
10568                 });
10569                 if(--count > 0){
10570                      animFn.defer((duration/2)*1000, this);
10571                 }else{
10572                     el.afterFx(o);
10573                 }
10574             };
10575             animFn.call(this);
10576         });
10577         return this;
10578     },
10579
10580    /**
10581     * Creates a pause before any subsequent queued effects begin.  If there are
10582     * no effects queued after the pause it will have no effect.
10583     * Usage:
10584 <pre><code>
10585 el.pause(1);
10586 </code></pre>
10587     * @param {Number} seconds The length of time to pause (in seconds)
10588     * @return {Roo.Element} The Element
10589     */
10590     pause : function(seconds){
10591         var el = this.getFxEl();
10592         var o = {};
10593
10594         el.queueFx(o, function(){
10595             setTimeout(function(){
10596                 el.afterFx(o);
10597             }, seconds * 1000);
10598         });
10599         return this;
10600     },
10601
10602    /**
10603     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10604     * using the "endOpacity" config option.
10605     * Usage:
10606 <pre><code>
10607 // default: fade in from opacity 0 to 100%
10608 el.fadeIn();
10609
10610 // custom: fade in from opacity 0 to 75% over 2 seconds
10611 el.fadeIn({ endOpacity: .75, duration: 2});
10612
10613 // common config options shown with default values
10614 el.fadeIn({
10615     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10616     easing: 'easeOut',
10617     duration: .5
10618 });
10619 </code></pre>
10620     * @param {Object} options (optional) Object literal with any of the Fx config options
10621     * @return {Roo.Element} The Element
10622     */
10623     fadeIn : function(o){
10624         var el = this.getFxEl();
10625         o = o || {};
10626         el.queueFx(o, function(){
10627             this.setOpacity(0);
10628             this.fixDisplay();
10629             this.dom.style.visibility = 'visible';
10630             var to = o.endOpacity || 1;
10631             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10632                 o, null, .5, "easeOut", function(){
10633                 if(to == 1){
10634                     this.clearOpacity();
10635                 }
10636                 el.afterFx(o);
10637             });
10638         });
10639         return this;
10640     },
10641
10642    /**
10643     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10644     * using the "endOpacity" config option.
10645     * Usage:
10646 <pre><code>
10647 // default: fade out from the element's current opacity to 0
10648 el.fadeOut();
10649
10650 // custom: fade out from the element's current opacity to 25% over 2 seconds
10651 el.fadeOut({ endOpacity: .25, duration: 2});
10652
10653 // common config options shown with default values
10654 el.fadeOut({
10655     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10656     easing: 'easeOut',
10657     duration: .5
10658     remove: false,
10659     useDisplay: false
10660 });
10661 </code></pre>
10662     * @param {Object} options (optional) Object literal with any of the Fx config options
10663     * @return {Roo.Element} The Element
10664     */
10665     fadeOut : function(o){
10666         var el = this.getFxEl();
10667         o = o || {};
10668         el.queueFx(o, function(){
10669             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10670                 o, null, .5, "easeOut", function(){
10671                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10672                      this.dom.style.display = "none";
10673                 }else{
10674                      this.dom.style.visibility = "hidden";
10675                 }
10676                 this.clearOpacity();
10677                 el.afterFx(o);
10678             });
10679         });
10680         return this;
10681     },
10682
10683    /**
10684     * Animates the transition of an element's dimensions from a starting height/width
10685     * to an ending height/width.
10686     * Usage:
10687 <pre><code>
10688 // change height and width to 100x100 pixels
10689 el.scale(100, 100);
10690
10691 // common config options shown with default values.  The height and width will default to
10692 // the element's existing values if passed as null.
10693 el.scale(
10694     [element's width],
10695     [element's height], {
10696     easing: 'easeOut',
10697     duration: .35
10698 });
10699 </code></pre>
10700     * @param {Number} width  The new width (pass undefined to keep the original width)
10701     * @param {Number} height  The new height (pass undefined to keep the original height)
10702     * @param {Object} options (optional) Object literal with any of the Fx config options
10703     * @return {Roo.Element} The Element
10704     */
10705     scale : function(w, h, o){
10706         this.shift(Roo.apply({}, o, {
10707             width: w,
10708             height: h
10709         }));
10710         return this;
10711     },
10712
10713    /**
10714     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10715     * Any of these properties not specified in the config object will not be changed.  This effect 
10716     * requires that at least one new dimension, position or opacity setting must be passed in on
10717     * the config object in order for the function to have any effect.
10718     * Usage:
10719 <pre><code>
10720 // slide the element horizontally to x position 200 while changing the height and opacity
10721 el.shift({ x: 200, height: 50, opacity: .8 });
10722
10723 // common config options shown with default values.
10724 el.shift({
10725     width: [element's width],
10726     height: [element's height],
10727     x: [element's x position],
10728     y: [element's y position],
10729     opacity: [element's opacity],
10730     easing: 'easeOut',
10731     duration: .35
10732 });
10733 </code></pre>
10734     * @param {Object} options  Object literal with any of the Fx config options
10735     * @return {Roo.Element} The Element
10736     */
10737     shift : function(o){
10738         var el = this.getFxEl();
10739         o = o || {};
10740         el.queueFx(o, function(){
10741             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10742             if(w !== undefined){
10743                 a.width = {to: this.adjustWidth(w)};
10744             }
10745             if(h !== undefined){
10746                 a.height = {to: this.adjustHeight(h)};
10747             }
10748             if(x !== undefined || y !== undefined){
10749                 a.points = {to: [
10750                     x !== undefined ? x : this.getX(),
10751                     y !== undefined ? y : this.getY()
10752                 ]};
10753             }
10754             if(op !== undefined){
10755                 a.opacity = {to: op};
10756             }
10757             if(o.xy !== undefined){
10758                 a.points = {to: o.xy};
10759             }
10760             arguments.callee.anim = this.fxanim(a,
10761                 o, 'motion', .35, "easeOut", function(){
10762                 el.afterFx(o);
10763             });
10764         });
10765         return this;
10766     },
10767
10768         /**
10769          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10770          * ending point of the effect.
10771          * Usage:
10772          *<pre><code>
10773 // default: slide the element downward while fading out
10774 el.ghost();
10775
10776 // custom: slide the element out to the right with a 2-second duration
10777 el.ghost('r', { duration: 2 });
10778
10779 // common config options shown with default values
10780 el.ghost('b', {
10781     easing: 'easeOut',
10782     duration: .5
10783     remove: false,
10784     useDisplay: false
10785 });
10786 </code></pre>
10787          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10788          * @param {Object} options (optional) Object literal with any of the Fx config options
10789          * @return {Roo.Element} The Element
10790          */
10791     ghost : function(anchor, o){
10792         var el = this.getFxEl();
10793         o = o || {};
10794
10795         el.queueFx(o, function(){
10796             anchor = anchor || "b";
10797
10798             // restore values after effect
10799             var r = this.getFxRestore();
10800             var w = this.getWidth(),
10801                 h = this.getHeight();
10802
10803             var st = this.dom.style;
10804
10805             var after = function(){
10806                 if(o.useDisplay){
10807                     el.setDisplayed(false);
10808                 }else{
10809                     el.hide();
10810                 }
10811
10812                 el.clearOpacity();
10813                 el.setPositioning(r.pos);
10814                 st.width = r.width;
10815                 st.height = r.height;
10816
10817                 el.afterFx(o);
10818             };
10819
10820             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10821             switch(anchor.toLowerCase()){
10822                 case "t":
10823                     pt.by = [0, -h];
10824                 break;
10825                 case "l":
10826                     pt.by = [-w, 0];
10827                 break;
10828                 case "r":
10829                     pt.by = [w, 0];
10830                 break;
10831                 case "b":
10832                     pt.by = [0, h];
10833                 break;
10834                 case "tl":
10835                     pt.by = [-w, -h];
10836                 break;
10837                 case "bl":
10838                     pt.by = [-w, h];
10839                 break;
10840                 case "br":
10841                     pt.by = [w, h];
10842                 break;
10843                 case "tr":
10844                     pt.by = [w, -h];
10845                 break;
10846             }
10847
10848             arguments.callee.anim = this.fxanim(a,
10849                 o,
10850                 'motion',
10851                 .5,
10852                 "easeOut", after);
10853         });
10854         return this;
10855     },
10856
10857         /**
10858          * Ensures that all effects queued after syncFx is called on the element are
10859          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10860          * @return {Roo.Element} The Element
10861          */
10862     syncFx : function(){
10863         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10864             block : false,
10865             concurrent : true,
10866             stopFx : false
10867         });
10868         return this;
10869     },
10870
10871         /**
10872          * Ensures that all effects queued after sequenceFx is called on the element are
10873          * run in sequence.  This is the opposite of {@link #syncFx}.
10874          * @return {Roo.Element} The Element
10875          */
10876     sequenceFx : function(){
10877         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10878             block : false,
10879             concurrent : false,
10880             stopFx : false
10881         });
10882         return this;
10883     },
10884
10885         /* @private */
10886     nextFx : function(){
10887         var ef = this.fxQueue[0];
10888         if(ef){
10889             ef.call(this);
10890         }
10891     },
10892
10893         /**
10894          * Returns true if the element has any effects actively running or queued, else returns false.
10895          * @return {Boolean} True if element has active effects, else false
10896          */
10897     hasActiveFx : function(){
10898         return this.fxQueue && this.fxQueue[0];
10899     },
10900
10901         /**
10902          * Stops any running effects and clears the element's internal effects queue if it contains
10903          * any additional effects that haven't started yet.
10904          * @return {Roo.Element} The Element
10905          */
10906     stopFx : function(){
10907         if(this.hasActiveFx()){
10908             var cur = this.fxQueue[0];
10909             if(cur && cur.anim && cur.anim.isAnimated()){
10910                 this.fxQueue = [cur]; // clear out others
10911                 cur.anim.stop(true);
10912             }
10913         }
10914         return this;
10915     },
10916
10917         /* @private */
10918     beforeFx : function(o){
10919         if(this.hasActiveFx() && !o.concurrent){
10920            if(o.stopFx){
10921                this.stopFx();
10922                return true;
10923            }
10924            return false;
10925         }
10926         return true;
10927     },
10928
10929         /**
10930          * Returns true if the element is currently blocking so that no other effect can be queued
10931          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10932          * used to ensure that an effect initiated by a user action runs to completion prior to the
10933          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10934          * @return {Boolean} True if blocking, else false
10935          */
10936     hasFxBlock : function(){
10937         var q = this.fxQueue;
10938         return q && q[0] && q[0].block;
10939     },
10940
10941         /* @private */
10942     queueFx : function(o, fn){
10943         if(!this.fxQueue){
10944             this.fxQueue = [];
10945         }
10946         if(!this.hasFxBlock()){
10947             Roo.applyIf(o, this.fxDefaults);
10948             if(!o.concurrent){
10949                 var run = this.beforeFx(o);
10950                 fn.block = o.block;
10951                 this.fxQueue.push(fn);
10952                 if(run){
10953                     this.nextFx();
10954                 }
10955             }else{
10956                 fn.call(this);
10957             }
10958         }
10959         return this;
10960     },
10961
10962         /* @private */
10963     fxWrap : function(pos, o, vis){
10964         var wrap;
10965         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10966             var wrapXY;
10967             if(o.fixPosition){
10968                 wrapXY = this.getXY();
10969             }
10970             var div = document.createElement("div");
10971             div.style.visibility = vis;
10972             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10973             wrap.setPositioning(pos);
10974             if(wrap.getStyle("position") == "static"){
10975                 wrap.position("relative");
10976             }
10977             this.clearPositioning('auto');
10978             wrap.clip();
10979             wrap.dom.appendChild(this.dom);
10980             if(wrapXY){
10981                 wrap.setXY(wrapXY);
10982             }
10983         }
10984         return wrap;
10985     },
10986
10987         /* @private */
10988     fxUnwrap : function(wrap, pos, o){
10989         this.clearPositioning();
10990         this.setPositioning(pos);
10991         if(!o.wrap){
10992             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10993             wrap.remove();
10994         }
10995     },
10996
10997         /* @private */
10998     getFxRestore : function(){
10999         var st = this.dom.style;
11000         return {pos: this.getPositioning(), width: st.width, height : st.height};
11001     },
11002
11003         /* @private */
11004     afterFx : function(o){
11005         if(o.afterStyle){
11006             this.applyStyles(o.afterStyle);
11007         }
11008         if(o.afterCls){
11009             this.addClass(o.afterCls);
11010         }
11011         if(o.remove === true){
11012             this.remove();
11013         }
11014         Roo.callback(o.callback, o.scope, [this]);
11015         if(!o.concurrent){
11016             this.fxQueue.shift();
11017             this.nextFx();
11018         }
11019     },
11020
11021         /* @private */
11022     getFxEl : function(){ // support for composite element fx
11023         return Roo.get(this.dom);
11024     },
11025
11026         /* @private */
11027     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11028         animType = animType || 'run';
11029         opt = opt || {};
11030         var anim = Roo.lib.Anim[animType](
11031             this.dom, args,
11032             (opt.duration || defaultDur) || .35,
11033             (opt.easing || defaultEase) || 'easeOut',
11034             function(){
11035                 Roo.callback(cb, this);
11036             },
11037             this
11038         );
11039         opt.anim = anim;
11040         return anim;
11041     }
11042 };
11043
11044 // backwords compat
11045 Roo.Fx.resize = Roo.Fx.scale;
11046
11047 //When included, Roo.Fx is automatically applied to Element so that all basic
11048 //effects are available directly via the Element API
11049 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11050  * Based on:
11051  * Ext JS Library 1.1.1
11052  * Copyright(c) 2006-2007, Ext JS, LLC.
11053  *
11054  * Originally Released Under LGPL - original licence link has changed is not relivant.
11055  *
11056  * Fork - LGPL
11057  * <script type="text/javascript">
11058  */
11059
11060
11061 /**
11062  * @class Roo.CompositeElement
11063  * Standard composite class. Creates a Roo.Element for every element in the collection.
11064  * <br><br>
11065  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11066  * actions will be performed on all the elements in this collection.</b>
11067  * <br><br>
11068  * All methods return <i>this</i> and can be chained.
11069  <pre><code>
11070  var els = Roo.select("#some-el div.some-class", true);
11071  // or select directly from an existing element
11072  var el = Roo.get('some-el');
11073  el.select('div.some-class', true);
11074
11075  els.setWidth(100); // all elements become 100 width
11076  els.hide(true); // all elements fade out and hide
11077  // or
11078  els.setWidth(100).hide(true);
11079  </code></pre>
11080  */
11081 Roo.CompositeElement = function(els){
11082     this.elements = [];
11083     this.addElements(els);
11084 };
11085 Roo.CompositeElement.prototype = {
11086     isComposite: true,
11087     addElements : function(els){
11088         if(!els) {
11089             return this;
11090         }
11091         if(typeof els == "string"){
11092             els = Roo.Element.selectorFunction(els);
11093         }
11094         var yels = this.elements;
11095         var index = yels.length-1;
11096         for(var i = 0, len = els.length; i < len; i++) {
11097                 yels[++index] = Roo.get(els[i]);
11098         }
11099         return this;
11100     },
11101
11102     /**
11103     * Clears this composite and adds the elements returned by the passed selector.
11104     * @param {String/Array} els A string CSS selector, an array of elements or an element
11105     * @return {CompositeElement} this
11106     */
11107     fill : function(els){
11108         this.elements = [];
11109         this.add(els);
11110         return this;
11111     },
11112
11113     /**
11114     * Filters this composite to only elements that match the passed selector.
11115     * @param {String} selector A string CSS selector
11116     * @param {Boolean} inverse return inverse filter (not matches)
11117     * @return {CompositeElement} this
11118     */
11119     filter : function(selector, inverse){
11120         var els = [];
11121         inverse = inverse || false;
11122         this.each(function(el){
11123             var match = inverse ? !el.is(selector) : el.is(selector);
11124             if(match){
11125                 els[els.length] = el.dom;
11126             }
11127         });
11128         this.fill(els);
11129         return this;
11130     },
11131
11132     invoke : function(fn, args){
11133         var els = this.elements;
11134         for(var i = 0, len = els.length; i < len; i++) {
11135                 Roo.Element.prototype[fn].apply(els[i], args);
11136         }
11137         return this;
11138     },
11139     /**
11140     * Adds elements to this composite.
11141     * @param {String/Array} els A string CSS selector, an array of elements or an element
11142     * @return {CompositeElement} this
11143     */
11144     add : function(els){
11145         if(typeof els == "string"){
11146             this.addElements(Roo.Element.selectorFunction(els));
11147         }else if(els.length !== undefined){
11148             this.addElements(els);
11149         }else{
11150             this.addElements([els]);
11151         }
11152         return this;
11153     },
11154     /**
11155     * Calls the passed function passing (el, this, index) for each element in this composite.
11156     * @param {Function} fn The function to call
11157     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11158     * @return {CompositeElement} this
11159     */
11160     each : function(fn, scope){
11161         var els = this.elements;
11162         for(var i = 0, len = els.length; i < len; i++){
11163             if(fn.call(scope || els[i], els[i], this, i) === false) {
11164                 break;
11165             }
11166         }
11167         return this;
11168     },
11169
11170     /**
11171      * Returns the Element object at the specified index
11172      * @param {Number} index
11173      * @return {Roo.Element}
11174      */
11175     item : function(index){
11176         return this.elements[index] || null;
11177     },
11178
11179     /**
11180      * Returns the first Element
11181      * @return {Roo.Element}
11182      */
11183     first : function(){
11184         return this.item(0);
11185     },
11186
11187     /**
11188      * Returns the last Element
11189      * @return {Roo.Element}
11190      */
11191     last : function(){
11192         return this.item(this.elements.length-1);
11193     },
11194
11195     /**
11196      * Returns the number of elements in this composite
11197      * @return Number
11198      */
11199     getCount : function(){
11200         return this.elements.length;
11201     },
11202
11203     /**
11204      * Returns true if this composite contains the passed element
11205      * @return Boolean
11206      */
11207     contains : function(el){
11208         return this.indexOf(el) !== -1;
11209     },
11210
11211     /**
11212      * Returns true if this composite contains the passed element
11213      * @return Boolean
11214      */
11215     indexOf : function(el){
11216         return this.elements.indexOf(Roo.get(el));
11217     },
11218
11219
11220     /**
11221     * Removes the specified element(s).
11222     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11223     * or an array of any of those.
11224     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11225     * @return {CompositeElement} this
11226     */
11227     removeElement : function(el, removeDom){
11228         if(el instanceof Array){
11229             for(var i = 0, len = el.length; i < len; i++){
11230                 this.removeElement(el[i]);
11231             }
11232             return this;
11233         }
11234         var index = typeof el == 'number' ? el : this.indexOf(el);
11235         if(index !== -1){
11236             if(removeDom){
11237                 var d = this.elements[index];
11238                 if(d.dom){
11239                     d.remove();
11240                 }else{
11241                     d.parentNode.removeChild(d);
11242                 }
11243             }
11244             this.elements.splice(index, 1);
11245         }
11246         return this;
11247     },
11248
11249     /**
11250     * Replaces the specified element with the passed element.
11251     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11252     * to replace.
11253     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11254     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11255     * @return {CompositeElement} this
11256     */
11257     replaceElement : function(el, replacement, domReplace){
11258         var index = typeof el == 'number' ? el : this.indexOf(el);
11259         if(index !== -1){
11260             if(domReplace){
11261                 this.elements[index].replaceWith(replacement);
11262             }else{
11263                 this.elements.splice(index, 1, Roo.get(replacement))
11264             }
11265         }
11266         return this;
11267     },
11268
11269     /**
11270      * Removes all elements.
11271      */
11272     clear : function(){
11273         this.elements = [];
11274     }
11275 };
11276 (function(){
11277     Roo.CompositeElement.createCall = function(proto, fnName){
11278         if(!proto[fnName]){
11279             proto[fnName] = function(){
11280                 return this.invoke(fnName, arguments);
11281             };
11282         }
11283     };
11284     for(var fnName in Roo.Element.prototype){
11285         if(typeof Roo.Element.prototype[fnName] == "function"){
11286             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11287         }
11288     };
11289 })();
11290 /*
11291  * Based on:
11292  * Ext JS Library 1.1.1
11293  * Copyright(c) 2006-2007, Ext JS, LLC.
11294  *
11295  * Originally Released Under LGPL - original licence link has changed is not relivant.
11296  *
11297  * Fork - LGPL
11298  * <script type="text/javascript">
11299  */
11300
11301 /**
11302  * @class Roo.CompositeElementLite
11303  * @extends Roo.CompositeElement
11304  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11305  <pre><code>
11306  var els = Roo.select("#some-el div.some-class");
11307  // or select directly from an existing element
11308  var el = Roo.get('some-el');
11309  el.select('div.some-class');
11310
11311  els.setWidth(100); // all elements become 100 width
11312  els.hide(true); // all elements fade out and hide
11313  // or
11314  els.setWidth(100).hide(true);
11315  </code></pre><br><br>
11316  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11317  * actions will be performed on all the elements in this collection.</b>
11318  */
11319 Roo.CompositeElementLite = function(els){
11320     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11321     this.el = new Roo.Element.Flyweight();
11322 };
11323 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11324     addElements : function(els){
11325         if(els){
11326             if(els instanceof Array){
11327                 this.elements = this.elements.concat(els);
11328             }else{
11329                 var yels = this.elements;
11330                 var index = yels.length-1;
11331                 for(var i = 0, len = els.length; i < len; i++) {
11332                     yels[++index] = els[i];
11333                 }
11334             }
11335         }
11336         return this;
11337     },
11338     invoke : function(fn, args){
11339         var els = this.elements;
11340         var el = this.el;
11341         for(var i = 0, len = els.length; i < len; i++) {
11342             el.dom = els[i];
11343                 Roo.Element.prototype[fn].apply(el, args);
11344         }
11345         return this;
11346     },
11347     /**
11348      * Returns a flyweight Element of the dom element object at the specified index
11349      * @param {Number} index
11350      * @return {Roo.Element}
11351      */
11352     item : function(index){
11353         if(!this.elements[index]){
11354             return null;
11355         }
11356         this.el.dom = this.elements[index];
11357         return this.el;
11358     },
11359
11360     // fixes scope with flyweight
11361     addListener : function(eventName, handler, scope, opt){
11362         var els = this.elements;
11363         for(var i = 0, len = els.length; i < len; i++) {
11364             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11365         }
11366         return this;
11367     },
11368
11369     /**
11370     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11371     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11372     * a reference to the dom node, use el.dom.</b>
11373     * @param {Function} fn The function to call
11374     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11375     * @return {CompositeElement} this
11376     */
11377     each : function(fn, scope){
11378         var els = this.elements;
11379         var el = this.el;
11380         for(var i = 0, len = els.length; i < len; i++){
11381             el.dom = els[i];
11382                 if(fn.call(scope || el, el, this, i) === false){
11383                 break;
11384             }
11385         }
11386         return this;
11387     },
11388
11389     indexOf : function(el){
11390         return this.elements.indexOf(Roo.getDom(el));
11391     },
11392
11393     replaceElement : function(el, replacement, domReplace){
11394         var index = typeof el == 'number' ? el : this.indexOf(el);
11395         if(index !== -1){
11396             replacement = Roo.getDom(replacement);
11397             if(domReplace){
11398                 var d = this.elements[index];
11399                 d.parentNode.insertBefore(replacement, d);
11400                 d.parentNode.removeChild(d);
11401             }
11402             this.elements.splice(index, 1, replacement);
11403         }
11404         return this;
11405     }
11406 });
11407 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11408
11409 /*
11410  * Based on:
11411  * Ext JS Library 1.1.1
11412  * Copyright(c) 2006-2007, Ext JS, LLC.
11413  *
11414  * Originally Released Under LGPL - original licence link has changed is not relivant.
11415  *
11416  * Fork - LGPL
11417  * <script type="text/javascript">
11418  */
11419
11420  
11421
11422 /**
11423  * @class Roo.data.Connection
11424  * @extends Roo.util.Observable
11425  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11426  * either to a configured URL, or to a URL specified at request time.<br><br>
11427  * <p>
11428  * Requests made by this class are asynchronous, and will return immediately. No data from
11429  * the server will be available to the statement immediately following the {@link #request} call.
11430  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11431  * <p>
11432  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11433  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11434  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11435  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11436  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11437  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11438  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11439  * standard DOM methods.
11440  * @constructor
11441  * @param {Object} config a configuration object.
11442  */
11443 Roo.data.Connection = function(config){
11444     Roo.apply(this, config);
11445     this.addEvents({
11446         /**
11447          * @event beforerequest
11448          * Fires before a network request is made to retrieve a data object.
11449          * @param {Connection} conn This Connection object.
11450          * @param {Object} options The options config object passed to the {@link #request} method.
11451          */
11452         "beforerequest" : true,
11453         /**
11454          * @event requestcomplete
11455          * Fires if the request was successfully completed.
11456          * @param {Connection} conn This Connection object.
11457          * @param {Object} response The XHR object containing the response data.
11458          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11459          * @param {Object} options The options config object passed to the {@link #request} method.
11460          */
11461         "requestcomplete" : true,
11462         /**
11463          * @event requestexception
11464          * Fires if an error HTTP status was returned from the server.
11465          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11466          * @param {Connection} conn This Connection object.
11467          * @param {Object} response The XHR object containing the response data.
11468          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11469          * @param {Object} options The options config object passed to the {@link #request} method.
11470          */
11471         "requestexception" : true
11472     });
11473     Roo.data.Connection.superclass.constructor.call(this);
11474 };
11475
11476 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11477     /**
11478      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11479      */
11480     /**
11481      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11482      * extra parameters to each request made by this object. (defaults to undefined)
11483      */
11484     /**
11485      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11486      *  to each request made by this object. (defaults to undefined)
11487      */
11488     /**
11489      * @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)
11490      */
11491     /**
11492      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11493      */
11494     timeout : 30000,
11495     /**
11496      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11497      * @type Boolean
11498      */
11499     autoAbort:false,
11500
11501     /**
11502      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11503      * @type Boolean
11504      */
11505     disableCaching: true,
11506
11507     /**
11508      * Sends an HTTP request to a remote server.
11509      * @param {Object} options An object which may contain the following properties:<ul>
11510      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11511      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11512      * request, a url encoded string or a function to call to get either.</li>
11513      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11514      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11515      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11516      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11517      * <li>options {Object} The parameter to the request call.</li>
11518      * <li>success {Boolean} True if the request succeeded.</li>
11519      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11520      * </ul></li>
11521      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11522      * The callback is passed the following parameters:<ul>
11523      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11524      * <li>options {Object} The parameter to the request call.</li>
11525      * </ul></li>
11526      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11527      * The callback is passed the following parameters:<ul>
11528      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11529      * <li>options {Object} The parameter to the request call.</li>
11530      * </ul></li>
11531      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11532      * for the callback function. Defaults to the browser window.</li>
11533      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11534      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11535      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11536      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11537      * params for the post data. Any params will be appended to the URL.</li>
11538      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11539      * </ul>
11540      * @return {Number} transactionId
11541      */
11542     request : function(o){
11543         if(this.fireEvent("beforerequest", this, o) !== false){
11544             var p = o.params;
11545
11546             if(typeof p == "function"){
11547                 p = p.call(o.scope||window, o);
11548             }
11549             if(typeof p == "object"){
11550                 p = Roo.urlEncode(o.params);
11551             }
11552             if(this.extraParams){
11553                 var extras = Roo.urlEncode(this.extraParams);
11554                 p = p ? (p + '&' + extras) : extras;
11555             }
11556
11557             var url = o.url || this.url;
11558             if(typeof url == 'function'){
11559                 url = url.call(o.scope||window, o);
11560             }
11561
11562             if(o.form){
11563                 var form = Roo.getDom(o.form);
11564                 url = url || form.action;
11565
11566                 var enctype = form.getAttribute("enctype");
11567                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11568                     return this.doFormUpload(o, p, url);
11569                 }
11570                 var f = Roo.lib.Ajax.serializeForm(form);
11571                 p = p ? (p + '&' + f) : f;
11572             }
11573
11574             var hs = o.headers;
11575             if(this.defaultHeaders){
11576                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11577                 if(!o.headers){
11578                     o.headers = hs;
11579                 }
11580             }
11581
11582             var cb = {
11583                 success: this.handleResponse,
11584                 failure: this.handleFailure,
11585                 scope: this,
11586                 argument: {options: o},
11587                 timeout : o.timeout || this.timeout
11588             };
11589
11590             var method = o.method||this.method||(p ? "POST" : "GET");
11591
11592             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11593                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11594             }
11595
11596             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11597                 if(o.autoAbort){
11598                     this.abort();
11599                 }
11600             }else if(this.autoAbort !== false){
11601                 this.abort();
11602             }
11603
11604             if((method == 'GET' && p) || o.xmlData){
11605                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11606                 p = '';
11607             }
11608             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11609             return this.transId;
11610         }else{
11611             Roo.callback(o.callback, o.scope, [o, null, null]);
11612             return null;
11613         }
11614     },
11615
11616     /**
11617      * Determine whether this object has a request outstanding.
11618      * @param {Number} transactionId (Optional) defaults to the last transaction
11619      * @return {Boolean} True if there is an outstanding request.
11620      */
11621     isLoading : function(transId){
11622         if(transId){
11623             return Roo.lib.Ajax.isCallInProgress(transId);
11624         }else{
11625             return this.transId ? true : false;
11626         }
11627     },
11628
11629     /**
11630      * Aborts any outstanding request.
11631      * @param {Number} transactionId (Optional) defaults to the last transaction
11632      */
11633     abort : function(transId){
11634         if(transId || this.isLoading()){
11635             Roo.lib.Ajax.abort(transId || this.transId);
11636         }
11637     },
11638
11639     // private
11640     handleResponse : function(response){
11641         this.transId = false;
11642         var options = response.argument.options;
11643         response.argument = options ? options.argument : null;
11644         this.fireEvent("requestcomplete", this, response, options);
11645         Roo.callback(options.success, options.scope, [response, options]);
11646         Roo.callback(options.callback, options.scope, [options, true, response]);
11647     },
11648
11649     // private
11650     handleFailure : function(response, e){
11651         this.transId = false;
11652         var options = response.argument.options;
11653         response.argument = options ? options.argument : null;
11654         this.fireEvent("requestexception", this, response, options, e);
11655         Roo.callback(options.failure, options.scope, [response, options]);
11656         Roo.callback(options.callback, options.scope, [options, false, response]);
11657     },
11658
11659     // private
11660     doFormUpload : function(o, ps, url){
11661         var id = Roo.id();
11662         var frame = document.createElement('iframe');
11663         frame.id = id;
11664         frame.name = id;
11665         frame.className = 'x-hidden';
11666         if(Roo.isIE){
11667             frame.src = Roo.SSL_SECURE_URL;
11668         }
11669         document.body.appendChild(frame);
11670
11671         if(Roo.isIE){
11672            document.frames[id].name = id;
11673         }
11674
11675         var form = Roo.getDom(o.form);
11676         form.target = id;
11677         form.method = 'POST';
11678         form.enctype = form.encoding = 'multipart/form-data';
11679         if(url){
11680             form.action = url;
11681         }
11682
11683         var hiddens, hd;
11684         if(ps){ // add dynamic params
11685             hiddens = [];
11686             ps = Roo.urlDecode(ps, false);
11687             for(var k in ps){
11688                 if(ps.hasOwnProperty(k)){
11689                     hd = document.createElement('input');
11690                     hd.type = 'hidden';
11691                     hd.name = k;
11692                     hd.value = ps[k];
11693                     form.appendChild(hd);
11694                     hiddens.push(hd);
11695                 }
11696             }
11697         }
11698
11699         function cb(){
11700             var r = {  // bogus response object
11701                 responseText : '',
11702                 responseXML : null
11703             };
11704
11705             r.argument = o ? o.argument : null;
11706
11707             try { //
11708                 var doc;
11709                 if(Roo.isIE){
11710                     doc = frame.contentWindow.document;
11711                 }else {
11712                     doc = (frame.contentDocument || window.frames[id].document);
11713                 }
11714                 if(doc && doc.body){
11715                     r.responseText = doc.body.innerHTML;
11716                 }
11717                 if(doc && doc.XMLDocument){
11718                     r.responseXML = doc.XMLDocument;
11719                 }else {
11720                     r.responseXML = doc;
11721                 }
11722             }
11723             catch(e) {
11724                 // ignore
11725             }
11726
11727             Roo.EventManager.removeListener(frame, 'load', cb, this);
11728
11729             this.fireEvent("requestcomplete", this, r, o);
11730             Roo.callback(o.success, o.scope, [r, o]);
11731             Roo.callback(o.callback, o.scope, [o, true, r]);
11732
11733             setTimeout(function(){document.body.removeChild(frame);}, 100);
11734         }
11735
11736         Roo.EventManager.on(frame, 'load', cb, this);
11737         form.submit();
11738
11739         if(hiddens){ // remove dynamic params
11740             for(var i = 0, len = hiddens.length; i < len; i++){
11741                 form.removeChild(hiddens[i]);
11742             }
11743         }
11744     }
11745 });
11746 /*
11747  * Based on:
11748  * Ext JS Library 1.1.1
11749  * Copyright(c) 2006-2007, Ext JS, LLC.
11750  *
11751  * Originally Released Under LGPL - original licence link has changed is not relivant.
11752  *
11753  * Fork - LGPL
11754  * <script type="text/javascript">
11755  */
11756  
11757 /**
11758  * Global Ajax request class.
11759  * 
11760  * @class Roo.Ajax
11761  * @extends Roo.data.Connection
11762  * @static
11763  * 
11764  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11765  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11766  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11767  * @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)
11768  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11769  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11770  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11771  */
11772 Roo.Ajax = new Roo.data.Connection({
11773     // fix up the docs
11774     /**
11775      * @scope Roo.Ajax
11776      * @type {Boolear} 
11777      */
11778     autoAbort : false,
11779
11780     /**
11781      * Serialize the passed form into a url encoded string
11782      * @scope Roo.Ajax
11783      * @param {String/HTMLElement} form
11784      * @return {String}
11785      */
11786     serializeForm : function(form){
11787         return Roo.lib.Ajax.serializeForm(form);
11788     }
11789 });/*
11790  * Based on:
11791  * Ext JS Library 1.1.1
11792  * Copyright(c) 2006-2007, Ext JS, LLC.
11793  *
11794  * Originally Released Under LGPL - original licence link has changed is not relivant.
11795  *
11796  * Fork - LGPL
11797  * <script type="text/javascript">
11798  */
11799
11800  
11801 /**
11802  * @class Roo.UpdateManager
11803  * @extends Roo.util.Observable
11804  * Provides AJAX-style update for Element object.<br><br>
11805  * Usage:<br>
11806  * <pre><code>
11807  * // Get it from a Roo.Element object
11808  * var el = Roo.get("foo");
11809  * var mgr = el.getUpdateManager();
11810  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11811  * ...
11812  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11813  * <br>
11814  * // or directly (returns the same UpdateManager instance)
11815  * var mgr = new Roo.UpdateManager("myElementId");
11816  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11817  * mgr.on("update", myFcnNeedsToKnow);
11818  * <br>
11819    // short handed call directly from the element object
11820    Roo.get("foo").load({
11821         url: "bar.php",
11822         scripts:true,
11823         params: "for=bar",
11824         text: "Loading Foo..."
11825    });
11826  * </code></pre>
11827  * @constructor
11828  * Create new UpdateManager directly.
11829  * @param {String/HTMLElement/Roo.Element} el The element to update
11830  * @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).
11831  */
11832 Roo.UpdateManager = function(el, forceNew){
11833     el = Roo.get(el);
11834     if(!forceNew && el.updateManager){
11835         return el.updateManager;
11836     }
11837     /**
11838      * The Element object
11839      * @type Roo.Element
11840      */
11841     this.el = el;
11842     /**
11843      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11844      * @type String
11845      */
11846     this.defaultUrl = null;
11847
11848     this.addEvents({
11849         /**
11850          * @event beforeupdate
11851          * Fired before an update is made, return false from your handler and the update is cancelled.
11852          * @param {Roo.Element} el
11853          * @param {String/Object/Function} url
11854          * @param {String/Object} params
11855          */
11856         "beforeupdate": true,
11857         /**
11858          * @event update
11859          * Fired after successful update is made.
11860          * @param {Roo.Element} el
11861          * @param {Object} oResponseObject The response Object
11862          */
11863         "update": true,
11864         /**
11865          * @event failure
11866          * Fired on update failure.
11867          * @param {Roo.Element} el
11868          * @param {Object} oResponseObject The response Object
11869          */
11870         "failure": true
11871     });
11872     var d = Roo.UpdateManager.defaults;
11873     /**
11874      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11875      * @type String
11876      */
11877     this.sslBlankUrl = d.sslBlankUrl;
11878     /**
11879      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11880      * @type Boolean
11881      */
11882     this.disableCaching = d.disableCaching;
11883     /**
11884      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11885      * @type String
11886      */
11887     this.indicatorText = d.indicatorText;
11888     /**
11889      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11890      * @type String
11891      */
11892     this.showLoadIndicator = d.showLoadIndicator;
11893     /**
11894      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11895      * @type Number
11896      */
11897     this.timeout = d.timeout;
11898
11899     /**
11900      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11901      * @type Boolean
11902      */
11903     this.loadScripts = d.loadScripts;
11904
11905     /**
11906      * Transaction object of current executing transaction
11907      */
11908     this.transaction = null;
11909
11910     /**
11911      * @private
11912      */
11913     this.autoRefreshProcId = null;
11914     /**
11915      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11916      * @type Function
11917      */
11918     this.refreshDelegate = this.refresh.createDelegate(this);
11919     /**
11920      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11921      * @type Function
11922      */
11923     this.updateDelegate = this.update.createDelegate(this);
11924     /**
11925      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11926      * @type Function
11927      */
11928     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11929     /**
11930      * @private
11931      */
11932     this.successDelegate = this.processSuccess.createDelegate(this);
11933     /**
11934      * @private
11935      */
11936     this.failureDelegate = this.processFailure.createDelegate(this);
11937
11938     if(!this.renderer){
11939      /**
11940       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11941       */
11942     this.renderer = new Roo.UpdateManager.BasicRenderer();
11943     }
11944     
11945     Roo.UpdateManager.superclass.constructor.call(this);
11946 };
11947
11948 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11949     /**
11950      * Get the Element this UpdateManager is bound to
11951      * @return {Roo.Element} The element
11952      */
11953     getEl : function(){
11954         return this.el;
11955     },
11956     /**
11957      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11958      * @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:
11959 <pre><code>
11960 um.update({<br/>
11961     url: "your-url.php",<br/>
11962     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11963     callback: yourFunction,<br/>
11964     scope: yourObject, //(optional scope)  <br/>
11965     discardUrl: false, <br/>
11966     nocache: false,<br/>
11967     text: "Loading...",<br/>
11968     timeout: 30,<br/>
11969     scripts: false<br/>
11970 });
11971 </code></pre>
11972      * The only required property is url. The optional properties nocache, text and scripts
11973      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11974      * @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}
11975      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11976      * @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.
11977      */
11978     update : function(url, params, callback, discardUrl){
11979         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11980             var method = this.method,
11981                 cfg;
11982             if(typeof url == "object"){ // must be config object
11983                 cfg = url;
11984                 url = cfg.url;
11985                 params = params || cfg.params;
11986                 callback = callback || cfg.callback;
11987                 discardUrl = discardUrl || cfg.discardUrl;
11988                 if(callback && cfg.scope){
11989                     callback = callback.createDelegate(cfg.scope);
11990                 }
11991                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11992                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11993                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11994                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11995                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11996             }
11997             this.showLoading();
11998             if(!discardUrl){
11999                 this.defaultUrl = url;
12000             }
12001             if(typeof url == "function"){
12002                 url = url.call(this);
12003             }
12004
12005             method = method || (params ? "POST" : "GET");
12006             if(method == "GET"){
12007                 url = this.prepareUrl(url);
12008             }
12009
12010             var o = Roo.apply(cfg ||{}, {
12011                 url : url,
12012                 params: params,
12013                 success: this.successDelegate,
12014                 failure: this.failureDelegate,
12015                 callback: undefined,
12016                 timeout: (this.timeout*1000),
12017                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12018             });
12019             Roo.log("updated manager called with timeout of " + o.timeout);
12020             this.transaction = Roo.Ajax.request(o);
12021         }
12022     },
12023
12024     /**
12025      * 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.
12026      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12027      * @param {String/HTMLElement} form The form Id or form element
12028      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12029      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12030      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12031      */
12032     formUpdate : function(form, url, reset, callback){
12033         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12034             if(typeof url == "function"){
12035                 url = url.call(this);
12036             }
12037             form = Roo.getDom(form);
12038             this.transaction = Roo.Ajax.request({
12039                 form: form,
12040                 url:url,
12041                 success: this.successDelegate,
12042                 failure: this.failureDelegate,
12043                 timeout: (this.timeout*1000),
12044                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12045             });
12046             this.showLoading.defer(1, this);
12047         }
12048     },
12049
12050     /**
12051      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12052      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12053      */
12054     refresh : function(callback){
12055         if(this.defaultUrl == null){
12056             return;
12057         }
12058         this.update(this.defaultUrl, null, callback, true);
12059     },
12060
12061     /**
12062      * Set this element to auto refresh.
12063      * @param {Number} interval How often to update (in seconds).
12064      * @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)
12065      * @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}
12066      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12067      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12068      */
12069     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12070         if(refreshNow){
12071             this.update(url || this.defaultUrl, params, callback, true);
12072         }
12073         if(this.autoRefreshProcId){
12074             clearInterval(this.autoRefreshProcId);
12075         }
12076         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12077     },
12078
12079     /**
12080      * Stop auto refresh on this element.
12081      */
12082      stopAutoRefresh : function(){
12083         if(this.autoRefreshProcId){
12084             clearInterval(this.autoRefreshProcId);
12085             delete this.autoRefreshProcId;
12086         }
12087     },
12088
12089     isAutoRefreshing : function(){
12090        return this.autoRefreshProcId ? true : false;
12091     },
12092     /**
12093      * Called to update the element to "Loading" state. Override to perform custom action.
12094      */
12095     showLoading : function(){
12096         if(this.showLoadIndicator){
12097             this.el.update(this.indicatorText);
12098         }
12099     },
12100
12101     /**
12102      * Adds unique parameter to query string if disableCaching = true
12103      * @private
12104      */
12105     prepareUrl : function(url){
12106         if(this.disableCaching){
12107             var append = "_dc=" + (new Date().getTime());
12108             if(url.indexOf("?") !== -1){
12109                 url += "&" + append;
12110             }else{
12111                 url += "?" + append;
12112             }
12113         }
12114         return url;
12115     },
12116
12117     /**
12118      * @private
12119      */
12120     processSuccess : function(response){
12121         this.transaction = null;
12122         if(response.argument.form && response.argument.reset){
12123             try{ // put in try/catch since some older FF releases had problems with this
12124                 response.argument.form.reset();
12125             }catch(e){}
12126         }
12127         if(this.loadScripts){
12128             this.renderer.render(this.el, response, this,
12129                 this.updateComplete.createDelegate(this, [response]));
12130         }else{
12131             this.renderer.render(this.el, response, this);
12132             this.updateComplete(response);
12133         }
12134     },
12135
12136     updateComplete : function(response){
12137         this.fireEvent("update", this.el, response);
12138         if(typeof response.argument.callback == "function"){
12139             response.argument.callback(this.el, true, response);
12140         }
12141     },
12142
12143     /**
12144      * @private
12145      */
12146     processFailure : function(response){
12147         this.transaction = null;
12148         this.fireEvent("failure", this.el, response);
12149         if(typeof response.argument.callback == "function"){
12150             response.argument.callback(this.el, false, response);
12151         }
12152     },
12153
12154     /**
12155      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12156      * @param {Object} renderer The object implementing the render() method
12157      */
12158     setRenderer : function(renderer){
12159         this.renderer = renderer;
12160     },
12161
12162     getRenderer : function(){
12163        return this.renderer;
12164     },
12165
12166     /**
12167      * Set the defaultUrl used for updates
12168      * @param {String/Function} defaultUrl The url or a function to call to get the url
12169      */
12170     setDefaultUrl : function(defaultUrl){
12171         this.defaultUrl = defaultUrl;
12172     },
12173
12174     /**
12175      * Aborts the executing transaction
12176      */
12177     abort : function(){
12178         if(this.transaction){
12179             Roo.Ajax.abort(this.transaction);
12180         }
12181     },
12182
12183     /**
12184      * Returns true if an update is in progress
12185      * @return {Boolean}
12186      */
12187     isUpdating : function(){
12188         if(this.transaction){
12189             return Roo.Ajax.isLoading(this.transaction);
12190         }
12191         return false;
12192     }
12193 });
12194
12195 /**
12196  * @class Roo.UpdateManager.defaults
12197  * @static (not really - but it helps the doc tool)
12198  * The defaults collection enables customizing the default properties of UpdateManager
12199  */
12200    Roo.UpdateManager.defaults = {
12201        /**
12202          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12203          * @type Number
12204          */
12205          timeout : 30,
12206
12207          /**
12208          * True to process scripts by default (Defaults to false).
12209          * @type Boolean
12210          */
12211         loadScripts : false,
12212
12213         /**
12214         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12215         * @type String
12216         */
12217         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12218         /**
12219          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12220          * @type Boolean
12221          */
12222         disableCaching : false,
12223         /**
12224          * Whether to show indicatorText when loading (Defaults to true).
12225          * @type Boolean
12226          */
12227         showLoadIndicator : true,
12228         /**
12229          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12230          * @type String
12231          */
12232         indicatorText : '<div class="loading-indicator">Loading...</div>'
12233    };
12234
12235 /**
12236  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12237  *Usage:
12238  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12239  * @param {String/HTMLElement/Roo.Element} el The element to update
12240  * @param {String} url The url
12241  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12242  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12243  * @static
12244  * @deprecated
12245  * @member Roo.UpdateManager
12246  */
12247 Roo.UpdateManager.updateElement = function(el, url, params, options){
12248     var um = Roo.get(el, true).getUpdateManager();
12249     Roo.apply(um, options);
12250     um.update(url, params, options ? options.callback : null);
12251 };
12252 // alias for backwards compat
12253 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12254 /**
12255  * @class Roo.UpdateManager.BasicRenderer
12256  * Default Content renderer. Updates the elements innerHTML with the responseText.
12257  */
12258 Roo.UpdateManager.BasicRenderer = function(){};
12259
12260 Roo.UpdateManager.BasicRenderer.prototype = {
12261     /**
12262      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12263      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12264      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12265      * @param {Roo.Element} el The element being rendered
12266      * @param {Object} response The YUI Connect response object
12267      * @param {UpdateManager} updateManager The calling update manager
12268      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12269      */
12270      render : function(el, response, updateManager, callback){
12271         el.update(response.responseText, updateManager.loadScripts, callback);
12272     }
12273 };
12274 /*
12275  * Based on:
12276  * Roo JS
12277  * (c)) Alan Knowles
12278  * Licence : LGPL
12279  */
12280
12281
12282 /**
12283  * @class Roo.DomTemplate
12284  * @extends Roo.Template
12285  * An effort at a dom based template engine..
12286  *
12287  * Similar to XTemplate, except it uses dom parsing to create the template..
12288  *
12289  * Supported features:
12290  *
12291  *  Tags:
12292
12293 <pre><code>
12294       {a_variable} - output encoded.
12295       {a_variable.format:("Y-m-d")} - call a method on the variable
12296       {a_variable:raw} - unencoded output
12297       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12298       {a_variable:this.method_on_template(...)} - call a method on the template object.
12299  
12300 </code></pre>
12301  *  The tpl tag:
12302 <pre><code>
12303         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12304         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12305         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12306         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12307   
12308 </code></pre>
12309  *      
12310  */
12311 Roo.DomTemplate = function()
12312 {
12313      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12314      if (this.html) {
12315         this.compile();
12316      }
12317 };
12318
12319
12320 Roo.extend(Roo.DomTemplate, Roo.Template, {
12321     /**
12322      * id counter for sub templates.
12323      */
12324     id : 0,
12325     /**
12326      * flag to indicate if dom parser is inside a pre,
12327      * it will strip whitespace if not.
12328      */
12329     inPre : false,
12330     
12331     /**
12332      * The various sub templates
12333      */
12334     tpls : false,
12335     
12336     
12337     
12338     /**
12339      *
12340      * basic tag replacing syntax
12341      * WORD:WORD()
12342      *
12343      * // you can fake an object call by doing this
12344      *  x.t:(test,tesT) 
12345      * 
12346      */
12347     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12348     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12349     
12350     iterChild : function (node, method) {
12351         
12352         var oldPre = this.inPre;
12353         if (node.tagName == 'PRE') {
12354             this.inPre = true;
12355         }
12356         for( var i = 0; i < node.childNodes.length; i++) {
12357             method.call(this, node.childNodes[i]);
12358         }
12359         this.inPre = oldPre;
12360     },
12361     
12362     
12363     
12364     /**
12365      * compile the template
12366      *
12367      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12368      *
12369      */
12370     compile: function()
12371     {
12372         var s = this.html;
12373         
12374         // covert the html into DOM...
12375         var doc = false;
12376         var div =false;
12377         try {
12378             doc = document.implementation.createHTMLDocument("");
12379             doc.documentElement.innerHTML =   this.html  ;
12380             div = doc.documentElement;
12381         } catch (e) {
12382             // old IE... - nasty -- it causes all sorts of issues.. with
12383             // images getting pulled from server..
12384             div = document.createElement('div');
12385             div.innerHTML = this.html;
12386         }
12387         //doc.documentElement.innerHTML = htmlBody
12388          
12389         
12390         
12391         this.tpls = [];
12392         var _t = this;
12393         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12394         
12395         var tpls = this.tpls;
12396         
12397         // create a top level template from the snippet..
12398         
12399         //Roo.log(div.innerHTML);
12400         
12401         var tpl = {
12402             uid : 'master',
12403             id : this.id++,
12404             attr : false,
12405             value : false,
12406             body : div.innerHTML,
12407             
12408             forCall : false,
12409             execCall : false,
12410             dom : div,
12411             isTop : true
12412             
12413         };
12414         tpls.unshift(tpl);
12415         
12416         
12417         // compile them...
12418         this.tpls = [];
12419         Roo.each(tpls, function(tp){
12420             this.compileTpl(tp);
12421             this.tpls[tp.id] = tp;
12422         }, this);
12423         
12424         this.master = tpls[0];
12425         return this;
12426         
12427         
12428     },
12429     
12430     compileNode : function(node, istop) {
12431         // test for
12432         //Roo.log(node);
12433         
12434         
12435         // skip anything not a tag..
12436         if (node.nodeType != 1) {
12437             if (node.nodeType == 3 && !this.inPre) {
12438                 // reduce white space..
12439                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12440                 
12441             }
12442             return;
12443         }
12444         
12445         var tpl = {
12446             uid : false,
12447             id : false,
12448             attr : false,
12449             value : false,
12450             body : '',
12451             
12452             forCall : false,
12453             execCall : false,
12454             dom : false,
12455             isTop : istop
12456             
12457             
12458         };
12459         
12460         
12461         switch(true) {
12462             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12463             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12464             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12465             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12466             // no default..
12467         }
12468         
12469         
12470         if (!tpl.attr) {
12471             // just itterate children..
12472             this.iterChild(node,this.compileNode);
12473             return;
12474         }
12475         tpl.uid = this.id++;
12476         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12477         node.removeAttribute('roo-'+ tpl.attr);
12478         if (tpl.attr != 'name') {
12479             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12480             node.parentNode.replaceChild(placeholder,  node);
12481         } else {
12482             
12483             var placeholder =  document.createElement('span');
12484             placeholder.className = 'roo-tpl-' + tpl.value;
12485             node.parentNode.replaceChild(placeholder,  node);
12486         }
12487         
12488         // parent now sees '{domtplXXXX}
12489         this.iterChild(node,this.compileNode);
12490         
12491         // we should now have node body...
12492         var div = document.createElement('div');
12493         div.appendChild(node);
12494         tpl.dom = node;
12495         // this has the unfortunate side effect of converting tagged attributes
12496         // eg. href="{...}" into %7C...%7D
12497         // this has been fixed by searching for those combo's although it's a bit hacky..
12498         
12499         
12500         tpl.body = div.innerHTML;
12501         
12502         
12503          
12504         tpl.id = tpl.uid;
12505         switch(tpl.attr) {
12506             case 'for' :
12507                 switch (tpl.value) {
12508                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12509                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12510                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12511                 }
12512                 break;
12513             
12514             case 'exec':
12515                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12516                 break;
12517             
12518             case 'if':     
12519                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12520                 break;
12521             
12522             case 'name':
12523                 tpl.id  = tpl.value; // replace non characters???
12524                 break;
12525             
12526         }
12527         
12528         
12529         this.tpls.push(tpl);
12530         
12531         
12532         
12533     },
12534     
12535     
12536     
12537     
12538     /**
12539      * Compile a segment of the template into a 'sub-template'
12540      *
12541      * 
12542      * 
12543      *
12544      */
12545     compileTpl : function(tpl)
12546     {
12547         var fm = Roo.util.Format;
12548         var useF = this.disableFormats !== true;
12549         
12550         var sep = Roo.isGecko ? "+\n" : ",\n";
12551         
12552         var undef = function(str) {
12553             Roo.debug && Roo.log("Property not found :"  + str);
12554             return '';
12555         };
12556           
12557         //Roo.log(tpl.body);
12558         
12559         
12560         
12561         var fn = function(m, lbrace, name, format, args)
12562         {
12563             //Roo.log("ARGS");
12564             //Roo.log(arguments);
12565             args = args ? args.replace(/\\'/g,"'") : args;
12566             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12567             if (typeof(format) == 'undefined') {
12568                 format =  'htmlEncode'; 
12569             }
12570             if (format == 'raw' ) {
12571                 format = false;
12572             }
12573             
12574             if(name.substr(0, 6) == 'domtpl'){
12575                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12576             }
12577             
12578             // build an array of options to determine if value is undefined..
12579             
12580             // basically get 'xxxx.yyyy' then do
12581             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12582             //    (function () { Roo.log("Property not found"); return ''; })() :
12583             //    ......
12584             
12585             var udef_ar = [];
12586             var lookfor = '';
12587             Roo.each(name.split('.'), function(st) {
12588                 lookfor += (lookfor.length ? '.': '') + st;
12589                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12590             });
12591             
12592             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12593             
12594             
12595             if(format && useF){
12596                 
12597                 args = args ? ',' + args : "";
12598                  
12599                 if(format.substr(0, 5) != "this."){
12600                     format = "fm." + format + '(';
12601                 }else{
12602                     format = 'this.call("'+ format.substr(5) + '", ';
12603                     args = ", values";
12604                 }
12605                 
12606                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12607             }
12608              
12609             if (args && args.length) {
12610                 // called with xxyx.yuu:(test,test)
12611                 // change to ()
12612                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12613             }
12614             // raw.. - :raw modifier..
12615             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12616             
12617         };
12618         var body;
12619         // branched to use + in gecko and [].join() in others
12620         if(Roo.isGecko){
12621             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12622                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12623                     "';};};";
12624         }else{
12625             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12626             body.push(tpl.body.replace(/(\r\n|\n)/g,
12627                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12628             body.push("'].join('');};};");
12629             body = body.join('');
12630         }
12631         
12632         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12633        
12634         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12635         eval(body);
12636         
12637         return this;
12638     },
12639      
12640     /**
12641      * same as applyTemplate, except it's done to one of the subTemplates
12642      * when using named templates, you can do:
12643      *
12644      * var str = pl.applySubTemplate('your-name', values);
12645      *
12646      * 
12647      * @param {Number} id of the template
12648      * @param {Object} values to apply to template
12649      * @param {Object} parent (normaly the instance of this object)
12650      */
12651     applySubTemplate : function(id, values, parent)
12652     {
12653         
12654         
12655         var t = this.tpls[id];
12656         
12657         
12658         try { 
12659             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12660                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12661                 return '';
12662             }
12663         } catch(e) {
12664             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12665             Roo.log(values);
12666           
12667             return '';
12668         }
12669         try { 
12670             
12671             if(t.execCall && t.execCall.call(this, values, parent)){
12672                 return '';
12673             }
12674         } catch(e) {
12675             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12676             Roo.log(values);
12677             return '';
12678         }
12679         
12680         try {
12681             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12682             parent = t.target ? values : parent;
12683             if(t.forCall && vs instanceof Array){
12684                 var buf = [];
12685                 for(var i = 0, len = vs.length; i < len; i++){
12686                     try {
12687                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12688                     } catch (e) {
12689                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12690                         Roo.log(e.body);
12691                         //Roo.log(t.compiled);
12692                         Roo.log(vs[i]);
12693                     }   
12694                 }
12695                 return buf.join('');
12696             }
12697         } catch (e) {
12698             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12699             Roo.log(values);
12700             return '';
12701         }
12702         try {
12703             return t.compiled.call(this, vs, parent);
12704         } catch (e) {
12705             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12706             Roo.log(e.body);
12707             //Roo.log(t.compiled);
12708             Roo.log(values);
12709             return '';
12710         }
12711     },
12712
12713    
12714
12715     applyTemplate : function(values){
12716         return this.master.compiled.call(this, values, {});
12717         //var s = this.subs;
12718     },
12719
12720     apply : function(){
12721         return this.applyTemplate.apply(this, arguments);
12722     }
12723
12724  });
12725
12726 Roo.DomTemplate.from = function(el){
12727     el = Roo.getDom(el);
12728     return new Roo.Domtemplate(el.value || el.innerHTML);
12729 };/*
12730  * Based on:
12731  * Ext JS Library 1.1.1
12732  * Copyright(c) 2006-2007, Ext JS, LLC.
12733  *
12734  * Originally Released Under LGPL - original licence link has changed is not relivant.
12735  *
12736  * Fork - LGPL
12737  * <script type="text/javascript">
12738  */
12739
12740 /**
12741  * @class Roo.util.DelayedTask
12742  * Provides a convenient method of performing setTimeout where a new
12743  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12744  * You can use this class to buffer
12745  * the keypress events for a certain number of milliseconds, and perform only if they stop
12746  * for that amount of time.
12747  * @constructor The parameters to this constructor serve as defaults and are not required.
12748  * @param {Function} fn (optional) The default function to timeout
12749  * @param {Object} scope (optional) The default scope of that timeout
12750  * @param {Array} args (optional) The default Array of arguments
12751  */
12752 Roo.util.DelayedTask = function(fn, scope, args){
12753     var id = null, d, t;
12754
12755     var call = function(){
12756         var now = new Date().getTime();
12757         if(now - t >= d){
12758             clearInterval(id);
12759             id = null;
12760             fn.apply(scope, args || []);
12761         }
12762     };
12763     /**
12764      * Cancels any pending timeout and queues a new one
12765      * @param {Number} delay The milliseconds to delay
12766      * @param {Function} newFn (optional) Overrides function passed to constructor
12767      * @param {Object} newScope (optional) Overrides scope passed to constructor
12768      * @param {Array} newArgs (optional) Overrides args passed to constructor
12769      */
12770     this.delay = function(delay, newFn, newScope, newArgs){
12771         if(id && delay != d){
12772             this.cancel();
12773         }
12774         d = delay;
12775         t = new Date().getTime();
12776         fn = newFn || fn;
12777         scope = newScope || scope;
12778         args = newArgs || args;
12779         if(!id){
12780             id = setInterval(call, d);
12781         }
12782     };
12783
12784     /**
12785      * Cancel the last queued timeout
12786      */
12787     this.cancel = function(){
12788         if(id){
12789             clearInterval(id);
12790             id = null;
12791         }
12792     };
12793 };/*
12794  * Based on:
12795  * Ext JS Library 1.1.1
12796  * Copyright(c) 2006-2007, Ext JS, LLC.
12797  *
12798  * Originally Released Under LGPL - original licence link has changed is not relivant.
12799  *
12800  * Fork - LGPL
12801  * <script type="text/javascript">
12802  */
12803  
12804  
12805 Roo.util.TaskRunner = function(interval){
12806     interval = interval || 10;
12807     var tasks = [], removeQueue = [];
12808     var id = 0;
12809     var running = false;
12810
12811     var stopThread = function(){
12812         running = false;
12813         clearInterval(id);
12814         id = 0;
12815     };
12816
12817     var startThread = function(){
12818         if(!running){
12819             running = true;
12820             id = setInterval(runTasks, interval);
12821         }
12822     };
12823
12824     var removeTask = function(task){
12825         removeQueue.push(task);
12826         if(task.onStop){
12827             task.onStop();
12828         }
12829     };
12830
12831     var runTasks = function(){
12832         if(removeQueue.length > 0){
12833             for(var i = 0, len = removeQueue.length; i < len; i++){
12834                 tasks.remove(removeQueue[i]);
12835             }
12836             removeQueue = [];
12837             if(tasks.length < 1){
12838                 stopThread();
12839                 return;
12840             }
12841         }
12842         var now = new Date().getTime();
12843         for(var i = 0, len = tasks.length; i < len; ++i){
12844             var t = tasks[i];
12845             var itime = now - t.taskRunTime;
12846             if(t.interval <= itime){
12847                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12848                 t.taskRunTime = now;
12849                 if(rt === false || t.taskRunCount === t.repeat){
12850                     removeTask(t);
12851                     return;
12852                 }
12853             }
12854             if(t.duration && t.duration <= (now - t.taskStartTime)){
12855                 removeTask(t);
12856             }
12857         }
12858     };
12859
12860     /**
12861      * Queues a new task.
12862      * @param {Object} task
12863      */
12864     this.start = function(task){
12865         tasks.push(task);
12866         task.taskStartTime = new Date().getTime();
12867         task.taskRunTime = 0;
12868         task.taskRunCount = 0;
12869         startThread();
12870         return task;
12871     };
12872
12873     this.stop = function(task){
12874         removeTask(task);
12875         return task;
12876     };
12877
12878     this.stopAll = function(){
12879         stopThread();
12880         for(var i = 0, len = tasks.length; i < len; i++){
12881             if(tasks[i].onStop){
12882                 tasks[i].onStop();
12883             }
12884         }
12885         tasks = [];
12886         removeQueue = [];
12887     };
12888 };
12889
12890 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12891  * Based on:
12892  * Ext JS Library 1.1.1
12893  * Copyright(c) 2006-2007, Ext JS, LLC.
12894  *
12895  * Originally Released Under LGPL - original licence link has changed is not relivant.
12896  *
12897  * Fork - LGPL
12898  * <script type="text/javascript">
12899  */
12900
12901  
12902 /**
12903  * @class Roo.util.MixedCollection
12904  * @extends Roo.util.Observable
12905  * A Collection class that maintains both numeric indexes and keys and exposes events.
12906  * @constructor
12907  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12908  * collection (defaults to false)
12909  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12910  * and return the key value for that item.  This is used when available to look up the key on items that
12911  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12912  * equivalent to providing an implementation for the {@link #getKey} method.
12913  */
12914 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12915     this.items = [];
12916     this.map = {};
12917     this.keys = [];
12918     this.length = 0;
12919     this.addEvents({
12920         /**
12921          * @event clear
12922          * Fires when the collection is cleared.
12923          */
12924         "clear" : true,
12925         /**
12926          * @event add
12927          * Fires when an item is added to the collection.
12928          * @param {Number} index The index at which the item was added.
12929          * @param {Object} o The item added.
12930          * @param {String} key The key associated with the added item.
12931          */
12932         "add" : true,
12933         /**
12934          * @event replace
12935          * Fires when an item is replaced in the collection.
12936          * @param {String} key he key associated with the new added.
12937          * @param {Object} old The item being replaced.
12938          * @param {Object} new The new item.
12939          */
12940         "replace" : true,
12941         /**
12942          * @event remove
12943          * Fires when an item is removed from the collection.
12944          * @param {Object} o The item being removed.
12945          * @param {String} key (optional) The key associated with the removed item.
12946          */
12947         "remove" : true,
12948         "sort" : true
12949     });
12950     this.allowFunctions = allowFunctions === true;
12951     if(keyFn){
12952         this.getKey = keyFn;
12953     }
12954     Roo.util.MixedCollection.superclass.constructor.call(this);
12955 };
12956
12957 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12958     allowFunctions : false,
12959     
12960 /**
12961  * Adds an item to the collection.
12962  * @param {String} key The key to associate with the item
12963  * @param {Object} o The item to add.
12964  * @return {Object} The item added.
12965  */
12966     add : function(key, o){
12967         if(arguments.length == 1){
12968             o = arguments[0];
12969             key = this.getKey(o);
12970         }
12971         if(typeof key == "undefined" || key === null){
12972             this.length++;
12973             this.items.push(o);
12974             this.keys.push(null);
12975         }else{
12976             var old = this.map[key];
12977             if(old){
12978                 return this.replace(key, o);
12979             }
12980             this.length++;
12981             this.items.push(o);
12982             this.map[key] = o;
12983             this.keys.push(key);
12984         }
12985         this.fireEvent("add", this.length-1, o, key);
12986         return o;
12987     },
12988        
12989 /**
12990   * MixedCollection has a generic way to fetch keys if you implement getKey.
12991 <pre><code>
12992 // normal way
12993 var mc = new Roo.util.MixedCollection();
12994 mc.add(someEl.dom.id, someEl);
12995 mc.add(otherEl.dom.id, otherEl);
12996 //and so on
12997
12998 // using getKey
12999 var mc = new Roo.util.MixedCollection();
13000 mc.getKey = function(el){
13001    return el.dom.id;
13002 };
13003 mc.add(someEl);
13004 mc.add(otherEl);
13005
13006 // or via the constructor
13007 var mc = new Roo.util.MixedCollection(false, function(el){
13008    return el.dom.id;
13009 });
13010 mc.add(someEl);
13011 mc.add(otherEl);
13012 </code></pre>
13013  * @param o {Object} The item for which to find the key.
13014  * @return {Object} The key for the passed item.
13015  */
13016     getKey : function(o){
13017          return o.id; 
13018     },
13019    
13020 /**
13021  * Replaces an item in the collection.
13022  * @param {String} key The key associated with the item to replace, or the item to replace.
13023  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13024  * @return {Object}  The new item.
13025  */
13026     replace : function(key, o){
13027         if(arguments.length == 1){
13028             o = arguments[0];
13029             key = this.getKey(o);
13030         }
13031         var old = this.item(key);
13032         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13033              return this.add(key, o);
13034         }
13035         var index = this.indexOfKey(key);
13036         this.items[index] = o;
13037         this.map[key] = o;
13038         this.fireEvent("replace", key, old, o);
13039         return o;
13040     },
13041    
13042 /**
13043  * Adds all elements of an Array or an Object to the collection.
13044  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13045  * an Array of values, each of which are added to the collection.
13046  */
13047     addAll : function(objs){
13048         if(arguments.length > 1 || objs instanceof Array){
13049             var args = arguments.length > 1 ? arguments : objs;
13050             for(var i = 0, len = args.length; i < len; i++){
13051                 this.add(args[i]);
13052             }
13053         }else{
13054             for(var key in objs){
13055                 if(this.allowFunctions || typeof objs[key] != "function"){
13056                     this.add(key, objs[key]);
13057                 }
13058             }
13059         }
13060     },
13061    
13062 /**
13063  * Executes the specified function once for every item in the collection, passing each
13064  * item as the first and only parameter. returning false from the function will stop the iteration.
13065  * @param {Function} fn The function to execute for each item.
13066  * @param {Object} scope (optional) The scope in which to execute the function.
13067  */
13068     each : function(fn, scope){
13069         var items = [].concat(this.items); // each safe for removal
13070         for(var i = 0, len = items.length; i < len; i++){
13071             if(fn.call(scope || items[i], items[i], i, len) === false){
13072                 break;
13073             }
13074         }
13075     },
13076    
13077 /**
13078  * Executes the specified function once for every key in the collection, passing each
13079  * key, and its associated item as the first two parameters.
13080  * @param {Function} fn The function to execute for each item.
13081  * @param {Object} scope (optional) The scope in which to execute the function.
13082  */
13083     eachKey : function(fn, scope){
13084         for(var i = 0, len = this.keys.length; i < len; i++){
13085             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13086         }
13087     },
13088    
13089 /**
13090  * Returns the first item in the collection which elicits a true return value from the
13091  * passed selection function.
13092  * @param {Function} fn The selection function to execute for each item.
13093  * @param {Object} scope (optional) The scope in which to execute the function.
13094  * @return {Object} The first item in the collection which returned true from the selection function.
13095  */
13096     find : function(fn, scope){
13097         for(var i = 0, len = this.items.length; i < len; i++){
13098             if(fn.call(scope || window, this.items[i], this.keys[i])){
13099                 return this.items[i];
13100             }
13101         }
13102         return null;
13103     },
13104    
13105 /**
13106  * Inserts an item at the specified index in the collection.
13107  * @param {Number} index The index to insert the item at.
13108  * @param {String} key The key to associate with the new item, or the item itself.
13109  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13110  * @return {Object} The item inserted.
13111  */
13112     insert : function(index, key, o){
13113         if(arguments.length == 2){
13114             o = arguments[1];
13115             key = this.getKey(o);
13116         }
13117         if(index >= this.length){
13118             return this.add(key, o);
13119         }
13120         this.length++;
13121         this.items.splice(index, 0, o);
13122         if(typeof key != "undefined" && key != null){
13123             this.map[key] = o;
13124         }
13125         this.keys.splice(index, 0, key);
13126         this.fireEvent("add", index, o, key);
13127         return o;
13128     },
13129    
13130 /**
13131  * Removed an item from the collection.
13132  * @param {Object} o The item to remove.
13133  * @return {Object} The item removed.
13134  */
13135     remove : function(o){
13136         return this.removeAt(this.indexOf(o));
13137     },
13138    
13139 /**
13140  * Remove an item from a specified index in the collection.
13141  * @param {Number} index The index within the collection of the item to remove.
13142  */
13143     removeAt : function(index){
13144         if(index < this.length && index >= 0){
13145             this.length--;
13146             var o = this.items[index];
13147             this.items.splice(index, 1);
13148             var key = this.keys[index];
13149             if(typeof key != "undefined"){
13150                 delete this.map[key];
13151             }
13152             this.keys.splice(index, 1);
13153             this.fireEvent("remove", o, key);
13154         }
13155     },
13156    
13157 /**
13158  * Removed an item associated with the passed key fom the collection.
13159  * @param {String} key The key of the item to remove.
13160  */
13161     removeKey : function(key){
13162         return this.removeAt(this.indexOfKey(key));
13163     },
13164    
13165 /**
13166  * Returns the number of items in the collection.
13167  * @return {Number} the number of items in the collection.
13168  */
13169     getCount : function(){
13170         return this.length; 
13171     },
13172    
13173 /**
13174  * Returns index within the collection of the passed Object.
13175  * @param {Object} o The item to find the index of.
13176  * @return {Number} index of the item.
13177  */
13178     indexOf : function(o){
13179         if(!this.items.indexOf){
13180             for(var i = 0, len = this.items.length; i < len; i++){
13181                 if(this.items[i] == o) {
13182                     return i;
13183                 }
13184             }
13185             return -1;
13186         }else{
13187             return this.items.indexOf(o);
13188         }
13189     },
13190    
13191 /**
13192  * Returns index within the collection of the passed key.
13193  * @param {String} key The key to find the index of.
13194  * @return {Number} index of the key.
13195  */
13196     indexOfKey : function(key){
13197         if(!this.keys.indexOf){
13198             for(var i = 0, len = this.keys.length; i < len; i++){
13199                 if(this.keys[i] == key) {
13200                     return i;
13201                 }
13202             }
13203             return -1;
13204         }else{
13205             return this.keys.indexOf(key);
13206         }
13207     },
13208    
13209 /**
13210  * Returns the item associated with the passed key OR index. Key has priority over index.
13211  * @param {String/Number} key The key or index of the item.
13212  * @return {Object} The item associated with the passed key.
13213  */
13214     item : function(key){
13215         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13216         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13217     },
13218     
13219 /**
13220  * Returns the item at the specified index.
13221  * @param {Number} index The index of the item.
13222  * @return {Object}
13223  */
13224     itemAt : function(index){
13225         return this.items[index];
13226     },
13227     
13228 /**
13229  * Returns the item associated with the passed key.
13230  * @param {String/Number} key The key of the item.
13231  * @return {Object} The item associated with the passed key.
13232  */
13233     key : function(key){
13234         return this.map[key];
13235     },
13236    
13237 /**
13238  * Returns true if the collection contains the passed Object as an item.
13239  * @param {Object} o  The Object to look for in the collection.
13240  * @return {Boolean} True if the collection contains the Object as an item.
13241  */
13242     contains : function(o){
13243         return this.indexOf(o) != -1;
13244     },
13245    
13246 /**
13247  * Returns true if the collection contains the passed Object as a key.
13248  * @param {String} key The key to look for in the collection.
13249  * @return {Boolean} True if the collection contains the Object as a key.
13250  */
13251     containsKey : function(key){
13252         return typeof this.map[key] != "undefined";
13253     },
13254    
13255 /**
13256  * Removes all items from the collection.
13257  */
13258     clear : function(){
13259         this.length = 0;
13260         this.items = [];
13261         this.keys = [];
13262         this.map = {};
13263         this.fireEvent("clear");
13264     },
13265    
13266 /**
13267  * Returns the first item in the collection.
13268  * @return {Object} the first item in the collection..
13269  */
13270     first : function(){
13271         return this.items[0]; 
13272     },
13273    
13274 /**
13275  * Returns the last item in the collection.
13276  * @return {Object} the last item in the collection..
13277  */
13278     last : function(){
13279         return this.items[this.length-1];   
13280     },
13281     
13282     _sort : function(property, dir, fn){
13283         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13284         fn = fn || function(a, b){
13285             return a-b;
13286         };
13287         var c = [], k = this.keys, items = this.items;
13288         for(var i = 0, len = items.length; i < len; i++){
13289             c[c.length] = {key: k[i], value: items[i], index: i};
13290         }
13291         c.sort(function(a, b){
13292             var v = fn(a[property], b[property]) * dsc;
13293             if(v == 0){
13294                 v = (a.index < b.index ? -1 : 1);
13295             }
13296             return v;
13297         });
13298         for(var i = 0, len = c.length; i < len; i++){
13299             items[i] = c[i].value;
13300             k[i] = c[i].key;
13301         }
13302         this.fireEvent("sort", this);
13303     },
13304     
13305     /**
13306      * Sorts this collection with the passed comparison function
13307      * @param {String} direction (optional) "ASC" or "DESC"
13308      * @param {Function} fn (optional) comparison function
13309      */
13310     sort : function(dir, fn){
13311         this._sort("value", dir, fn);
13312     },
13313     
13314     /**
13315      * Sorts this collection by keys
13316      * @param {String} direction (optional) "ASC" or "DESC"
13317      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13318      */
13319     keySort : function(dir, fn){
13320         this._sort("key", dir, fn || function(a, b){
13321             return String(a).toUpperCase()-String(b).toUpperCase();
13322         });
13323     },
13324     
13325     /**
13326      * Returns a range of items in this collection
13327      * @param {Number} startIndex (optional) defaults to 0
13328      * @param {Number} endIndex (optional) default to the last item
13329      * @return {Array} An array of items
13330      */
13331     getRange : function(start, end){
13332         var items = this.items;
13333         if(items.length < 1){
13334             return [];
13335         }
13336         start = start || 0;
13337         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13338         var r = [];
13339         if(start <= end){
13340             for(var i = start; i <= end; i++) {
13341                     r[r.length] = items[i];
13342             }
13343         }else{
13344             for(var i = start; i >= end; i--) {
13345                     r[r.length] = items[i];
13346             }
13347         }
13348         return r;
13349     },
13350         
13351     /**
13352      * Filter the <i>objects</i> in this collection by a specific property. 
13353      * Returns a new collection that has been filtered.
13354      * @param {String} property A property on your objects
13355      * @param {String/RegExp} value Either string that the property values 
13356      * should start with or a RegExp to test against the property
13357      * @return {MixedCollection} The new filtered collection
13358      */
13359     filter : function(property, value){
13360         if(!value.exec){ // not a regex
13361             value = String(value);
13362             if(value.length == 0){
13363                 return this.clone();
13364             }
13365             value = new RegExp("^" + Roo.escapeRe(value), "i");
13366         }
13367         return this.filterBy(function(o){
13368             return o && value.test(o[property]);
13369         });
13370         },
13371     
13372     /**
13373      * Filter by a function. * Returns a new collection that has been filtered.
13374      * The passed function will be called with each 
13375      * object in the collection. If the function returns true, the value is included 
13376      * otherwise it is filtered.
13377      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13378      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13379      * @return {MixedCollection} The new filtered collection
13380      */
13381     filterBy : function(fn, scope){
13382         var r = new Roo.util.MixedCollection();
13383         r.getKey = this.getKey;
13384         var k = this.keys, it = this.items;
13385         for(var i = 0, len = it.length; i < len; i++){
13386             if(fn.call(scope||this, it[i], k[i])){
13387                                 r.add(k[i], it[i]);
13388                         }
13389         }
13390         return r;
13391     },
13392     
13393     /**
13394      * Creates a duplicate of this collection
13395      * @return {MixedCollection}
13396      */
13397     clone : function(){
13398         var r = new Roo.util.MixedCollection();
13399         var k = this.keys, it = this.items;
13400         for(var i = 0, len = it.length; i < len; i++){
13401             r.add(k[i], it[i]);
13402         }
13403         r.getKey = this.getKey;
13404         return r;
13405     }
13406 });
13407 /**
13408  * Returns the item associated with the passed key or index.
13409  * @method
13410  * @param {String/Number} key The key or index of the item.
13411  * @return {Object} The item associated with the passed key.
13412  */
13413 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13414  * Based on:
13415  * Ext JS Library 1.1.1
13416  * Copyright(c) 2006-2007, Ext JS, LLC.
13417  *
13418  * Originally Released Under LGPL - original licence link has changed is not relivant.
13419  *
13420  * Fork - LGPL
13421  * <script type="text/javascript">
13422  */
13423 /**
13424  * @class Roo.util.JSON
13425  * Modified version of Douglas Crockford"s json.js that doesn"t
13426  * mess with the Object prototype 
13427  * http://www.json.org/js.html
13428  * @singleton
13429  */
13430 Roo.util.JSON = new (function(){
13431     var useHasOwn = {}.hasOwnProperty ? true : false;
13432     
13433     // crashes Safari in some instances
13434     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13435     
13436     var pad = function(n) {
13437         return n < 10 ? "0" + n : n;
13438     };
13439     
13440     var m = {
13441         "\b": '\\b',
13442         "\t": '\\t',
13443         "\n": '\\n',
13444         "\f": '\\f',
13445         "\r": '\\r',
13446         '"' : '\\"',
13447         "\\": '\\\\'
13448     };
13449
13450     var encodeString = function(s){
13451         if (/["\\\x00-\x1f]/.test(s)) {
13452             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13453                 var c = m[b];
13454                 if(c){
13455                     return c;
13456                 }
13457                 c = b.charCodeAt();
13458                 return "\\u00" +
13459                     Math.floor(c / 16).toString(16) +
13460                     (c % 16).toString(16);
13461             }) + '"';
13462         }
13463         return '"' + s + '"';
13464     };
13465     
13466     var encodeArray = function(o){
13467         var a = ["["], b, i, l = o.length, v;
13468             for (i = 0; i < l; i += 1) {
13469                 v = o[i];
13470                 switch (typeof v) {
13471                     case "undefined":
13472                     case "function":
13473                     case "unknown":
13474                         break;
13475                     default:
13476                         if (b) {
13477                             a.push(',');
13478                         }
13479                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13480                         b = true;
13481                 }
13482             }
13483             a.push("]");
13484             return a.join("");
13485     };
13486     
13487     var encodeDate = function(o){
13488         return '"' + o.getFullYear() + "-" +
13489                 pad(o.getMonth() + 1) + "-" +
13490                 pad(o.getDate()) + "T" +
13491                 pad(o.getHours()) + ":" +
13492                 pad(o.getMinutes()) + ":" +
13493                 pad(o.getSeconds()) + '"';
13494     };
13495     
13496     /**
13497      * Encodes an Object, Array or other value
13498      * @param {Mixed} o The variable to encode
13499      * @return {String} The JSON string
13500      */
13501     this.encode = function(o)
13502     {
13503         // should this be extended to fully wrap stringify..
13504         
13505         if(typeof o == "undefined" || o === null){
13506             return "null";
13507         }else if(o instanceof Array){
13508             return encodeArray(o);
13509         }else if(o instanceof Date){
13510             return encodeDate(o);
13511         }else if(typeof o == "string"){
13512             return encodeString(o);
13513         }else if(typeof o == "number"){
13514             return isFinite(o) ? String(o) : "null";
13515         }else if(typeof o == "boolean"){
13516             return String(o);
13517         }else {
13518             var a = ["{"], b, i, v;
13519             for (i in o) {
13520                 if(!useHasOwn || o.hasOwnProperty(i)) {
13521                     v = o[i];
13522                     switch (typeof v) {
13523                     case "undefined":
13524                     case "function":
13525                     case "unknown":
13526                         break;
13527                     default:
13528                         if(b){
13529                             a.push(',');
13530                         }
13531                         a.push(this.encode(i), ":",
13532                                 v === null ? "null" : this.encode(v));
13533                         b = true;
13534                     }
13535                 }
13536             }
13537             a.push("}");
13538             return a.join("");
13539         }
13540     };
13541     
13542     /**
13543      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13544      * @param {String} json The JSON string
13545      * @return {Object} The resulting object
13546      */
13547     this.decode = function(json){
13548         
13549         return  /** eval:var:json */ eval("(" + json + ')');
13550     };
13551 })();
13552 /** 
13553  * Shorthand for {@link Roo.util.JSON#encode}
13554  * @member Roo encode 
13555  * @method */
13556 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13557 /** 
13558  * Shorthand for {@link Roo.util.JSON#decode}
13559  * @member Roo decode 
13560  * @method */
13561 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13562 /*
13563  * Based on:
13564  * Ext JS Library 1.1.1
13565  * Copyright(c) 2006-2007, Ext JS, LLC.
13566  *
13567  * Originally Released Under LGPL - original licence link has changed is not relivant.
13568  *
13569  * Fork - LGPL
13570  * <script type="text/javascript">
13571  */
13572  
13573 /**
13574  * @class Roo.util.Format
13575  * Reusable data formatting functions
13576  * @singleton
13577  */
13578 Roo.util.Format = function(){
13579     var trimRe = /^\s+|\s+$/g;
13580     return {
13581         /**
13582          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13583          * @param {String} value The string to truncate
13584          * @param {Number} length The maximum length to allow before truncating
13585          * @return {String} The converted text
13586          */
13587         ellipsis : function(value, len){
13588             if(value && value.length > len){
13589                 return value.substr(0, len-3)+"...";
13590             }
13591             return value;
13592         },
13593
13594         /**
13595          * Checks a reference and converts it to empty string if it is undefined
13596          * @param {Mixed} value Reference to check
13597          * @return {Mixed} Empty string if converted, otherwise the original value
13598          */
13599         undef : function(value){
13600             return typeof value != "undefined" ? value : "";
13601         },
13602
13603         /**
13604          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13605          * @param {String} value The string to encode
13606          * @return {String} The encoded text
13607          */
13608         htmlEncode : function(value){
13609             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13610         },
13611
13612         /**
13613          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13614          * @param {String} value The string to decode
13615          * @return {String} The decoded text
13616          */
13617         htmlDecode : function(value){
13618             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13619         },
13620
13621         /**
13622          * Trims any whitespace from either side of a string
13623          * @param {String} value The text to trim
13624          * @return {String} The trimmed text
13625          */
13626         trim : function(value){
13627             return String(value).replace(trimRe, "");
13628         },
13629
13630         /**
13631          * Returns a substring from within an original string
13632          * @param {String} value The original text
13633          * @param {Number} start The start index of the substring
13634          * @param {Number} length The length of the substring
13635          * @return {String} The substring
13636          */
13637         substr : function(value, start, length){
13638             return String(value).substr(start, length);
13639         },
13640
13641         /**
13642          * Converts a string to all lower case letters
13643          * @param {String} value The text to convert
13644          * @return {String} The converted text
13645          */
13646         lowercase : function(value){
13647             return String(value).toLowerCase();
13648         },
13649
13650         /**
13651          * Converts a string to all upper case letters
13652          * @param {String} value The text to convert
13653          * @return {String} The converted text
13654          */
13655         uppercase : function(value){
13656             return String(value).toUpperCase();
13657         },
13658
13659         /**
13660          * Converts the first character only of a string to upper case
13661          * @param {String} value The text to convert
13662          * @return {String} The converted text
13663          */
13664         capitalize : function(value){
13665             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13666         },
13667
13668         // private
13669         call : function(value, fn){
13670             if(arguments.length > 2){
13671                 var args = Array.prototype.slice.call(arguments, 2);
13672                 args.unshift(value);
13673                  
13674                 return /** eval:var:value */  eval(fn).apply(window, args);
13675             }else{
13676                 /** eval:var:value */
13677                 return /** eval:var:value */ eval(fn).call(window, value);
13678             }
13679         },
13680
13681        
13682         /**
13683          * safer version of Math.toFixed..??/
13684          * @param {Number/String} value The numeric value to format
13685          * @param {Number/String} value Decimal places 
13686          * @return {String} The formatted currency string
13687          */
13688         toFixed : function(v, n)
13689         {
13690             // why not use to fixed - precision is buggered???
13691             if (!n) {
13692                 return Math.round(v-0);
13693             }
13694             var fact = Math.pow(10,n+1);
13695             v = (Math.round((v-0)*fact))/fact;
13696             var z = (''+fact).substring(2);
13697             if (v == Math.floor(v)) {
13698                 return Math.floor(v) + '.' + z;
13699             }
13700             
13701             // now just padd decimals..
13702             var ps = String(v).split('.');
13703             var fd = (ps[1] + z);
13704             var r = fd.substring(0,n); 
13705             var rm = fd.substring(n); 
13706             if (rm < 5) {
13707                 return ps[0] + '.' + r;
13708             }
13709             r*=1; // turn it into a number;
13710             r++;
13711             if (String(r).length != n) {
13712                 ps[0]*=1;
13713                 ps[0]++;
13714                 r = String(r).substring(1); // chop the end off.
13715             }
13716             
13717             return ps[0] + '.' + r;
13718              
13719         },
13720         
13721         /**
13722          * Format a number as US currency
13723          * @param {Number/String} value The numeric value to format
13724          * @return {String} The formatted currency string
13725          */
13726         usMoney : function(v){
13727             return '$' + Roo.util.Format.number(v);
13728         },
13729         
13730         /**
13731          * Format a number
13732          * eventually this should probably emulate php's number_format
13733          * @param {Number/String} value The numeric value to format
13734          * @param {Number} decimals number of decimal places
13735          * @return {String} The formatted currency string
13736          */
13737         number : function(v,decimals)
13738         {
13739             // multiply and round.
13740             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13741             var mul = Math.pow(10, decimals);
13742             var zero = String(mul).substring(1);
13743             v = (Math.round((v-0)*mul))/mul;
13744             
13745             // if it's '0' number.. then
13746             
13747             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13748             v = String(v);
13749             var ps = v.split('.');
13750             var whole = ps[0];
13751             
13752             
13753             var r = /(\d+)(\d{3})/;
13754             // add comma's
13755             while (r.test(whole)) {
13756                 whole = whole.replace(r, '$1' + ',' + '$2');
13757             }
13758             
13759             
13760             var sub = ps[1] ?
13761                     // has decimals..
13762                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13763                     // does not have decimals
13764                     (decimals ? ('.' + zero) : '');
13765             
13766             
13767             return whole + sub ;
13768         },
13769         
13770         /**
13771          * Parse a value into a formatted date using the specified format pattern.
13772          * @param {Mixed} value The value to format
13773          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13774          * @return {String} The formatted date string
13775          */
13776         date : function(v, format){
13777             if(!v){
13778                 return "";
13779             }
13780             if(!(v instanceof Date)){
13781                 v = new Date(Date.parse(v));
13782             }
13783             return v.dateFormat(format || Roo.util.Format.defaults.date);
13784         },
13785
13786         /**
13787          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13788          * @param {String} format Any valid date format string
13789          * @return {Function} The date formatting function
13790          */
13791         dateRenderer : function(format){
13792             return function(v){
13793                 return Roo.util.Format.date(v, format);  
13794             };
13795         },
13796
13797         // private
13798         stripTagsRE : /<\/?[^>]+>/gi,
13799         
13800         /**
13801          * Strips all HTML tags
13802          * @param {Mixed} value The text from which to strip tags
13803          * @return {String} The stripped text
13804          */
13805         stripTags : function(v){
13806             return !v ? v : String(v).replace(this.stripTagsRE, "");
13807         }
13808     };
13809 }();
13810 Roo.util.Format.defaults = {
13811     date : 'd/M/Y'
13812 };/*
13813  * Based on:
13814  * Ext JS Library 1.1.1
13815  * Copyright(c) 2006-2007, Ext JS, LLC.
13816  *
13817  * Originally Released Under LGPL - original licence link has changed is not relivant.
13818  *
13819  * Fork - LGPL
13820  * <script type="text/javascript">
13821  */
13822
13823
13824  
13825
13826 /**
13827  * @class Roo.MasterTemplate
13828  * @extends Roo.Template
13829  * Provides a template that can have child templates. The syntax is:
13830 <pre><code>
13831 var t = new Roo.MasterTemplate(
13832         '&lt;select name="{name}"&gt;',
13833                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13834         '&lt;/select&gt;'
13835 );
13836 t.add('options', {value: 'foo', text: 'bar'});
13837 // or you can add multiple child elements in one shot
13838 t.addAll('options', [
13839     {value: 'foo', text: 'bar'},
13840     {value: 'foo2', text: 'bar2'},
13841     {value: 'foo3', text: 'bar3'}
13842 ]);
13843 // then append, applying the master template values
13844 t.append('my-form', {name: 'my-select'});
13845 </code></pre>
13846 * A name attribute for the child template is not required if you have only one child
13847 * template or you want to refer to them by index.
13848  */
13849 Roo.MasterTemplate = function(){
13850     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13851     this.originalHtml = this.html;
13852     var st = {};
13853     var m, re = this.subTemplateRe;
13854     re.lastIndex = 0;
13855     var subIndex = 0;
13856     while(m = re.exec(this.html)){
13857         var name = m[1], content = m[2];
13858         st[subIndex] = {
13859             name: name,
13860             index: subIndex,
13861             buffer: [],
13862             tpl : new Roo.Template(content)
13863         };
13864         if(name){
13865             st[name] = st[subIndex];
13866         }
13867         st[subIndex].tpl.compile();
13868         st[subIndex].tpl.call = this.call.createDelegate(this);
13869         subIndex++;
13870     }
13871     this.subCount = subIndex;
13872     this.subs = st;
13873 };
13874 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13875     /**
13876     * The regular expression used to match sub templates
13877     * @type RegExp
13878     * @property
13879     */
13880     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13881
13882     /**
13883      * Applies the passed values to a child template.
13884      * @param {String/Number} name (optional) The name or index of the child template
13885      * @param {Array/Object} values The values to be applied to the template
13886      * @return {MasterTemplate} this
13887      */
13888      add : function(name, values){
13889         if(arguments.length == 1){
13890             values = arguments[0];
13891             name = 0;
13892         }
13893         var s = this.subs[name];
13894         s.buffer[s.buffer.length] = s.tpl.apply(values);
13895         return this;
13896     },
13897
13898     /**
13899      * Applies all the passed values to a child template.
13900      * @param {String/Number} name (optional) The name or index of the child template
13901      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13902      * @param {Boolean} reset (optional) True to reset the template first
13903      * @return {MasterTemplate} this
13904      */
13905     fill : function(name, values, reset){
13906         var a = arguments;
13907         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13908             values = a[0];
13909             name = 0;
13910             reset = a[1];
13911         }
13912         if(reset){
13913             this.reset();
13914         }
13915         for(var i = 0, len = values.length; i < len; i++){
13916             this.add(name, values[i]);
13917         }
13918         return this;
13919     },
13920
13921     /**
13922      * Resets the template for reuse
13923      * @return {MasterTemplate} this
13924      */
13925      reset : function(){
13926         var s = this.subs;
13927         for(var i = 0; i < this.subCount; i++){
13928             s[i].buffer = [];
13929         }
13930         return this;
13931     },
13932
13933     applyTemplate : function(values){
13934         var s = this.subs;
13935         var replaceIndex = -1;
13936         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13937             return s[++replaceIndex].buffer.join("");
13938         });
13939         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13940     },
13941
13942     apply : function(){
13943         return this.applyTemplate.apply(this, arguments);
13944     },
13945
13946     compile : function(){return this;}
13947 });
13948
13949 /**
13950  * Alias for fill().
13951  * @method
13952  */
13953 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13954  /**
13955  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13956  * var tpl = Roo.MasterTemplate.from('element-id');
13957  * @param {String/HTMLElement} el
13958  * @param {Object} config
13959  * @static
13960  */
13961 Roo.MasterTemplate.from = function(el, config){
13962     el = Roo.getDom(el);
13963     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13964 };/*
13965  * Based on:
13966  * Ext JS Library 1.1.1
13967  * Copyright(c) 2006-2007, Ext JS, LLC.
13968  *
13969  * Originally Released Under LGPL - original licence link has changed is not relivant.
13970  *
13971  * Fork - LGPL
13972  * <script type="text/javascript">
13973  */
13974
13975  
13976 /**
13977  * @class Roo.util.CSS
13978  * Utility class for manipulating CSS rules
13979  * @singleton
13980  */
13981 Roo.util.CSS = function(){
13982         var rules = null;
13983         var doc = document;
13984
13985     var camelRe = /(-[a-z])/gi;
13986     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13987
13988    return {
13989    /**
13990     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13991     * tag and appended to the HEAD of the document.
13992     * @param {String|Object} cssText The text containing the css rules
13993     * @param {String} id An id to add to the stylesheet for later removal
13994     * @return {StyleSheet}
13995     */
13996     createStyleSheet : function(cssText, id){
13997         var ss;
13998         var head = doc.getElementsByTagName("head")[0];
13999         var nrules = doc.createElement("style");
14000         nrules.setAttribute("type", "text/css");
14001         if(id){
14002             nrules.setAttribute("id", id);
14003         }
14004         if (typeof(cssText) != 'string') {
14005             // support object maps..
14006             // not sure if this a good idea.. 
14007             // perhaps it should be merged with the general css handling
14008             // and handle js style props.
14009             var cssTextNew = [];
14010             for(var n in cssText) {
14011                 var citems = [];
14012                 for(var k in cssText[n]) {
14013                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14014                 }
14015                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14016                 
14017             }
14018             cssText = cssTextNew.join("\n");
14019             
14020         }
14021        
14022        
14023        if(Roo.isIE){
14024            head.appendChild(nrules);
14025            ss = nrules.styleSheet;
14026            ss.cssText = cssText;
14027        }else{
14028            try{
14029                 nrules.appendChild(doc.createTextNode(cssText));
14030            }catch(e){
14031                nrules.cssText = cssText; 
14032            }
14033            head.appendChild(nrules);
14034            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14035        }
14036        this.cacheStyleSheet(ss);
14037        return ss;
14038    },
14039
14040    /**
14041     * Removes a style or link tag by id
14042     * @param {String} id The id of the tag
14043     */
14044    removeStyleSheet : function(id){
14045        var existing = doc.getElementById(id);
14046        if(existing){
14047            existing.parentNode.removeChild(existing);
14048        }
14049    },
14050
14051    /**
14052     * Dynamically swaps an existing stylesheet reference for a new one
14053     * @param {String} id The id of an existing link tag to remove
14054     * @param {String} url The href of the new stylesheet to include
14055     */
14056    swapStyleSheet : function(id, url){
14057        this.removeStyleSheet(id);
14058        var ss = doc.createElement("link");
14059        ss.setAttribute("rel", "stylesheet");
14060        ss.setAttribute("type", "text/css");
14061        ss.setAttribute("id", id);
14062        ss.setAttribute("href", url);
14063        doc.getElementsByTagName("head")[0].appendChild(ss);
14064    },
14065    
14066    /**
14067     * Refresh the rule cache if you have dynamically added stylesheets
14068     * @return {Object} An object (hash) of rules indexed by selector
14069     */
14070    refreshCache : function(){
14071        return this.getRules(true);
14072    },
14073
14074    // private
14075    cacheStyleSheet : function(stylesheet){
14076        if(!rules){
14077            rules = {};
14078        }
14079        try{// try catch for cross domain access issue
14080            var ssRules = stylesheet.cssRules || stylesheet.rules;
14081            for(var j = ssRules.length-1; j >= 0; --j){
14082                rules[ssRules[j].selectorText] = ssRules[j];
14083            }
14084        }catch(e){}
14085    },
14086    
14087    /**
14088     * Gets all css rules for the document
14089     * @param {Boolean} refreshCache true to refresh the internal cache
14090     * @return {Object} An object (hash) of rules indexed by selector
14091     */
14092    getRules : function(refreshCache){
14093                 if(rules == null || refreshCache){
14094                         rules = {};
14095                         var ds = doc.styleSheets;
14096                         for(var i =0, len = ds.length; i < len; i++){
14097                             try{
14098                         this.cacheStyleSheet(ds[i]);
14099                     }catch(e){} 
14100                 }
14101                 }
14102                 return rules;
14103         },
14104         
14105         /**
14106     * Gets an an individual CSS rule by selector(s)
14107     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14108     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14109     * @return {CSSRule} The CSS rule or null if one is not found
14110     */
14111    getRule : function(selector, refreshCache){
14112                 var rs = this.getRules(refreshCache);
14113                 if(!(selector instanceof Array)){
14114                     return rs[selector];
14115                 }
14116                 for(var i = 0; i < selector.length; i++){
14117                         if(rs[selector[i]]){
14118                                 return rs[selector[i]];
14119                         }
14120                 }
14121                 return null;
14122         },
14123         
14124         
14125         /**
14126     * Updates a rule property
14127     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14128     * @param {String} property The css property
14129     * @param {String} value The new value for the property
14130     * @return {Boolean} true If a rule was found and updated
14131     */
14132    updateRule : function(selector, property, value){
14133                 if(!(selector instanceof Array)){
14134                         var rule = this.getRule(selector);
14135                         if(rule){
14136                                 rule.style[property.replace(camelRe, camelFn)] = value;
14137                                 return true;
14138                         }
14139                 }else{
14140                         for(var i = 0; i < selector.length; i++){
14141                                 if(this.updateRule(selector[i], property, value)){
14142                                         return true;
14143                                 }
14144                         }
14145                 }
14146                 return false;
14147         }
14148    };   
14149 }();/*
14150  * Based on:
14151  * Ext JS Library 1.1.1
14152  * Copyright(c) 2006-2007, Ext JS, LLC.
14153  *
14154  * Originally Released Under LGPL - original licence link has changed is not relivant.
14155  *
14156  * Fork - LGPL
14157  * <script type="text/javascript">
14158  */
14159
14160  
14161
14162 /**
14163  * @class Roo.util.ClickRepeater
14164  * @extends Roo.util.Observable
14165  * 
14166  * A wrapper class which can be applied to any element. Fires a "click" event while the
14167  * mouse is pressed. The interval between firings may be specified in the config but
14168  * defaults to 10 milliseconds.
14169  * 
14170  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14171  * 
14172  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14173  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14174  * Similar to an autorepeat key delay.
14175  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14176  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14177  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14178  *           "interval" and "delay" are ignored. "immediate" is honored.
14179  * @cfg {Boolean} preventDefault True to prevent the default click event
14180  * @cfg {Boolean} stopDefault True to stop the default click event
14181  * 
14182  * @history
14183  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14184  *     2007-02-02 jvs Renamed to ClickRepeater
14185  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14186  *
14187  *  @constructor
14188  * @param {String/HTMLElement/Element} el The element to listen on
14189  * @param {Object} config
14190  **/
14191 Roo.util.ClickRepeater = function(el, config)
14192 {
14193     this.el = Roo.get(el);
14194     this.el.unselectable();
14195
14196     Roo.apply(this, config);
14197
14198     this.addEvents({
14199     /**
14200      * @event mousedown
14201      * Fires when the mouse button is depressed.
14202      * @param {Roo.util.ClickRepeater} this
14203      */
14204         "mousedown" : true,
14205     /**
14206      * @event click
14207      * Fires on a specified interval during the time the element is pressed.
14208      * @param {Roo.util.ClickRepeater} this
14209      */
14210         "click" : true,
14211     /**
14212      * @event mouseup
14213      * Fires when the mouse key is released.
14214      * @param {Roo.util.ClickRepeater} this
14215      */
14216         "mouseup" : true
14217     });
14218
14219     this.el.on("mousedown", this.handleMouseDown, this);
14220     if(this.preventDefault || this.stopDefault){
14221         this.el.on("click", function(e){
14222             if(this.preventDefault){
14223                 e.preventDefault();
14224             }
14225             if(this.stopDefault){
14226                 e.stopEvent();
14227             }
14228         }, this);
14229     }
14230
14231     // allow inline handler
14232     if(this.handler){
14233         this.on("click", this.handler,  this.scope || this);
14234     }
14235
14236     Roo.util.ClickRepeater.superclass.constructor.call(this);
14237 };
14238
14239 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14240     interval : 20,
14241     delay: 250,
14242     preventDefault : true,
14243     stopDefault : false,
14244     timer : 0,
14245
14246     // private
14247     handleMouseDown : function(){
14248         clearTimeout(this.timer);
14249         this.el.blur();
14250         if(this.pressClass){
14251             this.el.addClass(this.pressClass);
14252         }
14253         this.mousedownTime = new Date();
14254
14255         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14256         this.el.on("mouseout", this.handleMouseOut, this);
14257
14258         this.fireEvent("mousedown", this);
14259         this.fireEvent("click", this);
14260         
14261         this.timer = this.click.defer(this.delay || this.interval, this);
14262     },
14263
14264     // private
14265     click : function(){
14266         this.fireEvent("click", this);
14267         this.timer = this.click.defer(this.getInterval(), this);
14268     },
14269
14270     // private
14271     getInterval: function(){
14272         if(!this.accelerate){
14273             return this.interval;
14274         }
14275         var pressTime = this.mousedownTime.getElapsed();
14276         if(pressTime < 500){
14277             return 400;
14278         }else if(pressTime < 1700){
14279             return 320;
14280         }else if(pressTime < 2600){
14281             return 250;
14282         }else if(pressTime < 3500){
14283             return 180;
14284         }else if(pressTime < 4400){
14285             return 140;
14286         }else if(pressTime < 5300){
14287             return 80;
14288         }else if(pressTime < 6200){
14289             return 50;
14290         }else{
14291             return 10;
14292         }
14293     },
14294
14295     // private
14296     handleMouseOut : function(){
14297         clearTimeout(this.timer);
14298         if(this.pressClass){
14299             this.el.removeClass(this.pressClass);
14300         }
14301         this.el.on("mouseover", this.handleMouseReturn, this);
14302     },
14303
14304     // private
14305     handleMouseReturn : function(){
14306         this.el.un("mouseover", this.handleMouseReturn);
14307         if(this.pressClass){
14308             this.el.addClass(this.pressClass);
14309         }
14310         this.click();
14311     },
14312
14313     // private
14314     handleMouseUp : function(){
14315         clearTimeout(this.timer);
14316         this.el.un("mouseover", this.handleMouseReturn);
14317         this.el.un("mouseout", this.handleMouseOut);
14318         Roo.get(document).un("mouseup", this.handleMouseUp);
14319         this.el.removeClass(this.pressClass);
14320         this.fireEvent("mouseup", this);
14321     }
14322 });/*
14323  * Based on:
14324  * Ext JS Library 1.1.1
14325  * Copyright(c) 2006-2007, Ext JS, LLC.
14326  *
14327  * Originally Released Under LGPL - original licence link has changed is not relivant.
14328  *
14329  * Fork - LGPL
14330  * <script type="text/javascript">
14331  */
14332
14333  
14334 /**
14335  * @class Roo.KeyNav
14336  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14337  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14338  * way to implement custom navigation schemes for any UI component.</p>
14339  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14340  * pageUp, pageDown, del, home, end.  Usage:</p>
14341  <pre><code>
14342 var nav = new Roo.KeyNav("my-element", {
14343     "left" : function(e){
14344         this.moveLeft(e.ctrlKey);
14345     },
14346     "right" : function(e){
14347         this.moveRight(e.ctrlKey);
14348     },
14349     "enter" : function(e){
14350         this.save();
14351     },
14352     scope : this
14353 });
14354 </code></pre>
14355  * @constructor
14356  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14357  * @param {Object} config The config
14358  */
14359 Roo.KeyNav = function(el, config){
14360     this.el = Roo.get(el);
14361     Roo.apply(this, config);
14362     if(!this.disabled){
14363         this.disabled = true;
14364         this.enable();
14365     }
14366 };
14367
14368 Roo.KeyNav.prototype = {
14369     /**
14370      * @cfg {Boolean} disabled
14371      * True to disable this KeyNav instance (defaults to false)
14372      */
14373     disabled : false,
14374     /**
14375      * @cfg {String} defaultEventAction
14376      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14377      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14378      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14379      */
14380     defaultEventAction: "stopEvent",
14381     /**
14382      * @cfg {Boolean} forceKeyDown
14383      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14384      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14385      * handle keydown instead of keypress.
14386      */
14387     forceKeyDown : false,
14388
14389     // private
14390     prepareEvent : function(e){
14391         var k = e.getKey();
14392         var h = this.keyToHandler[k];
14393         //if(h && this[h]){
14394         //    e.stopPropagation();
14395         //}
14396         if(Roo.isSafari && h && k >= 37 && k <= 40){
14397             e.stopEvent();
14398         }
14399     },
14400
14401     // private
14402     relay : function(e){
14403         var k = e.getKey();
14404         var h = this.keyToHandler[k];
14405         if(h && this[h]){
14406             if(this.doRelay(e, this[h], h) !== true){
14407                 e[this.defaultEventAction]();
14408             }
14409         }
14410     },
14411
14412     // private
14413     doRelay : function(e, h, hname){
14414         return h.call(this.scope || this, e);
14415     },
14416
14417     // possible handlers
14418     enter : false,
14419     left : false,
14420     right : false,
14421     up : false,
14422     down : false,
14423     tab : false,
14424     esc : false,
14425     pageUp : false,
14426     pageDown : false,
14427     del : false,
14428     home : false,
14429     end : false,
14430
14431     // quick lookup hash
14432     keyToHandler : {
14433         37 : "left",
14434         39 : "right",
14435         38 : "up",
14436         40 : "down",
14437         33 : "pageUp",
14438         34 : "pageDown",
14439         46 : "del",
14440         36 : "home",
14441         35 : "end",
14442         13 : "enter",
14443         27 : "esc",
14444         9  : "tab"
14445     },
14446
14447         /**
14448          * Enable this KeyNav
14449          */
14450         enable: function(){
14451                 if(this.disabled){
14452             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14453             // the EventObject will normalize Safari automatically
14454             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14455                 this.el.on("keydown", this.relay,  this);
14456             }else{
14457                 this.el.on("keydown", this.prepareEvent,  this);
14458                 this.el.on("keypress", this.relay,  this);
14459             }
14460                     this.disabled = false;
14461                 }
14462         },
14463
14464         /**
14465          * Disable this KeyNav
14466          */
14467         disable: function(){
14468                 if(!this.disabled){
14469                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14470                 this.el.un("keydown", this.relay);
14471             }else{
14472                 this.el.un("keydown", this.prepareEvent);
14473                 this.el.un("keypress", this.relay);
14474             }
14475                     this.disabled = true;
14476                 }
14477         }
14478 };/*
14479  * Based on:
14480  * Ext JS Library 1.1.1
14481  * Copyright(c) 2006-2007, Ext JS, LLC.
14482  *
14483  * Originally Released Under LGPL - original licence link has changed is not relivant.
14484  *
14485  * Fork - LGPL
14486  * <script type="text/javascript">
14487  */
14488
14489  
14490 /**
14491  * @class Roo.KeyMap
14492  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14493  * The constructor accepts the same config object as defined by {@link #addBinding}.
14494  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14495  * combination it will call the function with this signature (if the match is a multi-key
14496  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14497  * A KeyMap can also handle a string representation of keys.<br />
14498  * Usage:
14499  <pre><code>
14500 // map one key by key code
14501 var map = new Roo.KeyMap("my-element", {
14502     key: 13, // or Roo.EventObject.ENTER
14503     fn: myHandler,
14504     scope: myObject
14505 });
14506
14507 // map multiple keys to one action by string
14508 var map = new Roo.KeyMap("my-element", {
14509     key: "a\r\n\t",
14510     fn: myHandler,
14511     scope: myObject
14512 });
14513
14514 // map multiple keys to multiple actions by strings and array of codes
14515 var map = new Roo.KeyMap("my-element", [
14516     {
14517         key: [10,13],
14518         fn: function(){ alert("Return was pressed"); }
14519     }, {
14520         key: "abc",
14521         fn: function(){ alert('a, b or c was pressed'); }
14522     }, {
14523         key: "\t",
14524         ctrl:true,
14525         shift:true,
14526         fn: function(){ alert('Control + shift + tab was pressed.'); }
14527     }
14528 ]);
14529 </code></pre>
14530  * <b>Note: A KeyMap starts enabled</b>
14531  * @constructor
14532  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14533  * @param {Object} config The config (see {@link #addBinding})
14534  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14535  */
14536 Roo.KeyMap = function(el, config, eventName){
14537     this.el  = Roo.get(el);
14538     this.eventName = eventName || "keydown";
14539     this.bindings = [];
14540     if(config){
14541         this.addBinding(config);
14542     }
14543     this.enable();
14544 };
14545
14546 Roo.KeyMap.prototype = {
14547     /**
14548      * True to stop the event from bubbling and prevent the default browser action if the
14549      * key was handled by the KeyMap (defaults to false)
14550      * @type Boolean
14551      */
14552     stopEvent : false,
14553
14554     /**
14555      * Add a new binding to this KeyMap. The following config object properties are supported:
14556      * <pre>
14557 Property    Type             Description
14558 ----------  ---------------  ----------------------------------------------------------------------
14559 key         String/Array     A single keycode or an array of keycodes to handle
14560 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14561 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14562 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14563 fn          Function         The function to call when KeyMap finds the expected key combination
14564 scope       Object           The scope of the callback function
14565 </pre>
14566      *
14567      * Usage:
14568      * <pre><code>
14569 // Create a KeyMap
14570 var map = new Roo.KeyMap(document, {
14571     key: Roo.EventObject.ENTER,
14572     fn: handleKey,
14573     scope: this
14574 });
14575
14576 //Add a new binding to the existing KeyMap later
14577 map.addBinding({
14578     key: 'abc',
14579     shift: true,
14580     fn: handleKey,
14581     scope: this
14582 });
14583 </code></pre>
14584      * @param {Object/Array} config A single KeyMap config or an array of configs
14585      */
14586         addBinding : function(config){
14587         if(config instanceof Array){
14588             for(var i = 0, len = config.length; i < len; i++){
14589                 this.addBinding(config[i]);
14590             }
14591             return;
14592         }
14593         var keyCode = config.key,
14594             shift = config.shift, 
14595             ctrl = config.ctrl, 
14596             alt = config.alt,
14597             fn = config.fn,
14598             scope = config.scope;
14599         if(typeof keyCode == "string"){
14600             var ks = [];
14601             var keyString = keyCode.toUpperCase();
14602             for(var j = 0, len = keyString.length; j < len; j++){
14603                 ks.push(keyString.charCodeAt(j));
14604             }
14605             keyCode = ks;
14606         }
14607         var keyArray = keyCode instanceof Array;
14608         var handler = function(e){
14609             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14610                 var k = e.getKey();
14611                 if(keyArray){
14612                     for(var i = 0, len = keyCode.length; i < len; i++){
14613                         if(keyCode[i] == k){
14614                           if(this.stopEvent){
14615                               e.stopEvent();
14616                           }
14617                           fn.call(scope || window, k, e);
14618                           return;
14619                         }
14620                     }
14621                 }else{
14622                     if(k == keyCode){
14623                         if(this.stopEvent){
14624                            e.stopEvent();
14625                         }
14626                         fn.call(scope || window, k, e);
14627                     }
14628                 }
14629             }
14630         };
14631         this.bindings.push(handler);  
14632         },
14633
14634     /**
14635      * Shorthand for adding a single key listener
14636      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14637      * following options:
14638      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14639      * @param {Function} fn The function to call
14640      * @param {Object} scope (optional) The scope of the function
14641      */
14642     on : function(key, fn, scope){
14643         var keyCode, shift, ctrl, alt;
14644         if(typeof key == "object" && !(key instanceof Array)){
14645             keyCode = key.key;
14646             shift = key.shift;
14647             ctrl = key.ctrl;
14648             alt = key.alt;
14649         }else{
14650             keyCode = key;
14651         }
14652         this.addBinding({
14653             key: keyCode,
14654             shift: shift,
14655             ctrl: ctrl,
14656             alt: alt,
14657             fn: fn,
14658             scope: scope
14659         })
14660     },
14661
14662     // private
14663     handleKeyDown : function(e){
14664             if(this.enabled){ //just in case
14665             var b = this.bindings;
14666             for(var i = 0, len = b.length; i < len; i++){
14667                 b[i].call(this, e);
14668             }
14669             }
14670         },
14671         
14672         /**
14673          * Returns true if this KeyMap is enabled
14674          * @return {Boolean} 
14675          */
14676         isEnabled : function(){
14677             return this.enabled;  
14678         },
14679         
14680         /**
14681          * Enables this KeyMap
14682          */
14683         enable: function(){
14684                 if(!this.enabled){
14685                     this.el.on(this.eventName, this.handleKeyDown, this);
14686                     this.enabled = true;
14687                 }
14688         },
14689
14690         /**
14691          * Disable this KeyMap
14692          */
14693         disable: function(){
14694                 if(this.enabled){
14695                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14696                     this.enabled = false;
14697                 }
14698         }
14699 };/*
14700  * Based on:
14701  * Ext JS Library 1.1.1
14702  * Copyright(c) 2006-2007, Ext JS, LLC.
14703  *
14704  * Originally Released Under LGPL - original licence link has changed is not relivant.
14705  *
14706  * Fork - LGPL
14707  * <script type="text/javascript">
14708  */
14709
14710  
14711 /**
14712  * @class Roo.util.TextMetrics
14713  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14714  * wide, in pixels, a given block of text will be.
14715  * @singleton
14716  */
14717 Roo.util.TextMetrics = function(){
14718     var shared;
14719     return {
14720         /**
14721          * Measures the size of the specified text
14722          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14723          * that can affect the size of the rendered text
14724          * @param {String} text The text to measure
14725          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14726          * in order to accurately measure the text height
14727          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14728          */
14729         measure : function(el, text, fixedWidth){
14730             if(!shared){
14731                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14732             }
14733             shared.bind(el);
14734             shared.setFixedWidth(fixedWidth || 'auto');
14735             return shared.getSize(text);
14736         },
14737
14738         /**
14739          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14740          * the overhead of multiple calls to initialize the style properties on each measurement.
14741          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14742          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14743          * in order to accurately measure the text height
14744          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14745          */
14746         createInstance : function(el, fixedWidth){
14747             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14748         }
14749     };
14750 }();
14751
14752  
14753
14754 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14755     var ml = new Roo.Element(document.createElement('div'));
14756     document.body.appendChild(ml.dom);
14757     ml.position('absolute');
14758     ml.setLeftTop(-1000, -1000);
14759     ml.hide();
14760
14761     if(fixedWidth){
14762         ml.setWidth(fixedWidth);
14763     }
14764      
14765     var instance = {
14766         /**
14767          * Returns the size of the specified text based on the internal element's style and width properties
14768          * @memberOf Roo.util.TextMetrics.Instance#
14769          * @param {String} text The text to measure
14770          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14771          */
14772         getSize : function(text){
14773             ml.update(text);
14774             var s = ml.getSize();
14775             ml.update('');
14776             return s;
14777         },
14778
14779         /**
14780          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14781          * that can affect the size of the rendered text
14782          * @memberOf Roo.util.TextMetrics.Instance#
14783          * @param {String/HTMLElement} el The element, dom node or id
14784          */
14785         bind : function(el){
14786             ml.setStyle(
14787                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14788             );
14789         },
14790
14791         /**
14792          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14793          * to set a fixed width in order to accurately measure the text height.
14794          * @memberOf Roo.util.TextMetrics.Instance#
14795          * @param {Number} width The width to set on the element
14796          */
14797         setFixedWidth : function(width){
14798             ml.setWidth(width);
14799         },
14800
14801         /**
14802          * Returns the measured width of the specified text
14803          * @memberOf Roo.util.TextMetrics.Instance#
14804          * @param {String} text The text to measure
14805          * @return {Number} width The width in pixels
14806          */
14807         getWidth : function(text){
14808             ml.dom.style.width = 'auto';
14809             return this.getSize(text).width;
14810         },
14811
14812         /**
14813          * Returns the measured height of the specified text.  For multiline text, be sure to call
14814          * {@link #setFixedWidth} if necessary.
14815          * @memberOf Roo.util.TextMetrics.Instance#
14816          * @param {String} text The text to measure
14817          * @return {Number} height The height in pixels
14818          */
14819         getHeight : function(text){
14820             return this.getSize(text).height;
14821         }
14822     };
14823
14824     instance.bind(bindTo);
14825
14826     return instance;
14827 };
14828
14829 // backwards compat
14830 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14831  * Based on:
14832  * Ext JS Library 1.1.1
14833  * Copyright(c) 2006-2007, Ext JS, LLC.
14834  *
14835  * Originally Released Under LGPL - original licence link has changed is not relivant.
14836  *
14837  * Fork - LGPL
14838  * <script type="text/javascript">
14839  */
14840
14841 /**
14842  * @class Roo.state.Provider
14843  * Abstract base class for state provider implementations. This class provides methods
14844  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14845  * Provider interface.
14846  */
14847 Roo.state.Provider = function(){
14848     /**
14849      * @event statechange
14850      * Fires when a state change occurs.
14851      * @param {Provider} this This state provider
14852      * @param {String} key The state key which was changed
14853      * @param {String} value The encoded value for the state
14854      */
14855     this.addEvents({
14856         "statechange": true
14857     });
14858     this.state = {};
14859     Roo.state.Provider.superclass.constructor.call(this);
14860 };
14861 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14862     /**
14863      * Returns the current value for a key
14864      * @param {String} name The key name
14865      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14866      * @return {Mixed} The state data
14867      */
14868     get : function(name, defaultValue){
14869         return typeof this.state[name] == "undefined" ?
14870             defaultValue : this.state[name];
14871     },
14872     
14873     /**
14874      * Clears a value from the state
14875      * @param {String} name The key name
14876      */
14877     clear : function(name){
14878         delete this.state[name];
14879         this.fireEvent("statechange", this, name, null);
14880     },
14881     
14882     /**
14883      * Sets the value for a key
14884      * @param {String} name The key name
14885      * @param {Mixed} value The value to set
14886      */
14887     set : function(name, value){
14888         this.state[name] = value;
14889         this.fireEvent("statechange", this, name, value);
14890     },
14891     
14892     /**
14893      * Decodes a string previously encoded with {@link #encodeValue}.
14894      * @param {String} value The value to decode
14895      * @return {Mixed} The decoded value
14896      */
14897     decodeValue : function(cookie){
14898         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14899         var matches = re.exec(unescape(cookie));
14900         if(!matches || !matches[1]) {
14901             return; // non state cookie
14902         }
14903         var type = matches[1];
14904         var v = matches[2];
14905         switch(type){
14906             case "n":
14907                 return parseFloat(v);
14908             case "d":
14909                 return new Date(Date.parse(v));
14910             case "b":
14911                 return (v == "1");
14912             case "a":
14913                 var all = [];
14914                 var values = v.split("^");
14915                 for(var i = 0, len = values.length; i < len; i++){
14916                     all.push(this.decodeValue(values[i]));
14917                 }
14918                 return all;
14919            case "o":
14920                 var all = {};
14921                 var values = v.split("^");
14922                 for(var i = 0, len = values.length; i < len; i++){
14923                     var kv = values[i].split("=");
14924                     all[kv[0]] = this.decodeValue(kv[1]);
14925                 }
14926                 return all;
14927            default:
14928                 return v;
14929         }
14930     },
14931     
14932     /**
14933      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14934      * @param {Mixed} value The value to encode
14935      * @return {String} The encoded value
14936      */
14937     encodeValue : function(v){
14938         var enc;
14939         if(typeof v == "number"){
14940             enc = "n:" + v;
14941         }else if(typeof v == "boolean"){
14942             enc = "b:" + (v ? "1" : "0");
14943         }else if(v instanceof Date){
14944             enc = "d:" + v.toGMTString();
14945         }else if(v instanceof Array){
14946             var flat = "";
14947             for(var i = 0, len = v.length; i < len; i++){
14948                 flat += this.encodeValue(v[i]);
14949                 if(i != len-1) {
14950                     flat += "^";
14951                 }
14952             }
14953             enc = "a:" + flat;
14954         }else if(typeof v == "object"){
14955             var flat = "";
14956             for(var key in v){
14957                 if(typeof v[key] != "function"){
14958                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14959                 }
14960             }
14961             enc = "o:" + flat.substring(0, flat.length-1);
14962         }else{
14963             enc = "s:" + v;
14964         }
14965         return escape(enc);        
14966     }
14967 });
14968
14969 /*
14970  * Based on:
14971  * Ext JS Library 1.1.1
14972  * Copyright(c) 2006-2007, Ext JS, LLC.
14973  *
14974  * Originally Released Under LGPL - original licence link has changed is not relivant.
14975  *
14976  * Fork - LGPL
14977  * <script type="text/javascript">
14978  */
14979 /**
14980  * @class Roo.state.Manager
14981  * This is the global state manager. By default all components that are "state aware" check this class
14982  * for state information if you don't pass them a custom state provider. In order for this class
14983  * to be useful, it must be initialized with a provider when your application initializes.
14984  <pre><code>
14985 // in your initialization function
14986 init : function(){
14987    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14988    ...
14989    // supposed you have a {@link Roo.BorderLayout}
14990    var layout = new Roo.BorderLayout(...);
14991    layout.restoreState();
14992    // or a {Roo.BasicDialog}
14993    var dialog = new Roo.BasicDialog(...);
14994    dialog.restoreState();
14995  </code></pre>
14996  * @singleton
14997  */
14998 Roo.state.Manager = function(){
14999     var provider = new Roo.state.Provider();
15000     
15001     return {
15002         /**
15003          * Configures the default state provider for your application
15004          * @param {Provider} stateProvider The state provider to set
15005          */
15006         setProvider : function(stateProvider){
15007             provider = stateProvider;
15008         },
15009         
15010         /**
15011          * Returns the current value for a key
15012          * @param {String} name The key name
15013          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15014          * @return {Mixed} The state data
15015          */
15016         get : function(key, defaultValue){
15017             return provider.get(key, defaultValue);
15018         },
15019         
15020         /**
15021          * Sets the value for a key
15022          * @param {String} name The key name
15023          * @param {Mixed} value The state data
15024          */
15025          set : function(key, value){
15026             provider.set(key, value);
15027         },
15028         
15029         /**
15030          * Clears a value from the state
15031          * @param {String} name The key name
15032          */
15033         clear : function(key){
15034             provider.clear(key);
15035         },
15036         
15037         /**
15038          * Gets the currently configured state provider
15039          * @return {Provider} The state provider
15040          */
15041         getProvider : function(){
15042             return provider;
15043         }
15044     };
15045 }();
15046 /*
15047  * Based on:
15048  * Ext JS Library 1.1.1
15049  * Copyright(c) 2006-2007, Ext JS, LLC.
15050  *
15051  * Originally Released Under LGPL - original licence link has changed is not relivant.
15052  *
15053  * Fork - LGPL
15054  * <script type="text/javascript">
15055  */
15056 /**
15057  * @class Roo.state.CookieProvider
15058  * @extends Roo.state.Provider
15059  * The default Provider implementation which saves state via cookies.
15060  * <br />Usage:
15061  <pre><code>
15062    var cp = new Roo.state.CookieProvider({
15063        path: "/cgi-bin/",
15064        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15065        domain: "roojs.com"
15066    })
15067    Roo.state.Manager.setProvider(cp);
15068  </code></pre>
15069  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15070  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15071  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15072  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15073  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15074  * domain the page is running on including the 'www' like 'www.roojs.com')
15075  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15076  * @constructor
15077  * Create a new CookieProvider
15078  * @param {Object} config The configuration object
15079  */
15080 Roo.state.CookieProvider = function(config){
15081     Roo.state.CookieProvider.superclass.constructor.call(this);
15082     this.path = "/";
15083     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15084     this.domain = null;
15085     this.secure = false;
15086     Roo.apply(this, config);
15087     this.state = this.readCookies();
15088 };
15089
15090 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15091     // private
15092     set : function(name, value){
15093         if(typeof value == "undefined" || value === null){
15094             this.clear(name);
15095             return;
15096         }
15097         this.setCookie(name, value);
15098         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15099     },
15100
15101     // private
15102     clear : function(name){
15103         this.clearCookie(name);
15104         Roo.state.CookieProvider.superclass.clear.call(this, name);
15105     },
15106
15107     // private
15108     readCookies : function(){
15109         var cookies = {};
15110         var c = document.cookie + ";";
15111         var re = /\s?(.*?)=(.*?);/g;
15112         var matches;
15113         while((matches = re.exec(c)) != null){
15114             var name = matches[1];
15115             var value = matches[2];
15116             if(name && name.substring(0,3) == "ys-"){
15117                 cookies[name.substr(3)] = this.decodeValue(value);
15118             }
15119         }
15120         return cookies;
15121     },
15122
15123     // private
15124     setCookie : function(name, value){
15125         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15126            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15127            ((this.path == null) ? "" : ("; path=" + this.path)) +
15128            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15129            ((this.secure == true) ? "; secure" : "");
15130     },
15131
15132     // private
15133     clearCookie : function(name){
15134         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15135            ((this.path == null) ? "" : ("; path=" + this.path)) +
15136            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15137            ((this.secure == true) ? "; secure" : "");
15138     }
15139 });/*
15140  * Based on:
15141  * Ext JS Library 1.1.1
15142  * Copyright(c) 2006-2007, Ext JS, LLC.
15143  *
15144  * Originally Released Under LGPL - original licence link has changed is not relivant.
15145  *
15146  * Fork - LGPL
15147  * <script type="text/javascript">
15148  */
15149  
15150
15151 /**
15152  * @class Roo.ComponentMgr
15153  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15154  * @singleton
15155  */
15156 Roo.ComponentMgr = function(){
15157     var all = new Roo.util.MixedCollection();
15158
15159     return {
15160         /**
15161          * Registers a component.
15162          * @param {Roo.Component} c The component
15163          */
15164         register : function(c){
15165             all.add(c);
15166         },
15167
15168         /**
15169          * Unregisters a component.
15170          * @param {Roo.Component} c The component
15171          */
15172         unregister : function(c){
15173             all.remove(c);
15174         },
15175
15176         /**
15177          * Returns a component by id
15178          * @param {String} id The component id
15179          */
15180         get : function(id){
15181             return all.get(id);
15182         },
15183
15184         /**
15185          * Registers a function that will be called when a specified component is added to ComponentMgr
15186          * @param {String} id The component id
15187          * @param {Funtction} fn The callback function
15188          * @param {Object} scope The scope of the callback
15189          */
15190         onAvailable : function(id, fn, scope){
15191             all.on("add", function(index, o){
15192                 if(o.id == id){
15193                     fn.call(scope || o, o);
15194                     all.un("add", fn, scope);
15195                 }
15196             });
15197         }
15198     };
15199 }();/*
15200  * Based on:
15201  * Ext JS Library 1.1.1
15202  * Copyright(c) 2006-2007, Ext JS, LLC.
15203  *
15204  * Originally Released Under LGPL - original licence link has changed is not relivant.
15205  *
15206  * Fork - LGPL
15207  * <script type="text/javascript">
15208  */
15209  
15210 /**
15211  * @class Roo.Component
15212  * @extends Roo.util.Observable
15213  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15214  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15215  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15216  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15217  * All visual components (widgets) that require rendering into a layout should subclass Component.
15218  * @constructor
15219  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15220  * 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
15221  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15222  */
15223 Roo.Component = function(config){
15224     config = config || {};
15225     if(config.tagName || config.dom || typeof config == "string"){ // element object
15226         config = {el: config, id: config.id || config};
15227     }
15228     this.initialConfig = config;
15229
15230     Roo.apply(this, config);
15231     this.addEvents({
15232         /**
15233          * @event disable
15234          * Fires after the component is disabled.
15235              * @param {Roo.Component} this
15236              */
15237         disable : true,
15238         /**
15239          * @event enable
15240          * Fires after the component is enabled.
15241              * @param {Roo.Component} this
15242              */
15243         enable : true,
15244         /**
15245          * @event beforeshow
15246          * Fires before the component is shown.  Return false to stop the show.
15247              * @param {Roo.Component} this
15248              */
15249         beforeshow : true,
15250         /**
15251          * @event show
15252          * Fires after the component is shown.
15253              * @param {Roo.Component} this
15254              */
15255         show : true,
15256         /**
15257          * @event beforehide
15258          * Fires before the component is hidden. Return false to stop the hide.
15259              * @param {Roo.Component} this
15260              */
15261         beforehide : true,
15262         /**
15263          * @event hide
15264          * Fires after the component is hidden.
15265              * @param {Roo.Component} this
15266              */
15267         hide : true,
15268         /**
15269          * @event beforerender
15270          * Fires before the component is rendered. Return false to stop the render.
15271              * @param {Roo.Component} this
15272              */
15273         beforerender : true,
15274         /**
15275          * @event render
15276          * Fires after the component is rendered.
15277              * @param {Roo.Component} this
15278              */
15279         render : true,
15280         /**
15281          * @event beforedestroy
15282          * Fires before the component is destroyed. Return false to stop the destroy.
15283              * @param {Roo.Component} this
15284              */
15285         beforedestroy : true,
15286         /**
15287          * @event destroy
15288          * Fires after the component is destroyed.
15289              * @param {Roo.Component} this
15290              */
15291         destroy : true
15292     });
15293     if(!this.id){
15294         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15295     }
15296     Roo.ComponentMgr.register(this);
15297     Roo.Component.superclass.constructor.call(this);
15298     this.initComponent();
15299     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15300         this.render(this.renderTo);
15301         delete this.renderTo;
15302     }
15303 };
15304
15305 /** @private */
15306 Roo.Component.AUTO_ID = 1000;
15307
15308 Roo.extend(Roo.Component, Roo.util.Observable, {
15309     /**
15310      * @scope Roo.Component.prototype
15311      * @type {Boolean}
15312      * true if this component is hidden. Read-only.
15313      */
15314     hidden : false,
15315     /**
15316      * @type {Boolean}
15317      * true if this component is disabled. Read-only.
15318      */
15319     disabled : false,
15320     /**
15321      * @type {Boolean}
15322      * true if this component has been rendered. Read-only.
15323      */
15324     rendered : false,
15325     
15326     /** @cfg {String} disableClass
15327      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15328      */
15329     disabledClass : "x-item-disabled",
15330         /** @cfg {Boolean} allowDomMove
15331          * Whether the component can move the Dom node when rendering (defaults to true).
15332          */
15333     allowDomMove : true,
15334     /** @cfg {String} hideMode (display|visibility)
15335      * How this component should hidden. Supported values are
15336      * "visibility" (css visibility), "offsets" (negative offset position) and
15337      * "display" (css display) - defaults to "display".
15338      */
15339     hideMode: 'display',
15340
15341     /** @private */
15342     ctype : "Roo.Component",
15343
15344     /**
15345      * @cfg {String} actionMode 
15346      * which property holds the element that used for  hide() / show() / disable() / enable()
15347      * default is 'el' 
15348      */
15349     actionMode : "el",
15350
15351     /** @private */
15352     getActionEl : function(){
15353         return this[this.actionMode];
15354     },
15355
15356     initComponent : Roo.emptyFn,
15357     /**
15358      * If this is a lazy rendering component, render it to its container element.
15359      * @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.
15360      */
15361     render : function(container, position){
15362         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15363             if(!container && this.el){
15364                 this.el = Roo.get(this.el);
15365                 container = this.el.dom.parentNode;
15366                 this.allowDomMove = false;
15367             }
15368             this.container = Roo.get(container);
15369             this.rendered = true;
15370             if(position !== undefined){
15371                 if(typeof position == 'number'){
15372                     position = this.container.dom.childNodes[position];
15373                 }else{
15374                     position = Roo.getDom(position);
15375                 }
15376             }
15377             this.onRender(this.container, position || null);
15378             if(this.cls){
15379                 this.el.addClass(this.cls);
15380                 delete this.cls;
15381             }
15382             if(this.style){
15383                 this.el.applyStyles(this.style);
15384                 delete this.style;
15385             }
15386             this.fireEvent("render", this);
15387             this.afterRender(this.container);
15388             if(this.hidden){
15389                 this.hide();
15390             }
15391             if(this.disabled){
15392                 this.disable();
15393             }
15394         }
15395         return this;
15396     },
15397
15398     /** @private */
15399     // default function is not really useful
15400     onRender : function(ct, position){
15401         if(this.el){
15402             this.el = Roo.get(this.el);
15403             if(this.allowDomMove !== false){
15404                 ct.dom.insertBefore(this.el.dom, position);
15405             }
15406         }
15407     },
15408
15409     /** @private */
15410     getAutoCreate : function(){
15411         var cfg = typeof this.autoCreate == "object" ?
15412                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15413         if(this.id && !cfg.id){
15414             cfg.id = this.id;
15415         }
15416         return cfg;
15417     },
15418
15419     /** @private */
15420     afterRender : Roo.emptyFn,
15421
15422     /**
15423      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15424      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15425      */
15426     destroy : function(){
15427         if(this.fireEvent("beforedestroy", this) !== false){
15428             this.purgeListeners();
15429             this.beforeDestroy();
15430             if(this.rendered){
15431                 this.el.removeAllListeners();
15432                 this.el.remove();
15433                 if(this.actionMode == "container"){
15434                     this.container.remove();
15435                 }
15436             }
15437             this.onDestroy();
15438             Roo.ComponentMgr.unregister(this);
15439             this.fireEvent("destroy", this);
15440         }
15441     },
15442
15443         /** @private */
15444     beforeDestroy : function(){
15445
15446     },
15447
15448         /** @private */
15449         onDestroy : function(){
15450
15451     },
15452
15453     /**
15454      * Returns the underlying {@link Roo.Element}.
15455      * @return {Roo.Element} The element
15456      */
15457     getEl : function(){
15458         return this.el;
15459     },
15460
15461     /**
15462      * Returns the id of this component.
15463      * @return {String}
15464      */
15465     getId : function(){
15466         return this.id;
15467     },
15468
15469     /**
15470      * Try to focus this component.
15471      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15472      * @return {Roo.Component} this
15473      */
15474     focus : function(selectText){
15475         if(this.rendered){
15476             this.el.focus();
15477             if(selectText === true){
15478                 this.el.dom.select();
15479             }
15480         }
15481         return this;
15482     },
15483
15484     /** @private */
15485     blur : function(){
15486         if(this.rendered){
15487             this.el.blur();
15488         }
15489         return this;
15490     },
15491
15492     /**
15493      * Disable this component.
15494      * @return {Roo.Component} this
15495      */
15496     disable : function(){
15497         if(this.rendered){
15498             this.onDisable();
15499         }
15500         this.disabled = true;
15501         this.fireEvent("disable", this);
15502         return this;
15503     },
15504
15505         // private
15506     onDisable : function(){
15507         this.getActionEl().addClass(this.disabledClass);
15508         this.el.dom.disabled = true;
15509     },
15510
15511     /**
15512      * Enable this component.
15513      * @return {Roo.Component} this
15514      */
15515     enable : function(){
15516         if(this.rendered){
15517             this.onEnable();
15518         }
15519         this.disabled = false;
15520         this.fireEvent("enable", this);
15521         return this;
15522     },
15523
15524         // private
15525     onEnable : function(){
15526         this.getActionEl().removeClass(this.disabledClass);
15527         this.el.dom.disabled = false;
15528     },
15529
15530     /**
15531      * Convenience function for setting disabled/enabled by boolean.
15532      * @param {Boolean} disabled
15533      */
15534     setDisabled : function(disabled){
15535         this[disabled ? "disable" : "enable"]();
15536     },
15537
15538     /**
15539      * Show this component.
15540      * @return {Roo.Component} this
15541      */
15542     show: function(){
15543         if(this.fireEvent("beforeshow", this) !== false){
15544             this.hidden = false;
15545             if(this.rendered){
15546                 this.onShow();
15547             }
15548             this.fireEvent("show", this);
15549         }
15550         return this;
15551     },
15552
15553     // private
15554     onShow : function(){
15555         var ae = this.getActionEl();
15556         if(this.hideMode == 'visibility'){
15557             ae.dom.style.visibility = "visible";
15558         }else if(this.hideMode == 'offsets'){
15559             ae.removeClass('x-hidden');
15560         }else{
15561             ae.dom.style.display = "";
15562         }
15563     },
15564
15565     /**
15566      * Hide this component.
15567      * @return {Roo.Component} this
15568      */
15569     hide: function(){
15570         if(this.fireEvent("beforehide", this) !== false){
15571             this.hidden = true;
15572             if(this.rendered){
15573                 this.onHide();
15574             }
15575             this.fireEvent("hide", this);
15576         }
15577         return this;
15578     },
15579
15580     // private
15581     onHide : function(){
15582         var ae = this.getActionEl();
15583         if(this.hideMode == 'visibility'){
15584             ae.dom.style.visibility = "hidden";
15585         }else if(this.hideMode == 'offsets'){
15586             ae.addClass('x-hidden');
15587         }else{
15588             ae.dom.style.display = "none";
15589         }
15590     },
15591
15592     /**
15593      * Convenience function to hide or show this component by boolean.
15594      * @param {Boolean} visible True to show, false to hide
15595      * @return {Roo.Component} this
15596      */
15597     setVisible: function(visible){
15598         if(visible) {
15599             this.show();
15600         }else{
15601             this.hide();
15602         }
15603         return this;
15604     },
15605
15606     /**
15607      * Returns true if this component is visible.
15608      */
15609     isVisible : function(){
15610         return this.getActionEl().isVisible();
15611     },
15612
15613     cloneConfig : function(overrides){
15614         overrides = overrides || {};
15615         var id = overrides.id || Roo.id();
15616         var cfg = Roo.applyIf(overrides, this.initialConfig);
15617         cfg.id = id; // prevent dup id
15618         return new this.constructor(cfg);
15619     }
15620 });/*
15621  * Based on:
15622  * Ext JS Library 1.1.1
15623  * Copyright(c) 2006-2007, Ext JS, LLC.
15624  *
15625  * Originally Released Under LGPL - original licence link has changed is not relivant.
15626  *
15627  * Fork - LGPL
15628  * <script type="text/javascript">
15629  */
15630
15631 /**
15632  * @class Roo.BoxComponent
15633  * @extends Roo.Component
15634  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15635  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15636  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15637  * layout containers.
15638  * @constructor
15639  * @param {Roo.Element/String/Object} config The configuration options.
15640  */
15641 Roo.BoxComponent = function(config){
15642     Roo.Component.call(this, config);
15643     this.addEvents({
15644         /**
15645          * @event resize
15646          * Fires after the component is resized.
15647              * @param {Roo.Component} this
15648              * @param {Number} adjWidth The box-adjusted width that was set
15649              * @param {Number} adjHeight The box-adjusted height that was set
15650              * @param {Number} rawWidth The width that was originally specified
15651              * @param {Number} rawHeight The height that was originally specified
15652              */
15653         resize : true,
15654         /**
15655          * @event move
15656          * Fires after the component is moved.
15657              * @param {Roo.Component} this
15658              * @param {Number} x The new x position
15659              * @param {Number} y The new y position
15660              */
15661         move : true
15662     });
15663 };
15664
15665 Roo.extend(Roo.BoxComponent, Roo.Component, {
15666     // private, set in afterRender to signify that the component has been rendered
15667     boxReady : false,
15668     // private, used to defer height settings to subclasses
15669     deferHeight: false,
15670     /** @cfg {Number} width
15671      * width (optional) size of component
15672      */
15673      /** @cfg {Number} height
15674      * height (optional) size of component
15675      */
15676      
15677     /**
15678      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15679      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15680      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15681      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15682      * @return {Roo.BoxComponent} this
15683      */
15684     setSize : function(w, h){
15685         // support for standard size objects
15686         if(typeof w == 'object'){
15687             h = w.height;
15688             w = w.width;
15689         }
15690         // not rendered
15691         if(!this.boxReady){
15692             this.width = w;
15693             this.height = h;
15694             return this;
15695         }
15696
15697         // prevent recalcs when not needed
15698         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15699             return this;
15700         }
15701         this.lastSize = {width: w, height: h};
15702
15703         var adj = this.adjustSize(w, h);
15704         var aw = adj.width, ah = adj.height;
15705         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15706             var rz = this.getResizeEl();
15707             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15708                 rz.setSize(aw, ah);
15709             }else if(!this.deferHeight && ah !== undefined){
15710                 rz.setHeight(ah);
15711             }else if(aw !== undefined){
15712                 rz.setWidth(aw);
15713             }
15714             this.onResize(aw, ah, w, h);
15715             this.fireEvent('resize', this, aw, ah, w, h);
15716         }
15717         return this;
15718     },
15719
15720     /**
15721      * Gets the current size of the component's underlying element.
15722      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15723      */
15724     getSize : function(){
15725         return this.el.getSize();
15726     },
15727
15728     /**
15729      * Gets the current XY position of the component's underlying element.
15730      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15731      * @return {Array} The XY position of the element (e.g., [100, 200])
15732      */
15733     getPosition : function(local){
15734         if(local === true){
15735             return [this.el.getLeft(true), this.el.getTop(true)];
15736         }
15737         return this.xy || this.el.getXY();
15738     },
15739
15740     /**
15741      * Gets the current box measurements of the component's underlying element.
15742      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15743      * @returns {Object} box An object in the format {x, y, width, height}
15744      */
15745     getBox : function(local){
15746         var s = this.el.getSize();
15747         if(local){
15748             s.x = this.el.getLeft(true);
15749             s.y = this.el.getTop(true);
15750         }else{
15751             var xy = this.xy || this.el.getXY();
15752             s.x = xy[0];
15753             s.y = xy[1];
15754         }
15755         return s;
15756     },
15757
15758     /**
15759      * Sets the current box measurements of the component's underlying element.
15760      * @param {Object} box An object in the format {x, y, width, height}
15761      * @returns {Roo.BoxComponent} this
15762      */
15763     updateBox : function(box){
15764         this.setSize(box.width, box.height);
15765         this.setPagePosition(box.x, box.y);
15766         return this;
15767     },
15768
15769     // protected
15770     getResizeEl : function(){
15771         return this.resizeEl || this.el;
15772     },
15773
15774     // protected
15775     getPositionEl : function(){
15776         return this.positionEl || this.el;
15777     },
15778
15779     /**
15780      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15781      * This method fires the move event.
15782      * @param {Number} left The new left
15783      * @param {Number} top The new top
15784      * @returns {Roo.BoxComponent} this
15785      */
15786     setPosition : function(x, y){
15787         this.x = x;
15788         this.y = y;
15789         if(!this.boxReady){
15790             return this;
15791         }
15792         var adj = this.adjustPosition(x, y);
15793         var ax = adj.x, ay = adj.y;
15794
15795         var el = this.getPositionEl();
15796         if(ax !== undefined || ay !== undefined){
15797             if(ax !== undefined && ay !== undefined){
15798                 el.setLeftTop(ax, ay);
15799             }else if(ax !== undefined){
15800                 el.setLeft(ax);
15801             }else if(ay !== undefined){
15802                 el.setTop(ay);
15803             }
15804             this.onPosition(ax, ay);
15805             this.fireEvent('move', this, ax, ay);
15806         }
15807         return this;
15808     },
15809
15810     /**
15811      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15812      * This method fires the move event.
15813      * @param {Number} x The new x position
15814      * @param {Number} y The new y position
15815      * @returns {Roo.BoxComponent} this
15816      */
15817     setPagePosition : function(x, y){
15818         this.pageX = x;
15819         this.pageY = y;
15820         if(!this.boxReady){
15821             return;
15822         }
15823         if(x === undefined || y === undefined){ // cannot translate undefined points
15824             return;
15825         }
15826         var p = this.el.translatePoints(x, y);
15827         this.setPosition(p.left, p.top);
15828         return this;
15829     },
15830
15831     // private
15832     onRender : function(ct, position){
15833         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15834         if(this.resizeEl){
15835             this.resizeEl = Roo.get(this.resizeEl);
15836         }
15837         if(this.positionEl){
15838             this.positionEl = Roo.get(this.positionEl);
15839         }
15840     },
15841
15842     // private
15843     afterRender : function(){
15844         Roo.BoxComponent.superclass.afterRender.call(this);
15845         this.boxReady = true;
15846         this.setSize(this.width, this.height);
15847         if(this.x || this.y){
15848             this.setPosition(this.x, this.y);
15849         }
15850         if(this.pageX || this.pageY){
15851             this.setPagePosition(this.pageX, this.pageY);
15852         }
15853     },
15854
15855     /**
15856      * Force the component's size to recalculate based on the underlying element's current height and width.
15857      * @returns {Roo.BoxComponent} this
15858      */
15859     syncSize : function(){
15860         delete this.lastSize;
15861         this.setSize(this.el.getWidth(), this.el.getHeight());
15862         return this;
15863     },
15864
15865     /**
15866      * Called after the component is resized, this method is empty by default but can be implemented by any
15867      * subclass that needs to perform custom logic after a resize occurs.
15868      * @param {Number} adjWidth The box-adjusted width that was set
15869      * @param {Number} adjHeight The box-adjusted height that was set
15870      * @param {Number} rawWidth The width that was originally specified
15871      * @param {Number} rawHeight The height that was originally specified
15872      */
15873     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15874
15875     },
15876
15877     /**
15878      * Called after the component is moved, this method is empty by default but can be implemented by any
15879      * subclass that needs to perform custom logic after a move occurs.
15880      * @param {Number} x The new x position
15881      * @param {Number} y The new y position
15882      */
15883     onPosition : function(x, y){
15884
15885     },
15886
15887     // private
15888     adjustSize : function(w, h){
15889         if(this.autoWidth){
15890             w = 'auto';
15891         }
15892         if(this.autoHeight){
15893             h = 'auto';
15894         }
15895         return {width : w, height: h};
15896     },
15897
15898     // private
15899     adjustPosition : function(x, y){
15900         return {x : x, y: y};
15901     }
15902 });/*
15903  * Original code for Roojs - LGPL
15904  * <script type="text/javascript">
15905  */
15906  
15907 /**
15908  * @class Roo.XComponent
15909  * A delayed Element creator...
15910  * Or a way to group chunks of interface together.
15911  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15912  *  used in conjunction with XComponent.build() it will create an instance of each element,
15913  *  then call addxtype() to build the User interface.
15914  * 
15915  * Mypart.xyx = new Roo.XComponent({
15916
15917     parent : 'Mypart.xyz', // empty == document.element.!!
15918     order : '001',
15919     name : 'xxxx'
15920     region : 'xxxx'
15921     disabled : function() {} 
15922      
15923     tree : function() { // return an tree of xtype declared components
15924         var MODULE = this;
15925         return 
15926         {
15927             xtype : 'NestedLayoutPanel',
15928             // technicall
15929         }
15930      ]
15931  *})
15932  *
15933  *
15934  * It can be used to build a big heiracy, with parent etc.
15935  * or you can just use this to render a single compoent to a dom element
15936  * MYPART.render(Roo.Element | String(id) | dom_element )
15937  *
15938  *
15939  * Usage patterns.
15940  *
15941  * Classic Roo
15942  *
15943  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15944  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15945  *
15946  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15947  *
15948  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15949  * - if mulitple topModules exist, the last one is defined as the top module.
15950  *
15951  * Embeded Roo
15952  * 
15953  * When the top level or multiple modules are to embedded into a existing HTML page,
15954  * the parent element can container '#id' of the element where the module will be drawn.
15955  *
15956  * Bootstrap Roo
15957  *
15958  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15959  * it relies more on a include mechanism, where sub modules are included into an outer page.
15960  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15961  * 
15962  * Bootstrap Roo Included elements
15963  *
15964  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15965  * hence confusing the component builder as it thinks there are multiple top level elements. 
15966  *
15967  * 
15968  * 
15969  * @extends Roo.util.Observable
15970  * @constructor
15971  * @param cfg {Object} configuration of component
15972  * 
15973  */
15974 Roo.XComponent = function(cfg) {
15975     Roo.apply(this, cfg);
15976     this.addEvents({ 
15977         /**
15978              * @event built
15979              * Fires when this the componnt is built
15980              * @param {Roo.XComponent} c the component
15981              */
15982         'built' : true
15983         
15984     });
15985     this.region = this.region || 'center'; // default..
15986     Roo.XComponent.register(this);
15987     this.modules = false;
15988     this.el = false; // where the layout goes..
15989     
15990     
15991 }
15992 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15993     /**
15994      * @property el
15995      * The created element (with Roo.factory())
15996      * @type {Roo.Layout}
15997      */
15998     el  : false,
15999     
16000     /**
16001      * @property el
16002      * for BC  - use el in new code
16003      * @type {Roo.Layout}
16004      */
16005     panel : false,
16006     
16007     /**
16008      * @property layout
16009      * for BC  - use el in new code
16010      * @type {Roo.Layout}
16011      */
16012     layout : false,
16013     
16014      /**
16015      * @cfg {Function|boolean} disabled
16016      * If this module is disabled by some rule, return true from the funtion
16017      */
16018     disabled : false,
16019     
16020     /**
16021      * @cfg {String} parent 
16022      * Name of parent element which it get xtype added to..
16023      */
16024     parent: false,
16025     
16026     /**
16027      * @cfg {String} order
16028      * Used to set the order in which elements are created (usefull for multiple tabs)
16029      */
16030     
16031     order : false,
16032     /**
16033      * @cfg {String} name
16034      * String to display while loading.
16035      */
16036     name : false,
16037     /**
16038      * @cfg {String} region
16039      * Region to render component to (defaults to center)
16040      */
16041     region : 'center',
16042     
16043     /**
16044      * @cfg {Array} items
16045      * A single item array - the first element is the root of the tree..
16046      * It's done this way to stay compatible with the Xtype system...
16047      */
16048     items : false,
16049     
16050     /**
16051      * @property _tree
16052      * The method that retuns the tree of parts that make up this compoennt 
16053      * @type {function}
16054      */
16055     _tree  : false,
16056     
16057      /**
16058      * render
16059      * render element to dom or tree
16060      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16061      */
16062     
16063     render : function(el)
16064     {
16065         
16066         el = el || false;
16067         var hp = this.parent ? 1 : 0;
16068         Roo.debug &&  Roo.log(this);
16069         
16070         var tree = this._tree ? this._tree() : this.tree();
16071
16072         
16073         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16074             // if parent is a '#.....' string, then let's use that..
16075             var ename = this.parent.substr(1);
16076             this.parent = false;
16077             Roo.debug && Roo.log(ename);
16078             switch (ename) {
16079                 case 'bootstrap-body':
16080                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16081                         // this is the BorderLayout standard?
16082                        this.parent = { el : true };
16083                        break;
16084                     }
16085                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16086                         // need to insert stuff...
16087                         this.parent =  {
16088                              el : new Roo.bootstrap.layout.Border({
16089                                  el : document.body, 
16090                      
16091                                  center: {
16092                                     titlebar: false,
16093                                     autoScroll:false,
16094                                     closeOnTab: true,
16095                                     tabPosition: 'top',
16096                                       //resizeTabs: true,
16097                                     alwaysShowTabs: true,
16098                                     hideTabs: false
16099                                      //minTabWidth: 140
16100                                  }
16101                              })
16102                         
16103                          };
16104                          break;
16105                     }
16106                          
16107                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16108                         this.parent = { el :  new  Roo.bootstrap.Body() };
16109                         Roo.debug && Roo.log("setting el to doc body");
16110                          
16111                     } else {
16112                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16113                     }
16114                     break;
16115                 case 'bootstrap':
16116                     this.parent = { el : true};
16117                     // fall through
16118                 default:
16119                     el = Roo.get(ename);
16120                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16121                         this.parent = { el : true};
16122                     }
16123                     
16124                     break;
16125             }
16126                 
16127             
16128             if (!el && !this.parent) {
16129                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16130                 return;
16131             }
16132         }
16133         
16134         Roo.debug && Roo.log("EL:");
16135         Roo.debug && Roo.log(el);
16136         Roo.debug && Roo.log("this.parent.el:");
16137         Roo.debug && Roo.log(this.parent.el);
16138         
16139
16140         // altertive root elements ??? - we need a better way to indicate these.
16141         var is_alt = Roo.XComponent.is_alt ||
16142                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16143                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16144                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16145         
16146         
16147         
16148         if (!this.parent && is_alt) {
16149             //el = Roo.get(document.body);
16150             this.parent = { el : true };
16151         }
16152             
16153             
16154         
16155         if (!this.parent) {
16156             
16157             Roo.debug && Roo.log("no parent - creating one");
16158             
16159             el = el ? Roo.get(el) : false;      
16160             
16161             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16162                 
16163                 this.parent =  {
16164                     el : new Roo.bootstrap.layout.Border({
16165                         el: el || document.body,
16166                     
16167                         center: {
16168                             titlebar: false,
16169                             autoScroll:false,
16170                             closeOnTab: true,
16171                             tabPosition: 'top',
16172                              //resizeTabs: true,
16173                             alwaysShowTabs: false,
16174                             hideTabs: true,
16175                             minTabWidth: 140,
16176                             overflow: 'visible'
16177                          }
16178                      })
16179                 };
16180             } else {
16181             
16182                 // it's a top level one..
16183                 this.parent =  {
16184                     el : new Roo.BorderLayout(el || document.body, {
16185                         center: {
16186                             titlebar: false,
16187                             autoScroll:false,
16188                             closeOnTab: true,
16189                             tabPosition: 'top',
16190                              //resizeTabs: true,
16191                             alwaysShowTabs: el && hp? false :  true,
16192                             hideTabs: el || !hp ? true :  false,
16193                             minTabWidth: 140
16194                          }
16195                     })
16196                 };
16197             }
16198         }
16199         
16200         if (!this.parent.el) {
16201                 // probably an old style ctor, which has been disabled.
16202                 return;
16203
16204         }
16205                 // The 'tree' method is  '_tree now' 
16206             
16207         tree.region = tree.region || this.region;
16208         var is_body = false;
16209         if (this.parent.el === true) {
16210             // bootstrap... - body..
16211             if (el) {
16212                 tree.el = el;
16213             }
16214             this.parent.el = Roo.factory(tree);
16215             is_body = true;
16216         }
16217         
16218         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16219         this.fireEvent('built', this);
16220         
16221         this.panel = this.el;
16222         this.layout = this.panel.layout;
16223         this.parentLayout = this.parent.layout  || false;  
16224          
16225     }
16226     
16227 });
16228
16229 Roo.apply(Roo.XComponent, {
16230     /**
16231      * @property  hideProgress
16232      * true to disable the building progress bar.. usefull on single page renders.
16233      * @type Boolean
16234      */
16235     hideProgress : false,
16236     /**
16237      * @property  buildCompleted
16238      * True when the builder has completed building the interface.
16239      * @type Boolean
16240      */
16241     buildCompleted : false,
16242      
16243     /**
16244      * @property  topModule
16245      * the upper most module - uses document.element as it's constructor.
16246      * @type Object
16247      */
16248      
16249     topModule  : false,
16250       
16251     /**
16252      * @property  modules
16253      * array of modules to be created by registration system.
16254      * @type {Array} of Roo.XComponent
16255      */
16256     
16257     modules : [],
16258     /**
16259      * @property  elmodules
16260      * array of modules to be created by which use #ID 
16261      * @type {Array} of Roo.XComponent
16262      */
16263      
16264     elmodules : [],
16265
16266      /**
16267      * @property  is_alt
16268      * Is an alternative Root - normally used by bootstrap or other systems,
16269      *    where the top element in the tree can wrap 'body' 
16270      * @type {boolean}  (default false)
16271      */
16272      
16273     is_alt : false,
16274     /**
16275      * @property  build_from_html
16276      * Build elements from html - used by bootstrap HTML stuff 
16277      *    - this is cleared after build is completed
16278      * @type {boolean}    (default false)
16279      */
16280      
16281     build_from_html : false,
16282     /**
16283      * Register components to be built later.
16284      *
16285      * This solves the following issues
16286      * - Building is not done on page load, but after an authentication process has occured.
16287      * - Interface elements are registered on page load
16288      * - Parent Interface elements may not be loaded before child, so this handles that..
16289      * 
16290      *
16291      * example:
16292      * 
16293      * MyApp.register({
16294           order : '000001',
16295           module : 'Pman.Tab.projectMgr',
16296           region : 'center',
16297           parent : 'Pman.layout',
16298           disabled : false,  // or use a function..
16299         })
16300      
16301      * * @param {Object} details about module
16302      */
16303     register : function(obj) {
16304                 
16305         Roo.XComponent.event.fireEvent('register', obj);
16306         switch(typeof(obj.disabled) ) {
16307                 
16308             case 'undefined':
16309                 break;
16310             
16311             case 'function':
16312                 if ( obj.disabled() ) {
16313                         return;
16314                 }
16315                 break;
16316             
16317             default:
16318                 if (obj.disabled) {
16319                         return;
16320                 }
16321                 break;
16322         }
16323                 
16324         this.modules.push(obj);
16325          
16326     },
16327     /**
16328      * convert a string to an object..
16329      * eg. 'AAA.BBB' -> finds AAA.BBB
16330
16331      */
16332     
16333     toObject : function(str)
16334     {
16335         if (!str || typeof(str) == 'object') {
16336             return str;
16337         }
16338         if (str.substring(0,1) == '#') {
16339             return str;
16340         }
16341
16342         var ar = str.split('.');
16343         var rt, o;
16344         rt = ar.shift();
16345             /** eval:var:o */
16346         try {
16347             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16348         } catch (e) {
16349             throw "Module not found : " + str;
16350         }
16351         
16352         if (o === false) {
16353             throw "Module not found : " + str;
16354         }
16355         Roo.each(ar, function(e) {
16356             if (typeof(o[e]) == 'undefined') {
16357                 throw "Module not found : " + str;
16358             }
16359             o = o[e];
16360         });
16361         
16362         return o;
16363         
16364     },
16365     
16366     
16367     /**
16368      * move modules into their correct place in the tree..
16369      * 
16370      */
16371     preBuild : function ()
16372     {
16373         var _t = this;
16374         Roo.each(this.modules , function (obj)
16375         {
16376             Roo.XComponent.event.fireEvent('beforebuild', obj);
16377             
16378             var opar = obj.parent;
16379             try { 
16380                 obj.parent = this.toObject(opar);
16381             } catch(e) {
16382                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16383                 return;
16384             }
16385             
16386             if (!obj.parent) {
16387                 Roo.debug && Roo.log("GOT top level module");
16388                 Roo.debug && Roo.log(obj);
16389                 obj.modules = new Roo.util.MixedCollection(false, 
16390                     function(o) { return o.order + '' }
16391                 );
16392                 this.topModule = obj;
16393                 return;
16394             }
16395                         // parent is a string (usually a dom element name..)
16396             if (typeof(obj.parent) == 'string') {
16397                 this.elmodules.push(obj);
16398                 return;
16399             }
16400             if (obj.parent.constructor != Roo.XComponent) {
16401                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16402             }
16403             if (!obj.parent.modules) {
16404                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16405                     function(o) { return o.order + '' }
16406                 );
16407             }
16408             if (obj.parent.disabled) {
16409                 obj.disabled = true;
16410             }
16411             obj.parent.modules.add(obj);
16412         }, this);
16413     },
16414     
16415      /**
16416      * make a list of modules to build.
16417      * @return {Array} list of modules. 
16418      */ 
16419     
16420     buildOrder : function()
16421     {
16422         var _this = this;
16423         var cmp = function(a,b) {   
16424             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16425         };
16426         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16427             throw "No top level modules to build";
16428         }
16429         
16430         // make a flat list in order of modules to build.
16431         var mods = this.topModule ? [ this.topModule ] : [];
16432                 
16433         
16434         // elmodules (is a list of DOM based modules )
16435         Roo.each(this.elmodules, function(e) {
16436             mods.push(e);
16437             if (!this.topModule &&
16438                 typeof(e.parent) == 'string' &&
16439                 e.parent.substring(0,1) == '#' &&
16440                 Roo.get(e.parent.substr(1))
16441                ) {
16442                 
16443                 _this.topModule = e;
16444             }
16445             
16446         });
16447
16448         
16449         // add modules to their parents..
16450         var addMod = function(m) {
16451             Roo.debug && Roo.log("build Order: add: " + m.name);
16452                 
16453             mods.push(m);
16454             if (m.modules && !m.disabled) {
16455                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16456                 m.modules.keySort('ASC',  cmp );
16457                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16458     
16459                 m.modules.each(addMod);
16460             } else {
16461                 Roo.debug && Roo.log("build Order: no child modules");
16462             }
16463             // not sure if this is used any more..
16464             if (m.finalize) {
16465                 m.finalize.name = m.name + " (clean up) ";
16466                 mods.push(m.finalize);
16467             }
16468             
16469         }
16470         if (this.topModule && this.topModule.modules) { 
16471             this.topModule.modules.keySort('ASC',  cmp );
16472             this.topModule.modules.each(addMod);
16473         } 
16474         return mods;
16475     },
16476     
16477      /**
16478      * Build the registered modules.
16479      * @param {Object} parent element.
16480      * @param {Function} optional method to call after module has been added.
16481      * 
16482      */ 
16483    
16484     build : function(opts) 
16485     {
16486         
16487         if (typeof(opts) != 'undefined') {
16488             Roo.apply(this,opts);
16489         }
16490         
16491         this.preBuild();
16492         var mods = this.buildOrder();
16493       
16494         //this.allmods = mods;
16495         //Roo.debug && Roo.log(mods);
16496         //return;
16497         if (!mods.length) { // should not happen
16498             throw "NO modules!!!";
16499         }
16500         
16501         
16502         var msg = "Building Interface...";
16503         // flash it up as modal - so we store the mask!?
16504         if (!this.hideProgress && Roo.MessageBox) {
16505             Roo.MessageBox.show({ title: 'loading' });
16506             Roo.MessageBox.show({
16507                title: "Please wait...",
16508                msg: msg,
16509                width:450,
16510                progress:true,
16511                closable:false,
16512                modal: false
16513               
16514             });
16515         }
16516         var total = mods.length;
16517         
16518         var _this = this;
16519         var progressRun = function() {
16520             if (!mods.length) {
16521                 Roo.debug && Roo.log('hide?');
16522                 if (!this.hideProgress && Roo.MessageBox) {
16523                     Roo.MessageBox.hide();
16524                 }
16525                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16526                 
16527                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16528                 
16529                 // THE END...
16530                 return false;   
16531             }
16532             
16533             var m = mods.shift();
16534             
16535             
16536             Roo.debug && Roo.log(m);
16537             // not sure if this is supported any more.. - modules that are are just function
16538             if (typeof(m) == 'function') { 
16539                 m.call(this);
16540                 return progressRun.defer(10, _this);
16541             } 
16542             
16543             
16544             msg = "Building Interface " + (total  - mods.length) + 
16545                     " of " + total + 
16546                     (m.name ? (' - ' + m.name) : '');
16547                         Roo.debug && Roo.log(msg);
16548             if (!_this.hideProgress &&  Roo.MessageBox) { 
16549                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16550             }
16551             
16552          
16553             // is the module disabled?
16554             var disabled = (typeof(m.disabled) == 'function') ?
16555                 m.disabled.call(m.module.disabled) : m.disabled;    
16556             
16557             
16558             if (disabled) {
16559                 return progressRun(); // we do not update the display!
16560             }
16561             
16562             // now build 
16563             
16564                         
16565                         
16566             m.render();
16567             // it's 10 on top level, and 1 on others??? why...
16568             return progressRun.defer(10, _this);
16569              
16570         }
16571         progressRun.defer(1, _this);
16572      
16573         
16574         
16575     },
16576         
16577         
16578         /**
16579          * Event Object.
16580          *
16581          *
16582          */
16583         event: false, 
16584     /**
16585          * wrapper for event.on - aliased later..  
16586          * Typically use to register a event handler for register:
16587          *
16588          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16589          *
16590          */
16591     on : false
16592    
16593     
16594     
16595 });
16596
16597 Roo.XComponent.event = new Roo.util.Observable({
16598                 events : { 
16599                         /**
16600                          * @event register
16601                          * Fires when an Component is registered,
16602                          * set the disable property on the Component to stop registration.
16603                          * @param {Roo.XComponent} c the component being registerd.
16604                          * 
16605                          */
16606                         'register' : true,
16607             /**
16608                          * @event beforebuild
16609                          * Fires before each Component is built
16610                          * can be used to apply permissions.
16611                          * @param {Roo.XComponent} c the component being registerd.
16612                          * 
16613                          */
16614                         'beforebuild' : true,
16615                         /**
16616                          * @event buildcomplete
16617                          * Fires on the top level element when all elements have been built
16618                          * @param {Roo.XComponent} the top level component.
16619                          */
16620                         'buildcomplete' : true
16621                         
16622                 }
16623 });
16624
16625 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16626  //
16627  /**
16628  * marked - a markdown parser
16629  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16630  * https://github.com/chjj/marked
16631  */
16632
16633
16634 /**
16635  *
16636  * Roo.Markdown - is a very crude wrapper around marked..
16637  *
16638  * usage:
16639  * 
16640  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16641  * 
16642  * Note: move the sample code to the bottom of this
16643  * file before uncommenting it.
16644  *
16645  */
16646
16647 Roo.Markdown = {};
16648 Roo.Markdown.toHtml = function(text) {
16649     
16650     var c = new Roo.Markdown.marked.setOptions({
16651             renderer: new Roo.Markdown.marked.Renderer(),
16652             gfm: true,
16653             tables: true,
16654             breaks: false,
16655             pedantic: false,
16656             sanitize: false,
16657             smartLists: true,
16658             smartypants: false
16659           });
16660     // A FEW HACKS!!?
16661     
16662     text = text.replace(/\\\n/g,' ');
16663     return Roo.Markdown.marked(text);
16664 };
16665 //
16666 // converter
16667 //
16668 // Wraps all "globals" so that the only thing
16669 // exposed is makeHtml().
16670 //
16671 (function() {
16672     
16673     /**
16674      * Block-Level Grammar
16675      */
16676     
16677     var block = {
16678       newline: /^\n+/,
16679       code: /^( {4}[^\n]+\n*)+/,
16680       fences: noop,
16681       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16682       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16683       nptable: noop,
16684       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16685       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16686       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16687       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16688       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16689       table: noop,
16690       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16691       text: /^[^\n]+/
16692     };
16693     
16694     block.bullet = /(?:[*+-]|\d+\.)/;
16695     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16696     block.item = replace(block.item, 'gm')
16697       (/bull/g, block.bullet)
16698       ();
16699     
16700     block.list = replace(block.list)
16701       (/bull/g, block.bullet)
16702       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16703       ('def', '\\n+(?=' + block.def.source + ')')
16704       ();
16705     
16706     block.blockquote = replace(block.blockquote)
16707       ('def', block.def)
16708       ();
16709     
16710     block._tag = '(?!(?:'
16711       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16712       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16713       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16714     
16715     block.html = replace(block.html)
16716       ('comment', /<!--[\s\S]*?-->/)
16717       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16718       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16719       (/tag/g, block._tag)
16720       ();
16721     
16722     block.paragraph = replace(block.paragraph)
16723       ('hr', block.hr)
16724       ('heading', block.heading)
16725       ('lheading', block.lheading)
16726       ('blockquote', block.blockquote)
16727       ('tag', '<' + block._tag)
16728       ('def', block.def)
16729       ();
16730     
16731     /**
16732      * Normal Block Grammar
16733      */
16734     
16735     block.normal = merge({}, block);
16736     
16737     /**
16738      * GFM Block Grammar
16739      */
16740     
16741     block.gfm = merge({}, block.normal, {
16742       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16743       paragraph: /^/,
16744       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16745     });
16746     
16747     block.gfm.paragraph = replace(block.paragraph)
16748       ('(?!', '(?!'
16749         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16750         + block.list.source.replace('\\1', '\\3') + '|')
16751       ();
16752     
16753     /**
16754      * GFM + Tables Block Grammar
16755      */
16756     
16757     block.tables = merge({}, block.gfm, {
16758       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16759       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16760     });
16761     
16762     /**
16763      * Block Lexer
16764      */
16765     
16766     function Lexer(options) {
16767       this.tokens = [];
16768       this.tokens.links = {};
16769       this.options = options || marked.defaults;
16770       this.rules = block.normal;
16771     
16772       if (this.options.gfm) {
16773         if (this.options.tables) {
16774           this.rules = block.tables;
16775         } else {
16776           this.rules = block.gfm;
16777         }
16778       }
16779     }
16780     
16781     /**
16782      * Expose Block Rules
16783      */
16784     
16785     Lexer.rules = block;
16786     
16787     /**
16788      * Static Lex Method
16789      */
16790     
16791     Lexer.lex = function(src, options) {
16792       var lexer = new Lexer(options);
16793       return lexer.lex(src);
16794     };
16795     
16796     /**
16797      * Preprocessing
16798      */
16799     
16800     Lexer.prototype.lex = function(src) {
16801       src = src
16802         .replace(/\r\n|\r/g, '\n')
16803         .replace(/\t/g, '    ')
16804         .replace(/\u00a0/g, ' ')
16805         .replace(/\u2424/g, '\n');
16806     
16807       return this.token(src, true);
16808     };
16809     
16810     /**
16811      * Lexing
16812      */
16813     
16814     Lexer.prototype.token = function(src, top, bq) {
16815       var src = src.replace(/^ +$/gm, '')
16816         , next
16817         , loose
16818         , cap
16819         , bull
16820         , b
16821         , item
16822         , space
16823         , i
16824         , l;
16825     
16826       while (src) {
16827         // newline
16828         if (cap = this.rules.newline.exec(src)) {
16829           src = src.substring(cap[0].length);
16830           if (cap[0].length > 1) {
16831             this.tokens.push({
16832               type: 'space'
16833             });
16834           }
16835         }
16836     
16837         // code
16838         if (cap = this.rules.code.exec(src)) {
16839           src = src.substring(cap[0].length);
16840           cap = cap[0].replace(/^ {4}/gm, '');
16841           this.tokens.push({
16842             type: 'code',
16843             text: !this.options.pedantic
16844               ? cap.replace(/\n+$/, '')
16845               : cap
16846           });
16847           continue;
16848         }
16849     
16850         // fences (gfm)
16851         if (cap = this.rules.fences.exec(src)) {
16852           src = src.substring(cap[0].length);
16853           this.tokens.push({
16854             type: 'code',
16855             lang: cap[2],
16856             text: cap[3] || ''
16857           });
16858           continue;
16859         }
16860     
16861         // heading
16862         if (cap = this.rules.heading.exec(src)) {
16863           src = src.substring(cap[0].length);
16864           this.tokens.push({
16865             type: 'heading',
16866             depth: cap[1].length,
16867             text: cap[2]
16868           });
16869           continue;
16870         }
16871     
16872         // table no leading pipe (gfm)
16873         if (top && (cap = this.rules.nptable.exec(src))) {
16874           src = src.substring(cap[0].length);
16875     
16876           item = {
16877             type: 'table',
16878             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16879             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16880             cells: cap[3].replace(/\n$/, '').split('\n')
16881           };
16882     
16883           for (i = 0; i < item.align.length; i++) {
16884             if (/^ *-+: *$/.test(item.align[i])) {
16885               item.align[i] = 'right';
16886             } else if (/^ *:-+: *$/.test(item.align[i])) {
16887               item.align[i] = 'center';
16888             } else if (/^ *:-+ *$/.test(item.align[i])) {
16889               item.align[i] = 'left';
16890             } else {
16891               item.align[i] = null;
16892             }
16893           }
16894     
16895           for (i = 0; i < item.cells.length; i++) {
16896             item.cells[i] = item.cells[i].split(/ *\| */);
16897           }
16898     
16899           this.tokens.push(item);
16900     
16901           continue;
16902         }
16903     
16904         // lheading
16905         if (cap = this.rules.lheading.exec(src)) {
16906           src = src.substring(cap[0].length);
16907           this.tokens.push({
16908             type: 'heading',
16909             depth: cap[2] === '=' ? 1 : 2,
16910             text: cap[1]
16911           });
16912           continue;
16913         }
16914     
16915         // hr
16916         if (cap = this.rules.hr.exec(src)) {
16917           src = src.substring(cap[0].length);
16918           this.tokens.push({
16919             type: 'hr'
16920           });
16921           continue;
16922         }
16923     
16924         // blockquote
16925         if (cap = this.rules.blockquote.exec(src)) {
16926           src = src.substring(cap[0].length);
16927     
16928           this.tokens.push({
16929             type: 'blockquote_start'
16930           });
16931     
16932           cap = cap[0].replace(/^ *> ?/gm, '');
16933     
16934           // Pass `top` to keep the current
16935           // "toplevel" state. This is exactly
16936           // how markdown.pl works.
16937           this.token(cap, top, true);
16938     
16939           this.tokens.push({
16940             type: 'blockquote_end'
16941           });
16942     
16943           continue;
16944         }
16945     
16946         // list
16947         if (cap = this.rules.list.exec(src)) {
16948           src = src.substring(cap[0].length);
16949           bull = cap[2];
16950     
16951           this.tokens.push({
16952             type: 'list_start',
16953             ordered: bull.length > 1
16954           });
16955     
16956           // Get each top-level item.
16957           cap = cap[0].match(this.rules.item);
16958     
16959           next = false;
16960           l = cap.length;
16961           i = 0;
16962     
16963           for (; i < l; i++) {
16964             item = cap[i];
16965     
16966             // Remove the list item's bullet
16967             // so it is seen as the next token.
16968             space = item.length;
16969             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16970     
16971             // Outdent whatever the
16972             // list item contains. Hacky.
16973             if (~item.indexOf('\n ')) {
16974               space -= item.length;
16975               item = !this.options.pedantic
16976                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16977                 : item.replace(/^ {1,4}/gm, '');
16978             }
16979     
16980             // Determine whether the next list item belongs here.
16981             // Backpedal if it does not belong in this list.
16982             if (this.options.smartLists && i !== l - 1) {
16983               b = block.bullet.exec(cap[i + 1])[0];
16984               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16985                 src = cap.slice(i + 1).join('\n') + src;
16986                 i = l - 1;
16987               }
16988             }
16989     
16990             // Determine whether item is loose or not.
16991             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16992             // for discount behavior.
16993             loose = next || /\n\n(?!\s*$)/.test(item);
16994             if (i !== l - 1) {
16995               next = item.charAt(item.length - 1) === '\n';
16996               if (!loose) { loose = next; }
16997             }
16998     
16999             this.tokens.push({
17000               type: loose
17001                 ? 'loose_item_start'
17002                 : 'list_item_start'
17003             });
17004     
17005             // Recurse.
17006             this.token(item, false, bq);
17007     
17008             this.tokens.push({
17009               type: 'list_item_end'
17010             });
17011           }
17012     
17013           this.tokens.push({
17014             type: 'list_end'
17015           });
17016     
17017           continue;
17018         }
17019     
17020         // html
17021         if (cap = this.rules.html.exec(src)) {
17022           src = src.substring(cap[0].length);
17023           this.tokens.push({
17024             type: this.options.sanitize
17025               ? 'paragraph'
17026               : 'html',
17027             pre: !this.options.sanitizer
17028               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17029             text: cap[0]
17030           });
17031           continue;
17032         }
17033     
17034         // def
17035         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17036           src = src.substring(cap[0].length);
17037           this.tokens.links[cap[1].toLowerCase()] = {
17038             href: cap[2],
17039             title: cap[3]
17040           };
17041           continue;
17042         }
17043     
17044         // table (gfm)
17045         if (top && (cap = this.rules.table.exec(src))) {
17046           src = src.substring(cap[0].length);
17047     
17048           item = {
17049             type: 'table',
17050             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17051             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17052             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17053           };
17054     
17055           for (i = 0; i < item.align.length; i++) {
17056             if (/^ *-+: *$/.test(item.align[i])) {
17057               item.align[i] = 'right';
17058             } else if (/^ *:-+: *$/.test(item.align[i])) {
17059               item.align[i] = 'center';
17060             } else if (/^ *:-+ *$/.test(item.align[i])) {
17061               item.align[i] = 'left';
17062             } else {
17063               item.align[i] = null;
17064             }
17065           }
17066     
17067           for (i = 0; i < item.cells.length; i++) {
17068             item.cells[i] = item.cells[i]
17069               .replace(/^ *\| *| *\| *$/g, '')
17070               .split(/ *\| */);
17071           }
17072     
17073           this.tokens.push(item);
17074     
17075           continue;
17076         }
17077     
17078         // top-level paragraph
17079         if (top && (cap = this.rules.paragraph.exec(src))) {
17080           src = src.substring(cap[0].length);
17081           this.tokens.push({
17082             type: 'paragraph',
17083             text: cap[1].charAt(cap[1].length - 1) === '\n'
17084               ? cap[1].slice(0, -1)
17085               : cap[1]
17086           });
17087           continue;
17088         }
17089     
17090         // text
17091         if (cap = this.rules.text.exec(src)) {
17092           // Top-level should never reach here.
17093           src = src.substring(cap[0].length);
17094           this.tokens.push({
17095             type: 'text',
17096             text: cap[0]
17097           });
17098           continue;
17099         }
17100     
17101         if (src) {
17102           throw new
17103             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17104         }
17105       }
17106     
17107       return this.tokens;
17108     };
17109     
17110     /**
17111      * Inline-Level Grammar
17112      */
17113     
17114     var inline = {
17115       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17116       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17117       url: noop,
17118       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17119       link: /^!?\[(inside)\]\(href\)/,
17120       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17121       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17122       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17123       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17124       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17125       br: /^ {2,}\n(?!\s*$)/,
17126       del: noop,
17127       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17128     };
17129     
17130     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17131     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17132     
17133     inline.link = replace(inline.link)
17134       ('inside', inline._inside)
17135       ('href', inline._href)
17136       ();
17137     
17138     inline.reflink = replace(inline.reflink)
17139       ('inside', inline._inside)
17140       ();
17141     
17142     /**
17143      * Normal Inline Grammar
17144      */
17145     
17146     inline.normal = merge({}, inline);
17147     
17148     /**
17149      * Pedantic Inline Grammar
17150      */
17151     
17152     inline.pedantic = merge({}, inline.normal, {
17153       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17154       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17155     });
17156     
17157     /**
17158      * GFM Inline Grammar
17159      */
17160     
17161     inline.gfm = merge({}, inline.normal, {
17162       escape: replace(inline.escape)('])', '~|])')(),
17163       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17164       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17165       text: replace(inline.text)
17166         (']|', '~]|')
17167         ('|', '|https?://|')
17168         ()
17169     });
17170     
17171     /**
17172      * GFM + Line Breaks Inline Grammar
17173      */
17174     
17175     inline.breaks = merge({}, inline.gfm, {
17176       br: replace(inline.br)('{2,}', '*')(),
17177       text: replace(inline.gfm.text)('{2,}', '*')()
17178     });
17179     
17180     /**
17181      * Inline Lexer & Compiler
17182      */
17183     
17184     function InlineLexer(links, options) {
17185       this.options = options || marked.defaults;
17186       this.links = links;
17187       this.rules = inline.normal;
17188       this.renderer = this.options.renderer || new Renderer;
17189       this.renderer.options = this.options;
17190     
17191       if (!this.links) {
17192         throw new
17193           Error('Tokens array requires a `links` property.');
17194       }
17195     
17196       if (this.options.gfm) {
17197         if (this.options.breaks) {
17198           this.rules = inline.breaks;
17199         } else {
17200           this.rules = inline.gfm;
17201         }
17202       } else if (this.options.pedantic) {
17203         this.rules = inline.pedantic;
17204       }
17205     }
17206     
17207     /**
17208      * Expose Inline Rules
17209      */
17210     
17211     InlineLexer.rules = inline;
17212     
17213     /**
17214      * Static Lexing/Compiling Method
17215      */
17216     
17217     InlineLexer.output = function(src, links, options) {
17218       var inline = new InlineLexer(links, options);
17219       return inline.output(src);
17220     };
17221     
17222     /**
17223      * Lexing/Compiling
17224      */
17225     
17226     InlineLexer.prototype.output = function(src) {
17227       var out = ''
17228         , link
17229         , text
17230         , href
17231         , cap;
17232     
17233       while (src) {
17234         // escape
17235         if (cap = this.rules.escape.exec(src)) {
17236           src = src.substring(cap[0].length);
17237           out += cap[1];
17238           continue;
17239         }
17240     
17241         // autolink
17242         if (cap = this.rules.autolink.exec(src)) {
17243           src = src.substring(cap[0].length);
17244           if (cap[2] === '@') {
17245             text = cap[1].charAt(6) === ':'
17246               ? this.mangle(cap[1].substring(7))
17247               : this.mangle(cap[1]);
17248             href = this.mangle('mailto:') + text;
17249           } else {
17250             text = escape(cap[1]);
17251             href = text;
17252           }
17253           out += this.renderer.link(href, null, text);
17254           continue;
17255         }
17256     
17257         // url (gfm)
17258         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17259           src = src.substring(cap[0].length);
17260           text = escape(cap[1]);
17261           href = text;
17262           out += this.renderer.link(href, null, text);
17263           continue;
17264         }
17265     
17266         // tag
17267         if (cap = this.rules.tag.exec(src)) {
17268           if (!this.inLink && /^<a /i.test(cap[0])) {
17269             this.inLink = true;
17270           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17271             this.inLink = false;
17272           }
17273           src = src.substring(cap[0].length);
17274           out += this.options.sanitize
17275             ? this.options.sanitizer
17276               ? this.options.sanitizer(cap[0])
17277               : escape(cap[0])
17278             : cap[0];
17279           continue;
17280         }
17281     
17282         // link
17283         if (cap = this.rules.link.exec(src)) {
17284           src = src.substring(cap[0].length);
17285           this.inLink = true;
17286           out += this.outputLink(cap, {
17287             href: cap[2],
17288             title: cap[3]
17289           });
17290           this.inLink = false;
17291           continue;
17292         }
17293     
17294         // reflink, nolink
17295         if ((cap = this.rules.reflink.exec(src))
17296             || (cap = this.rules.nolink.exec(src))) {
17297           src = src.substring(cap[0].length);
17298           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17299           link = this.links[link.toLowerCase()];
17300           if (!link || !link.href) {
17301             out += cap[0].charAt(0);
17302             src = cap[0].substring(1) + src;
17303             continue;
17304           }
17305           this.inLink = true;
17306           out += this.outputLink(cap, link);
17307           this.inLink = false;
17308           continue;
17309         }
17310     
17311         // strong
17312         if (cap = this.rules.strong.exec(src)) {
17313           src = src.substring(cap[0].length);
17314           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17315           continue;
17316         }
17317     
17318         // em
17319         if (cap = this.rules.em.exec(src)) {
17320           src = src.substring(cap[0].length);
17321           out += this.renderer.em(this.output(cap[2] || cap[1]));
17322           continue;
17323         }
17324     
17325         // code
17326         if (cap = this.rules.code.exec(src)) {
17327           src = src.substring(cap[0].length);
17328           out += this.renderer.codespan(escape(cap[2], true));
17329           continue;
17330         }
17331     
17332         // br
17333         if (cap = this.rules.br.exec(src)) {
17334           src = src.substring(cap[0].length);
17335           out += this.renderer.br();
17336           continue;
17337         }
17338     
17339         // del (gfm)
17340         if (cap = this.rules.del.exec(src)) {
17341           src = src.substring(cap[0].length);
17342           out += this.renderer.del(this.output(cap[1]));
17343           continue;
17344         }
17345     
17346         // text
17347         if (cap = this.rules.text.exec(src)) {
17348           src = src.substring(cap[0].length);
17349           out += this.renderer.text(escape(this.smartypants(cap[0])));
17350           continue;
17351         }
17352     
17353         if (src) {
17354           throw new
17355             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17356         }
17357       }
17358     
17359       return out;
17360     };
17361     
17362     /**
17363      * Compile Link
17364      */
17365     
17366     InlineLexer.prototype.outputLink = function(cap, link) {
17367       var href = escape(link.href)
17368         , title = link.title ? escape(link.title) : null;
17369     
17370       return cap[0].charAt(0) !== '!'
17371         ? this.renderer.link(href, title, this.output(cap[1]))
17372         : this.renderer.image(href, title, escape(cap[1]));
17373     };
17374     
17375     /**
17376      * Smartypants Transformations
17377      */
17378     
17379     InlineLexer.prototype.smartypants = function(text) {
17380       if (!this.options.smartypants)  { return text; }
17381       return text
17382         // em-dashes
17383         .replace(/---/g, '\u2014')
17384         // en-dashes
17385         .replace(/--/g, '\u2013')
17386         // opening singles
17387         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17388         // closing singles & apostrophes
17389         .replace(/'/g, '\u2019')
17390         // opening doubles
17391         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17392         // closing doubles
17393         .replace(/"/g, '\u201d')
17394         // ellipses
17395         .replace(/\.{3}/g, '\u2026');
17396     };
17397     
17398     /**
17399      * Mangle Links
17400      */
17401     
17402     InlineLexer.prototype.mangle = function(text) {
17403       if (!this.options.mangle) { return text; }
17404       var out = ''
17405         , l = text.length
17406         , i = 0
17407         , ch;
17408     
17409       for (; i < l; i++) {
17410         ch = text.charCodeAt(i);
17411         if (Math.random() > 0.5) {
17412           ch = 'x' + ch.toString(16);
17413         }
17414         out += '&#' + ch + ';';
17415       }
17416     
17417       return out;
17418     };
17419     
17420     /**
17421      * Renderer
17422      */
17423     
17424     function Renderer(options) {
17425       this.options = options || {};
17426     }
17427     
17428     Renderer.prototype.code = function(code, lang, escaped) {
17429       if (this.options.highlight) {
17430         var out = this.options.highlight(code, lang);
17431         if (out != null && out !== code) {
17432           escaped = true;
17433           code = out;
17434         }
17435       } else {
17436             // hack!!! - it's already escapeD?
17437             escaped = true;
17438       }
17439     
17440       if (!lang) {
17441         return '<pre><code>'
17442           + (escaped ? code : escape(code, true))
17443           + '\n</code></pre>';
17444       }
17445     
17446       return '<pre><code class="'
17447         + this.options.langPrefix
17448         + escape(lang, true)
17449         + '">'
17450         + (escaped ? code : escape(code, true))
17451         + '\n</code></pre>\n';
17452     };
17453     
17454     Renderer.prototype.blockquote = function(quote) {
17455       return '<blockquote>\n' + quote + '</blockquote>\n';
17456     };
17457     
17458     Renderer.prototype.html = function(html) {
17459       return html;
17460     };
17461     
17462     Renderer.prototype.heading = function(text, level, raw) {
17463       return '<h'
17464         + level
17465         + ' id="'
17466         + this.options.headerPrefix
17467         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17468         + '">'
17469         + text
17470         + '</h'
17471         + level
17472         + '>\n';
17473     };
17474     
17475     Renderer.prototype.hr = function() {
17476       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17477     };
17478     
17479     Renderer.prototype.list = function(body, ordered) {
17480       var type = ordered ? 'ol' : 'ul';
17481       return '<' + type + '>\n' + body + '</' + type + '>\n';
17482     };
17483     
17484     Renderer.prototype.listitem = function(text) {
17485       return '<li>' + text + '</li>\n';
17486     };
17487     
17488     Renderer.prototype.paragraph = function(text) {
17489       return '<p>' + text + '</p>\n';
17490     };
17491     
17492     Renderer.prototype.table = function(header, body) {
17493       return '<table class="table table-striped">\n'
17494         + '<thead>\n'
17495         + header
17496         + '</thead>\n'
17497         + '<tbody>\n'
17498         + body
17499         + '</tbody>\n'
17500         + '</table>\n';
17501     };
17502     
17503     Renderer.prototype.tablerow = function(content) {
17504       return '<tr>\n' + content + '</tr>\n';
17505     };
17506     
17507     Renderer.prototype.tablecell = function(content, flags) {
17508       var type = flags.header ? 'th' : 'td';
17509       var tag = flags.align
17510         ? '<' + type + ' style="text-align:' + flags.align + '">'
17511         : '<' + type + '>';
17512       return tag + content + '</' + type + '>\n';
17513     };
17514     
17515     // span level renderer
17516     Renderer.prototype.strong = function(text) {
17517       return '<strong>' + text + '</strong>';
17518     };
17519     
17520     Renderer.prototype.em = function(text) {
17521       return '<em>' + text + '</em>';
17522     };
17523     
17524     Renderer.prototype.codespan = function(text) {
17525       return '<code>' + text + '</code>';
17526     };
17527     
17528     Renderer.prototype.br = function() {
17529       return this.options.xhtml ? '<br/>' : '<br>';
17530     };
17531     
17532     Renderer.prototype.del = function(text) {
17533       return '<del>' + text + '</del>';
17534     };
17535     
17536     Renderer.prototype.link = function(href, title, text) {
17537       if (this.options.sanitize) {
17538         try {
17539           var prot = decodeURIComponent(unescape(href))
17540             .replace(/[^\w:]/g, '')
17541             .toLowerCase();
17542         } catch (e) {
17543           return '';
17544         }
17545         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17546           return '';
17547         }
17548       }
17549       var out = '<a href="' + href + '"';
17550       if (title) {
17551         out += ' title="' + title + '"';
17552       }
17553       out += '>' + text + '</a>';
17554       return out;
17555     };
17556     
17557     Renderer.prototype.image = function(href, title, text) {
17558       var out = '<img src="' + href + '" alt="' + text + '"';
17559       if (title) {
17560         out += ' title="' + title + '"';
17561       }
17562       out += this.options.xhtml ? '/>' : '>';
17563       return out;
17564     };
17565     
17566     Renderer.prototype.text = function(text) {
17567       return text;
17568     };
17569     
17570     /**
17571      * Parsing & Compiling
17572      */
17573     
17574     function Parser(options) {
17575       this.tokens = [];
17576       this.token = null;
17577       this.options = options || marked.defaults;
17578       this.options.renderer = this.options.renderer || new Renderer;
17579       this.renderer = this.options.renderer;
17580       this.renderer.options = this.options;
17581     }
17582     
17583     /**
17584      * Static Parse Method
17585      */
17586     
17587     Parser.parse = function(src, options, renderer) {
17588       var parser = new Parser(options, renderer);
17589       return parser.parse(src);
17590     };
17591     
17592     /**
17593      * Parse Loop
17594      */
17595     
17596     Parser.prototype.parse = function(src) {
17597       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17598       this.tokens = src.reverse();
17599     
17600       var out = '';
17601       while (this.next()) {
17602         out += this.tok();
17603       }
17604     
17605       return out;
17606     };
17607     
17608     /**
17609      * Next Token
17610      */
17611     
17612     Parser.prototype.next = function() {
17613       return this.token = this.tokens.pop();
17614     };
17615     
17616     /**
17617      * Preview Next Token
17618      */
17619     
17620     Parser.prototype.peek = function() {
17621       return this.tokens[this.tokens.length - 1] || 0;
17622     };
17623     
17624     /**
17625      * Parse Text Tokens
17626      */
17627     
17628     Parser.prototype.parseText = function() {
17629       var body = this.token.text;
17630     
17631       while (this.peek().type === 'text') {
17632         body += '\n' + this.next().text;
17633       }
17634     
17635       return this.inline.output(body);
17636     };
17637     
17638     /**
17639      * Parse Current Token
17640      */
17641     
17642     Parser.prototype.tok = function() {
17643       switch (this.token.type) {
17644         case 'space': {
17645           return '';
17646         }
17647         case 'hr': {
17648           return this.renderer.hr();
17649         }
17650         case 'heading': {
17651           return this.renderer.heading(
17652             this.inline.output(this.token.text),
17653             this.token.depth,
17654             this.token.text);
17655         }
17656         case 'code': {
17657           return this.renderer.code(this.token.text,
17658             this.token.lang,
17659             this.token.escaped);
17660         }
17661         case 'table': {
17662           var header = ''
17663             , body = ''
17664             , i
17665             , row
17666             , cell
17667             , flags
17668             , j;
17669     
17670           // header
17671           cell = '';
17672           for (i = 0; i < this.token.header.length; i++) {
17673             flags = { header: true, align: this.token.align[i] };
17674             cell += this.renderer.tablecell(
17675               this.inline.output(this.token.header[i]),
17676               { header: true, align: this.token.align[i] }
17677             );
17678           }
17679           header += this.renderer.tablerow(cell);
17680     
17681           for (i = 0; i < this.token.cells.length; i++) {
17682             row = this.token.cells[i];
17683     
17684             cell = '';
17685             for (j = 0; j < row.length; j++) {
17686               cell += this.renderer.tablecell(
17687                 this.inline.output(row[j]),
17688                 { header: false, align: this.token.align[j] }
17689               );
17690             }
17691     
17692             body += this.renderer.tablerow(cell);
17693           }
17694           return this.renderer.table(header, body);
17695         }
17696         case 'blockquote_start': {
17697           var body = '';
17698     
17699           while (this.next().type !== 'blockquote_end') {
17700             body += this.tok();
17701           }
17702     
17703           return this.renderer.blockquote(body);
17704         }
17705         case 'list_start': {
17706           var body = ''
17707             , ordered = this.token.ordered;
17708     
17709           while (this.next().type !== 'list_end') {
17710             body += this.tok();
17711           }
17712     
17713           return this.renderer.list(body, ordered);
17714         }
17715         case 'list_item_start': {
17716           var body = '';
17717     
17718           while (this.next().type !== 'list_item_end') {
17719             body += this.token.type === 'text'
17720               ? this.parseText()
17721               : this.tok();
17722           }
17723     
17724           return this.renderer.listitem(body);
17725         }
17726         case 'loose_item_start': {
17727           var body = '';
17728     
17729           while (this.next().type !== 'list_item_end') {
17730             body += this.tok();
17731           }
17732     
17733           return this.renderer.listitem(body);
17734         }
17735         case 'html': {
17736           var html = !this.token.pre && !this.options.pedantic
17737             ? this.inline.output(this.token.text)
17738             : this.token.text;
17739           return this.renderer.html(html);
17740         }
17741         case 'paragraph': {
17742           return this.renderer.paragraph(this.inline.output(this.token.text));
17743         }
17744         case 'text': {
17745           return this.renderer.paragraph(this.parseText());
17746         }
17747       }
17748     };
17749     
17750     /**
17751      * Helpers
17752      */
17753     
17754     function escape(html, encode) {
17755       return html
17756         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17757         .replace(/</g, '&lt;')
17758         .replace(/>/g, '&gt;')
17759         .replace(/"/g, '&quot;')
17760         .replace(/'/g, '&#39;');
17761     }
17762     
17763     function unescape(html) {
17764         // explicitly match decimal, hex, and named HTML entities 
17765       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17766         n = n.toLowerCase();
17767         if (n === 'colon') { return ':'; }
17768         if (n.charAt(0) === '#') {
17769           return n.charAt(1) === 'x'
17770             ? String.fromCharCode(parseInt(n.substring(2), 16))
17771             : String.fromCharCode(+n.substring(1));
17772         }
17773         return '';
17774       });
17775     }
17776     
17777     function replace(regex, opt) {
17778       regex = regex.source;
17779       opt = opt || '';
17780       return function self(name, val) {
17781         if (!name) { return new RegExp(regex, opt); }
17782         val = val.source || val;
17783         val = val.replace(/(^|[^\[])\^/g, '$1');
17784         regex = regex.replace(name, val);
17785         return self;
17786       };
17787     }
17788     
17789     function noop() {}
17790     noop.exec = noop;
17791     
17792     function merge(obj) {
17793       var i = 1
17794         , target
17795         , key;
17796     
17797       for (; i < arguments.length; i++) {
17798         target = arguments[i];
17799         for (key in target) {
17800           if (Object.prototype.hasOwnProperty.call(target, key)) {
17801             obj[key] = target[key];
17802           }
17803         }
17804       }
17805     
17806       return obj;
17807     }
17808     
17809     
17810     /**
17811      * Marked
17812      */
17813     
17814     function marked(src, opt, callback) {
17815       if (callback || typeof opt === 'function') {
17816         if (!callback) {
17817           callback = opt;
17818           opt = null;
17819         }
17820     
17821         opt = merge({}, marked.defaults, opt || {});
17822     
17823         var highlight = opt.highlight
17824           , tokens
17825           , pending
17826           , i = 0;
17827     
17828         try {
17829           tokens = Lexer.lex(src, opt)
17830         } catch (e) {
17831           return callback(e);
17832         }
17833     
17834         pending = tokens.length;
17835     
17836         var done = function(err) {
17837           if (err) {
17838             opt.highlight = highlight;
17839             return callback(err);
17840           }
17841     
17842           var out;
17843     
17844           try {
17845             out = Parser.parse(tokens, opt);
17846           } catch (e) {
17847             err = e;
17848           }
17849     
17850           opt.highlight = highlight;
17851     
17852           return err
17853             ? callback(err)
17854             : callback(null, out);
17855         };
17856     
17857         if (!highlight || highlight.length < 3) {
17858           return done();
17859         }
17860     
17861         delete opt.highlight;
17862     
17863         if (!pending) { return done(); }
17864     
17865         for (; i < tokens.length; i++) {
17866           (function(token) {
17867             if (token.type !== 'code') {
17868               return --pending || done();
17869             }
17870             return highlight(token.text, token.lang, function(err, code) {
17871               if (err) { return done(err); }
17872               if (code == null || code === token.text) {
17873                 return --pending || done();
17874               }
17875               token.text = code;
17876               token.escaped = true;
17877               --pending || done();
17878             });
17879           })(tokens[i]);
17880         }
17881     
17882         return;
17883       }
17884       try {
17885         if (opt) { opt = merge({}, marked.defaults, opt); }
17886         return Parser.parse(Lexer.lex(src, opt), opt);
17887       } catch (e) {
17888         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17889         if ((opt || marked.defaults).silent) {
17890           return '<p>An error occured:</p><pre>'
17891             + escape(e.message + '', true)
17892             + '</pre>';
17893         }
17894         throw e;
17895       }
17896     }
17897     
17898     /**
17899      * Options
17900      */
17901     
17902     marked.options =
17903     marked.setOptions = function(opt) {
17904       merge(marked.defaults, opt);
17905       return marked;
17906     };
17907     
17908     marked.defaults = {
17909       gfm: true,
17910       tables: true,
17911       breaks: false,
17912       pedantic: false,
17913       sanitize: false,
17914       sanitizer: null,
17915       mangle: true,
17916       smartLists: false,
17917       silent: false,
17918       highlight: null,
17919       langPrefix: 'lang-',
17920       smartypants: false,
17921       headerPrefix: '',
17922       renderer: new Renderer,
17923       xhtml: false
17924     };
17925     
17926     /**
17927      * Expose
17928      */
17929     
17930     marked.Parser = Parser;
17931     marked.parser = Parser.parse;
17932     
17933     marked.Renderer = Renderer;
17934     
17935     marked.Lexer = Lexer;
17936     marked.lexer = Lexer.lex;
17937     
17938     marked.InlineLexer = InlineLexer;
17939     marked.inlineLexer = InlineLexer.output;
17940     
17941     marked.parse = marked;
17942     
17943     Roo.Markdown.marked = marked;
17944
17945 })();/*
17946  * Based on:
17947  * Ext JS Library 1.1.1
17948  * Copyright(c) 2006-2007, Ext JS, LLC.
17949  *
17950  * Originally Released Under LGPL - original licence link has changed is not relivant.
17951  *
17952  * Fork - LGPL
17953  * <script type="text/javascript">
17954  */
17955
17956
17957
17958 /*
17959  * These classes are derivatives of the similarly named classes in the YUI Library.
17960  * The original license:
17961  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17962  * Code licensed under the BSD License:
17963  * http://developer.yahoo.net/yui/license.txt
17964  */
17965
17966 (function() {
17967
17968 var Event=Roo.EventManager;
17969 var Dom=Roo.lib.Dom;
17970
17971 /**
17972  * @class Roo.dd.DragDrop
17973  * @extends Roo.util.Observable
17974  * Defines the interface and base operation of items that that can be
17975  * dragged or can be drop targets.  It was designed to be extended, overriding
17976  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17977  * Up to three html elements can be associated with a DragDrop instance:
17978  * <ul>
17979  * <li>linked element: the element that is passed into the constructor.
17980  * This is the element which defines the boundaries for interaction with
17981  * other DragDrop objects.</li>
17982  * <li>handle element(s): The drag operation only occurs if the element that
17983  * was clicked matches a handle element.  By default this is the linked
17984  * element, but there are times that you will want only a portion of the
17985  * linked element to initiate the drag operation, and the setHandleElId()
17986  * method provides a way to define this.</li>
17987  * <li>drag element: this represents the element that would be moved along
17988  * with the cursor during a drag operation.  By default, this is the linked
17989  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
17990  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17991  * </li>
17992  * </ul>
17993  * This class should not be instantiated until the onload event to ensure that
17994  * the associated elements are available.
17995  * The following would define a DragDrop obj that would interact with any
17996  * other DragDrop obj in the "group1" group:
17997  * <pre>
17998  *  dd = new Roo.dd.DragDrop("div1", "group1");
17999  * </pre>
18000  * Since none of the event handlers have been implemented, nothing would
18001  * actually happen if you were to run the code above.  Normally you would
18002  * override this class or one of the default implementations, but you can
18003  * also override the methods you want on an instance of the class...
18004  * <pre>
18005  *  dd.onDragDrop = function(e, id) {
18006  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18007  *  }
18008  * </pre>
18009  * @constructor
18010  * @param {String} id of the element that is linked to this instance
18011  * @param {String} sGroup the group of related DragDrop objects
18012  * @param {object} config an object containing configurable attributes
18013  *                Valid properties for DragDrop:
18014  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18015  */
18016 Roo.dd.DragDrop = function(id, sGroup, config) {
18017     if (id) {
18018         this.init(id, sGroup, config);
18019     }
18020     
18021 };
18022
18023 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18024
18025     /**
18026      * The id of the element associated with this object.  This is what we
18027      * refer to as the "linked element" because the size and position of
18028      * this element is used to determine when the drag and drop objects have
18029      * interacted.
18030      * @property id
18031      * @type String
18032      */
18033     id: null,
18034
18035     /**
18036      * Configuration attributes passed into the constructor
18037      * @property config
18038      * @type object
18039      */
18040     config: null,
18041
18042     /**
18043      * The id of the element that will be dragged.  By default this is same
18044      * as the linked element , but could be changed to another element. Ex:
18045      * Roo.dd.DDProxy
18046      * @property dragElId
18047      * @type String
18048      * @private
18049      */
18050     dragElId: null,
18051
18052     /**
18053      * the id of the element that initiates the drag operation.  By default
18054      * this is the linked element, but could be changed to be a child of this
18055      * element.  This lets us do things like only starting the drag when the
18056      * header element within the linked html element is clicked.
18057      * @property handleElId
18058      * @type String
18059      * @private
18060      */
18061     handleElId: null,
18062
18063     /**
18064      * An associative array of HTML tags that will be ignored if clicked.
18065      * @property invalidHandleTypes
18066      * @type {string: string}
18067      */
18068     invalidHandleTypes: null,
18069
18070     /**
18071      * An associative array of ids for elements that will be ignored if clicked
18072      * @property invalidHandleIds
18073      * @type {string: string}
18074      */
18075     invalidHandleIds: null,
18076
18077     /**
18078      * An indexted array of css class names for elements that will be ignored
18079      * if clicked.
18080      * @property invalidHandleClasses
18081      * @type string[]
18082      */
18083     invalidHandleClasses: null,
18084
18085     /**
18086      * The linked element's absolute X position at the time the drag was
18087      * started
18088      * @property startPageX
18089      * @type int
18090      * @private
18091      */
18092     startPageX: 0,
18093
18094     /**
18095      * The linked element's absolute X position at the time the drag was
18096      * started
18097      * @property startPageY
18098      * @type int
18099      * @private
18100      */
18101     startPageY: 0,
18102
18103     /**
18104      * The group defines a logical collection of DragDrop objects that are
18105      * related.  Instances only get events when interacting with other
18106      * DragDrop object in the same group.  This lets us define multiple
18107      * groups using a single DragDrop subclass if we want.
18108      * @property groups
18109      * @type {string: string}
18110      */
18111     groups: null,
18112
18113     /**
18114      * Individual drag/drop instances can be locked.  This will prevent
18115      * onmousedown start drag.
18116      * @property locked
18117      * @type boolean
18118      * @private
18119      */
18120     locked: false,
18121
18122     /**
18123      * Lock this instance
18124      * @method lock
18125      */
18126     lock: function() { this.locked = true; },
18127
18128     /**
18129      * Unlock this instace
18130      * @method unlock
18131      */
18132     unlock: function() { this.locked = false; },
18133
18134     /**
18135      * By default, all insances can be a drop target.  This can be disabled by
18136      * setting isTarget to false.
18137      * @method isTarget
18138      * @type boolean
18139      */
18140     isTarget: true,
18141
18142     /**
18143      * The padding configured for this drag and drop object for calculating
18144      * the drop zone intersection with this object.
18145      * @method padding
18146      * @type int[]
18147      */
18148     padding: null,
18149
18150     /**
18151      * Cached reference to the linked element
18152      * @property _domRef
18153      * @private
18154      */
18155     _domRef: null,
18156
18157     /**
18158      * Internal typeof flag
18159      * @property __ygDragDrop
18160      * @private
18161      */
18162     __ygDragDrop: true,
18163
18164     /**
18165      * Set to true when horizontal contraints are applied
18166      * @property constrainX
18167      * @type boolean
18168      * @private
18169      */
18170     constrainX: false,
18171
18172     /**
18173      * Set to true when vertical contraints are applied
18174      * @property constrainY
18175      * @type boolean
18176      * @private
18177      */
18178     constrainY: false,
18179
18180     /**
18181      * The left constraint
18182      * @property minX
18183      * @type int
18184      * @private
18185      */
18186     minX: 0,
18187
18188     /**
18189      * The right constraint
18190      * @property maxX
18191      * @type int
18192      * @private
18193      */
18194     maxX: 0,
18195
18196     /**
18197      * The up constraint
18198      * @property minY
18199      * @type int
18200      * @type int
18201      * @private
18202      */
18203     minY: 0,
18204
18205     /**
18206      * The down constraint
18207      * @property maxY
18208      * @type int
18209      * @private
18210      */
18211     maxY: 0,
18212
18213     /**
18214      * Maintain offsets when we resetconstraints.  Set to true when you want
18215      * the position of the element relative to its parent to stay the same
18216      * when the page changes
18217      *
18218      * @property maintainOffset
18219      * @type boolean
18220      */
18221     maintainOffset: false,
18222
18223     /**
18224      * Array of pixel locations the element will snap to if we specified a
18225      * horizontal graduation/interval.  This array is generated automatically
18226      * when you define a tick interval.
18227      * @property xTicks
18228      * @type int[]
18229      */
18230     xTicks: null,
18231
18232     /**
18233      * Array of pixel locations the element will snap to if we specified a
18234      * vertical graduation/interval.  This array is generated automatically
18235      * when you define a tick interval.
18236      * @property yTicks
18237      * @type int[]
18238      */
18239     yTicks: null,
18240
18241     /**
18242      * By default the drag and drop instance will only respond to the primary
18243      * button click (left button for a right-handed mouse).  Set to true to
18244      * allow drag and drop to start with any mouse click that is propogated
18245      * by the browser
18246      * @property primaryButtonOnly
18247      * @type boolean
18248      */
18249     primaryButtonOnly: true,
18250
18251     /**
18252      * The availabe property is false until the linked dom element is accessible.
18253      * @property available
18254      * @type boolean
18255      */
18256     available: false,
18257
18258     /**
18259      * By default, drags can only be initiated if the mousedown occurs in the
18260      * region the linked element is.  This is done in part to work around a
18261      * bug in some browsers that mis-report the mousedown if the previous
18262      * mouseup happened outside of the window.  This property is set to true
18263      * if outer handles are defined.
18264      *
18265      * @property hasOuterHandles
18266      * @type boolean
18267      * @default false
18268      */
18269     hasOuterHandles: false,
18270
18271     /**
18272      * Code that executes immediately before the startDrag event
18273      * @method b4StartDrag
18274      * @private
18275      */
18276     b4StartDrag: function(x, y) { },
18277
18278     /**
18279      * Abstract method called after a drag/drop object is clicked
18280      * and the drag or mousedown time thresholds have beeen met.
18281      * @method startDrag
18282      * @param {int} X click location
18283      * @param {int} Y click location
18284      */
18285     startDrag: function(x, y) { /* override this */ },
18286
18287     /**
18288      * Code that executes immediately before the onDrag event
18289      * @method b4Drag
18290      * @private
18291      */
18292     b4Drag: function(e) { },
18293
18294     /**
18295      * Abstract method called during the onMouseMove event while dragging an
18296      * object.
18297      * @method onDrag
18298      * @param {Event} e the mousemove event
18299      */
18300     onDrag: function(e) { /* override this */ },
18301
18302     /**
18303      * Abstract method called when this element fist begins hovering over
18304      * another DragDrop obj
18305      * @method onDragEnter
18306      * @param {Event} e the mousemove event
18307      * @param {String|DragDrop[]} id In POINT mode, the element
18308      * id this is hovering over.  In INTERSECT mode, an array of one or more
18309      * dragdrop items being hovered over.
18310      */
18311     onDragEnter: function(e, id) { /* override this */ },
18312
18313     /**
18314      * Code that executes immediately before the onDragOver event
18315      * @method b4DragOver
18316      * @private
18317      */
18318     b4DragOver: function(e) { },
18319
18320     /**
18321      * Abstract method called when this element is hovering over another
18322      * DragDrop obj
18323      * @method onDragOver
18324      * @param {Event} e the mousemove event
18325      * @param {String|DragDrop[]} id In POINT mode, the element
18326      * id this is hovering over.  In INTERSECT mode, an array of dd items
18327      * being hovered over.
18328      */
18329     onDragOver: function(e, id) { /* override this */ },
18330
18331     /**
18332      * Code that executes immediately before the onDragOut event
18333      * @method b4DragOut
18334      * @private
18335      */
18336     b4DragOut: function(e) { },
18337
18338     /**
18339      * Abstract method called when we are no longer hovering over an element
18340      * @method onDragOut
18341      * @param {Event} e the mousemove event
18342      * @param {String|DragDrop[]} id In POINT mode, the element
18343      * id this was hovering over.  In INTERSECT mode, an array of dd items
18344      * that the mouse is no longer over.
18345      */
18346     onDragOut: function(e, id) { /* override this */ },
18347
18348     /**
18349      * Code that executes immediately before the onDragDrop event
18350      * @method b4DragDrop
18351      * @private
18352      */
18353     b4DragDrop: function(e) { },
18354
18355     /**
18356      * Abstract method called when this item is dropped on another DragDrop
18357      * obj
18358      * @method onDragDrop
18359      * @param {Event} e the mouseup event
18360      * @param {String|DragDrop[]} id In POINT mode, the element
18361      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18362      * was dropped on.
18363      */
18364     onDragDrop: function(e, id) { /* override this */ },
18365
18366     /**
18367      * Abstract method called when this item is dropped on an area with no
18368      * drop target
18369      * @method onInvalidDrop
18370      * @param {Event} e the mouseup event
18371      */
18372     onInvalidDrop: function(e) { /* override this */ },
18373
18374     /**
18375      * Code that executes immediately before the endDrag event
18376      * @method b4EndDrag
18377      * @private
18378      */
18379     b4EndDrag: function(e) { },
18380
18381     /**
18382      * Fired when we are done dragging the object
18383      * @method endDrag
18384      * @param {Event} e the mouseup event
18385      */
18386     endDrag: function(e) { /* override this */ },
18387
18388     /**
18389      * Code executed immediately before the onMouseDown event
18390      * @method b4MouseDown
18391      * @param {Event} e the mousedown event
18392      * @private
18393      */
18394     b4MouseDown: function(e) {  },
18395
18396     /**
18397      * Event handler that fires when a drag/drop obj gets a mousedown
18398      * @method onMouseDown
18399      * @param {Event} e the mousedown event
18400      */
18401     onMouseDown: function(e) { /* override this */ },
18402
18403     /**
18404      * Event handler that fires when a drag/drop obj gets a mouseup
18405      * @method onMouseUp
18406      * @param {Event} e the mouseup event
18407      */
18408     onMouseUp: function(e) { /* override this */ },
18409
18410     /**
18411      * Override the onAvailable method to do what is needed after the initial
18412      * position was determined.
18413      * @method onAvailable
18414      */
18415     onAvailable: function () {
18416     },
18417
18418     /*
18419      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18420      * @type Object
18421      */
18422     defaultPadding : {left:0, right:0, top:0, bottom:0},
18423
18424     /*
18425      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18426  *
18427  * Usage:
18428  <pre><code>
18429  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18430                 { dragElId: "existingProxyDiv" });
18431  dd.startDrag = function(){
18432      this.constrainTo("parent-id");
18433  };
18434  </code></pre>
18435  * Or you can initalize it using the {@link Roo.Element} object:
18436  <pre><code>
18437  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18438      startDrag : function(){
18439          this.constrainTo("parent-id");
18440      }
18441  });
18442  </code></pre>
18443      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18444      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18445      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18446      * an object containing the sides to pad. For example: {right:10, bottom:10}
18447      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18448      */
18449     constrainTo : function(constrainTo, pad, inContent){
18450         if(typeof pad == "number"){
18451             pad = {left: pad, right:pad, top:pad, bottom:pad};
18452         }
18453         pad = pad || this.defaultPadding;
18454         var b = Roo.get(this.getEl()).getBox();
18455         var ce = Roo.get(constrainTo);
18456         var s = ce.getScroll();
18457         var c, cd = ce.dom;
18458         if(cd == document.body){
18459             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18460         }else{
18461             xy = ce.getXY();
18462             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18463         }
18464
18465
18466         var topSpace = b.y - c.y;
18467         var leftSpace = b.x - c.x;
18468
18469         this.resetConstraints();
18470         this.setXConstraint(leftSpace - (pad.left||0), // left
18471                 c.width - leftSpace - b.width - (pad.right||0) //right
18472         );
18473         this.setYConstraint(topSpace - (pad.top||0), //top
18474                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18475         );
18476     },
18477
18478     /**
18479      * Returns a reference to the linked element
18480      * @method getEl
18481      * @return {HTMLElement} the html element
18482      */
18483     getEl: function() {
18484         if (!this._domRef) {
18485             this._domRef = Roo.getDom(this.id);
18486         }
18487
18488         return this._domRef;
18489     },
18490
18491     /**
18492      * Returns a reference to the actual element to drag.  By default this is
18493      * the same as the html element, but it can be assigned to another
18494      * element. An example of this can be found in Roo.dd.DDProxy
18495      * @method getDragEl
18496      * @return {HTMLElement} the html element
18497      */
18498     getDragEl: function() {
18499         return Roo.getDom(this.dragElId);
18500     },
18501
18502     /**
18503      * Sets up the DragDrop object.  Must be called in the constructor of any
18504      * Roo.dd.DragDrop subclass
18505      * @method init
18506      * @param id the id of the linked element
18507      * @param {String} sGroup the group of related items
18508      * @param {object} config configuration attributes
18509      */
18510     init: function(id, sGroup, config) {
18511         this.initTarget(id, sGroup, config);
18512         if (!Roo.isTouch) {
18513             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18514         }
18515         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18516         // Event.on(this.id, "selectstart", Event.preventDefault);
18517     },
18518
18519     /**
18520      * Initializes Targeting functionality only... the object does not
18521      * get a mousedown handler.
18522      * @method initTarget
18523      * @param id the id of the linked element
18524      * @param {String} sGroup the group of related items
18525      * @param {object} config configuration attributes
18526      */
18527     initTarget: function(id, sGroup, config) {
18528
18529         // configuration attributes
18530         this.config = config || {};
18531
18532         // create a local reference to the drag and drop manager
18533         this.DDM = Roo.dd.DDM;
18534         // initialize the groups array
18535         this.groups = {};
18536
18537         // assume that we have an element reference instead of an id if the
18538         // parameter is not a string
18539         if (typeof id !== "string") {
18540             id = Roo.id(id);
18541         }
18542
18543         // set the id
18544         this.id = id;
18545
18546         // add to an interaction group
18547         this.addToGroup((sGroup) ? sGroup : "default");
18548
18549         // We don't want to register this as the handle with the manager
18550         // so we just set the id rather than calling the setter.
18551         this.handleElId = id;
18552
18553         // the linked element is the element that gets dragged by default
18554         this.setDragElId(id);
18555
18556         // by default, clicked anchors will not start drag operations.
18557         this.invalidHandleTypes = { A: "A" };
18558         this.invalidHandleIds = {};
18559         this.invalidHandleClasses = [];
18560
18561         this.applyConfig();
18562
18563         this.handleOnAvailable();
18564     },
18565
18566     /**
18567      * Applies the configuration parameters that were passed into the constructor.
18568      * This is supposed to happen at each level through the inheritance chain.  So
18569      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18570      * DragDrop in order to get all of the parameters that are available in
18571      * each object.
18572      * @method applyConfig
18573      */
18574     applyConfig: function() {
18575
18576         // configurable properties:
18577         //    padding, isTarget, maintainOffset, primaryButtonOnly
18578         this.padding           = this.config.padding || [0, 0, 0, 0];
18579         this.isTarget          = (this.config.isTarget !== false);
18580         this.maintainOffset    = (this.config.maintainOffset);
18581         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18582
18583     },
18584
18585     /**
18586      * Executed when the linked element is available
18587      * @method handleOnAvailable
18588      * @private
18589      */
18590     handleOnAvailable: function() {
18591         this.available = true;
18592         this.resetConstraints();
18593         this.onAvailable();
18594     },
18595
18596      /**
18597      * Configures the padding for the target zone in px.  Effectively expands
18598      * (or reduces) the virtual object size for targeting calculations.
18599      * Supports css-style shorthand; if only one parameter is passed, all sides
18600      * will have that padding, and if only two are passed, the top and bottom
18601      * will have the first param, the left and right the second.
18602      * @method setPadding
18603      * @param {int} iTop    Top pad
18604      * @param {int} iRight  Right pad
18605      * @param {int} iBot    Bot pad
18606      * @param {int} iLeft   Left pad
18607      */
18608     setPadding: function(iTop, iRight, iBot, iLeft) {
18609         // this.padding = [iLeft, iRight, iTop, iBot];
18610         if (!iRight && 0 !== iRight) {
18611             this.padding = [iTop, iTop, iTop, iTop];
18612         } else if (!iBot && 0 !== iBot) {
18613             this.padding = [iTop, iRight, iTop, iRight];
18614         } else {
18615             this.padding = [iTop, iRight, iBot, iLeft];
18616         }
18617     },
18618
18619     /**
18620      * Stores the initial placement of the linked element.
18621      * @method setInitialPosition
18622      * @param {int} diffX   the X offset, default 0
18623      * @param {int} diffY   the Y offset, default 0
18624      */
18625     setInitPosition: function(diffX, diffY) {
18626         var el = this.getEl();
18627
18628         if (!this.DDM.verifyEl(el)) {
18629             return;
18630         }
18631
18632         var dx = diffX || 0;
18633         var dy = diffY || 0;
18634
18635         var p = Dom.getXY( el );
18636
18637         this.initPageX = p[0] - dx;
18638         this.initPageY = p[1] - dy;
18639
18640         this.lastPageX = p[0];
18641         this.lastPageY = p[1];
18642
18643
18644         this.setStartPosition(p);
18645     },
18646
18647     /**
18648      * Sets the start position of the element.  This is set when the obj
18649      * is initialized, the reset when a drag is started.
18650      * @method setStartPosition
18651      * @param pos current position (from previous lookup)
18652      * @private
18653      */
18654     setStartPosition: function(pos) {
18655         var p = pos || Dom.getXY( this.getEl() );
18656         this.deltaSetXY = null;
18657
18658         this.startPageX = p[0];
18659         this.startPageY = p[1];
18660     },
18661
18662     /**
18663      * Add this instance to a group of related drag/drop objects.  All
18664      * instances belong to at least one group, and can belong to as many
18665      * groups as needed.
18666      * @method addToGroup
18667      * @param sGroup {string} the name of the group
18668      */
18669     addToGroup: function(sGroup) {
18670         this.groups[sGroup] = true;
18671         this.DDM.regDragDrop(this, sGroup);
18672     },
18673
18674     /**
18675      * Remove's this instance from the supplied interaction group
18676      * @method removeFromGroup
18677      * @param {string}  sGroup  The group to drop
18678      */
18679     removeFromGroup: function(sGroup) {
18680         if (this.groups[sGroup]) {
18681             delete this.groups[sGroup];
18682         }
18683
18684         this.DDM.removeDDFromGroup(this, sGroup);
18685     },
18686
18687     /**
18688      * Allows you to specify that an element other than the linked element
18689      * will be moved with the cursor during a drag
18690      * @method setDragElId
18691      * @param id {string} the id of the element that will be used to initiate the drag
18692      */
18693     setDragElId: function(id) {
18694         this.dragElId = id;
18695     },
18696
18697     /**
18698      * Allows you to specify a child of the linked element that should be
18699      * used to initiate the drag operation.  An example of this would be if
18700      * you have a content div with text and links.  Clicking anywhere in the
18701      * content area would normally start the drag operation.  Use this method
18702      * to specify that an element inside of the content div is the element
18703      * that starts the drag operation.
18704      * @method setHandleElId
18705      * @param id {string} the id of the element that will be used to
18706      * initiate the drag.
18707      */
18708     setHandleElId: function(id) {
18709         if (typeof id !== "string") {
18710             id = Roo.id(id);
18711         }
18712         this.handleElId = id;
18713         this.DDM.regHandle(this.id, id);
18714     },
18715
18716     /**
18717      * Allows you to set an element outside of the linked element as a drag
18718      * handle
18719      * @method setOuterHandleElId
18720      * @param id the id of the element that will be used to initiate the drag
18721      */
18722     setOuterHandleElId: function(id) {
18723         if (typeof id !== "string") {
18724             id = Roo.id(id);
18725         }
18726         Event.on(id, "mousedown",
18727                 this.handleMouseDown, this);
18728         this.setHandleElId(id);
18729
18730         this.hasOuterHandles = true;
18731     },
18732
18733     /**
18734      * Remove all drag and drop hooks for this element
18735      * @method unreg
18736      */
18737     unreg: function() {
18738         Event.un(this.id, "mousedown",
18739                 this.handleMouseDown);
18740         Event.un(this.id, "touchstart",
18741                 this.handleMouseDown);
18742         this._domRef = null;
18743         this.DDM._remove(this);
18744     },
18745
18746     destroy : function(){
18747         this.unreg();
18748     },
18749
18750     /**
18751      * Returns true if this instance is locked, or the drag drop mgr is locked
18752      * (meaning that all drag/drop is disabled on the page.)
18753      * @method isLocked
18754      * @return {boolean} true if this obj or all drag/drop is locked, else
18755      * false
18756      */
18757     isLocked: function() {
18758         return (this.DDM.isLocked() || this.locked);
18759     },
18760
18761     /**
18762      * Fired when this object is clicked
18763      * @method handleMouseDown
18764      * @param {Event} e
18765      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18766      * @private
18767      */
18768     handleMouseDown: function(e, oDD){
18769      
18770         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18771             //Roo.log('not touch/ button !=0');
18772             return;
18773         }
18774         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18775             return; // double touch..
18776         }
18777         
18778
18779         if (this.isLocked()) {
18780             //Roo.log('locked');
18781             return;
18782         }
18783
18784         this.DDM.refreshCache(this.groups);
18785 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18786         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18787         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18788             //Roo.log('no outer handes or not over target');
18789                 // do nothing.
18790         } else {
18791 //            Roo.log('check validator');
18792             if (this.clickValidator(e)) {
18793 //                Roo.log('validate success');
18794                 // set the initial element position
18795                 this.setStartPosition();
18796
18797
18798                 this.b4MouseDown(e);
18799                 this.onMouseDown(e);
18800
18801                 this.DDM.handleMouseDown(e, this);
18802
18803                 this.DDM.stopEvent(e);
18804             } else {
18805
18806
18807             }
18808         }
18809     },
18810
18811     clickValidator: function(e) {
18812         var target = e.getTarget();
18813         return ( this.isValidHandleChild(target) &&
18814                     (this.id == this.handleElId ||
18815                         this.DDM.handleWasClicked(target, this.id)) );
18816     },
18817
18818     /**
18819      * Allows you to specify a tag name that should not start a drag operation
18820      * when clicked.  This is designed to facilitate embedding links within a
18821      * drag handle that do something other than start the drag.
18822      * @method addInvalidHandleType
18823      * @param {string} tagName the type of element to exclude
18824      */
18825     addInvalidHandleType: function(tagName) {
18826         var type = tagName.toUpperCase();
18827         this.invalidHandleTypes[type] = type;
18828     },
18829
18830     /**
18831      * Lets you to specify an element id for a child of a drag handle
18832      * that should not initiate a drag
18833      * @method addInvalidHandleId
18834      * @param {string} id the element id of the element you wish to ignore
18835      */
18836     addInvalidHandleId: function(id) {
18837         if (typeof id !== "string") {
18838             id = Roo.id(id);
18839         }
18840         this.invalidHandleIds[id] = id;
18841     },
18842
18843     /**
18844      * Lets you specify a css class of elements that will not initiate a drag
18845      * @method addInvalidHandleClass
18846      * @param {string} cssClass the class of the elements you wish to ignore
18847      */
18848     addInvalidHandleClass: function(cssClass) {
18849         this.invalidHandleClasses.push(cssClass);
18850     },
18851
18852     /**
18853      * Unsets an excluded tag name set by addInvalidHandleType
18854      * @method removeInvalidHandleType
18855      * @param {string} tagName the type of element to unexclude
18856      */
18857     removeInvalidHandleType: function(tagName) {
18858         var type = tagName.toUpperCase();
18859         // this.invalidHandleTypes[type] = null;
18860         delete this.invalidHandleTypes[type];
18861     },
18862
18863     /**
18864      * Unsets an invalid handle id
18865      * @method removeInvalidHandleId
18866      * @param {string} id the id of the element to re-enable
18867      */
18868     removeInvalidHandleId: function(id) {
18869         if (typeof id !== "string") {
18870             id = Roo.id(id);
18871         }
18872         delete this.invalidHandleIds[id];
18873     },
18874
18875     /**
18876      * Unsets an invalid css class
18877      * @method removeInvalidHandleClass
18878      * @param {string} cssClass the class of the element(s) you wish to
18879      * re-enable
18880      */
18881     removeInvalidHandleClass: function(cssClass) {
18882         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18883             if (this.invalidHandleClasses[i] == cssClass) {
18884                 delete this.invalidHandleClasses[i];
18885             }
18886         }
18887     },
18888
18889     /**
18890      * Checks the tag exclusion list to see if this click should be ignored
18891      * @method isValidHandleChild
18892      * @param {HTMLElement} node the HTMLElement to evaluate
18893      * @return {boolean} true if this is a valid tag type, false if not
18894      */
18895     isValidHandleChild: function(node) {
18896
18897         var valid = true;
18898         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18899         var nodeName;
18900         try {
18901             nodeName = node.nodeName.toUpperCase();
18902         } catch(e) {
18903             nodeName = node.nodeName;
18904         }
18905         valid = valid && !this.invalidHandleTypes[nodeName];
18906         valid = valid && !this.invalidHandleIds[node.id];
18907
18908         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18909             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18910         }
18911
18912
18913         return valid;
18914
18915     },
18916
18917     /**
18918      * Create the array of horizontal tick marks if an interval was specified
18919      * in setXConstraint().
18920      * @method setXTicks
18921      * @private
18922      */
18923     setXTicks: function(iStartX, iTickSize) {
18924         this.xTicks = [];
18925         this.xTickSize = iTickSize;
18926
18927         var tickMap = {};
18928
18929         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18930             if (!tickMap[i]) {
18931                 this.xTicks[this.xTicks.length] = i;
18932                 tickMap[i] = true;
18933             }
18934         }
18935
18936         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18937             if (!tickMap[i]) {
18938                 this.xTicks[this.xTicks.length] = i;
18939                 tickMap[i] = true;
18940             }
18941         }
18942
18943         this.xTicks.sort(this.DDM.numericSort) ;
18944     },
18945
18946     /**
18947      * Create the array of vertical tick marks if an interval was specified in
18948      * setYConstraint().
18949      * @method setYTicks
18950      * @private
18951      */
18952     setYTicks: function(iStartY, iTickSize) {
18953         this.yTicks = [];
18954         this.yTickSize = iTickSize;
18955
18956         var tickMap = {};
18957
18958         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18959             if (!tickMap[i]) {
18960                 this.yTicks[this.yTicks.length] = i;
18961                 tickMap[i] = true;
18962             }
18963         }
18964
18965         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18966             if (!tickMap[i]) {
18967                 this.yTicks[this.yTicks.length] = i;
18968                 tickMap[i] = true;
18969             }
18970         }
18971
18972         this.yTicks.sort(this.DDM.numericSort) ;
18973     },
18974
18975     /**
18976      * By default, the element can be dragged any place on the screen.  Use
18977      * this method to limit the horizontal travel of the element.  Pass in
18978      * 0,0 for the parameters if you want to lock the drag to the y axis.
18979      * @method setXConstraint
18980      * @param {int} iLeft the number of pixels the element can move to the left
18981      * @param {int} iRight the number of pixels the element can move to the
18982      * right
18983      * @param {int} iTickSize optional parameter for specifying that the
18984      * element
18985      * should move iTickSize pixels at a time.
18986      */
18987     setXConstraint: function(iLeft, iRight, iTickSize) {
18988         this.leftConstraint = iLeft;
18989         this.rightConstraint = iRight;
18990
18991         this.minX = this.initPageX - iLeft;
18992         this.maxX = this.initPageX + iRight;
18993         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18994
18995         this.constrainX = true;
18996     },
18997
18998     /**
18999      * Clears any constraints applied to this instance.  Also clears ticks
19000      * since they can't exist independent of a constraint at this time.
19001      * @method clearConstraints
19002      */
19003     clearConstraints: function() {
19004         this.constrainX = false;
19005         this.constrainY = false;
19006         this.clearTicks();
19007     },
19008
19009     /**
19010      * Clears any tick interval defined for this instance
19011      * @method clearTicks
19012      */
19013     clearTicks: function() {
19014         this.xTicks = null;
19015         this.yTicks = null;
19016         this.xTickSize = 0;
19017         this.yTickSize = 0;
19018     },
19019
19020     /**
19021      * By default, the element can be dragged any place on the screen.  Set
19022      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19023      * parameters if you want to lock the drag to the x axis.
19024      * @method setYConstraint
19025      * @param {int} iUp the number of pixels the element can move up
19026      * @param {int} iDown the number of pixels the element can move down
19027      * @param {int} iTickSize optional parameter for specifying that the
19028      * element should move iTickSize pixels at a time.
19029      */
19030     setYConstraint: function(iUp, iDown, iTickSize) {
19031         this.topConstraint = iUp;
19032         this.bottomConstraint = iDown;
19033
19034         this.minY = this.initPageY - iUp;
19035         this.maxY = this.initPageY + iDown;
19036         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19037
19038         this.constrainY = true;
19039
19040     },
19041
19042     /**
19043      * resetConstraints must be called if you manually reposition a dd element.
19044      * @method resetConstraints
19045      * @param {boolean} maintainOffset
19046      */
19047     resetConstraints: function() {
19048
19049
19050         // Maintain offsets if necessary
19051         if (this.initPageX || this.initPageX === 0) {
19052             // figure out how much this thing has moved
19053             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19054             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19055
19056             this.setInitPosition(dx, dy);
19057
19058         // This is the first time we have detected the element's position
19059         } else {
19060             this.setInitPosition();
19061         }
19062
19063         if (this.constrainX) {
19064             this.setXConstraint( this.leftConstraint,
19065                                  this.rightConstraint,
19066                                  this.xTickSize        );
19067         }
19068
19069         if (this.constrainY) {
19070             this.setYConstraint( this.topConstraint,
19071                                  this.bottomConstraint,
19072                                  this.yTickSize         );
19073         }
19074     },
19075
19076     /**
19077      * Normally the drag element is moved pixel by pixel, but we can specify
19078      * that it move a number of pixels at a time.  This method resolves the
19079      * location when we have it set up like this.
19080      * @method getTick
19081      * @param {int} val where we want to place the object
19082      * @param {int[]} tickArray sorted array of valid points
19083      * @return {int} the closest tick
19084      * @private
19085      */
19086     getTick: function(val, tickArray) {
19087
19088         if (!tickArray) {
19089             // If tick interval is not defined, it is effectively 1 pixel,
19090             // so we return the value passed to us.
19091             return val;
19092         } else if (tickArray[0] >= val) {
19093             // The value is lower than the first tick, so we return the first
19094             // tick.
19095             return tickArray[0];
19096         } else {
19097             for (var i=0, len=tickArray.length; i<len; ++i) {
19098                 var next = i + 1;
19099                 if (tickArray[next] && tickArray[next] >= val) {
19100                     var diff1 = val - tickArray[i];
19101                     var diff2 = tickArray[next] - val;
19102                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19103                 }
19104             }
19105
19106             // The value is larger than the last tick, so we return the last
19107             // tick.
19108             return tickArray[tickArray.length - 1];
19109         }
19110     },
19111
19112     /**
19113      * toString method
19114      * @method toString
19115      * @return {string} string representation of the dd obj
19116      */
19117     toString: function() {
19118         return ("DragDrop " + this.id);
19119     }
19120
19121 });
19122
19123 })();
19124 /*
19125  * Based on:
19126  * Ext JS Library 1.1.1
19127  * Copyright(c) 2006-2007, Ext JS, LLC.
19128  *
19129  * Originally Released Under LGPL - original licence link has changed is not relivant.
19130  *
19131  * Fork - LGPL
19132  * <script type="text/javascript">
19133  */
19134
19135
19136 /**
19137  * The drag and drop utility provides a framework for building drag and drop
19138  * applications.  In addition to enabling drag and drop for specific elements,
19139  * the drag and drop elements are tracked by the manager class, and the
19140  * interactions between the various elements are tracked during the drag and
19141  * the implementing code is notified about these important moments.
19142  */
19143
19144 // Only load the library once.  Rewriting the manager class would orphan
19145 // existing drag and drop instances.
19146 if (!Roo.dd.DragDropMgr) {
19147
19148 /**
19149  * @class Roo.dd.DragDropMgr
19150  * DragDropMgr is a singleton that tracks the element interaction for
19151  * all DragDrop items in the window.  Generally, you will not call
19152  * this class directly, but it does have helper methods that could
19153  * be useful in your DragDrop implementations.
19154  * @singleton
19155  */
19156 Roo.dd.DragDropMgr = function() {
19157
19158     var Event = Roo.EventManager;
19159
19160     return {
19161
19162         /**
19163          * Two dimensional Array of registered DragDrop objects.  The first
19164          * dimension is the DragDrop item group, the second the DragDrop
19165          * object.
19166          * @property ids
19167          * @type {string: string}
19168          * @private
19169          * @static
19170          */
19171         ids: {},
19172
19173         /**
19174          * Array of element ids defined as drag handles.  Used to determine
19175          * if the element that generated the mousedown event is actually the
19176          * handle and not the html element itself.
19177          * @property handleIds
19178          * @type {string: string}
19179          * @private
19180          * @static
19181          */
19182         handleIds: {},
19183
19184         /**
19185          * the DragDrop object that is currently being dragged
19186          * @property dragCurrent
19187          * @type DragDrop
19188          * @private
19189          * @static
19190          **/
19191         dragCurrent: null,
19192
19193         /**
19194          * the DragDrop object(s) that are being hovered over
19195          * @property dragOvers
19196          * @type Array
19197          * @private
19198          * @static
19199          */
19200         dragOvers: {},
19201
19202         /**
19203          * the X distance between the cursor and the object being dragged
19204          * @property deltaX
19205          * @type int
19206          * @private
19207          * @static
19208          */
19209         deltaX: 0,
19210
19211         /**
19212          * the Y distance between the cursor and the object being dragged
19213          * @property deltaY
19214          * @type int
19215          * @private
19216          * @static
19217          */
19218         deltaY: 0,
19219
19220         /**
19221          * Flag to determine if we should prevent the default behavior of the
19222          * events we define. By default this is true, but this can be set to
19223          * false if you need the default behavior (not recommended)
19224          * @property preventDefault
19225          * @type boolean
19226          * @static
19227          */
19228         preventDefault: true,
19229
19230         /**
19231          * Flag to determine if we should stop the propagation of the events
19232          * we generate. This is true by default but you may want to set it to
19233          * false if the html element contains other features that require the
19234          * mouse click.
19235          * @property stopPropagation
19236          * @type boolean
19237          * @static
19238          */
19239         stopPropagation: true,
19240
19241         /**
19242          * Internal flag that is set to true when drag and drop has been
19243          * intialized
19244          * @property initialized
19245          * @private
19246          * @static
19247          */
19248         initalized: false,
19249
19250         /**
19251          * All drag and drop can be disabled.
19252          * @property locked
19253          * @private
19254          * @static
19255          */
19256         locked: false,
19257
19258         /**
19259          * Called the first time an element is registered.
19260          * @method init
19261          * @private
19262          * @static
19263          */
19264         init: function() {
19265             this.initialized = true;
19266         },
19267
19268         /**
19269          * In point mode, drag and drop interaction is defined by the
19270          * location of the cursor during the drag/drop
19271          * @property POINT
19272          * @type int
19273          * @static
19274          */
19275         POINT: 0,
19276
19277         /**
19278          * In intersect mode, drag and drop interactio nis defined by the
19279          * overlap of two or more drag and drop objects.
19280          * @property INTERSECT
19281          * @type int
19282          * @static
19283          */
19284         INTERSECT: 1,
19285
19286         /**
19287          * The current drag and drop mode.  Default: POINT
19288          * @property mode
19289          * @type int
19290          * @static
19291          */
19292         mode: 0,
19293
19294         /**
19295          * Runs method on all drag and drop objects
19296          * @method _execOnAll
19297          * @private
19298          * @static
19299          */
19300         _execOnAll: function(sMethod, args) {
19301             for (var i in this.ids) {
19302                 for (var j in this.ids[i]) {
19303                     var oDD = this.ids[i][j];
19304                     if (! this.isTypeOfDD(oDD)) {
19305                         continue;
19306                     }
19307                     oDD[sMethod].apply(oDD, args);
19308                 }
19309             }
19310         },
19311
19312         /**
19313          * Drag and drop initialization.  Sets up the global event handlers
19314          * @method _onLoad
19315          * @private
19316          * @static
19317          */
19318         _onLoad: function() {
19319
19320             this.init();
19321
19322             if (!Roo.isTouch) {
19323                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19324                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19325             }
19326             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19327             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19328             
19329             Event.on(window,   "unload",    this._onUnload, this, true);
19330             Event.on(window,   "resize",    this._onResize, this, true);
19331             // Event.on(window,   "mouseout",    this._test);
19332
19333         },
19334
19335         /**
19336          * Reset constraints on all drag and drop objs
19337          * @method _onResize
19338          * @private
19339          * @static
19340          */
19341         _onResize: function(e) {
19342             this._execOnAll("resetConstraints", []);
19343         },
19344
19345         /**
19346          * Lock all drag and drop functionality
19347          * @method lock
19348          * @static
19349          */
19350         lock: function() { this.locked = true; },
19351
19352         /**
19353          * Unlock all drag and drop functionality
19354          * @method unlock
19355          * @static
19356          */
19357         unlock: function() { this.locked = false; },
19358
19359         /**
19360          * Is drag and drop locked?
19361          * @method isLocked
19362          * @return {boolean} True if drag and drop is locked, false otherwise.
19363          * @static
19364          */
19365         isLocked: function() { return this.locked; },
19366
19367         /**
19368          * Location cache that is set for all drag drop objects when a drag is
19369          * initiated, cleared when the drag is finished.
19370          * @property locationCache
19371          * @private
19372          * @static
19373          */
19374         locationCache: {},
19375
19376         /**
19377          * Set useCache to false if you want to force object the lookup of each
19378          * drag and drop linked element constantly during a drag.
19379          * @property useCache
19380          * @type boolean
19381          * @static
19382          */
19383         useCache: true,
19384
19385         /**
19386          * The number of pixels that the mouse needs to move after the
19387          * mousedown before the drag is initiated.  Default=3;
19388          * @property clickPixelThresh
19389          * @type int
19390          * @static
19391          */
19392         clickPixelThresh: 3,
19393
19394         /**
19395          * The number of milliseconds after the mousedown event to initiate the
19396          * drag if we don't get a mouseup event. Default=1000
19397          * @property clickTimeThresh
19398          * @type int
19399          * @static
19400          */
19401         clickTimeThresh: 350,
19402
19403         /**
19404          * Flag that indicates that either the drag pixel threshold or the
19405          * mousdown time threshold has been met
19406          * @property dragThreshMet
19407          * @type boolean
19408          * @private
19409          * @static
19410          */
19411         dragThreshMet: false,
19412
19413         /**
19414          * Timeout used for the click time threshold
19415          * @property clickTimeout
19416          * @type Object
19417          * @private
19418          * @static
19419          */
19420         clickTimeout: null,
19421
19422         /**
19423          * The X position of the mousedown event stored for later use when a
19424          * drag threshold is met.
19425          * @property startX
19426          * @type int
19427          * @private
19428          * @static
19429          */
19430         startX: 0,
19431
19432         /**
19433          * The Y position of the mousedown event stored for later use when a
19434          * drag threshold is met.
19435          * @property startY
19436          * @type int
19437          * @private
19438          * @static
19439          */
19440         startY: 0,
19441
19442         /**
19443          * Each DragDrop instance must be registered with the DragDropMgr.
19444          * This is executed in DragDrop.init()
19445          * @method regDragDrop
19446          * @param {DragDrop} oDD the DragDrop object to register
19447          * @param {String} sGroup the name of the group this element belongs to
19448          * @static
19449          */
19450         regDragDrop: function(oDD, sGroup) {
19451             if (!this.initialized) { this.init(); }
19452
19453             if (!this.ids[sGroup]) {
19454                 this.ids[sGroup] = {};
19455             }
19456             this.ids[sGroup][oDD.id] = oDD;
19457         },
19458
19459         /**
19460          * Removes the supplied dd instance from the supplied group. Executed
19461          * by DragDrop.removeFromGroup, so don't call this function directly.
19462          * @method removeDDFromGroup
19463          * @private
19464          * @static
19465          */
19466         removeDDFromGroup: function(oDD, sGroup) {
19467             if (!this.ids[sGroup]) {
19468                 this.ids[sGroup] = {};
19469             }
19470
19471             var obj = this.ids[sGroup];
19472             if (obj && obj[oDD.id]) {
19473                 delete obj[oDD.id];
19474             }
19475         },
19476
19477         /**
19478          * Unregisters a drag and drop item.  This is executed in
19479          * DragDrop.unreg, use that method instead of calling this directly.
19480          * @method _remove
19481          * @private
19482          * @static
19483          */
19484         _remove: function(oDD) {
19485             for (var g in oDD.groups) {
19486                 if (g && this.ids[g][oDD.id]) {
19487                     delete this.ids[g][oDD.id];
19488                 }
19489             }
19490             delete this.handleIds[oDD.id];
19491         },
19492
19493         /**
19494          * Each DragDrop handle element must be registered.  This is done
19495          * automatically when executing DragDrop.setHandleElId()
19496          * @method regHandle
19497          * @param {String} sDDId the DragDrop id this element is a handle for
19498          * @param {String} sHandleId the id of the element that is the drag
19499          * handle
19500          * @static
19501          */
19502         regHandle: function(sDDId, sHandleId) {
19503             if (!this.handleIds[sDDId]) {
19504                 this.handleIds[sDDId] = {};
19505             }
19506             this.handleIds[sDDId][sHandleId] = sHandleId;
19507         },
19508
19509         /**
19510          * Utility function to determine if a given element has been
19511          * registered as a drag drop item.
19512          * @method isDragDrop
19513          * @param {String} id the element id to check
19514          * @return {boolean} true if this element is a DragDrop item,
19515          * false otherwise
19516          * @static
19517          */
19518         isDragDrop: function(id) {
19519             return ( this.getDDById(id) ) ? true : false;
19520         },
19521
19522         /**
19523          * Returns the drag and drop instances that are in all groups the
19524          * passed in instance belongs to.
19525          * @method getRelated
19526          * @param {DragDrop} p_oDD the obj to get related data for
19527          * @param {boolean} bTargetsOnly if true, only return targetable objs
19528          * @return {DragDrop[]} the related instances
19529          * @static
19530          */
19531         getRelated: function(p_oDD, bTargetsOnly) {
19532             var oDDs = [];
19533             for (var i in p_oDD.groups) {
19534                 for (j in this.ids[i]) {
19535                     var dd = this.ids[i][j];
19536                     if (! this.isTypeOfDD(dd)) {
19537                         continue;
19538                     }
19539                     if (!bTargetsOnly || dd.isTarget) {
19540                         oDDs[oDDs.length] = dd;
19541                     }
19542                 }
19543             }
19544
19545             return oDDs;
19546         },
19547
19548         /**
19549          * Returns true if the specified dd target is a legal target for
19550          * the specifice drag obj
19551          * @method isLegalTarget
19552          * @param {DragDrop} the drag obj
19553          * @param {DragDrop} the target
19554          * @return {boolean} true if the target is a legal target for the
19555          * dd obj
19556          * @static
19557          */
19558         isLegalTarget: function (oDD, oTargetDD) {
19559             var targets = this.getRelated(oDD, true);
19560             for (var i=0, len=targets.length;i<len;++i) {
19561                 if (targets[i].id == oTargetDD.id) {
19562                     return true;
19563                 }
19564             }
19565
19566             return false;
19567         },
19568
19569         /**
19570          * My goal is to be able to transparently determine if an object is
19571          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19572          * returns "object", oDD.constructor.toString() always returns
19573          * "DragDrop" and not the name of the subclass.  So for now it just
19574          * evaluates a well-known variable in DragDrop.
19575          * @method isTypeOfDD
19576          * @param {Object} the object to evaluate
19577          * @return {boolean} true if typeof oDD = DragDrop
19578          * @static
19579          */
19580         isTypeOfDD: function (oDD) {
19581             return (oDD && oDD.__ygDragDrop);
19582         },
19583
19584         /**
19585          * Utility function to determine if a given element has been
19586          * registered as a drag drop handle for the given Drag Drop object.
19587          * @method isHandle
19588          * @param {String} id the element id to check
19589          * @return {boolean} true if this element is a DragDrop handle, false
19590          * otherwise
19591          * @static
19592          */
19593         isHandle: function(sDDId, sHandleId) {
19594             return ( this.handleIds[sDDId] &&
19595                             this.handleIds[sDDId][sHandleId] );
19596         },
19597
19598         /**
19599          * Returns the DragDrop instance for a given id
19600          * @method getDDById
19601          * @param {String} id the id of the DragDrop object
19602          * @return {DragDrop} the drag drop object, null if it is not found
19603          * @static
19604          */
19605         getDDById: function(id) {
19606             for (var i in this.ids) {
19607                 if (this.ids[i][id]) {
19608                     return this.ids[i][id];
19609                 }
19610             }
19611             return null;
19612         },
19613
19614         /**
19615          * Fired after a registered DragDrop object gets the mousedown event.
19616          * Sets up the events required to track the object being dragged
19617          * @method handleMouseDown
19618          * @param {Event} e the event
19619          * @param oDD the DragDrop object being dragged
19620          * @private
19621          * @static
19622          */
19623         handleMouseDown: function(e, oDD) {
19624             if(Roo.QuickTips){
19625                 Roo.QuickTips.disable();
19626             }
19627             this.currentTarget = e.getTarget();
19628
19629             this.dragCurrent = oDD;
19630
19631             var el = oDD.getEl();
19632
19633             // track start position
19634             this.startX = e.getPageX();
19635             this.startY = e.getPageY();
19636
19637             this.deltaX = this.startX - el.offsetLeft;
19638             this.deltaY = this.startY - el.offsetTop;
19639
19640             this.dragThreshMet = false;
19641
19642             this.clickTimeout = setTimeout(
19643                     function() {
19644                         var DDM = Roo.dd.DDM;
19645                         DDM.startDrag(DDM.startX, DDM.startY);
19646                     },
19647                     this.clickTimeThresh );
19648         },
19649
19650         /**
19651          * Fired when either the drag pixel threshol or the mousedown hold
19652          * time threshold has been met.
19653          * @method startDrag
19654          * @param x {int} the X position of the original mousedown
19655          * @param y {int} the Y position of the original mousedown
19656          * @static
19657          */
19658         startDrag: function(x, y) {
19659             clearTimeout(this.clickTimeout);
19660             if (this.dragCurrent) {
19661                 this.dragCurrent.b4StartDrag(x, y);
19662                 this.dragCurrent.startDrag(x, y);
19663             }
19664             this.dragThreshMet = true;
19665         },
19666
19667         /**
19668          * Internal function to handle the mouseup event.  Will be invoked
19669          * from the context of the document.
19670          * @method handleMouseUp
19671          * @param {Event} e the event
19672          * @private
19673          * @static
19674          */
19675         handleMouseUp: function(e) {
19676
19677             if(Roo.QuickTips){
19678                 Roo.QuickTips.enable();
19679             }
19680             if (! this.dragCurrent) {
19681                 return;
19682             }
19683
19684             clearTimeout(this.clickTimeout);
19685
19686             if (this.dragThreshMet) {
19687                 this.fireEvents(e, true);
19688             } else {
19689             }
19690
19691             this.stopDrag(e);
19692
19693             this.stopEvent(e);
19694         },
19695
19696         /**
19697          * Utility to stop event propagation and event default, if these
19698          * features are turned on.
19699          * @method stopEvent
19700          * @param {Event} e the event as returned by this.getEvent()
19701          * @static
19702          */
19703         stopEvent: function(e){
19704             if(this.stopPropagation) {
19705                 e.stopPropagation();
19706             }
19707
19708             if (this.preventDefault) {
19709                 e.preventDefault();
19710             }
19711         },
19712
19713         /**
19714          * Internal function to clean up event handlers after the drag
19715          * operation is complete
19716          * @method stopDrag
19717          * @param {Event} e the event
19718          * @private
19719          * @static
19720          */
19721         stopDrag: function(e) {
19722             // Fire the drag end event for the item that was dragged
19723             if (this.dragCurrent) {
19724                 if (this.dragThreshMet) {
19725                     this.dragCurrent.b4EndDrag(e);
19726                     this.dragCurrent.endDrag(e);
19727                 }
19728
19729                 this.dragCurrent.onMouseUp(e);
19730             }
19731
19732             this.dragCurrent = null;
19733             this.dragOvers = {};
19734         },
19735
19736         /**
19737          * Internal function to handle the mousemove event.  Will be invoked
19738          * from the context of the html element.
19739          *
19740          * @TODO figure out what we can do about mouse events lost when the
19741          * user drags objects beyond the window boundary.  Currently we can
19742          * detect this in internet explorer by verifying that the mouse is
19743          * down during the mousemove event.  Firefox doesn't give us the
19744          * button state on the mousemove event.
19745          * @method handleMouseMove
19746          * @param {Event} e the event
19747          * @private
19748          * @static
19749          */
19750         handleMouseMove: function(e) {
19751             if (! this.dragCurrent) {
19752                 return true;
19753             }
19754
19755             // var button = e.which || e.button;
19756
19757             // check for IE mouseup outside of page boundary
19758             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19759                 this.stopEvent(e);
19760                 return this.handleMouseUp(e);
19761             }
19762
19763             if (!this.dragThreshMet) {
19764                 var diffX = Math.abs(this.startX - e.getPageX());
19765                 var diffY = Math.abs(this.startY - e.getPageY());
19766                 if (diffX > this.clickPixelThresh ||
19767                             diffY > this.clickPixelThresh) {
19768                     this.startDrag(this.startX, this.startY);
19769                 }
19770             }
19771
19772             if (this.dragThreshMet) {
19773                 this.dragCurrent.b4Drag(e);
19774                 this.dragCurrent.onDrag(e);
19775                 if(!this.dragCurrent.moveOnly){
19776                     this.fireEvents(e, false);
19777                 }
19778             }
19779
19780             this.stopEvent(e);
19781
19782             return true;
19783         },
19784
19785         /**
19786          * Iterates over all of the DragDrop elements to find ones we are
19787          * hovering over or dropping on
19788          * @method fireEvents
19789          * @param {Event} e the event
19790          * @param {boolean} isDrop is this a drop op or a mouseover op?
19791          * @private
19792          * @static
19793          */
19794         fireEvents: function(e, isDrop) {
19795             var dc = this.dragCurrent;
19796
19797             // If the user did the mouse up outside of the window, we could
19798             // get here even though we have ended the drag.
19799             if (!dc || dc.isLocked()) {
19800                 return;
19801             }
19802
19803             var pt = e.getPoint();
19804
19805             // cache the previous dragOver array
19806             var oldOvers = [];
19807
19808             var outEvts   = [];
19809             var overEvts  = [];
19810             var dropEvts  = [];
19811             var enterEvts = [];
19812
19813             // Check to see if the object(s) we were hovering over is no longer
19814             // being hovered over so we can fire the onDragOut event
19815             for (var i in this.dragOvers) {
19816
19817                 var ddo = this.dragOvers[i];
19818
19819                 if (! this.isTypeOfDD(ddo)) {
19820                     continue;
19821                 }
19822
19823                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19824                     outEvts.push( ddo );
19825                 }
19826
19827                 oldOvers[i] = true;
19828                 delete this.dragOvers[i];
19829             }
19830
19831             for (var sGroup in dc.groups) {
19832
19833                 if ("string" != typeof sGroup) {
19834                     continue;
19835                 }
19836
19837                 for (i in this.ids[sGroup]) {
19838                     var oDD = this.ids[sGroup][i];
19839                     if (! this.isTypeOfDD(oDD)) {
19840                         continue;
19841                     }
19842
19843                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19844                         if (this.isOverTarget(pt, oDD, this.mode)) {
19845                             // look for drop interactions
19846                             if (isDrop) {
19847                                 dropEvts.push( oDD );
19848                             // look for drag enter and drag over interactions
19849                             } else {
19850
19851                                 // initial drag over: dragEnter fires
19852                                 if (!oldOvers[oDD.id]) {
19853                                     enterEvts.push( oDD );
19854                                 // subsequent drag overs: dragOver fires
19855                                 } else {
19856                                     overEvts.push( oDD );
19857                                 }
19858
19859                                 this.dragOvers[oDD.id] = oDD;
19860                             }
19861                         }
19862                     }
19863                 }
19864             }
19865
19866             if (this.mode) {
19867                 if (outEvts.length) {
19868                     dc.b4DragOut(e, outEvts);
19869                     dc.onDragOut(e, outEvts);
19870                 }
19871
19872                 if (enterEvts.length) {
19873                     dc.onDragEnter(e, enterEvts);
19874                 }
19875
19876                 if (overEvts.length) {
19877                     dc.b4DragOver(e, overEvts);
19878                     dc.onDragOver(e, overEvts);
19879                 }
19880
19881                 if (dropEvts.length) {
19882                     dc.b4DragDrop(e, dropEvts);
19883                     dc.onDragDrop(e, dropEvts);
19884                 }
19885
19886             } else {
19887                 // fire dragout events
19888                 var len = 0;
19889                 for (i=0, len=outEvts.length; i<len; ++i) {
19890                     dc.b4DragOut(e, outEvts[i].id);
19891                     dc.onDragOut(e, outEvts[i].id);
19892                 }
19893
19894                 // fire enter events
19895                 for (i=0,len=enterEvts.length; i<len; ++i) {
19896                     // dc.b4DragEnter(e, oDD.id);
19897                     dc.onDragEnter(e, enterEvts[i].id);
19898                 }
19899
19900                 // fire over events
19901                 for (i=0,len=overEvts.length; i<len; ++i) {
19902                     dc.b4DragOver(e, overEvts[i].id);
19903                     dc.onDragOver(e, overEvts[i].id);
19904                 }
19905
19906                 // fire drop events
19907                 for (i=0, len=dropEvts.length; i<len; ++i) {
19908                     dc.b4DragDrop(e, dropEvts[i].id);
19909                     dc.onDragDrop(e, dropEvts[i].id);
19910                 }
19911
19912             }
19913
19914             // notify about a drop that did not find a target
19915             if (isDrop && !dropEvts.length) {
19916                 dc.onInvalidDrop(e);
19917             }
19918
19919         },
19920
19921         /**
19922          * Helper function for getting the best match from the list of drag
19923          * and drop objects returned by the drag and drop events when we are
19924          * in INTERSECT mode.  It returns either the first object that the
19925          * cursor is over, or the object that has the greatest overlap with
19926          * the dragged element.
19927          * @method getBestMatch
19928          * @param  {DragDrop[]} dds The array of drag and drop objects
19929          * targeted
19930          * @return {DragDrop}       The best single match
19931          * @static
19932          */
19933         getBestMatch: function(dds) {
19934             var winner = null;
19935             // Return null if the input is not what we expect
19936             //if (!dds || !dds.length || dds.length == 0) {
19937                // winner = null;
19938             // If there is only one item, it wins
19939             //} else if (dds.length == 1) {
19940
19941             var len = dds.length;
19942
19943             if (len == 1) {
19944                 winner = dds[0];
19945             } else {
19946                 // Loop through the targeted items
19947                 for (var i=0; i<len; ++i) {
19948                     var dd = dds[i];
19949                     // If the cursor is over the object, it wins.  If the
19950                     // cursor is over multiple matches, the first one we come
19951                     // to wins.
19952                     if (dd.cursorIsOver) {
19953                         winner = dd;
19954                         break;
19955                     // Otherwise the object with the most overlap wins
19956                     } else {
19957                         if (!winner ||
19958                             winner.overlap.getArea() < dd.overlap.getArea()) {
19959                             winner = dd;
19960                         }
19961                     }
19962                 }
19963             }
19964
19965             return winner;
19966         },
19967
19968         /**
19969          * Refreshes the cache of the top-left and bottom-right points of the
19970          * drag and drop objects in the specified group(s).  This is in the
19971          * format that is stored in the drag and drop instance, so typical
19972          * usage is:
19973          * <code>
19974          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19975          * </code>
19976          * Alternatively:
19977          * <code>
19978          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19979          * </code>
19980          * @TODO this really should be an indexed array.  Alternatively this
19981          * method could accept both.
19982          * @method refreshCache
19983          * @param {Object} groups an associative array of groups to refresh
19984          * @static
19985          */
19986         refreshCache: function(groups) {
19987             for (var sGroup in groups) {
19988                 if ("string" != typeof sGroup) {
19989                     continue;
19990                 }
19991                 for (var i in this.ids[sGroup]) {
19992                     var oDD = this.ids[sGroup][i];
19993
19994                     if (this.isTypeOfDD(oDD)) {
19995                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19996                         var loc = this.getLocation(oDD);
19997                         if (loc) {
19998                             this.locationCache[oDD.id] = loc;
19999                         } else {
20000                             delete this.locationCache[oDD.id];
20001                             // this will unregister the drag and drop object if
20002                             // the element is not in a usable state
20003                             // oDD.unreg();
20004                         }
20005                     }
20006                 }
20007             }
20008         },
20009
20010         /**
20011          * This checks to make sure an element exists and is in the DOM.  The
20012          * main purpose is to handle cases where innerHTML is used to remove
20013          * drag and drop objects from the DOM.  IE provides an 'unspecified
20014          * error' when trying to access the offsetParent of such an element
20015          * @method verifyEl
20016          * @param {HTMLElement} el the element to check
20017          * @return {boolean} true if the element looks usable
20018          * @static
20019          */
20020         verifyEl: function(el) {
20021             if (el) {
20022                 var parent;
20023                 if(Roo.isIE){
20024                     try{
20025                         parent = el.offsetParent;
20026                     }catch(e){}
20027                 }else{
20028                     parent = el.offsetParent;
20029                 }
20030                 if (parent) {
20031                     return true;
20032                 }
20033             }
20034
20035             return false;
20036         },
20037
20038         /**
20039          * Returns a Region object containing the drag and drop element's position
20040          * and size, including the padding configured for it
20041          * @method getLocation
20042          * @param {DragDrop} oDD the drag and drop object to get the
20043          *                       location for
20044          * @return {Roo.lib.Region} a Region object representing the total area
20045          *                             the element occupies, including any padding
20046          *                             the instance is configured for.
20047          * @static
20048          */
20049         getLocation: function(oDD) {
20050             if (! this.isTypeOfDD(oDD)) {
20051                 return null;
20052             }
20053
20054             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20055
20056             try {
20057                 pos= Roo.lib.Dom.getXY(el);
20058             } catch (e) { }
20059
20060             if (!pos) {
20061                 return null;
20062             }
20063
20064             x1 = pos[0];
20065             x2 = x1 + el.offsetWidth;
20066             y1 = pos[1];
20067             y2 = y1 + el.offsetHeight;
20068
20069             t = y1 - oDD.padding[0];
20070             r = x2 + oDD.padding[1];
20071             b = y2 + oDD.padding[2];
20072             l = x1 - oDD.padding[3];
20073
20074             return new Roo.lib.Region( t, r, b, l );
20075         },
20076
20077         /**
20078          * Checks the cursor location to see if it over the target
20079          * @method isOverTarget
20080          * @param {Roo.lib.Point} pt The point to evaluate
20081          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20082          * @return {boolean} true if the mouse is over the target
20083          * @private
20084          * @static
20085          */
20086         isOverTarget: function(pt, oTarget, intersect) {
20087             // use cache if available
20088             var loc = this.locationCache[oTarget.id];
20089             if (!loc || !this.useCache) {
20090                 loc = this.getLocation(oTarget);
20091                 this.locationCache[oTarget.id] = loc;
20092
20093             }
20094
20095             if (!loc) {
20096                 return false;
20097             }
20098
20099             oTarget.cursorIsOver = loc.contains( pt );
20100
20101             // DragDrop is using this as a sanity check for the initial mousedown
20102             // in this case we are done.  In POINT mode, if the drag obj has no
20103             // contraints, we are also done. Otherwise we need to evaluate the
20104             // location of the target as related to the actual location of the
20105             // dragged element.
20106             var dc = this.dragCurrent;
20107             if (!dc || !dc.getTargetCoord ||
20108                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20109                 return oTarget.cursorIsOver;
20110             }
20111
20112             oTarget.overlap = null;
20113
20114             // Get the current location of the drag element, this is the
20115             // location of the mouse event less the delta that represents
20116             // where the original mousedown happened on the element.  We
20117             // need to consider constraints and ticks as well.
20118             var pos = dc.getTargetCoord(pt.x, pt.y);
20119
20120             var el = dc.getDragEl();
20121             var curRegion = new Roo.lib.Region( pos.y,
20122                                                    pos.x + el.offsetWidth,
20123                                                    pos.y + el.offsetHeight,
20124                                                    pos.x );
20125
20126             var overlap = curRegion.intersect(loc);
20127
20128             if (overlap) {
20129                 oTarget.overlap = overlap;
20130                 return (intersect) ? true : oTarget.cursorIsOver;
20131             } else {
20132                 return false;
20133             }
20134         },
20135
20136         /**
20137          * unload event handler
20138          * @method _onUnload
20139          * @private
20140          * @static
20141          */
20142         _onUnload: function(e, me) {
20143             Roo.dd.DragDropMgr.unregAll();
20144         },
20145
20146         /**
20147          * Cleans up the drag and drop events and objects.
20148          * @method unregAll
20149          * @private
20150          * @static
20151          */
20152         unregAll: function() {
20153
20154             if (this.dragCurrent) {
20155                 this.stopDrag();
20156                 this.dragCurrent = null;
20157             }
20158
20159             this._execOnAll("unreg", []);
20160
20161             for (i in this.elementCache) {
20162                 delete this.elementCache[i];
20163             }
20164
20165             this.elementCache = {};
20166             this.ids = {};
20167         },
20168
20169         /**
20170          * A cache of DOM elements
20171          * @property elementCache
20172          * @private
20173          * @static
20174          */
20175         elementCache: {},
20176
20177         /**
20178          * Get the wrapper for the DOM element specified
20179          * @method getElWrapper
20180          * @param {String} id the id of the element to get
20181          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20182          * @private
20183          * @deprecated This wrapper isn't that useful
20184          * @static
20185          */
20186         getElWrapper: function(id) {
20187             var oWrapper = this.elementCache[id];
20188             if (!oWrapper || !oWrapper.el) {
20189                 oWrapper = this.elementCache[id] =
20190                     new this.ElementWrapper(Roo.getDom(id));
20191             }
20192             return oWrapper;
20193         },
20194
20195         /**
20196          * Returns the actual DOM element
20197          * @method getElement
20198          * @param {String} id the id of the elment to get
20199          * @return {Object} The element
20200          * @deprecated use Roo.getDom instead
20201          * @static
20202          */
20203         getElement: function(id) {
20204             return Roo.getDom(id);
20205         },
20206
20207         /**
20208          * Returns the style property for the DOM element (i.e.,
20209          * document.getElById(id).style)
20210          * @method getCss
20211          * @param {String} id the id of the elment to get
20212          * @return {Object} The style property of the element
20213          * @deprecated use Roo.getDom instead
20214          * @static
20215          */
20216         getCss: function(id) {
20217             var el = Roo.getDom(id);
20218             return (el) ? el.style : null;
20219         },
20220
20221         /**
20222          * Inner class for cached elements
20223          * @class DragDropMgr.ElementWrapper
20224          * @for DragDropMgr
20225          * @private
20226          * @deprecated
20227          */
20228         ElementWrapper: function(el) {
20229                 /**
20230                  * The element
20231                  * @property el
20232                  */
20233                 this.el = el || null;
20234                 /**
20235                  * The element id
20236                  * @property id
20237                  */
20238                 this.id = this.el && el.id;
20239                 /**
20240                  * A reference to the style property
20241                  * @property css
20242                  */
20243                 this.css = this.el && el.style;
20244             },
20245
20246         /**
20247          * Returns the X position of an html element
20248          * @method getPosX
20249          * @param el the element for which to get the position
20250          * @return {int} the X coordinate
20251          * @for DragDropMgr
20252          * @deprecated use Roo.lib.Dom.getX instead
20253          * @static
20254          */
20255         getPosX: function(el) {
20256             return Roo.lib.Dom.getX(el);
20257         },
20258
20259         /**
20260          * Returns the Y position of an html element
20261          * @method getPosY
20262          * @param el the element for which to get the position
20263          * @return {int} the Y coordinate
20264          * @deprecated use Roo.lib.Dom.getY instead
20265          * @static
20266          */
20267         getPosY: function(el) {
20268             return Roo.lib.Dom.getY(el);
20269         },
20270
20271         /**
20272          * Swap two nodes.  In IE, we use the native method, for others we
20273          * emulate the IE behavior
20274          * @method swapNode
20275          * @param n1 the first node to swap
20276          * @param n2 the other node to swap
20277          * @static
20278          */
20279         swapNode: function(n1, n2) {
20280             if (n1.swapNode) {
20281                 n1.swapNode(n2);
20282             } else {
20283                 var p = n2.parentNode;
20284                 var s = n2.nextSibling;
20285
20286                 if (s == n1) {
20287                     p.insertBefore(n1, n2);
20288                 } else if (n2 == n1.nextSibling) {
20289                     p.insertBefore(n2, n1);
20290                 } else {
20291                     n1.parentNode.replaceChild(n2, n1);
20292                     p.insertBefore(n1, s);
20293                 }
20294             }
20295         },
20296
20297         /**
20298          * Returns the current scroll position
20299          * @method getScroll
20300          * @private
20301          * @static
20302          */
20303         getScroll: function () {
20304             var t, l, dde=document.documentElement, db=document.body;
20305             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20306                 t = dde.scrollTop;
20307                 l = dde.scrollLeft;
20308             } else if (db) {
20309                 t = db.scrollTop;
20310                 l = db.scrollLeft;
20311             } else {
20312
20313             }
20314             return { top: t, left: l };
20315         },
20316
20317         /**
20318          * Returns the specified element style property
20319          * @method getStyle
20320          * @param {HTMLElement} el          the element
20321          * @param {string}      styleProp   the style property
20322          * @return {string} The value of the style property
20323          * @deprecated use Roo.lib.Dom.getStyle
20324          * @static
20325          */
20326         getStyle: function(el, styleProp) {
20327             return Roo.fly(el).getStyle(styleProp);
20328         },
20329
20330         /**
20331          * Gets the scrollTop
20332          * @method getScrollTop
20333          * @return {int} the document's scrollTop
20334          * @static
20335          */
20336         getScrollTop: function () { return this.getScroll().top; },
20337
20338         /**
20339          * Gets the scrollLeft
20340          * @method getScrollLeft
20341          * @return {int} the document's scrollTop
20342          * @static
20343          */
20344         getScrollLeft: function () { return this.getScroll().left; },
20345
20346         /**
20347          * Sets the x/y position of an element to the location of the
20348          * target element.
20349          * @method moveToEl
20350          * @param {HTMLElement} moveEl      The element to move
20351          * @param {HTMLElement} targetEl    The position reference element
20352          * @static
20353          */
20354         moveToEl: function (moveEl, targetEl) {
20355             var aCoord = Roo.lib.Dom.getXY(targetEl);
20356             Roo.lib.Dom.setXY(moveEl, aCoord);
20357         },
20358
20359         /**
20360          * Numeric array sort function
20361          * @method numericSort
20362          * @static
20363          */
20364         numericSort: function(a, b) { return (a - b); },
20365
20366         /**
20367          * Internal counter
20368          * @property _timeoutCount
20369          * @private
20370          * @static
20371          */
20372         _timeoutCount: 0,
20373
20374         /**
20375          * Trying to make the load order less important.  Without this we get
20376          * an error if this file is loaded before the Event Utility.
20377          * @method _addListeners
20378          * @private
20379          * @static
20380          */
20381         _addListeners: function() {
20382             var DDM = Roo.dd.DDM;
20383             if ( Roo.lib.Event && document ) {
20384                 DDM._onLoad();
20385             } else {
20386                 if (DDM._timeoutCount > 2000) {
20387                 } else {
20388                     setTimeout(DDM._addListeners, 10);
20389                     if (document && document.body) {
20390                         DDM._timeoutCount += 1;
20391                     }
20392                 }
20393             }
20394         },
20395
20396         /**
20397          * Recursively searches the immediate parent and all child nodes for
20398          * the handle element in order to determine wheter or not it was
20399          * clicked.
20400          * @method handleWasClicked
20401          * @param node the html element to inspect
20402          * @static
20403          */
20404         handleWasClicked: function(node, id) {
20405             if (this.isHandle(id, node.id)) {
20406                 return true;
20407             } else {
20408                 // check to see if this is a text node child of the one we want
20409                 var p = node.parentNode;
20410
20411                 while (p) {
20412                     if (this.isHandle(id, p.id)) {
20413                         return true;
20414                     } else {
20415                         p = p.parentNode;
20416                     }
20417                 }
20418             }
20419
20420             return false;
20421         }
20422
20423     };
20424
20425 }();
20426
20427 // shorter alias, save a few bytes
20428 Roo.dd.DDM = Roo.dd.DragDropMgr;
20429 Roo.dd.DDM._addListeners();
20430
20431 }/*
20432  * Based on:
20433  * Ext JS Library 1.1.1
20434  * Copyright(c) 2006-2007, Ext JS, LLC.
20435  *
20436  * Originally Released Under LGPL - original licence link has changed is not relivant.
20437  *
20438  * Fork - LGPL
20439  * <script type="text/javascript">
20440  */
20441
20442 /**
20443  * @class Roo.dd.DD
20444  * A DragDrop implementation where the linked element follows the
20445  * mouse cursor during a drag.
20446  * @extends Roo.dd.DragDrop
20447  * @constructor
20448  * @param {String} id the id of the linked element
20449  * @param {String} sGroup the group of related DragDrop items
20450  * @param {object} config an object containing configurable attributes
20451  *                Valid properties for DD:
20452  *                    scroll
20453  */
20454 Roo.dd.DD = function(id, sGroup, config) {
20455     if (id) {
20456         this.init(id, sGroup, config);
20457     }
20458 };
20459
20460 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20461
20462     /**
20463      * When set to true, the utility automatically tries to scroll the browser
20464      * window wehn a drag and drop element is dragged near the viewport boundary.
20465      * Defaults to true.
20466      * @property scroll
20467      * @type boolean
20468      */
20469     scroll: true,
20470
20471     /**
20472      * Sets the pointer offset to the distance between the linked element's top
20473      * left corner and the location the element was clicked
20474      * @method autoOffset
20475      * @param {int} iPageX the X coordinate of the click
20476      * @param {int} iPageY the Y coordinate of the click
20477      */
20478     autoOffset: function(iPageX, iPageY) {
20479         var x = iPageX - this.startPageX;
20480         var y = iPageY - this.startPageY;
20481         this.setDelta(x, y);
20482     },
20483
20484     /**
20485      * Sets the pointer offset.  You can call this directly to force the
20486      * offset to be in a particular location (e.g., pass in 0,0 to set it
20487      * to the center of the object)
20488      * @method setDelta
20489      * @param {int} iDeltaX the distance from the left
20490      * @param {int} iDeltaY the distance from the top
20491      */
20492     setDelta: function(iDeltaX, iDeltaY) {
20493         this.deltaX = iDeltaX;
20494         this.deltaY = iDeltaY;
20495     },
20496
20497     /**
20498      * Sets the drag element to the location of the mousedown or click event,
20499      * maintaining the cursor location relative to the location on the element
20500      * that was clicked.  Override this if you want to place the element in a
20501      * location other than where the cursor is.
20502      * @method setDragElPos
20503      * @param {int} iPageX the X coordinate of the mousedown or drag event
20504      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20505      */
20506     setDragElPos: function(iPageX, iPageY) {
20507         // the first time we do this, we are going to check to make sure
20508         // the element has css positioning
20509
20510         var el = this.getDragEl();
20511         this.alignElWithMouse(el, iPageX, iPageY);
20512     },
20513
20514     /**
20515      * Sets the element to the location of the mousedown or click event,
20516      * maintaining the cursor location relative to the location on the element
20517      * that was clicked.  Override this if you want to place the element in a
20518      * location other than where the cursor is.
20519      * @method alignElWithMouse
20520      * @param {HTMLElement} el the element to move
20521      * @param {int} iPageX the X coordinate of the mousedown or drag event
20522      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20523      */
20524     alignElWithMouse: function(el, iPageX, iPageY) {
20525         var oCoord = this.getTargetCoord(iPageX, iPageY);
20526         var fly = el.dom ? el : Roo.fly(el);
20527         if (!this.deltaSetXY) {
20528             var aCoord = [oCoord.x, oCoord.y];
20529             fly.setXY(aCoord);
20530             var newLeft = fly.getLeft(true);
20531             var newTop  = fly.getTop(true);
20532             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20533         } else {
20534             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20535         }
20536
20537         this.cachePosition(oCoord.x, oCoord.y);
20538         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20539         return oCoord;
20540     },
20541
20542     /**
20543      * Saves the most recent position so that we can reset the constraints and
20544      * tick marks on-demand.  We need to know this so that we can calculate the
20545      * number of pixels the element is offset from its original position.
20546      * @method cachePosition
20547      * @param iPageX the current x position (optional, this just makes it so we
20548      * don't have to look it up again)
20549      * @param iPageY the current y position (optional, this just makes it so we
20550      * don't have to look it up again)
20551      */
20552     cachePosition: function(iPageX, iPageY) {
20553         if (iPageX) {
20554             this.lastPageX = iPageX;
20555             this.lastPageY = iPageY;
20556         } else {
20557             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20558             this.lastPageX = aCoord[0];
20559             this.lastPageY = aCoord[1];
20560         }
20561     },
20562
20563     /**
20564      * Auto-scroll the window if the dragged object has been moved beyond the
20565      * visible window boundary.
20566      * @method autoScroll
20567      * @param {int} x the drag element's x position
20568      * @param {int} y the drag element's y position
20569      * @param {int} h the height of the drag element
20570      * @param {int} w the width of the drag element
20571      * @private
20572      */
20573     autoScroll: function(x, y, h, w) {
20574
20575         if (this.scroll) {
20576             // The client height
20577             var clientH = Roo.lib.Dom.getViewWidth();
20578
20579             // The client width
20580             var clientW = Roo.lib.Dom.getViewHeight();
20581
20582             // The amt scrolled down
20583             var st = this.DDM.getScrollTop();
20584
20585             // The amt scrolled right
20586             var sl = this.DDM.getScrollLeft();
20587
20588             // Location of the bottom of the element
20589             var bot = h + y;
20590
20591             // Location of the right of the element
20592             var right = w + x;
20593
20594             // The distance from the cursor to the bottom of the visible area,
20595             // adjusted so that we don't scroll if the cursor is beyond the
20596             // element drag constraints
20597             var toBot = (clientH + st - y - this.deltaY);
20598
20599             // The distance from the cursor to the right of the visible area
20600             var toRight = (clientW + sl - x - this.deltaX);
20601
20602
20603             // How close to the edge the cursor must be before we scroll
20604             // var thresh = (document.all) ? 100 : 40;
20605             var thresh = 40;
20606
20607             // How many pixels to scroll per autoscroll op.  This helps to reduce
20608             // clunky scrolling. IE is more sensitive about this ... it needs this
20609             // value to be higher.
20610             var scrAmt = (document.all) ? 80 : 30;
20611
20612             // Scroll down if we are near the bottom of the visible page and the
20613             // obj extends below the crease
20614             if ( bot > clientH && toBot < thresh ) {
20615                 window.scrollTo(sl, st + scrAmt);
20616             }
20617
20618             // Scroll up if the window is scrolled down and the top of the object
20619             // goes above the top border
20620             if ( y < st && st > 0 && y - st < thresh ) {
20621                 window.scrollTo(sl, st - scrAmt);
20622             }
20623
20624             // Scroll right if the obj is beyond the right border and the cursor is
20625             // near the border.
20626             if ( right > clientW && toRight < thresh ) {
20627                 window.scrollTo(sl + scrAmt, st);
20628             }
20629
20630             // Scroll left if the window has been scrolled to the right and the obj
20631             // extends past the left border
20632             if ( x < sl && sl > 0 && x - sl < thresh ) {
20633                 window.scrollTo(sl - scrAmt, st);
20634             }
20635         }
20636     },
20637
20638     /**
20639      * Finds the location the element should be placed if we want to move
20640      * it to where the mouse location less the click offset would place us.
20641      * @method getTargetCoord
20642      * @param {int} iPageX the X coordinate of the click
20643      * @param {int} iPageY the Y coordinate of the click
20644      * @return an object that contains the coordinates (Object.x and Object.y)
20645      * @private
20646      */
20647     getTargetCoord: function(iPageX, iPageY) {
20648
20649
20650         var x = iPageX - this.deltaX;
20651         var y = iPageY - this.deltaY;
20652
20653         if (this.constrainX) {
20654             if (x < this.minX) { x = this.minX; }
20655             if (x > this.maxX) { x = this.maxX; }
20656         }
20657
20658         if (this.constrainY) {
20659             if (y < this.minY) { y = this.minY; }
20660             if (y > this.maxY) { y = this.maxY; }
20661         }
20662
20663         x = this.getTick(x, this.xTicks);
20664         y = this.getTick(y, this.yTicks);
20665
20666
20667         return {x:x, y:y};
20668     },
20669
20670     /*
20671      * Sets up config options specific to this class. Overrides
20672      * Roo.dd.DragDrop, but all versions of this method through the
20673      * inheritance chain are called
20674      */
20675     applyConfig: function() {
20676         Roo.dd.DD.superclass.applyConfig.call(this);
20677         this.scroll = (this.config.scroll !== false);
20678     },
20679
20680     /*
20681      * Event that fires prior to the onMouseDown event.  Overrides
20682      * Roo.dd.DragDrop.
20683      */
20684     b4MouseDown: function(e) {
20685         // this.resetConstraints();
20686         this.autoOffset(e.getPageX(),
20687                             e.getPageY());
20688     },
20689
20690     /*
20691      * Event that fires prior to the onDrag event.  Overrides
20692      * Roo.dd.DragDrop.
20693      */
20694     b4Drag: function(e) {
20695         this.setDragElPos(e.getPageX(),
20696                             e.getPageY());
20697     },
20698
20699     toString: function() {
20700         return ("DD " + this.id);
20701     }
20702
20703     //////////////////////////////////////////////////////////////////////////
20704     // Debugging ygDragDrop events that can be overridden
20705     //////////////////////////////////////////////////////////////////////////
20706     /*
20707     startDrag: function(x, y) {
20708     },
20709
20710     onDrag: function(e) {
20711     },
20712
20713     onDragEnter: function(e, id) {
20714     },
20715
20716     onDragOver: function(e, id) {
20717     },
20718
20719     onDragOut: function(e, id) {
20720     },
20721
20722     onDragDrop: function(e, id) {
20723     },
20724
20725     endDrag: function(e) {
20726     }
20727
20728     */
20729
20730 });/*
20731  * Based on:
20732  * Ext JS Library 1.1.1
20733  * Copyright(c) 2006-2007, Ext JS, LLC.
20734  *
20735  * Originally Released Under LGPL - original licence link has changed is not relivant.
20736  *
20737  * Fork - LGPL
20738  * <script type="text/javascript">
20739  */
20740
20741 /**
20742  * @class Roo.dd.DDProxy
20743  * A DragDrop implementation that inserts an empty, bordered div into
20744  * the document that follows the cursor during drag operations.  At the time of
20745  * the click, the frame div is resized to the dimensions of the linked html
20746  * element, and moved to the exact location of the linked element.
20747  *
20748  * References to the "frame" element refer to the single proxy element that
20749  * was created to be dragged in place of all DDProxy elements on the
20750  * page.
20751  *
20752  * @extends Roo.dd.DD
20753  * @constructor
20754  * @param {String} id the id of the linked html element
20755  * @param {String} sGroup the group of related DragDrop objects
20756  * @param {object} config an object containing configurable attributes
20757  *                Valid properties for DDProxy in addition to those in DragDrop:
20758  *                   resizeFrame, centerFrame, dragElId
20759  */
20760 Roo.dd.DDProxy = function(id, sGroup, config) {
20761     if (id) {
20762         this.init(id, sGroup, config);
20763         this.initFrame();
20764     }
20765 };
20766
20767 /**
20768  * The default drag frame div id
20769  * @property Roo.dd.DDProxy.dragElId
20770  * @type String
20771  * @static
20772  */
20773 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20774
20775 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20776
20777     /**
20778      * By default we resize the drag frame to be the same size as the element
20779      * we want to drag (this is to get the frame effect).  We can turn it off
20780      * if we want a different behavior.
20781      * @property resizeFrame
20782      * @type boolean
20783      */
20784     resizeFrame: true,
20785
20786     /**
20787      * By default the frame is positioned exactly where the drag element is, so
20788      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20789      * you do not have constraints on the obj is to have the drag frame centered
20790      * around the cursor.  Set centerFrame to true for this effect.
20791      * @property centerFrame
20792      * @type boolean
20793      */
20794     centerFrame: false,
20795
20796     /**
20797      * Creates the proxy element if it does not yet exist
20798      * @method createFrame
20799      */
20800     createFrame: function() {
20801         var self = this;
20802         var body = document.body;
20803
20804         if (!body || !body.firstChild) {
20805             setTimeout( function() { self.createFrame(); }, 50 );
20806             return;
20807         }
20808
20809         var div = this.getDragEl();
20810
20811         if (!div) {
20812             div    = document.createElement("div");
20813             div.id = this.dragElId;
20814             var s  = div.style;
20815
20816             s.position   = "absolute";
20817             s.visibility = "hidden";
20818             s.cursor     = "move";
20819             s.border     = "2px solid #aaa";
20820             s.zIndex     = 999;
20821
20822             // appendChild can blow up IE if invoked prior to the window load event
20823             // while rendering a table.  It is possible there are other scenarios
20824             // that would cause this to happen as well.
20825             body.insertBefore(div, body.firstChild);
20826         }
20827     },
20828
20829     /**
20830      * Initialization for the drag frame element.  Must be called in the
20831      * constructor of all subclasses
20832      * @method initFrame
20833      */
20834     initFrame: function() {
20835         this.createFrame();
20836     },
20837
20838     applyConfig: function() {
20839         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20840
20841         this.resizeFrame = (this.config.resizeFrame !== false);
20842         this.centerFrame = (this.config.centerFrame);
20843         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20844     },
20845
20846     /**
20847      * Resizes the drag frame to the dimensions of the clicked object, positions
20848      * it over the object, and finally displays it
20849      * @method showFrame
20850      * @param {int} iPageX X click position
20851      * @param {int} iPageY Y click position
20852      * @private
20853      */
20854     showFrame: function(iPageX, iPageY) {
20855         var el = this.getEl();
20856         var dragEl = this.getDragEl();
20857         var s = dragEl.style;
20858
20859         this._resizeProxy();
20860
20861         if (this.centerFrame) {
20862             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20863                            Math.round(parseInt(s.height, 10)/2) );
20864         }
20865
20866         this.setDragElPos(iPageX, iPageY);
20867
20868         Roo.fly(dragEl).show();
20869     },
20870
20871     /**
20872      * The proxy is automatically resized to the dimensions of the linked
20873      * element when a drag is initiated, unless resizeFrame is set to false
20874      * @method _resizeProxy
20875      * @private
20876      */
20877     _resizeProxy: function() {
20878         if (this.resizeFrame) {
20879             var el = this.getEl();
20880             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20881         }
20882     },
20883
20884     // overrides Roo.dd.DragDrop
20885     b4MouseDown: function(e) {
20886         var x = e.getPageX();
20887         var y = e.getPageY();
20888         this.autoOffset(x, y);
20889         this.setDragElPos(x, y);
20890     },
20891
20892     // overrides Roo.dd.DragDrop
20893     b4StartDrag: function(x, y) {
20894         // show the drag frame
20895         this.showFrame(x, y);
20896     },
20897
20898     // overrides Roo.dd.DragDrop
20899     b4EndDrag: function(e) {
20900         Roo.fly(this.getDragEl()).hide();
20901     },
20902
20903     // overrides Roo.dd.DragDrop
20904     // By default we try to move the element to the last location of the frame.
20905     // This is so that the default behavior mirrors that of Roo.dd.DD.
20906     endDrag: function(e) {
20907
20908         var lel = this.getEl();
20909         var del = this.getDragEl();
20910
20911         // Show the drag frame briefly so we can get its position
20912         del.style.visibility = "";
20913
20914         this.beforeMove();
20915         // Hide the linked element before the move to get around a Safari
20916         // rendering bug.
20917         lel.style.visibility = "hidden";
20918         Roo.dd.DDM.moveToEl(lel, del);
20919         del.style.visibility = "hidden";
20920         lel.style.visibility = "";
20921
20922         this.afterDrag();
20923     },
20924
20925     beforeMove : function(){
20926
20927     },
20928
20929     afterDrag : function(){
20930
20931     },
20932
20933     toString: function() {
20934         return ("DDProxy " + this.id);
20935     }
20936
20937 });
20938 /*
20939  * Based on:
20940  * Ext JS Library 1.1.1
20941  * Copyright(c) 2006-2007, Ext JS, LLC.
20942  *
20943  * Originally Released Under LGPL - original licence link has changed is not relivant.
20944  *
20945  * Fork - LGPL
20946  * <script type="text/javascript">
20947  */
20948
20949  /**
20950  * @class Roo.dd.DDTarget
20951  * A DragDrop implementation that does not move, but can be a drop
20952  * target.  You would get the same result by simply omitting implementation
20953  * for the event callbacks, but this way we reduce the processing cost of the
20954  * event listener and the callbacks.
20955  * @extends Roo.dd.DragDrop
20956  * @constructor
20957  * @param {String} id the id of the element that is a drop target
20958  * @param {String} sGroup the group of related DragDrop objects
20959  * @param {object} config an object containing configurable attributes
20960  *                 Valid properties for DDTarget in addition to those in
20961  *                 DragDrop:
20962  *                    none
20963  */
20964 Roo.dd.DDTarget = function(id, sGroup, config) {
20965     if (id) {
20966         this.initTarget(id, sGroup, config);
20967     }
20968     if (config.listeners || config.events) { 
20969        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20970             listeners : config.listeners || {}, 
20971             events : config.events || {} 
20972         });    
20973     }
20974 };
20975
20976 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20977 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20978     toString: function() {
20979         return ("DDTarget " + this.id);
20980     }
20981 });
20982 /*
20983  * Based on:
20984  * Ext JS Library 1.1.1
20985  * Copyright(c) 2006-2007, Ext JS, LLC.
20986  *
20987  * Originally Released Under LGPL - original licence link has changed is not relivant.
20988  *
20989  * Fork - LGPL
20990  * <script type="text/javascript">
20991  */
20992  
20993
20994 /**
20995  * @class Roo.dd.ScrollManager
20996  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20997  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20998  * @singleton
20999  */
21000 Roo.dd.ScrollManager = function(){
21001     var ddm = Roo.dd.DragDropMgr;
21002     var els = {};
21003     var dragEl = null;
21004     var proc = {};
21005     
21006     
21007     
21008     var onStop = function(e){
21009         dragEl = null;
21010         clearProc();
21011     };
21012     
21013     var triggerRefresh = function(){
21014         if(ddm.dragCurrent){
21015              ddm.refreshCache(ddm.dragCurrent.groups);
21016         }
21017     };
21018     
21019     var doScroll = function(){
21020         if(ddm.dragCurrent){
21021             var dds = Roo.dd.ScrollManager;
21022             if(!dds.animate){
21023                 if(proc.el.scroll(proc.dir, dds.increment)){
21024                     triggerRefresh();
21025                 }
21026             }else{
21027                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21028             }
21029         }
21030     };
21031     
21032     var clearProc = function(){
21033         if(proc.id){
21034             clearInterval(proc.id);
21035         }
21036         proc.id = 0;
21037         proc.el = null;
21038         proc.dir = "";
21039     };
21040     
21041     var startProc = function(el, dir){
21042          Roo.log('scroll startproc');
21043         clearProc();
21044         proc.el = el;
21045         proc.dir = dir;
21046         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21047     };
21048     
21049     var onFire = function(e, isDrop){
21050        
21051         if(isDrop || !ddm.dragCurrent){ return; }
21052         var dds = Roo.dd.ScrollManager;
21053         if(!dragEl || dragEl != ddm.dragCurrent){
21054             dragEl = ddm.dragCurrent;
21055             // refresh regions on drag start
21056             dds.refreshCache();
21057         }
21058         
21059         var xy = Roo.lib.Event.getXY(e);
21060         var pt = new Roo.lib.Point(xy[0], xy[1]);
21061         for(var id in els){
21062             var el = els[id], r = el._region;
21063             if(r && r.contains(pt) && el.isScrollable()){
21064                 if(r.bottom - pt.y <= dds.thresh){
21065                     if(proc.el != el){
21066                         startProc(el, "down");
21067                     }
21068                     return;
21069                 }else if(r.right - pt.x <= dds.thresh){
21070                     if(proc.el != el){
21071                         startProc(el, "left");
21072                     }
21073                     return;
21074                 }else if(pt.y - r.top <= dds.thresh){
21075                     if(proc.el != el){
21076                         startProc(el, "up");
21077                     }
21078                     return;
21079                 }else if(pt.x - r.left <= dds.thresh){
21080                     if(proc.el != el){
21081                         startProc(el, "right");
21082                     }
21083                     return;
21084                 }
21085             }
21086         }
21087         clearProc();
21088     };
21089     
21090     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21091     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21092     
21093     return {
21094         /**
21095          * Registers new overflow element(s) to auto scroll
21096          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21097          */
21098         register : function(el){
21099             if(el instanceof Array){
21100                 for(var i = 0, len = el.length; i < len; i++) {
21101                         this.register(el[i]);
21102                 }
21103             }else{
21104                 el = Roo.get(el);
21105                 els[el.id] = el;
21106             }
21107             Roo.dd.ScrollManager.els = els;
21108         },
21109         
21110         /**
21111          * Unregisters overflow element(s) so they are no longer scrolled
21112          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21113          */
21114         unregister : function(el){
21115             if(el instanceof Array){
21116                 for(var i = 0, len = el.length; i < len; i++) {
21117                         this.unregister(el[i]);
21118                 }
21119             }else{
21120                 el = Roo.get(el);
21121                 delete els[el.id];
21122             }
21123         },
21124         
21125         /**
21126          * The number of pixels from the edge of a container the pointer needs to be to 
21127          * trigger scrolling (defaults to 25)
21128          * @type Number
21129          */
21130         thresh : 25,
21131         
21132         /**
21133          * The number of pixels to scroll in each scroll increment (defaults to 50)
21134          * @type Number
21135          */
21136         increment : 100,
21137         
21138         /**
21139          * The frequency of scrolls in milliseconds (defaults to 500)
21140          * @type Number
21141          */
21142         frequency : 500,
21143         
21144         /**
21145          * True to animate the scroll (defaults to true)
21146          * @type Boolean
21147          */
21148         animate: true,
21149         
21150         /**
21151          * The animation duration in seconds - 
21152          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21153          * @type Number
21154          */
21155         animDuration: .4,
21156         
21157         /**
21158          * Manually trigger a cache refresh.
21159          */
21160         refreshCache : function(){
21161             for(var id in els){
21162                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21163                     els[id]._region = els[id].getRegion();
21164                 }
21165             }
21166         }
21167     };
21168 }();/*
21169  * Based on:
21170  * Ext JS Library 1.1.1
21171  * Copyright(c) 2006-2007, Ext JS, LLC.
21172  *
21173  * Originally Released Under LGPL - original licence link has changed is not relivant.
21174  *
21175  * Fork - LGPL
21176  * <script type="text/javascript">
21177  */
21178  
21179
21180 /**
21181  * @class Roo.dd.Registry
21182  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21183  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21184  * @singleton
21185  */
21186 Roo.dd.Registry = function(){
21187     var elements = {}; 
21188     var handles = {}; 
21189     var autoIdSeed = 0;
21190
21191     var getId = function(el, autogen){
21192         if(typeof el == "string"){
21193             return el;
21194         }
21195         var id = el.id;
21196         if(!id && autogen !== false){
21197             id = "roodd-" + (++autoIdSeed);
21198             el.id = id;
21199         }
21200         return id;
21201     };
21202     
21203     return {
21204     /**
21205      * Register a drag drop element
21206      * @param {String|HTMLElement} element The id or DOM node to register
21207      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21208      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21209      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21210      * populated in the data object (if applicable):
21211      * <pre>
21212 Value      Description<br />
21213 ---------  ------------------------------------------<br />
21214 handles    Array of DOM nodes that trigger dragging<br />
21215            for the element being registered<br />
21216 isHandle   True if the element passed in triggers<br />
21217            dragging itself, else false
21218 </pre>
21219      */
21220         register : function(el, data){
21221             data = data || {};
21222             if(typeof el == "string"){
21223                 el = document.getElementById(el);
21224             }
21225             data.ddel = el;
21226             elements[getId(el)] = data;
21227             if(data.isHandle !== false){
21228                 handles[data.ddel.id] = data;
21229             }
21230             if(data.handles){
21231                 var hs = data.handles;
21232                 for(var i = 0, len = hs.length; i < len; i++){
21233                         handles[getId(hs[i])] = data;
21234                 }
21235             }
21236         },
21237
21238     /**
21239      * Unregister a drag drop element
21240      * @param {String|HTMLElement}  element The id or DOM node to unregister
21241      */
21242         unregister : function(el){
21243             var id = getId(el, false);
21244             var data = elements[id];
21245             if(data){
21246                 delete elements[id];
21247                 if(data.handles){
21248                     var hs = data.handles;
21249                     for(var i = 0, len = hs.length; i < len; i++){
21250                         delete handles[getId(hs[i], false)];
21251                     }
21252                 }
21253             }
21254         },
21255
21256     /**
21257      * Returns the handle registered for a DOM Node by id
21258      * @param {String|HTMLElement} id The DOM node or id to look up
21259      * @return {Object} handle The custom handle data
21260      */
21261         getHandle : function(id){
21262             if(typeof id != "string"){ // must be element?
21263                 id = id.id;
21264             }
21265             return handles[id];
21266         },
21267
21268     /**
21269      * Returns the handle that is registered for the DOM node that is the target of the event
21270      * @param {Event} e The event
21271      * @return {Object} handle The custom handle data
21272      */
21273         getHandleFromEvent : function(e){
21274             var t = Roo.lib.Event.getTarget(e);
21275             return t ? handles[t.id] : null;
21276         },
21277
21278     /**
21279      * Returns a custom data object that is registered for a DOM node by id
21280      * @param {String|HTMLElement} id The DOM node or id to look up
21281      * @return {Object} data The custom data
21282      */
21283         getTarget : function(id){
21284             if(typeof id != "string"){ // must be element?
21285                 id = id.id;
21286             }
21287             return elements[id];
21288         },
21289
21290     /**
21291      * Returns a custom data object that is registered for the DOM node that is the target of the event
21292      * @param {Event} e The event
21293      * @return {Object} data The custom data
21294      */
21295         getTargetFromEvent : function(e){
21296             var t = Roo.lib.Event.getTarget(e);
21297             return t ? elements[t.id] || handles[t.id] : null;
21298         }
21299     };
21300 }();/*
21301  * Based on:
21302  * Ext JS Library 1.1.1
21303  * Copyright(c) 2006-2007, Ext JS, LLC.
21304  *
21305  * Originally Released Under LGPL - original licence link has changed is not relivant.
21306  *
21307  * Fork - LGPL
21308  * <script type="text/javascript">
21309  */
21310  
21311
21312 /**
21313  * @class Roo.dd.StatusProxy
21314  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21315  * default drag proxy used by all Roo.dd components.
21316  * @constructor
21317  * @param {Object} config
21318  */
21319 Roo.dd.StatusProxy = function(config){
21320     Roo.apply(this, config);
21321     this.id = this.id || Roo.id();
21322     this.el = new Roo.Layer({
21323         dh: {
21324             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21325                 {tag: "div", cls: "x-dd-drop-icon"},
21326                 {tag: "div", cls: "x-dd-drag-ghost"}
21327             ]
21328         }, 
21329         shadow: !config || config.shadow !== false
21330     });
21331     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21332     this.dropStatus = this.dropNotAllowed;
21333 };
21334
21335 Roo.dd.StatusProxy.prototype = {
21336     /**
21337      * @cfg {String} dropAllowed
21338      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21339      */
21340     dropAllowed : "x-dd-drop-ok",
21341     /**
21342      * @cfg {String} dropNotAllowed
21343      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21344      */
21345     dropNotAllowed : "x-dd-drop-nodrop",
21346
21347     /**
21348      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21349      * over the current target element.
21350      * @param {String} cssClass The css class for the new drop status indicator image
21351      */
21352     setStatus : function(cssClass){
21353         cssClass = cssClass || this.dropNotAllowed;
21354         if(this.dropStatus != cssClass){
21355             this.el.replaceClass(this.dropStatus, cssClass);
21356             this.dropStatus = cssClass;
21357         }
21358     },
21359
21360     /**
21361      * Resets the status indicator to the default dropNotAllowed value
21362      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21363      */
21364     reset : function(clearGhost){
21365         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21366         this.dropStatus = this.dropNotAllowed;
21367         if(clearGhost){
21368             this.ghost.update("");
21369         }
21370     },
21371
21372     /**
21373      * Updates the contents of the ghost element
21374      * @param {String} html The html that will replace the current innerHTML of the ghost element
21375      */
21376     update : function(html){
21377         if(typeof html == "string"){
21378             this.ghost.update(html);
21379         }else{
21380             this.ghost.update("");
21381             html.style.margin = "0";
21382             this.ghost.dom.appendChild(html);
21383         }
21384         // ensure float = none set?? cant remember why though.
21385         var el = this.ghost.dom.firstChild;
21386                 if(el){
21387                         Roo.fly(el).setStyle('float', 'none');
21388                 }
21389     },
21390     
21391     /**
21392      * Returns the underlying proxy {@link Roo.Layer}
21393      * @return {Roo.Layer} el
21394     */
21395     getEl : function(){
21396         return this.el;
21397     },
21398
21399     /**
21400      * Returns the ghost element
21401      * @return {Roo.Element} el
21402      */
21403     getGhost : function(){
21404         return this.ghost;
21405     },
21406
21407     /**
21408      * Hides the proxy
21409      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21410      */
21411     hide : function(clear){
21412         this.el.hide();
21413         if(clear){
21414             this.reset(true);
21415         }
21416     },
21417
21418     /**
21419      * Stops the repair animation if it's currently running
21420      */
21421     stop : function(){
21422         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21423             this.anim.stop();
21424         }
21425     },
21426
21427     /**
21428      * Displays this proxy
21429      */
21430     show : function(){
21431         this.el.show();
21432     },
21433
21434     /**
21435      * Force the Layer to sync its shadow and shim positions to the element
21436      */
21437     sync : function(){
21438         this.el.sync();
21439     },
21440
21441     /**
21442      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21443      * invalid drop operation by the item being dragged.
21444      * @param {Array} xy The XY position of the element ([x, y])
21445      * @param {Function} callback The function to call after the repair is complete
21446      * @param {Object} scope The scope in which to execute the callback
21447      */
21448     repair : function(xy, callback, scope){
21449         this.callback = callback;
21450         this.scope = scope;
21451         if(xy && this.animRepair !== false){
21452             this.el.addClass("x-dd-drag-repair");
21453             this.el.hideUnders(true);
21454             this.anim = this.el.shift({
21455                 duration: this.repairDuration || .5,
21456                 easing: 'easeOut',
21457                 xy: xy,
21458                 stopFx: true,
21459                 callback: this.afterRepair,
21460                 scope: this
21461             });
21462         }else{
21463             this.afterRepair();
21464         }
21465     },
21466
21467     // private
21468     afterRepair : function(){
21469         this.hide(true);
21470         if(typeof this.callback == "function"){
21471             this.callback.call(this.scope || this);
21472         }
21473         this.callback = null;
21474         this.scope = null;
21475     }
21476 };/*
21477  * Based on:
21478  * Ext JS Library 1.1.1
21479  * Copyright(c) 2006-2007, Ext JS, LLC.
21480  *
21481  * Originally Released Under LGPL - original licence link has changed is not relivant.
21482  *
21483  * Fork - LGPL
21484  * <script type="text/javascript">
21485  */
21486
21487 /**
21488  * @class Roo.dd.DragSource
21489  * @extends Roo.dd.DDProxy
21490  * A simple class that provides the basic implementation needed to make any element draggable.
21491  * @constructor
21492  * @param {String/HTMLElement/Element} el The container element
21493  * @param {Object} config
21494  */
21495 Roo.dd.DragSource = function(el, config){
21496     this.el = Roo.get(el);
21497     this.dragData = {};
21498     
21499     Roo.apply(this, config);
21500     
21501     if(!this.proxy){
21502         this.proxy = new Roo.dd.StatusProxy();
21503     }
21504
21505     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21506           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21507     
21508     this.dragging = false;
21509 };
21510
21511 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21512     /**
21513      * @cfg {String} dropAllowed
21514      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21515      */
21516     dropAllowed : "x-dd-drop-ok",
21517     /**
21518      * @cfg {String} dropNotAllowed
21519      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21520      */
21521     dropNotAllowed : "x-dd-drop-nodrop",
21522
21523     /**
21524      * Returns the data object associated with this drag source
21525      * @return {Object} data An object containing arbitrary data
21526      */
21527     getDragData : function(e){
21528         return this.dragData;
21529     },
21530
21531     // private
21532     onDragEnter : function(e, id){
21533         var target = Roo.dd.DragDropMgr.getDDById(id);
21534         this.cachedTarget = target;
21535         if(this.beforeDragEnter(target, e, id) !== false){
21536             if(target.isNotifyTarget){
21537                 var status = target.notifyEnter(this, e, this.dragData);
21538                 this.proxy.setStatus(status);
21539             }else{
21540                 this.proxy.setStatus(this.dropAllowed);
21541             }
21542             
21543             if(this.afterDragEnter){
21544                 /**
21545                  * An empty function by default, but provided so that you can perform a custom action
21546                  * when the dragged item enters the drop target by providing an implementation.
21547                  * @param {Roo.dd.DragDrop} target The drop target
21548                  * @param {Event} e The event object
21549                  * @param {String} id The id of the dragged element
21550                  * @method afterDragEnter
21551                  */
21552                 this.afterDragEnter(target, e, id);
21553             }
21554         }
21555     },
21556
21557     /**
21558      * An empty function by default, but provided so that you can perform a custom action
21559      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21560      * @param {Roo.dd.DragDrop} target The drop target
21561      * @param {Event} e The event object
21562      * @param {String} id The id of the dragged element
21563      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21564      */
21565     beforeDragEnter : function(target, e, id){
21566         return true;
21567     },
21568
21569     // private
21570     alignElWithMouse: function() {
21571         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21572         this.proxy.sync();
21573     },
21574
21575     // private
21576     onDragOver : function(e, id){
21577         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21578         if(this.beforeDragOver(target, e, id) !== false){
21579             if(target.isNotifyTarget){
21580                 var status = target.notifyOver(this, e, this.dragData);
21581                 this.proxy.setStatus(status);
21582             }
21583
21584             if(this.afterDragOver){
21585                 /**
21586                  * An empty function by default, but provided so that you can perform a custom action
21587                  * while the dragged item is over the drop target by providing an implementation.
21588                  * @param {Roo.dd.DragDrop} target The drop target
21589                  * @param {Event} e The event object
21590                  * @param {String} id The id of the dragged element
21591                  * @method afterDragOver
21592                  */
21593                 this.afterDragOver(target, e, id);
21594             }
21595         }
21596     },
21597
21598     /**
21599      * An empty function by default, but provided so that you can perform a custom action
21600      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21601      * @param {Roo.dd.DragDrop} target The drop target
21602      * @param {Event} e The event object
21603      * @param {String} id The id of the dragged element
21604      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21605      */
21606     beforeDragOver : function(target, e, id){
21607         return true;
21608     },
21609
21610     // private
21611     onDragOut : function(e, id){
21612         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21613         if(this.beforeDragOut(target, e, id) !== false){
21614             if(target.isNotifyTarget){
21615                 target.notifyOut(this, e, this.dragData);
21616             }
21617             this.proxy.reset();
21618             if(this.afterDragOut){
21619                 /**
21620                  * An empty function by default, but provided so that you can perform a custom action
21621                  * after the dragged item is dragged out of the target without dropping.
21622                  * @param {Roo.dd.DragDrop} target The drop target
21623                  * @param {Event} e The event object
21624                  * @param {String} id The id of the dragged element
21625                  * @method afterDragOut
21626                  */
21627                 this.afterDragOut(target, e, id);
21628             }
21629         }
21630         this.cachedTarget = null;
21631     },
21632
21633     /**
21634      * An empty function by default, but provided so that you can perform a custom action before the dragged
21635      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21636      * @param {Roo.dd.DragDrop} target The drop target
21637      * @param {Event} e The event object
21638      * @param {String} id The id of the dragged element
21639      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21640      */
21641     beforeDragOut : function(target, e, id){
21642         return true;
21643     },
21644     
21645     // private
21646     onDragDrop : function(e, id){
21647         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21648         if(this.beforeDragDrop(target, e, id) !== false){
21649             if(target.isNotifyTarget){
21650                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21651                     this.onValidDrop(target, e, id);
21652                 }else{
21653                     this.onInvalidDrop(target, e, id);
21654                 }
21655             }else{
21656                 this.onValidDrop(target, e, id);
21657             }
21658             
21659             if(this.afterDragDrop){
21660                 /**
21661                  * An empty function by default, but provided so that you can perform a custom action
21662                  * after a valid drag drop has occurred by providing an implementation.
21663                  * @param {Roo.dd.DragDrop} target The drop target
21664                  * @param {Event} e The event object
21665                  * @param {String} id The id of the dropped element
21666                  * @method afterDragDrop
21667                  */
21668                 this.afterDragDrop(target, e, id);
21669             }
21670         }
21671         delete this.cachedTarget;
21672     },
21673
21674     /**
21675      * An empty function by default, but provided so that you can perform a custom action before the dragged
21676      * item is dropped onto the target and optionally cancel the onDragDrop.
21677      * @param {Roo.dd.DragDrop} target The drop target
21678      * @param {Event} e The event object
21679      * @param {String} id The id of the dragged element
21680      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21681      */
21682     beforeDragDrop : function(target, e, id){
21683         return true;
21684     },
21685
21686     // private
21687     onValidDrop : function(target, e, id){
21688         this.hideProxy();
21689         if(this.afterValidDrop){
21690             /**
21691              * An empty function by default, but provided so that you can perform a custom action
21692              * after a valid drop has occurred by providing an implementation.
21693              * @param {Object} target The target DD 
21694              * @param {Event} e The event object
21695              * @param {String} id The id of the dropped element
21696              * @method afterInvalidDrop
21697              */
21698             this.afterValidDrop(target, e, id);
21699         }
21700     },
21701
21702     // private
21703     getRepairXY : function(e, data){
21704         return this.el.getXY();  
21705     },
21706
21707     // private
21708     onInvalidDrop : function(target, e, id){
21709         this.beforeInvalidDrop(target, e, id);
21710         if(this.cachedTarget){
21711             if(this.cachedTarget.isNotifyTarget){
21712                 this.cachedTarget.notifyOut(this, e, this.dragData);
21713             }
21714             this.cacheTarget = null;
21715         }
21716         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21717
21718         if(this.afterInvalidDrop){
21719             /**
21720              * An empty function by default, but provided so that you can perform a custom action
21721              * after an invalid drop has occurred by providing an implementation.
21722              * @param {Event} e The event object
21723              * @param {String} id The id of the dropped element
21724              * @method afterInvalidDrop
21725              */
21726             this.afterInvalidDrop(e, id);
21727         }
21728     },
21729
21730     // private
21731     afterRepair : function(){
21732         if(Roo.enableFx){
21733             this.el.highlight(this.hlColor || "c3daf9");
21734         }
21735         this.dragging = false;
21736     },
21737
21738     /**
21739      * An empty function by default, but provided so that you can perform a custom action after an invalid
21740      * drop has occurred.
21741      * @param {Roo.dd.DragDrop} target The drop target
21742      * @param {Event} e The event object
21743      * @param {String} id The id of the dragged element
21744      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21745      */
21746     beforeInvalidDrop : function(target, e, id){
21747         return true;
21748     },
21749
21750     // private
21751     handleMouseDown : function(e){
21752         if(this.dragging) {
21753             return;
21754         }
21755         var data = this.getDragData(e);
21756         if(data && this.onBeforeDrag(data, e) !== false){
21757             this.dragData = data;
21758             this.proxy.stop();
21759             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21760         } 
21761     },
21762
21763     /**
21764      * An empty function by default, but provided so that you can perform a custom action before the initial
21765      * drag event begins and optionally cancel it.
21766      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21767      * @param {Event} e The event object
21768      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21769      */
21770     onBeforeDrag : function(data, e){
21771         return true;
21772     },
21773
21774     /**
21775      * An empty function by default, but provided so that you can perform a custom action once the initial
21776      * drag event has begun.  The drag cannot be canceled from this function.
21777      * @param {Number} x The x position of the click on the dragged object
21778      * @param {Number} y The y position of the click on the dragged object
21779      */
21780     onStartDrag : Roo.emptyFn,
21781
21782     // private - YUI override
21783     startDrag : function(x, y){
21784         this.proxy.reset();
21785         this.dragging = true;
21786         this.proxy.update("");
21787         this.onInitDrag(x, y);
21788         this.proxy.show();
21789     },
21790
21791     // private
21792     onInitDrag : function(x, y){
21793         var clone = this.el.dom.cloneNode(true);
21794         clone.id = Roo.id(); // prevent duplicate ids
21795         this.proxy.update(clone);
21796         this.onStartDrag(x, y);
21797         return true;
21798     },
21799
21800     /**
21801      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21802      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21803      */
21804     getProxy : function(){
21805         return this.proxy;  
21806     },
21807
21808     /**
21809      * Hides the drag source's {@link Roo.dd.StatusProxy}
21810      */
21811     hideProxy : function(){
21812         this.proxy.hide();  
21813         this.proxy.reset(true);
21814         this.dragging = false;
21815     },
21816
21817     // private
21818     triggerCacheRefresh : function(){
21819         Roo.dd.DDM.refreshCache(this.groups);
21820     },
21821
21822     // private - override to prevent hiding
21823     b4EndDrag: function(e) {
21824     },
21825
21826     // private - override to prevent moving
21827     endDrag : function(e){
21828         this.onEndDrag(this.dragData, e);
21829     },
21830
21831     // private
21832     onEndDrag : function(data, e){
21833     },
21834     
21835     // private - pin to cursor
21836     autoOffset : function(x, y) {
21837         this.setDelta(-12, -20);
21838     }    
21839 });/*
21840  * Based on:
21841  * Ext JS Library 1.1.1
21842  * Copyright(c) 2006-2007, Ext JS, LLC.
21843  *
21844  * Originally Released Under LGPL - original licence link has changed is not relivant.
21845  *
21846  * Fork - LGPL
21847  * <script type="text/javascript">
21848  */
21849
21850
21851 /**
21852  * @class Roo.dd.DropTarget
21853  * @extends Roo.dd.DDTarget
21854  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21855  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21856  * @constructor
21857  * @param {String/HTMLElement/Element} el The container element
21858  * @param {Object} config
21859  */
21860 Roo.dd.DropTarget = function(el, config){
21861     this.el = Roo.get(el);
21862     
21863     var listeners = false; ;
21864     if (config && config.listeners) {
21865         listeners= config.listeners;
21866         delete config.listeners;
21867     }
21868     Roo.apply(this, config);
21869     
21870     if(this.containerScroll){
21871         Roo.dd.ScrollManager.register(this.el);
21872     }
21873     this.addEvents( {
21874          /**
21875          * @scope Roo.dd.DropTarget
21876          */
21877          
21878          /**
21879          * @event enter
21880          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21881          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21882          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21883          * 
21884          * IMPORTANT : it should set this.overClass and this.dropAllowed
21885          * 
21886          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21887          * @param {Event} e The event
21888          * @param {Object} data An object containing arbitrary data supplied by the drag source
21889          */
21890         "enter" : true,
21891         
21892          /**
21893          * @event over
21894          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21895          * This method will be called on every mouse movement while the drag source is over the drop target.
21896          * This default implementation simply returns the dropAllowed config value.
21897          * 
21898          * IMPORTANT : it should set this.dropAllowed
21899          * 
21900          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21901          * @param {Event} e The event
21902          * @param {Object} data An object containing arbitrary data supplied by the drag source
21903          
21904          */
21905         "over" : true,
21906         /**
21907          * @event out
21908          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21909          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21910          * overClass (if any) from the drop element.
21911          * 
21912          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21913          * @param {Event} e The event
21914          * @param {Object} data An object containing arbitrary data supplied by the drag source
21915          */
21916          "out" : true,
21917          
21918         /**
21919          * @event drop
21920          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21921          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21922          * implementation that does something to process the drop event and returns true so that the drag source's
21923          * repair action does not run.
21924          * 
21925          * IMPORTANT : it should set this.success
21926          * 
21927          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21928          * @param {Event} e The event
21929          * @param {Object} data An object containing arbitrary data supplied by the drag source
21930         */
21931          "drop" : true
21932     });
21933             
21934      
21935     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21936         this.el.dom, 
21937         this.ddGroup || this.group,
21938         {
21939             isTarget: true,
21940             listeners : listeners || {} 
21941            
21942         
21943         }
21944     );
21945
21946 };
21947
21948 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21949     /**
21950      * @cfg {String} overClass
21951      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21952      */
21953      /**
21954      * @cfg {String} ddGroup
21955      * The drag drop group to handle drop events for
21956      */
21957      
21958     /**
21959      * @cfg {String} dropAllowed
21960      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21961      */
21962     dropAllowed : "x-dd-drop-ok",
21963     /**
21964      * @cfg {String} dropNotAllowed
21965      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21966      */
21967     dropNotAllowed : "x-dd-drop-nodrop",
21968     /**
21969      * @cfg {boolean} success
21970      * set this after drop listener.. 
21971      */
21972     success : false,
21973     /**
21974      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21975      * if the drop point is valid for over/enter..
21976      */
21977     valid : false,
21978     // private
21979     isTarget : true,
21980
21981     // private
21982     isNotifyTarget : true,
21983     
21984     /**
21985      * @hide
21986      */
21987     notifyEnter : function(dd, e, data)
21988     {
21989         this.valid = true;
21990         this.fireEvent('enter', dd, e, data);
21991         if(this.overClass){
21992             this.el.addClass(this.overClass);
21993         }
21994         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21995             this.valid ? this.dropAllowed : this.dropNotAllowed
21996         );
21997     },
21998
21999     /**
22000      * @hide
22001      */
22002     notifyOver : function(dd, e, data)
22003     {
22004         this.valid = true;
22005         this.fireEvent('over', dd, e, data);
22006         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22007             this.valid ? this.dropAllowed : this.dropNotAllowed
22008         );
22009     },
22010
22011     /**
22012      * @hide
22013      */
22014     notifyOut : function(dd, e, data)
22015     {
22016         this.fireEvent('out', dd, e, data);
22017         if(this.overClass){
22018             this.el.removeClass(this.overClass);
22019         }
22020     },
22021
22022     /**
22023      * @hide
22024      */
22025     notifyDrop : function(dd, e, data)
22026     {
22027         this.success = false;
22028         this.fireEvent('drop', dd, e, data);
22029         return this.success;
22030     }
22031 });/*
22032  * Based on:
22033  * Ext JS Library 1.1.1
22034  * Copyright(c) 2006-2007, Ext JS, LLC.
22035  *
22036  * Originally Released Under LGPL - original licence link has changed is not relivant.
22037  *
22038  * Fork - LGPL
22039  * <script type="text/javascript">
22040  */
22041
22042
22043 /**
22044  * @class Roo.dd.DragZone
22045  * @extends Roo.dd.DragSource
22046  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22047  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22048  * @constructor
22049  * @param {String/HTMLElement/Element} el The container element
22050  * @param {Object} config
22051  */
22052 Roo.dd.DragZone = function(el, config){
22053     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22054     if(this.containerScroll){
22055         Roo.dd.ScrollManager.register(this.el);
22056     }
22057 };
22058
22059 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22060     /**
22061      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22062      * for auto scrolling during drag operations.
22063      */
22064     /**
22065      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22066      * method after a failed drop (defaults to "c3daf9" - light blue)
22067      */
22068
22069     /**
22070      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22071      * for a valid target to drag based on the mouse down. Override this method
22072      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22073      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22074      * @param {EventObject} e The mouse down event
22075      * @return {Object} The dragData
22076      */
22077     getDragData : function(e){
22078         return Roo.dd.Registry.getHandleFromEvent(e);
22079     },
22080     
22081     /**
22082      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22083      * this.dragData.ddel
22084      * @param {Number} x The x position of the click on the dragged object
22085      * @param {Number} y The y position of the click on the dragged object
22086      * @return {Boolean} true to continue the drag, false to cancel
22087      */
22088     onInitDrag : function(x, y){
22089         this.proxy.update(this.dragData.ddel.cloneNode(true));
22090         this.onStartDrag(x, y);
22091         return true;
22092     },
22093     
22094     /**
22095      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22096      */
22097     afterRepair : function(){
22098         if(Roo.enableFx){
22099             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22100         }
22101         this.dragging = false;
22102     },
22103
22104     /**
22105      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22106      * the XY of this.dragData.ddel
22107      * @param {EventObject} e The mouse up event
22108      * @return {Array} The xy location (e.g. [100, 200])
22109      */
22110     getRepairXY : function(e){
22111         return Roo.Element.fly(this.dragData.ddel).getXY();  
22112     }
22113 });/*
22114  * Based on:
22115  * Ext JS Library 1.1.1
22116  * Copyright(c) 2006-2007, Ext JS, LLC.
22117  *
22118  * Originally Released Under LGPL - original licence link has changed is not relivant.
22119  *
22120  * Fork - LGPL
22121  * <script type="text/javascript">
22122  */
22123 /**
22124  * @class Roo.dd.DropZone
22125  * @extends Roo.dd.DropTarget
22126  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22127  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22128  * @constructor
22129  * @param {String/HTMLElement/Element} el The container element
22130  * @param {Object} config
22131  */
22132 Roo.dd.DropZone = function(el, config){
22133     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22134 };
22135
22136 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22137     /**
22138      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22139      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22140      * provide your own custom lookup.
22141      * @param {Event} e The event
22142      * @return {Object} data The custom data
22143      */
22144     getTargetFromEvent : function(e){
22145         return Roo.dd.Registry.getTargetFromEvent(e);
22146     },
22147
22148     /**
22149      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22150      * that it has registered.  This method has no default implementation and should be overridden to provide
22151      * node-specific processing if necessary.
22152      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22153      * {@link #getTargetFromEvent} for this node)
22154      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22155      * @param {Event} e The event
22156      * @param {Object} data An object containing arbitrary data supplied by the drag source
22157      */
22158     onNodeEnter : function(n, dd, e, data){
22159         
22160     },
22161
22162     /**
22163      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22164      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22165      * overridden to provide the proper feedback.
22166      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22167      * {@link #getTargetFromEvent} for this node)
22168      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22169      * @param {Event} e The event
22170      * @param {Object} data An object containing arbitrary data supplied by the drag source
22171      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22172      * underlying {@link Roo.dd.StatusProxy} can be updated
22173      */
22174     onNodeOver : function(n, dd, e, data){
22175         return this.dropAllowed;
22176     },
22177
22178     /**
22179      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22180      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22181      * node-specific processing if necessary.
22182      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22183      * {@link #getTargetFromEvent} for this node)
22184      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22185      * @param {Event} e The event
22186      * @param {Object} data An object containing arbitrary data supplied by the drag source
22187      */
22188     onNodeOut : function(n, dd, e, data){
22189         
22190     },
22191
22192     /**
22193      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22194      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22195      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22196      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22197      * {@link #getTargetFromEvent} for this node)
22198      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22199      * @param {Event} e The event
22200      * @param {Object} data An object containing arbitrary data supplied by the drag source
22201      * @return {Boolean} True if the drop was valid, else false
22202      */
22203     onNodeDrop : function(n, dd, e, data){
22204         return false;
22205     },
22206
22207     /**
22208      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22209      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22210      * it should be overridden to provide the proper feedback if necessary.
22211      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22212      * @param {Event} e The event
22213      * @param {Object} data An object containing arbitrary data supplied by the drag source
22214      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22215      * underlying {@link Roo.dd.StatusProxy} can be updated
22216      */
22217     onContainerOver : function(dd, e, data){
22218         return this.dropNotAllowed;
22219     },
22220
22221     /**
22222      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22223      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22224      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22225      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22226      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22227      * @param {Event} e The event
22228      * @param {Object} data An object containing arbitrary data supplied by the drag source
22229      * @return {Boolean} True if the drop was valid, else false
22230      */
22231     onContainerDrop : function(dd, e, data){
22232         return false;
22233     },
22234
22235     /**
22236      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22237      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22238      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22239      * you should override this method and provide a custom implementation.
22240      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22241      * @param {Event} e The event
22242      * @param {Object} data An object containing arbitrary data supplied by the drag source
22243      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22244      * underlying {@link Roo.dd.StatusProxy} can be updated
22245      */
22246     notifyEnter : function(dd, e, data){
22247         return this.dropNotAllowed;
22248     },
22249
22250     /**
22251      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22252      * This method will be called on every mouse movement while the drag source is over the drop zone.
22253      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22254      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22255      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22256      * registered node, it will call {@link #onContainerOver}.
22257      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22258      * @param {Event} e The event
22259      * @param {Object} data An object containing arbitrary data supplied by the drag source
22260      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22261      * underlying {@link Roo.dd.StatusProxy} can be updated
22262      */
22263     notifyOver : function(dd, e, data){
22264         var n = this.getTargetFromEvent(e);
22265         if(!n){ // not over valid drop target
22266             if(this.lastOverNode){
22267                 this.onNodeOut(this.lastOverNode, dd, e, data);
22268                 this.lastOverNode = null;
22269             }
22270             return this.onContainerOver(dd, e, data);
22271         }
22272         if(this.lastOverNode != n){
22273             if(this.lastOverNode){
22274                 this.onNodeOut(this.lastOverNode, dd, e, data);
22275             }
22276             this.onNodeEnter(n, dd, e, data);
22277             this.lastOverNode = n;
22278         }
22279         return this.onNodeOver(n, dd, e, data);
22280     },
22281
22282     /**
22283      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22284      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22285      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22286      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22287      * @param {Event} e The event
22288      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22289      */
22290     notifyOut : function(dd, e, data){
22291         if(this.lastOverNode){
22292             this.onNodeOut(this.lastOverNode, dd, e, data);
22293             this.lastOverNode = null;
22294         }
22295     },
22296
22297     /**
22298      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22299      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22300      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22301      * otherwise it will call {@link #onContainerDrop}.
22302      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22303      * @param {Event} e The event
22304      * @param {Object} data An object containing arbitrary data supplied by the drag source
22305      * @return {Boolean} True if the drop was valid, else false
22306      */
22307     notifyDrop : function(dd, e, data){
22308         if(this.lastOverNode){
22309             this.onNodeOut(this.lastOverNode, dd, e, data);
22310             this.lastOverNode = null;
22311         }
22312         var n = this.getTargetFromEvent(e);
22313         return n ?
22314             this.onNodeDrop(n, dd, e, data) :
22315             this.onContainerDrop(dd, e, data);
22316     },
22317
22318     // private
22319     triggerCacheRefresh : function(){
22320         Roo.dd.DDM.refreshCache(this.groups);
22321     }  
22322 });