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 (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7186                     return parent;
7187                 }
7188             }
7189             
7190             return Roo.get(document.body);
7191         },
7192
7193         /**
7194          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7195          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7196          * @param {String} selector The simple selector to test
7197          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7198                 search as a number or element (defaults to 10 || document.body)
7199          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7200          */
7201         up : function(simpleSelector, maxDepth){
7202             return this.findParentNode(simpleSelector, maxDepth, true);
7203         },
7204
7205
7206
7207         /**
7208          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7209          * @param {String} selector The simple selector to test
7210          * @return {Boolean} True if this element matches the selector, else false
7211          */
7212         is : function(simpleSelector){
7213             return Roo.DomQuery.is(this.dom, simpleSelector);
7214         },
7215
7216         /**
7217          * Perform animation on this element.
7218          * @param {Object} args The YUI animation control args
7219          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7220          * @param {Function} onComplete (optional) Function to call when animation completes
7221          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7222          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7223          * @return {Roo.Element} this
7224          */
7225         animate : function(args, duration, onComplete, easing, animType){
7226             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7227             return this;
7228         },
7229
7230         /*
7231          * @private Internal animation call
7232          */
7233         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7234             animType = animType || 'run';
7235             opt = opt || {};
7236             var anim = Roo.lib.Anim[animType](
7237                 this.dom, args,
7238                 (opt.duration || defaultDur) || .35,
7239                 (opt.easing || defaultEase) || 'easeOut',
7240                 function(){
7241                     Roo.callback(cb, this);
7242                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7243                 },
7244                 this
7245             );
7246             opt.anim = anim;
7247             return anim;
7248         },
7249
7250         // private legacy anim prep
7251         preanim : function(a, i){
7252             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7253         },
7254
7255         /**
7256          * Removes worthless text nodes
7257          * @param {Boolean} forceReclean (optional) By default the element
7258          * keeps track if it has been cleaned already so
7259          * you can call this over and over. However, if you update the element and
7260          * need to force a reclean, you can pass true.
7261          */
7262         clean : function(forceReclean){
7263             if(this.isCleaned && forceReclean !== true){
7264                 return this;
7265             }
7266             var ns = /\S/;
7267             var d = this.dom, n = d.firstChild, ni = -1;
7268             while(n){
7269                 var nx = n.nextSibling;
7270                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7271                     d.removeChild(n);
7272                 }else{
7273                     n.nodeIndex = ++ni;
7274                 }
7275                 n = nx;
7276             }
7277             this.isCleaned = true;
7278             return this;
7279         },
7280
7281         // private
7282         calcOffsetsTo : function(el){
7283             el = Roo.get(el);
7284             var d = el.dom;
7285             var restorePos = false;
7286             if(el.getStyle('position') == 'static'){
7287                 el.position('relative');
7288                 restorePos = true;
7289             }
7290             var x = 0, y =0;
7291             var op = this.dom;
7292             while(op && op != d && op.tagName != 'HTML'){
7293                 x+= op.offsetLeft;
7294                 y+= op.offsetTop;
7295                 op = op.offsetParent;
7296             }
7297             if(restorePos){
7298                 el.position('static');
7299             }
7300             return [x, y];
7301         },
7302
7303         /**
7304          * Scrolls this element into view within the passed container.
7305          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7306          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7307          * @return {Roo.Element} this
7308          */
7309         scrollIntoView : function(container, hscroll){
7310             var c = Roo.getDom(container) || document.body;
7311             var el = this.dom;
7312
7313             var o = this.calcOffsetsTo(c),
7314                 l = o[0],
7315                 t = o[1],
7316                 b = t+el.offsetHeight,
7317                 r = l+el.offsetWidth;
7318
7319             var ch = c.clientHeight;
7320             var ct = parseInt(c.scrollTop, 10);
7321             var cl = parseInt(c.scrollLeft, 10);
7322             var cb = ct + ch;
7323             var cr = cl + c.clientWidth;
7324
7325             if(t < ct){
7326                 c.scrollTop = t;
7327             }else if(b > cb){
7328                 c.scrollTop = b-ch;
7329             }
7330
7331             if(hscroll !== false){
7332                 if(l < cl){
7333                     c.scrollLeft = l;
7334                 }else if(r > cr){
7335                     c.scrollLeft = r-c.clientWidth;
7336                 }
7337             }
7338             return this;
7339         },
7340
7341         // private
7342         scrollChildIntoView : function(child, hscroll){
7343             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7344         },
7345
7346         /**
7347          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7348          * the new height may not be available immediately.
7349          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7350          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7351          * @param {Function} onComplete (optional) Function to call when animation completes
7352          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7353          * @return {Roo.Element} this
7354          */
7355         autoHeight : function(animate, duration, onComplete, easing){
7356             var oldHeight = this.getHeight();
7357             this.clip();
7358             this.setHeight(1); // force clipping
7359             setTimeout(function(){
7360                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7361                 if(!animate){
7362                     this.setHeight(height);
7363                     this.unclip();
7364                     if(typeof onComplete == "function"){
7365                         onComplete();
7366                     }
7367                 }else{
7368                     this.setHeight(oldHeight); // restore original height
7369                     this.setHeight(height, animate, duration, function(){
7370                         this.unclip();
7371                         if(typeof onComplete == "function") { onComplete(); }
7372                     }.createDelegate(this), easing);
7373                 }
7374             }.createDelegate(this), 0);
7375             return this;
7376         },
7377
7378         /**
7379          * Returns true if this element is an ancestor of the passed element
7380          * @param {HTMLElement/String} el The element to check
7381          * @return {Boolean} True if this element is an ancestor of el, else false
7382          */
7383         contains : function(el){
7384             if(!el){return false;}
7385             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7386         },
7387
7388         /**
7389          * Checks whether the element is currently visible using both visibility and display properties.
7390          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7391          * @return {Boolean} True if the element is currently visible, else false
7392          */
7393         isVisible : function(deep) {
7394             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7395             if(deep !== true || !vis){
7396                 return vis;
7397             }
7398             var p = this.dom.parentNode;
7399             while(p && p.tagName.toLowerCase() != "body"){
7400                 if(!Roo.fly(p, '_isVisible').isVisible()){
7401                     return false;
7402                 }
7403                 p = p.parentNode;
7404             }
7405             return true;
7406         },
7407
7408         /**
7409          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7410          * @param {String} selector The CSS selector
7411          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7412          * @return {CompositeElement/CompositeElementLite} The composite element
7413          */
7414         select : function(selector, unique){
7415             return El.select(selector, unique, this.dom);
7416         },
7417
7418         /**
7419          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7420          * @param {String} selector The CSS selector
7421          * @return {Array} An array of the matched nodes
7422          */
7423         query : function(selector, unique){
7424             return Roo.DomQuery.select(selector, this.dom);
7425         },
7426
7427         /**
7428          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7429          * @param {String} selector The CSS selector
7430          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7431          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7432          */
7433         child : function(selector, returnDom){
7434             var n = Roo.DomQuery.selectNode(selector, this.dom);
7435             return returnDom ? n : Roo.get(n);
7436         },
7437
7438         /**
7439          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7440          * @param {String} selector The CSS selector
7441          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7442          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7443          */
7444         down : function(selector, returnDom){
7445             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7446             return returnDom ? n : Roo.get(n);
7447         },
7448
7449         /**
7450          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7451          * @param {String} group The group the DD object is member of
7452          * @param {Object} config The DD config object
7453          * @param {Object} overrides An object containing methods to override/implement on the DD object
7454          * @return {Roo.dd.DD} The DD object
7455          */
7456         initDD : function(group, config, overrides){
7457             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7458             return Roo.apply(dd, overrides);
7459         },
7460
7461         /**
7462          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7463          * @param {String} group The group the DDProxy object is member of
7464          * @param {Object} config The DDProxy config object
7465          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7466          * @return {Roo.dd.DDProxy} The DDProxy object
7467          */
7468         initDDProxy : function(group, config, overrides){
7469             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7470             return Roo.apply(dd, overrides);
7471         },
7472
7473         /**
7474          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7475          * @param {String} group The group the DDTarget object is member of
7476          * @param {Object} config The DDTarget config object
7477          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7478          * @return {Roo.dd.DDTarget} The DDTarget object
7479          */
7480         initDDTarget : function(group, config, overrides){
7481             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7482             return Roo.apply(dd, overrides);
7483         },
7484
7485         /**
7486          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7487          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7488          * @param {Boolean} visible Whether the element is visible
7489          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7490          * @return {Roo.Element} this
7491          */
7492          setVisible : function(visible, animate){
7493             if(!animate || !A){
7494                 if(this.visibilityMode == El.DISPLAY){
7495                     this.setDisplayed(visible);
7496                 }else{
7497                     this.fixDisplay();
7498                     this.dom.style.visibility = visible ? "visible" : "hidden";
7499                 }
7500             }else{
7501                 // closure for composites
7502                 var dom = this.dom;
7503                 var visMode = this.visibilityMode;
7504                 if(visible){
7505                     this.setOpacity(.01);
7506                     this.setVisible(true);
7507                 }
7508                 this.anim({opacity: { to: (visible?1:0) }},
7509                       this.preanim(arguments, 1),
7510                       null, .35, 'easeIn', function(){
7511                          if(!visible){
7512                              if(visMode == El.DISPLAY){
7513                                  dom.style.display = "none";
7514                              }else{
7515                                  dom.style.visibility = "hidden";
7516                              }
7517                              Roo.get(dom).setOpacity(1);
7518                          }
7519                      });
7520             }
7521             return this;
7522         },
7523
7524         /**
7525          * Returns true if display is not "none"
7526          * @return {Boolean}
7527          */
7528         isDisplayed : function() {
7529             return this.getStyle("display") != "none";
7530         },
7531
7532         /**
7533          * Toggles the element's visibility or display, depending on visibility mode.
7534          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7535          * @return {Roo.Element} this
7536          */
7537         toggle : function(animate){
7538             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7539             return this;
7540         },
7541
7542         /**
7543          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7544          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7545          * @return {Roo.Element} this
7546          */
7547         setDisplayed : function(value) {
7548             if(typeof value == "boolean"){
7549                value = value ? this.originalDisplay : "none";
7550             }
7551             this.setStyle("display", value);
7552             return this;
7553         },
7554
7555         /**
7556          * Tries to focus the element. Any exceptions are caught and ignored.
7557          * @return {Roo.Element} this
7558          */
7559         focus : function() {
7560             try{
7561                 this.dom.focus();
7562             }catch(e){}
7563             return this;
7564         },
7565
7566         /**
7567          * Tries to blur the element. Any exceptions are caught and ignored.
7568          * @return {Roo.Element} this
7569          */
7570         blur : function() {
7571             try{
7572                 this.dom.blur();
7573             }catch(e){}
7574             return this;
7575         },
7576
7577         /**
7578          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7579          * @param {String/Array} className The CSS class to add, or an array of classes
7580          * @return {Roo.Element} this
7581          */
7582         addClass : function(className){
7583             if(className instanceof Array){
7584                 for(var i = 0, len = className.length; i < len; i++) {
7585                     this.addClass(className[i]);
7586                 }
7587             }else{
7588                 if(className && !this.hasClass(className)){
7589                     this.dom.className = this.dom.className + " " + className;
7590                 }
7591             }
7592             return this;
7593         },
7594
7595         /**
7596          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7597          * @param {String/Array} className The CSS class to add, or an array of classes
7598          * @return {Roo.Element} this
7599          */
7600         radioClass : function(className){
7601             var siblings = this.dom.parentNode.childNodes;
7602             for(var i = 0; i < siblings.length; i++) {
7603                 var s = siblings[i];
7604                 if(s.nodeType == 1){
7605                     Roo.get(s).removeClass(className);
7606                 }
7607             }
7608             this.addClass(className);
7609             return this;
7610         },
7611
7612         /**
7613          * Removes one or more CSS classes from the element.
7614          * @param {String/Array} className The CSS class to remove, or an array of classes
7615          * @return {Roo.Element} this
7616          */
7617         removeClass : function(className){
7618             if(!className || !this.dom.className){
7619                 return this;
7620             }
7621             if(className instanceof Array){
7622                 for(var i = 0, len = className.length; i < len; i++) {
7623                     this.removeClass(className[i]);
7624                 }
7625             }else{
7626                 if(this.hasClass(className)){
7627                     var re = this.classReCache[className];
7628                     if (!re) {
7629                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7630                        this.classReCache[className] = re;
7631                     }
7632                     this.dom.className =
7633                         this.dom.className.replace(re, " ");
7634                 }
7635             }
7636             return this;
7637         },
7638
7639         // private
7640         classReCache: {},
7641
7642         /**
7643          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7644          * @param {String} className The CSS class to toggle
7645          * @return {Roo.Element} this
7646          */
7647         toggleClass : function(className){
7648             if(this.hasClass(className)){
7649                 this.removeClass(className);
7650             }else{
7651                 this.addClass(className);
7652             }
7653             return this;
7654         },
7655
7656         /**
7657          * Checks if the specified CSS class exists on this element's DOM node.
7658          * @param {String} className The CSS class to check for
7659          * @return {Boolean} True if the class exists, else false
7660          */
7661         hasClass : function(className){
7662             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7663         },
7664
7665         /**
7666          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7667          * @param {String} oldClassName The CSS class to replace
7668          * @param {String} newClassName The replacement CSS class
7669          * @return {Roo.Element} this
7670          */
7671         replaceClass : function(oldClassName, newClassName){
7672             this.removeClass(oldClassName);
7673             this.addClass(newClassName);
7674             return this;
7675         },
7676
7677         /**
7678          * Returns an object with properties matching the styles requested.
7679          * For example, el.getStyles('color', 'font-size', 'width') might return
7680          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7681          * @param {String} style1 A style name
7682          * @param {String} style2 A style name
7683          * @param {String} etc.
7684          * @return {Object} The style object
7685          */
7686         getStyles : function(){
7687             var a = arguments, len = a.length, r = {};
7688             for(var i = 0; i < len; i++){
7689                 r[a[i]] = this.getStyle(a[i]);
7690             }
7691             return r;
7692         },
7693
7694         /**
7695          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7696          * @param {String} property The style property whose value is returned.
7697          * @return {String} The current value of the style property for this element.
7698          */
7699         getStyle : function(){
7700             return view && view.getComputedStyle ?
7701                 function(prop){
7702                     var el = this.dom, v, cs, camel;
7703                     if(prop == 'float'){
7704                         prop = "cssFloat";
7705                     }
7706                     if(el.style && (v = el.style[prop])){
7707                         return v;
7708                     }
7709                     if(cs = view.getComputedStyle(el, "")){
7710                         if(!(camel = propCache[prop])){
7711                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7712                         }
7713                         return cs[camel];
7714                     }
7715                     return null;
7716                 } :
7717                 function(prop){
7718                     var el = this.dom, v, cs, camel;
7719                     if(prop == 'opacity'){
7720                         if(typeof el.style.filter == 'string'){
7721                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7722                             if(m){
7723                                 var fv = parseFloat(m[1]);
7724                                 if(!isNaN(fv)){
7725                                     return fv ? fv / 100 : 0;
7726                                 }
7727                             }
7728                         }
7729                         return 1;
7730                     }else if(prop == 'float'){
7731                         prop = "styleFloat";
7732                     }
7733                     if(!(camel = propCache[prop])){
7734                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7735                     }
7736                     if(v = el.style[camel]){
7737                         return v;
7738                     }
7739                     if(cs = el.currentStyle){
7740                         return cs[camel];
7741                     }
7742                     return null;
7743                 };
7744         }(),
7745
7746         /**
7747          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7748          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7749          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7750          * @return {Roo.Element} this
7751          */
7752         setStyle : function(prop, value){
7753             if(typeof prop == "string"){
7754                 
7755                 if (prop == 'float') {
7756                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7757                     return this;
7758                 }
7759                 
7760                 var camel;
7761                 if(!(camel = propCache[prop])){
7762                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7763                 }
7764                 
7765                 if(camel == 'opacity') {
7766                     this.setOpacity(value);
7767                 }else{
7768                     this.dom.style[camel] = value;
7769                 }
7770             }else{
7771                 for(var style in prop){
7772                     if(typeof prop[style] != "function"){
7773                        this.setStyle(style, prop[style]);
7774                     }
7775                 }
7776             }
7777             return this;
7778         },
7779
7780         /**
7781          * More flexible version of {@link #setStyle} for setting style properties.
7782          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7783          * a function which returns such a specification.
7784          * @return {Roo.Element} this
7785          */
7786         applyStyles : function(style){
7787             Roo.DomHelper.applyStyles(this.dom, style);
7788             return this;
7789         },
7790
7791         /**
7792           * 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).
7793           * @return {Number} The X position of the element
7794           */
7795         getX : function(){
7796             return D.getX(this.dom);
7797         },
7798
7799         /**
7800           * 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).
7801           * @return {Number} The Y position of the element
7802           */
7803         getY : function(){
7804             return D.getY(this.dom);
7805         },
7806
7807         /**
7808           * 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).
7809           * @return {Array} The XY position of the element
7810           */
7811         getXY : function(){
7812             return D.getXY(this.dom);
7813         },
7814
7815         /**
7816          * 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).
7817          * @param {Number} The X position of the element
7818          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7819          * @return {Roo.Element} this
7820          */
7821         setX : function(x, animate){
7822             if(!animate || !A){
7823                 D.setX(this.dom, x);
7824             }else{
7825                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7826             }
7827             return this;
7828         },
7829
7830         /**
7831          * 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).
7832          * @param {Number} The Y position of the element
7833          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7834          * @return {Roo.Element} this
7835          */
7836         setY : function(y, animate){
7837             if(!animate || !A){
7838                 D.setY(this.dom, y);
7839             }else{
7840                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7841             }
7842             return this;
7843         },
7844
7845         /**
7846          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7847          * @param {String} left The left CSS property value
7848          * @return {Roo.Element} this
7849          */
7850         setLeft : function(left){
7851             this.setStyle("left", this.addUnits(left));
7852             return this;
7853         },
7854
7855         /**
7856          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7857          * @param {String} top The top CSS property value
7858          * @return {Roo.Element} this
7859          */
7860         setTop : function(top){
7861             this.setStyle("top", this.addUnits(top));
7862             return this;
7863         },
7864
7865         /**
7866          * Sets the element's CSS right style.
7867          * @param {String} right The right CSS property value
7868          * @return {Roo.Element} this
7869          */
7870         setRight : function(right){
7871             this.setStyle("right", this.addUnits(right));
7872             return this;
7873         },
7874
7875         /**
7876          * Sets the element's CSS bottom style.
7877          * @param {String} bottom The bottom CSS property value
7878          * @return {Roo.Element} this
7879          */
7880         setBottom : function(bottom){
7881             this.setStyle("bottom", this.addUnits(bottom));
7882             return this;
7883         },
7884
7885         /**
7886          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7887          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7888          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7889          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7890          * @return {Roo.Element} this
7891          */
7892         setXY : function(pos, animate){
7893             if(!animate || !A){
7894                 D.setXY(this.dom, pos);
7895             }else{
7896                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7897             }
7898             return this;
7899         },
7900
7901         /**
7902          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7903          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7904          * @param {Number} x X value for new position (coordinates are page-based)
7905          * @param {Number} y Y value for new position (coordinates are page-based)
7906          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7907          * @return {Roo.Element} this
7908          */
7909         setLocation : function(x, y, animate){
7910             this.setXY([x, y], this.preanim(arguments, 2));
7911             return this;
7912         },
7913
7914         /**
7915          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7916          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7917          * @param {Number} x X value for new position (coordinates are page-based)
7918          * @param {Number} y Y value for new position (coordinates are page-based)
7919          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7920          * @return {Roo.Element} this
7921          */
7922         moveTo : function(x, y, animate){
7923             this.setXY([x, y], this.preanim(arguments, 2));
7924             return this;
7925         },
7926
7927         /**
7928          * Returns the region of the given element.
7929          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7930          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7931          */
7932         getRegion : function(){
7933             return D.getRegion(this.dom);
7934         },
7935
7936         /**
7937          * Returns the offset height of the element
7938          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7939          * @return {Number} The element's height
7940          */
7941         getHeight : function(contentHeight){
7942             var h = this.dom.offsetHeight || 0;
7943             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7944         },
7945
7946         /**
7947          * Returns the offset width of the element
7948          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7949          * @return {Number} The element's width
7950          */
7951         getWidth : function(contentWidth){
7952             var w = this.dom.offsetWidth || 0;
7953             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7954         },
7955
7956         /**
7957          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7958          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7959          * if a height has not been set using CSS.
7960          * @return {Number}
7961          */
7962         getComputedHeight : function(){
7963             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7964             if(!h){
7965                 h = parseInt(this.getStyle('height'), 10) || 0;
7966                 if(!this.isBorderBox()){
7967                     h += this.getFrameWidth('tb');
7968                 }
7969             }
7970             return h;
7971         },
7972
7973         /**
7974          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7975          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7976          * if a width has not been set using CSS.
7977          * @return {Number}
7978          */
7979         getComputedWidth : function(){
7980             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7981             if(!w){
7982                 w = parseInt(this.getStyle('width'), 10) || 0;
7983                 if(!this.isBorderBox()){
7984                     w += this.getFrameWidth('lr');
7985                 }
7986             }
7987             return w;
7988         },
7989
7990         /**
7991          * Returns the size of the element.
7992          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7993          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7994          */
7995         getSize : function(contentSize){
7996             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7997         },
7998
7999         /**
8000          * Returns the width and height of the viewport.
8001          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8002          */
8003         getViewSize : function(){
8004             var d = this.dom, doc = document, aw = 0, ah = 0;
8005             if(d == doc || d == doc.body){
8006                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8007             }else{
8008                 return {
8009                     width : d.clientWidth,
8010                     height: d.clientHeight
8011                 };
8012             }
8013         },
8014
8015         /**
8016          * Returns the value of the "value" attribute
8017          * @param {Boolean} asNumber true to parse the value as a number
8018          * @return {String/Number}
8019          */
8020         getValue : function(asNumber){
8021             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8022         },
8023
8024         // private
8025         adjustWidth : function(width){
8026             if(typeof width == "number"){
8027                 if(this.autoBoxAdjust && !this.isBorderBox()){
8028                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8029                 }
8030                 if(width < 0){
8031                     width = 0;
8032                 }
8033             }
8034             return width;
8035         },
8036
8037         // private
8038         adjustHeight : function(height){
8039             if(typeof height == "number"){
8040                if(this.autoBoxAdjust && !this.isBorderBox()){
8041                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8042                }
8043                if(height < 0){
8044                    height = 0;
8045                }
8046             }
8047             return height;
8048         },
8049
8050         /**
8051          * Set the width of the element
8052          * @param {Number} width The new width
8053          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8054          * @return {Roo.Element} this
8055          */
8056         setWidth : function(width, animate){
8057             width = this.adjustWidth(width);
8058             if(!animate || !A){
8059                 this.dom.style.width = this.addUnits(width);
8060             }else{
8061                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8062             }
8063             return this;
8064         },
8065
8066         /**
8067          * Set the height of the element
8068          * @param {Number} height The new height
8069          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8070          * @return {Roo.Element} this
8071          */
8072          setHeight : function(height, animate){
8073             height = this.adjustHeight(height);
8074             if(!animate || !A){
8075                 this.dom.style.height = this.addUnits(height);
8076             }else{
8077                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8078             }
8079             return this;
8080         },
8081
8082         /**
8083          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8084          * @param {Number} width The new width
8085          * @param {Number} height The new height
8086          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8087          * @return {Roo.Element} this
8088          */
8089          setSize : function(width, height, animate){
8090             if(typeof width == "object"){ // in case of object from getSize()
8091                 height = width.height; width = width.width;
8092             }
8093             width = this.adjustWidth(width); height = this.adjustHeight(height);
8094             if(!animate || !A){
8095                 this.dom.style.width = this.addUnits(width);
8096                 this.dom.style.height = this.addUnits(height);
8097             }else{
8098                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8099             }
8100             return this;
8101         },
8102
8103         /**
8104          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8105          * @param {Number} x X value for new position (coordinates are page-based)
8106          * @param {Number} y Y value for new position (coordinates are page-based)
8107          * @param {Number} width The new width
8108          * @param {Number} height The new height
8109          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8110          * @return {Roo.Element} this
8111          */
8112         setBounds : function(x, y, width, height, animate){
8113             if(!animate || !A){
8114                 this.setSize(width, height);
8115                 this.setLocation(x, y);
8116             }else{
8117                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8118                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8119                               this.preanim(arguments, 4), 'motion');
8120             }
8121             return this;
8122         },
8123
8124         /**
8125          * 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.
8126          * @param {Roo.lib.Region} region The region to fill
8127          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8128          * @return {Roo.Element} this
8129          */
8130         setRegion : function(region, animate){
8131             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8132             return this;
8133         },
8134
8135         /**
8136          * Appends an event handler
8137          *
8138          * @param {String}   eventName     The type of event to append
8139          * @param {Function} fn        The method the event invokes
8140          * @param {Object} scope       (optional) The scope (this object) of the fn
8141          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8142          */
8143         addListener : function(eventName, fn, scope, options){
8144             if (this.dom) {
8145                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8146             }
8147         },
8148
8149         /**
8150          * Removes an event handler from this element
8151          * @param {String} eventName the type of event to remove
8152          * @param {Function} fn the method the event invokes
8153          * @return {Roo.Element} this
8154          */
8155         removeListener : function(eventName, fn){
8156             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8157             return this;
8158         },
8159
8160         /**
8161          * Removes all previous added listeners from this element
8162          * @return {Roo.Element} this
8163          */
8164         removeAllListeners : function(){
8165             E.purgeElement(this.dom);
8166             return this;
8167         },
8168
8169         relayEvent : function(eventName, observable){
8170             this.on(eventName, function(e){
8171                 observable.fireEvent(eventName, e);
8172             });
8173         },
8174
8175         /**
8176          * Set the opacity of the element
8177          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8178          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8179          * @return {Roo.Element} this
8180          */
8181          setOpacity : function(opacity, animate){
8182             if(!animate || !A){
8183                 var s = this.dom.style;
8184                 if(Roo.isIE){
8185                     s.zoom = 1;
8186                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8187                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8188                 }else{
8189                     s.opacity = opacity;
8190                 }
8191             }else{
8192                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8193             }
8194             return this;
8195         },
8196
8197         /**
8198          * Gets the left X coordinate
8199          * @param {Boolean} local True to get the local css position instead of page coordinate
8200          * @return {Number}
8201          */
8202         getLeft : function(local){
8203             if(!local){
8204                 return this.getX();
8205             }else{
8206                 return parseInt(this.getStyle("left"), 10) || 0;
8207             }
8208         },
8209
8210         /**
8211          * Gets the right X coordinate of the element (element X position + element width)
8212          * @param {Boolean} local True to get the local css position instead of page coordinate
8213          * @return {Number}
8214          */
8215         getRight : function(local){
8216             if(!local){
8217                 return this.getX() + this.getWidth();
8218             }else{
8219                 return (this.getLeft(true) + this.getWidth()) || 0;
8220             }
8221         },
8222
8223         /**
8224          * Gets the top Y coordinate
8225          * @param {Boolean} local True to get the local css position instead of page coordinate
8226          * @return {Number}
8227          */
8228         getTop : function(local) {
8229             if(!local){
8230                 return this.getY();
8231             }else{
8232                 return parseInt(this.getStyle("top"), 10) || 0;
8233             }
8234         },
8235
8236         /**
8237          * Gets the bottom Y coordinate of the element (element Y position + element height)
8238          * @param {Boolean} local True to get the local css position instead of page coordinate
8239          * @return {Number}
8240          */
8241         getBottom : function(local){
8242             if(!local){
8243                 return this.getY() + this.getHeight();
8244             }else{
8245                 return (this.getTop(true) + this.getHeight()) || 0;
8246             }
8247         },
8248
8249         /**
8250         * Initializes positioning on this element. If a desired position is not passed, it will make the
8251         * the element positioned relative IF it is not already positioned.
8252         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8253         * @param {Number} zIndex (optional) The zIndex to apply
8254         * @param {Number} x (optional) Set the page X position
8255         * @param {Number} y (optional) Set the page Y position
8256         */
8257         position : function(pos, zIndex, x, y){
8258             if(!pos){
8259                if(this.getStyle('position') == 'static'){
8260                    this.setStyle('position', 'relative');
8261                }
8262             }else{
8263                 this.setStyle("position", pos);
8264             }
8265             if(zIndex){
8266                 this.setStyle("z-index", zIndex);
8267             }
8268             if(x !== undefined && y !== undefined){
8269                 this.setXY([x, y]);
8270             }else if(x !== undefined){
8271                 this.setX(x);
8272             }else if(y !== undefined){
8273                 this.setY(y);
8274             }
8275         },
8276
8277         /**
8278         * Clear positioning back to the default when the document was loaded
8279         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8280         * @return {Roo.Element} this
8281          */
8282         clearPositioning : function(value){
8283             value = value ||'';
8284             this.setStyle({
8285                 "left": value,
8286                 "right": value,
8287                 "top": value,
8288                 "bottom": value,
8289                 "z-index": "",
8290                 "position" : "static"
8291             });
8292             return this;
8293         },
8294
8295         /**
8296         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8297         * snapshot before performing an update and then restoring the element.
8298         * @return {Object}
8299         */
8300         getPositioning : function(){
8301             var l = this.getStyle("left");
8302             var t = this.getStyle("top");
8303             return {
8304                 "position" : this.getStyle("position"),
8305                 "left" : l,
8306                 "right" : l ? "" : this.getStyle("right"),
8307                 "top" : t,
8308                 "bottom" : t ? "" : this.getStyle("bottom"),
8309                 "z-index" : this.getStyle("z-index")
8310             };
8311         },
8312
8313         /**
8314          * Gets the width of the border(s) for the specified side(s)
8315          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8316          * passing lr would get the border (l)eft width + the border (r)ight width.
8317          * @return {Number} The width of the sides passed added together
8318          */
8319         getBorderWidth : function(side){
8320             return this.addStyles(side, El.borders);
8321         },
8322
8323         /**
8324          * Gets the width of the padding(s) for the specified side(s)
8325          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8326          * passing lr would get the padding (l)eft + the padding (r)ight.
8327          * @return {Number} The padding of the sides passed added together
8328          */
8329         getPadding : function(side){
8330             return this.addStyles(side, El.paddings);
8331         },
8332
8333         /**
8334         * Set positioning with an object returned by getPositioning().
8335         * @param {Object} posCfg
8336         * @return {Roo.Element} this
8337          */
8338         setPositioning : function(pc){
8339             this.applyStyles(pc);
8340             if(pc.right == "auto"){
8341                 this.dom.style.right = "";
8342             }
8343             if(pc.bottom == "auto"){
8344                 this.dom.style.bottom = "";
8345             }
8346             return this;
8347         },
8348
8349         // private
8350         fixDisplay : function(){
8351             if(this.getStyle("display") == "none"){
8352                 this.setStyle("visibility", "hidden");
8353                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8354                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8355                     this.setStyle("display", "block");
8356                 }
8357             }
8358         },
8359
8360         /**
8361          * Quick set left and top adding default units
8362          * @param {String} left The left CSS property value
8363          * @param {String} top The top CSS property value
8364          * @return {Roo.Element} this
8365          */
8366          setLeftTop : function(left, top){
8367             this.dom.style.left = this.addUnits(left);
8368             this.dom.style.top = this.addUnits(top);
8369             return this;
8370         },
8371
8372         /**
8373          * Move this element relative to its current position.
8374          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8375          * @param {Number} distance How far to move the element in pixels
8376          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8377          * @return {Roo.Element} this
8378          */
8379          move : function(direction, distance, animate){
8380             var xy = this.getXY();
8381             direction = direction.toLowerCase();
8382             switch(direction){
8383                 case "l":
8384                 case "left":
8385                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8386                     break;
8387                case "r":
8388                case "right":
8389                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8390                     break;
8391                case "t":
8392                case "top":
8393                case "up":
8394                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8395                     break;
8396                case "b":
8397                case "bottom":
8398                case "down":
8399                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8400                     break;
8401             }
8402             return this;
8403         },
8404
8405         /**
8406          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8407          * @return {Roo.Element} this
8408          */
8409         clip : function(){
8410             if(!this.isClipped){
8411                this.isClipped = true;
8412                this.originalClip = {
8413                    "o": this.getStyle("overflow"),
8414                    "x": this.getStyle("overflow-x"),
8415                    "y": this.getStyle("overflow-y")
8416                };
8417                this.setStyle("overflow", "hidden");
8418                this.setStyle("overflow-x", "hidden");
8419                this.setStyle("overflow-y", "hidden");
8420             }
8421             return this;
8422         },
8423
8424         /**
8425          *  Return clipping (overflow) to original clipping before clip() was called
8426          * @return {Roo.Element} this
8427          */
8428         unclip : function(){
8429             if(this.isClipped){
8430                 this.isClipped = false;
8431                 var o = this.originalClip;
8432                 if(o.o){this.setStyle("overflow", o.o);}
8433                 if(o.x){this.setStyle("overflow-x", o.x);}
8434                 if(o.y){this.setStyle("overflow-y", o.y);}
8435             }
8436             return this;
8437         },
8438
8439
8440         /**
8441          * Gets the x,y coordinates specified by the anchor position on the element.
8442          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8443          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8444          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8445          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8446          * @return {Array} [x, y] An array containing the element's x and y coordinates
8447          */
8448         getAnchorXY : function(anchor, local, s){
8449             //Passing a different size is useful for pre-calculating anchors,
8450             //especially for anchored animations that change the el size.
8451
8452             var w, h, vp = false;
8453             if(!s){
8454                 var d = this.dom;
8455                 if(d == document.body || d == document){
8456                     vp = true;
8457                     w = D.getViewWidth(); h = D.getViewHeight();
8458                 }else{
8459                     w = this.getWidth(); h = this.getHeight();
8460                 }
8461             }else{
8462                 w = s.width;  h = s.height;
8463             }
8464             var x = 0, y = 0, r = Math.round;
8465             switch((anchor || "tl").toLowerCase()){
8466                 case "c":
8467                     x = r(w*.5);
8468                     y = r(h*.5);
8469                 break;
8470                 case "t":
8471                     x = r(w*.5);
8472                     y = 0;
8473                 break;
8474                 case "l":
8475                     x = 0;
8476                     y = r(h*.5);
8477                 break;
8478                 case "r":
8479                     x = w;
8480                     y = r(h*.5);
8481                 break;
8482                 case "b":
8483                     x = r(w*.5);
8484                     y = h;
8485                 break;
8486                 case "tl":
8487                     x = 0;
8488                     y = 0;
8489                 break;
8490                 case "bl":
8491                     x = 0;
8492                     y = h;
8493                 break;
8494                 case "br":
8495                     x = w;
8496                     y = h;
8497                 break;
8498                 case "tr":
8499                     x = w;
8500                     y = 0;
8501                 break;
8502             }
8503             if(local === true){
8504                 return [x, y];
8505             }
8506             if(vp){
8507                 var sc = this.getScroll();
8508                 return [x + sc.left, y + sc.top];
8509             }
8510             //Add the element's offset xy
8511             var o = this.getXY();
8512             return [x+o[0], y+o[1]];
8513         },
8514
8515         /**
8516          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8517          * supported position values.
8518          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8519          * @param {String} position The position to align to.
8520          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8521          * @return {Array} [x, y]
8522          */
8523         getAlignToXY : function(el, p, o){
8524             el = Roo.get(el);
8525             var d = this.dom;
8526             if(!el.dom){
8527                 throw "Element.alignTo with an element that doesn't exist";
8528             }
8529             var c = false; //constrain to viewport
8530             var p1 = "", p2 = "";
8531             o = o || [0,0];
8532
8533             if(!p){
8534                 p = "tl-bl";
8535             }else if(p == "?"){
8536                 p = "tl-bl?";
8537             }else if(p.indexOf("-") == -1){
8538                 p = "tl-" + p;
8539             }
8540             p = p.toLowerCase();
8541             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8542             if(!m){
8543                throw "Element.alignTo with an invalid alignment " + p;
8544             }
8545             p1 = m[1]; p2 = m[2]; c = !!m[3];
8546
8547             //Subtract the aligned el's internal xy from the target's offset xy
8548             //plus custom offset to get the aligned el's new offset xy
8549             var a1 = this.getAnchorXY(p1, true);
8550             var a2 = el.getAnchorXY(p2, false);
8551             var x = a2[0] - a1[0] + o[0];
8552             var y = a2[1] - a1[1] + o[1];
8553             if(c){
8554                 //constrain the aligned el to viewport if necessary
8555                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8556                 // 5px of margin for ie
8557                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8558
8559                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8560                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8561                 //otherwise swap the aligned el to the opposite border of the target.
8562                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8563                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8564                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8565                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8566
8567                var doc = document;
8568                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8569                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8570
8571                if((x+w) > dw + scrollX){
8572                     x = swapX ? r.left-w : dw+scrollX-w;
8573                 }
8574                if(x < scrollX){
8575                    x = swapX ? r.right : scrollX;
8576                }
8577                if((y+h) > dh + scrollY){
8578                     y = swapY ? r.top-h : dh+scrollY-h;
8579                 }
8580                if (y < scrollY){
8581                    y = swapY ? r.bottom : scrollY;
8582                }
8583             }
8584             return [x,y];
8585         },
8586
8587         // private
8588         getConstrainToXY : function(){
8589             var os = {top:0, left:0, bottom:0, right: 0};
8590
8591             return function(el, local, offsets, proposedXY){
8592                 el = Roo.get(el);
8593                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8594
8595                 var vw, vh, vx = 0, vy = 0;
8596                 if(el.dom == document.body || el.dom == document){
8597                     vw = Roo.lib.Dom.getViewWidth();
8598                     vh = Roo.lib.Dom.getViewHeight();
8599                 }else{
8600                     vw = el.dom.clientWidth;
8601                     vh = el.dom.clientHeight;
8602                     if(!local){
8603                         var vxy = el.getXY();
8604                         vx = vxy[0];
8605                         vy = vxy[1];
8606                     }
8607                 }
8608
8609                 var s = el.getScroll();
8610
8611                 vx += offsets.left + s.left;
8612                 vy += offsets.top + s.top;
8613
8614                 vw -= offsets.right;
8615                 vh -= offsets.bottom;
8616
8617                 var vr = vx+vw;
8618                 var vb = vy+vh;
8619
8620                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8621                 var x = xy[0], y = xy[1];
8622                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8623
8624                 // only move it if it needs it
8625                 var moved = false;
8626
8627                 // first validate right/bottom
8628                 if((x + w) > vr){
8629                     x = vr - w;
8630                     moved = true;
8631                 }
8632                 if((y + h) > vb){
8633                     y = vb - h;
8634                     moved = true;
8635                 }
8636                 // then make sure top/left isn't negative
8637                 if(x < vx){
8638                     x = vx;
8639                     moved = true;
8640                 }
8641                 if(y < vy){
8642                     y = vy;
8643                     moved = true;
8644                 }
8645                 return moved ? [x, y] : false;
8646             };
8647         }(),
8648
8649         // private
8650         adjustForConstraints : function(xy, parent, offsets){
8651             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8652         },
8653
8654         /**
8655          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8656          * document it aligns it to the viewport.
8657          * The position parameter is optional, and can be specified in any one of the following formats:
8658          * <ul>
8659          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8660          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8661          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8662          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8663          *   <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
8664          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8665          * </ul>
8666          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8667          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8668          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8669          * that specified in order to enforce the viewport constraints.
8670          * Following are all of the supported anchor positions:
8671     <pre>
8672     Value  Description
8673     -----  -----------------------------
8674     tl     The top left corner (default)
8675     t      The center of the top edge
8676     tr     The top right corner
8677     l      The center of the left edge
8678     c      In the center of the element
8679     r      The center of the right edge
8680     bl     The bottom left corner
8681     b      The center of the bottom edge
8682     br     The bottom right corner
8683     </pre>
8684     Example Usage:
8685     <pre><code>
8686     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8687     el.alignTo("other-el");
8688
8689     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8690     el.alignTo("other-el", "tr?");
8691
8692     // align the bottom right corner of el with the center left edge of other-el
8693     el.alignTo("other-el", "br-l?");
8694
8695     // align the center of el with the bottom left corner of other-el and
8696     // adjust the x position by -6 pixels (and the y position by 0)
8697     el.alignTo("other-el", "c-bl", [-6, 0]);
8698     </code></pre>
8699          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8700          * @param {String} position The position to align to.
8701          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8702          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8703          * @return {Roo.Element} this
8704          */
8705         alignTo : function(element, position, offsets, animate){
8706             var xy = this.getAlignToXY(element, position, offsets);
8707             this.setXY(xy, this.preanim(arguments, 3));
8708             return this;
8709         },
8710
8711         /**
8712          * Anchors an element to another element and realigns it when the window is resized.
8713          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8714          * @param {String} position The position to align to.
8715          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8716          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8717          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8718          * is a number, it is used as the buffer delay (defaults to 50ms).
8719          * @param {Function} callback The function to call after the animation finishes
8720          * @return {Roo.Element} this
8721          */
8722         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8723             var action = function(){
8724                 this.alignTo(el, alignment, offsets, animate);
8725                 Roo.callback(callback, this);
8726             };
8727             Roo.EventManager.onWindowResize(action, this);
8728             var tm = typeof monitorScroll;
8729             if(tm != 'undefined'){
8730                 Roo.EventManager.on(window, 'scroll', action, this,
8731                     {buffer: tm == 'number' ? monitorScroll : 50});
8732             }
8733             action.call(this); // align immediately
8734             return this;
8735         },
8736         /**
8737          * Clears any opacity settings from this element. Required in some cases for IE.
8738          * @return {Roo.Element} this
8739          */
8740         clearOpacity : function(){
8741             if (window.ActiveXObject) {
8742                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8743                     this.dom.style.filter = "";
8744                 }
8745             } else {
8746                 this.dom.style.opacity = "";
8747                 this.dom.style["-moz-opacity"] = "";
8748                 this.dom.style["-khtml-opacity"] = "";
8749             }
8750             return this;
8751         },
8752
8753         /**
8754          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8755          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8756          * @return {Roo.Element} this
8757          */
8758         hide : function(animate){
8759             this.setVisible(false, this.preanim(arguments, 0));
8760             return this;
8761         },
8762
8763         /**
8764         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8765         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8766          * @return {Roo.Element} this
8767          */
8768         show : function(animate){
8769             this.setVisible(true, this.preanim(arguments, 0));
8770             return this;
8771         },
8772
8773         /**
8774          * @private Test if size has a unit, otherwise appends the default
8775          */
8776         addUnits : function(size){
8777             return Roo.Element.addUnits(size, this.defaultUnit);
8778         },
8779
8780         /**
8781          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8782          * @return {Roo.Element} this
8783          */
8784         beginMeasure : function(){
8785             var el = this.dom;
8786             if(el.offsetWidth || el.offsetHeight){
8787                 return this; // offsets work already
8788             }
8789             var changed = [];
8790             var p = this.dom, b = document.body; // start with this element
8791             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8792                 var pe = Roo.get(p);
8793                 if(pe.getStyle('display') == 'none'){
8794                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8795                     p.style.visibility = "hidden";
8796                     p.style.display = "block";
8797                 }
8798                 p = p.parentNode;
8799             }
8800             this._measureChanged = changed;
8801             return this;
8802
8803         },
8804
8805         /**
8806          * Restores displays to before beginMeasure was called
8807          * @return {Roo.Element} this
8808          */
8809         endMeasure : function(){
8810             var changed = this._measureChanged;
8811             if(changed){
8812                 for(var i = 0, len = changed.length; i < len; i++) {
8813                     var r = changed[i];
8814                     r.el.style.visibility = r.visibility;
8815                     r.el.style.display = "none";
8816                 }
8817                 this._measureChanged = null;
8818             }
8819             return this;
8820         },
8821
8822         /**
8823         * Update the innerHTML of this element, optionally searching for and processing scripts
8824         * @param {String} html The new HTML
8825         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8826         * @param {Function} callback For async script loading you can be noticed when the update completes
8827         * @return {Roo.Element} this
8828          */
8829         update : function(html, loadScripts, callback){
8830             if(typeof html == "undefined"){
8831                 html = "";
8832             }
8833             if(loadScripts !== true){
8834                 this.dom.innerHTML = html;
8835                 if(typeof callback == "function"){
8836                     callback();
8837                 }
8838                 return this;
8839             }
8840             var id = Roo.id();
8841             var dom = this.dom;
8842
8843             html += '<span id="' + id + '"></span>';
8844
8845             E.onAvailable(id, function(){
8846                 var hd = document.getElementsByTagName("head")[0];
8847                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8848                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8849                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8850
8851                 var match;
8852                 while(match = re.exec(html)){
8853                     var attrs = match[1];
8854                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8855                     if(srcMatch && srcMatch[2]){
8856                        var s = document.createElement("script");
8857                        s.src = srcMatch[2];
8858                        var typeMatch = attrs.match(typeRe);
8859                        if(typeMatch && typeMatch[2]){
8860                            s.type = typeMatch[2];
8861                        }
8862                        hd.appendChild(s);
8863                     }else if(match[2] && match[2].length > 0){
8864                         if(window.execScript) {
8865                            window.execScript(match[2]);
8866                         } else {
8867                             /**
8868                              * eval:var:id
8869                              * eval:var:dom
8870                              * eval:var:html
8871                              * 
8872                              */
8873                            window.eval(match[2]);
8874                         }
8875                     }
8876                 }
8877                 var el = document.getElementById(id);
8878                 if(el){el.parentNode.removeChild(el);}
8879                 if(typeof callback == "function"){
8880                     callback();
8881                 }
8882             });
8883             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8884             return this;
8885         },
8886
8887         /**
8888          * Direct access to the UpdateManager update() method (takes the same parameters).
8889          * @param {String/Function} url The url for this request or a function to call to get the url
8890          * @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}
8891          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8892          * @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.
8893          * @return {Roo.Element} this
8894          */
8895         load : function(){
8896             var um = this.getUpdateManager();
8897             um.update.apply(um, arguments);
8898             return this;
8899         },
8900
8901         /**
8902         * Gets this element's UpdateManager
8903         * @return {Roo.UpdateManager} The UpdateManager
8904         */
8905         getUpdateManager : function(){
8906             if(!this.updateManager){
8907                 this.updateManager = new Roo.UpdateManager(this);
8908             }
8909             return this.updateManager;
8910         },
8911
8912         /**
8913          * Disables text selection for this element (normalized across browsers)
8914          * @return {Roo.Element} this
8915          */
8916         unselectable : function(){
8917             this.dom.unselectable = "on";
8918             this.swallowEvent("selectstart", true);
8919             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8920             this.addClass("x-unselectable");
8921             return this;
8922         },
8923
8924         /**
8925         * Calculates the x, y to center this element on the screen
8926         * @return {Array} The x, y values [x, y]
8927         */
8928         getCenterXY : function(){
8929             return this.getAlignToXY(document, 'c-c');
8930         },
8931
8932         /**
8933         * Centers the Element in either the viewport, or another Element.
8934         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8935         */
8936         center : function(centerIn){
8937             this.alignTo(centerIn || document, 'c-c');
8938             return this;
8939         },
8940
8941         /**
8942          * Tests various css rules/browsers to determine if this element uses a border box
8943          * @return {Boolean}
8944          */
8945         isBorderBox : function(){
8946             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8947         },
8948
8949         /**
8950          * Return a box {x, y, width, height} that can be used to set another elements
8951          * size/location to match this element.
8952          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8953          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8954          * @return {Object} box An object in the format {x, y, width, height}
8955          */
8956         getBox : function(contentBox, local){
8957             var xy;
8958             if(!local){
8959                 xy = this.getXY();
8960             }else{
8961                 var left = parseInt(this.getStyle("left"), 10) || 0;
8962                 var top = parseInt(this.getStyle("top"), 10) || 0;
8963                 xy = [left, top];
8964             }
8965             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8966             if(!contentBox){
8967                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8968             }else{
8969                 var l = this.getBorderWidth("l")+this.getPadding("l");
8970                 var r = this.getBorderWidth("r")+this.getPadding("r");
8971                 var t = this.getBorderWidth("t")+this.getPadding("t");
8972                 var b = this.getBorderWidth("b")+this.getPadding("b");
8973                 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)};
8974             }
8975             bx.right = bx.x + bx.width;
8976             bx.bottom = bx.y + bx.height;
8977             return bx;
8978         },
8979
8980         /**
8981          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8982          for more information about the sides.
8983          * @param {String} sides
8984          * @return {Number}
8985          */
8986         getFrameWidth : function(sides, onlyContentBox){
8987             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8988         },
8989
8990         /**
8991          * 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.
8992          * @param {Object} box The box to fill {x, y, width, height}
8993          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8994          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8995          * @return {Roo.Element} this
8996          */
8997         setBox : function(box, adjust, animate){
8998             var w = box.width, h = box.height;
8999             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9000                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9001                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9002             }
9003             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9004             return this;
9005         },
9006
9007         /**
9008          * Forces the browser to repaint this element
9009          * @return {Roo.Element} this
9010          */
9011          repaint : function(){
9012             var dom = this.dom;
9013             this.addClass("x-repaint");
9014             setTimeout(function(){
9015                 Roo.get(dom).removeClass("x-repaint");
9016             }, 1);
9017             return this;
9018         },
9019
9020         /**
9021          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9022          * then it returns the calculated width of the sides (see getPadding)
9023          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9024          * @return {Object/Number}
9025          */
9026         getMargins : function(side){
9027             if(!side){
9028                 return {
9029                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9030                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9031                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9032                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9033                 };
9034             }else{
9035                 return this.addStyles(side, El.margins);
9036              }
9037         },
9038
9039         // private
9040         addStyles : function(sides, styles){
9041             var val = 0, v, w;
9042             for(var i = 0, len = sides.length; i < len; i++){
9043                 v = this.getStyle(styles[sides.charAt(i)]);
9044                 if(v){
9045                      w = parseInt(v, 10);
9046                      if(w){ val += w; }
9047                 }
9048             }
9049             return val;
9050         },
9051
9052         /**
9053          * Creates a proxy element of this element
9054          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9055          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9056          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9057          * @return {Roo.Element} The new proxy element
9058          */
9059         createProxy : function(config, renderTo, matchBox){
9060             if(renderTo){
9061                 renderTo = Roo.getDom(renderTo);
9062             }else{
9063                 renderTo = document.body;
9064             }
9065             config = typeof config == "object" ?
9066                 config : {tag : "div", cls: config};
9067             var proxy = Roo.DomHelper.append(renderTo, config, true);
9068             if(matchBox){
9069                proxy.setBox(this.getBox());
9070             }
9071             return proxy;
9072         },
9073
9074         /**
9075          * Puts a mask over this element to disable user interaction. Requires core.css.
9076          * This method can only be applied to elements which accept child nodes.
9077          * @param {String} msg (optional) A message to display in the mask
9078          * @param {String} msgCls (optional) A css class to apply to the msg element
9079          * @return {Element} The mask  element
9080          */
9081         mask : function(msg, msgCls)
9082         {
9083             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9084                 this.setStyle("position", "relative");
9085             }
9086             if(!this._mask){
9087                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9088             }
9089             this.addClass("x-masked");
9090             this._mask.setDisplayed(true);
9091             
9092             // we wander
9093             var z = 0;
9094             var dom = this.dom;
9095             while (dom && dom.style) {
9096                 if (!isNaN(parseInt(dom.style.zIndex))) {
9097                     z = Math.max(z, parseInt(dom.style.zIndex));
9098                 }
9099                 dom = dom.parentNode;
9100             }
9101             // if we are masking the body - then it hides everything..
9102             if (this.dom == document.body) {
9103                 z = 1000000;
9104                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9105                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9106             }
9107            
9108             if(typeof msg == 'string'){
9109                 if(!this._maskMsg){
9110                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9111                 }
9112                 var mm = this._maskMsg;
9113                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9114                 if (mm.dom.firstChild) { // weird IE issue?
9115                     mm.dom.firstChild.innerHTML = msg;
9116                 }
9117                 mm.setDisplayed(true);
9118                 mm.center(this);
9119                 mm.setStyle('z-index', z + 102);
9120             }
9121             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9122                 this._mask.setHeight(this.getHeight());
9123             }
9124             this._mask.setStyle('z-index', z + 100);
9125             
9126             return this._mask;
9127         },
9128
9129         /**
9130          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9131          * it is cached for reuse.
9132          */
9133         unmask : function(removeEl){
9134             if(this._mask){
9135                 if(removeEl === true){
9136                     this._mask.remove();
9137                     delete this._mask;
9138                     if(this._maskMsg){
9139                         this._maskMsg.remove();
9140                         delete this._maskMsg;
9141                     }
9142                 }else{
9143                     this._mask.setDisplayed(false);
9144                     if(this._maskMsg){
9145                         this._maskMsg.setDisplayed(false);
9146                     }
9147                 }
9148             }
9149             this.removeClass("x-masked");
9150         },
9151
9152         /**
9153          * Returns true if this element is masked
9154          * @return {Boolean}
9155          */
9156         isMasked : function(){
9157             return this._mask && this._mask.isVisible();
9158         },
9159
9160         /**
9161          * Creates an iframe shim for this element to keep selects and other windowed objects from
9162          * showing through.
9163          * @return {Roo.Element} The new shim element
9164          */
9165         createShim : function(){
9166             var el = document.createElement('iframe');
9167             el.frameBorder = 'no';
9168             el.className = 'roo-shim';
9169             if(Roo.isIE && Roo.isSecure){
9170                 el.src = Roo.SSL_SECURE_URL;
9171             }
9172             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9173             shim.autoBoxAdjust = false;
9174             return shim;
9175         },
9176
9177         /**
9178          * Removes this element from the DOM and deletes it from the cache
9179          */
9180         remove : function(){
9181             if(this.dom.parentNode){
9182                 this.dom.parentNode.removeChild(this.dom);
9183             }
9184             delete El.cache[this.dom.id];
9185         },
9186
9187         /**
9188          * Sets up event handlers to add and remove a css class when the mouse is over this element
9189          * @param {String} className
9190          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9191          * mouseout events for children elements
9192          * @return {Roo.Element} this
9193          */
9194         addClassOnOver : function(className, preventFlicker){
9195             this.on("mouseover", function(){
9196                 Roo.fly(this, '_internal').addClass(className);
9197             }, this.dom);
9198             var removeFn = function(e){
9199                 if(preventFlicker !== true || !e.within(this, true)){
9200                     Roo.fly(this, '_internal').removeClass(className);
9201                 }
9202             };
9203             this.on("mouseout", removeFn, this.dom);
9204             return this;
9205         },
9206
9207         /**
9208          * Sets up event handlers to add and remove a css class when this element has the focus
9209          * @param {String} className
9210          * @return {Roo.Element} this
9211          */
9212         addClassOnFocus : function(className){
9213             this.on("focus", function(){
9214                 Roo.fly(this, '_internal').addClass(className);
9215             }, this.dom);
9216             this.on("blur", function(){
9217                 Roo.fly(this, '_internal').removeClass(className);
9218             }, this.dom);
9219             return this;
9220         },
9221         /**
9222          * 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)
9223          * @param {String} className
9224          * @return {Roo.Element} this
9225          */
9226         addClassOnClick : function(className){
9227             var dom = this.dom;
9228             this.on("mousedown", function(){
9229                 Roo.fly(dom, '_internal').addClass(className);
9230                 var d = Roo.get(document);
9231                 var fn = function(){
9232                     Roo.fly(dom, '_internal').removeClass(className);
9233                     d.removeListener("mouseup", fn);
9234                 };
9235                 d.on("mouseup", fn);
9236             });
9237             return this;
9238         },
9239
9240         /**
9241          * Stops the specified event from bubbling and optionally prevents the default action
9242          * @param {String} eventName
9243          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9244          * @return {Roo.Element} this
9245          */
9246         swallowEvent : function(eventName, preventDefault){
9247             var fn = function(e){
9248                 e.stopPropagation();
9249                 if(preventDefault){
9250                     e.preventDefault();
9251                 }
9252             };
9253             if(eventName instanceof Array){
9254                 for(var i = 0, len = eventName.length; i < len; i++){
9255                      this.on(eventName[i], fn);
9256                 }
9257                 return this;
9258             }
9259             this.on(eventName, fn);
9260             return this;
9261         },
9262
9263         /**
9264          * @private
9265          */
9266       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9267
9268         /**
9269          * Sizes this element to its parent element's dimensions performing
9270          * neccessary box adjustments.
9271          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9272          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9273          * @return {Roo.Element} this
9274          */
9275         fitToParent : function(monitorResize, targetParent) {
9276           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9277           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9278           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9279             return;
9280           }
9281           var p = Roo.get(targetParent || this.dom.parentNode);
9282           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9283           if (monitorResize === true) {
9284             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9285             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9286           }
9287           return this;
9288         },
9289
9290         /**
9291          * Gets the next sibling, skipping text nodes
9292          * @return {HTMLElement} The next sibling or null
9293          */
9294         getNextSibling : function(){
9295             var n = this.dom.nextSibling;
9296             while(n && n.nodeType != 1){
9297                 n = n.nextSibling;
9298             }
9299             return n;
9300         },
9301
9302         /**
9303          * Gets the previous sibling, skipping text nodes
9304          * @return {HTMLElement} The previous sibling or null
9305          */
9306         getPrevSibling : function(){
9307             var n = this.dom.previousSibling;
9308             while(n && n.nodeType != 1){
9309                 n = n.previousSibling;
9310             }
9311             return n;
9312         },
9313
9314
9315         /**
9316          * Appends the passed element(s) to this element
9317          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9318          * @return {Roo.Element} this
9319          */
9320         appendChild: function(el){
9321             el = Roo.get(el);
9322             el.appendTo(this);
9323             return this;
9324         },
9325
9326         /**
9327          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9328          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9329          * automatically generated with the specified attributes.
9330          * @param {HTMLElement} insertBefore (optional) a child element of this element
9331          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9332          * @return {Roo.Element} The new child element
9333          */
9334         createChild: function(config, insertBefore, returnDom){
9335             config = config || {tag:'div'};
9336             if(insertBefore){
9337                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9338             }
9339             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9340         },
9341
9342         /**
9343          * Appends this element to the passed element
9344          * @param {String/HTMLElement/Element} el The new parent element
9345          * @return {Roo.Element} this
9346          */
9347         appendTo: function(el){
9348             el = Roo.getDom(el);
9349             el.appendChild(this.dom);
9350             return this;
9351         },
9352
9353         /**
9354          * Inserts this element before the passed element in the DOM
9355          * @param {String/HTMLElement/Element} el The element to insert before
9356          * @return {Roo.Element} this
9357          */
9358         insertBefore: function(el){
9359             el = Roo.getDom(el);
9360             el.parentNode.insertBefore(this.dom, el);
9361             return this;
9362         },
9363
9364         /**
9365          * Inserts this element after the passed element in the DOM
9366          * @param {String/HTMLElement/Element} el The element to insert after
9367          * @return {Roo.Element} this
9368          */
9369         insertAfter: function(el){
9370             el = Roo.getDom(el);
9371             el.parentNode.insertBefore(this.dom, el.nextSibling);
9372             return this;
9373         },
9374
9375         /**
9376          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9377          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9378          * @return {Roo.Element} The new child
9379          */
9380         insertFirst: function(el, returnDom){
9381             el = el || {};
9382             if(typeof el == 'object' && !el.nodeType){ // dh config
9383                 return this.createChild(el, this.dom.firstChild, returnDom);
9384             }else{
9385                 el = Roo.getDom(el);
9386                 this.dom.insertBefore(el, this.dom.firstChild);
9387                 return !returnDom ? Roo.get(el) : el;
9388             }
9389         },
9390
9391         /**
9392          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9393          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9394          * @param {String} where (optional) 'before' or 'after' defaults to before
9395          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9396          * @return {Roo.Element} the inserted Element
9397          */
9398         insertSibling: function(el, where, returnDom){
9399             where = where ? where.toLowerCase() : 'before';
9400             el = el || {};
9401             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9402
9403             if(typeof el == 'object' && !el.nodeType){ // dh config
9404                 if(where == 'after' && !this.dom.nextSibling){
9405                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9406                 }else{
9407                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9408                 }
9409
9410             }else{
9411                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9412                             where == 'before' ? this.dom : this.dom.nextSibling);
9413                 if(!returnDom){
9414                     rt = Roo.get(rt);
9415                 }
9416             }
9417             return rt;
9418         },
9419
9420         /**
9421          * Creates and wraps this element with another element
9422          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9423          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9424          * @return {HTMLElement/Element} The newly created wrapper element
9425          */
9426         wrap: function(config, returnDom){
9427             if(!config){
9428                 config = {tag: "div"};
9429             }
9430             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9431             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9432             return newEl;
9433         },
9434
9435         /**
9436          * Replaces the passed element with this element
9437          * @param {String/HTMLElement/Element} el The element to replace
9438          * @return {Roo.Element} this
9439          */
9440         replace: function(el){
9441             el = Roo.get(el);
9442             this.insertBefore(el);
9443             el.remove();
9444             return this;
9445         },
9446
9447         /**
9448          * Inserts an html fragment into this element
9449          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9450          * @param {String} html The HTML fragment
9451          * @param {Boolean} returnEl True to return an Roo.Element
9452          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9453          */
9454         insertHtml : function(where, html, returnEl){
9455             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9456             return returnEl ? Roo.get(el) : el;
9457         },
9458
9459         /**
9460          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9461          * @param {Object} o The object with the attributes
9462          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9463          * @return {Roo.Element} this
9464          */
9465         set : function(o, useSet){
9466             var el = this.dom;
9467             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9468             for(var attr in o){
9469                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9470                 if(attr=="cls"){
9471                     el.className = o["cls"];
9472                 }else{
9473                     if(useSet) {
9474                         el.setAttribute(attr, o[attr]);
9475                     } else {
9476                         el[attr] = o[attr];
9477                     }
9478                 }
9479             }
9480             if(o.style){
9481                 Roo.DomHelper.applyStyles(el, o.style);
9482             }
9483             return this;
9484         },
9485
9486         /**
9487          * Convenience method for constructing a KeyMap
9488          * @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:
9489          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9490          * @param {Function} fn The function to call
9491          * @param {Object} scope (optional) The scope of the function
9492          * @return {Roo.KeyMap} The KeyMap created
9493          */
9494         addKeyListener : function(key, fn, scope){
9495             var config;
9496             if(typeof key != "object" || key instanceof Array){
9497                 config = {
9498                     key: key,
9499                     fn: fn,
9500                     scope: scope
9501                 };
9502             }else{
9503                 config = {
9504                     key : key.key,
9505                     shift : key.shift,
9506                     ctrl : key.ctrl,
9507                     alt : key.alt,
9508                     fn: fn,
9509                     scope: scope
9510                 };
9511             }
9512             return new Roo.KeyMap(this, config);
9513         },
9514
9515         /**
9516          * Creates a KeyMap for this element
9517          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9518          * @return {Roo.KeyMap} The KeyMap created
9519          */
9520         addKeyMap : function(config){
9521             return new Roo.KeyMap(this, config);
9522         },
9523
9524         /**
9525          * Returns true if this element is scrollable.
9526          * @return {Boolean}
9527          */
9528          isScrollable : function(){
9529             var dom = this.dom;
9530             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9531         },
9532
9533         /**
9534          * 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().
9535          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9536          * @param {Number} value The new scroll value
9537          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9538          * @return {Element} this
9539          */
9540
9541         scrollTo : function(side, value, animate){
9542             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9543             if(!animate || !A){
9544                 this.dom[prop] = value;
9545             }else{
9546                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9547                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9548             }
9549             return this;
9550         },
9551
9552         /**
9553          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9554          * within this element's scrollable range.
9555          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9556          * @param {Number} distance How far to scroll the element in pixels
9557          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9558          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9559          * was scrolled as far as it could go.
9560          */
9561          scroll : function(direction, distance, animate){
9562              if(!this.isScrollable()){
9563                  return;
9564              }
9565              var el = this.dom;
9566              var l = el.scrollLeft, t = el.scrollTop;
9567              var w = el.scrollWidth, h = el.scrollHeight;
9568              var cw = el.clientWidth, ch = el.clientHeight;
9569              direction = direction.toLowerCase();
9570              var scrolled = false;
9571              var a = this.preanim(arguments, 2);
9572              switch(direction){
9573                  case "l":
9574                  case "left":
9575                      if(w - l > cw){
9576                          var v = Math.min(l + distance, w-cw);
9577                          this.scrollTo("left", v, a);
9578                          scrolled = true;
9579                      }
9580                      break;
9581                 case "r":
9582                 case "right":
9583                      if(l > 0){
9584                          var v = Math.max(l - distance, 0);
9585                          this.scrollTo("left", v, a);
9586                          scrolled = true;
9587                      }
9588                      break;
9589                 case "t":
9590                 case "top":
9591                 case "up":
9592                      if(t > 0){
9593                          var v = Math.max(t - distance, 0);
9594                          this.scrollTo("top", v, a);
9595                          scrolled = true;
9596                      }
9597                      break;
9598                 case "b":
9599                 case "bottom":
9600                 case "down":
9601                      if(h - t > ch){
9602                          var v = Math.min(t + distance, h-ch);
9603                          this.scrollTo("top", v, a);
9604                          scrolled = true;
9605                      }
9606                      break;
9607              }
9608              return scrolled;
9609         },
9610
9611         /**
9612          * Translates the passed page coordinates into left/top css values for this element
9613          * @param {Number/Array} x The page x or an array containing [x, y]
9614          * @param {Number} y The page y
9615          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9616          */
9617         translatePoints : function(x, y){
9618             if(typeof x == 'object' || x instanceof Array){
9619                 y = x[1]; x = x[0];
9620             }
9621             var p = this.getStyle('position');
9622             var o = this.getXY();
9623
9624             var l = parseInt(this.getStyle('left'), 10);
9625             var t = parseInt(this.getStyle('top'), 10);
9626
9627             if(isNaN(l)){
9628                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9629             }
9630             if(isNaN(t)){
9631                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9632             }
9633
9634             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9635         },
9636
9637         /**
9638          * Returns the current scroll position of the element.
9639          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9640          */
9641         getScroll : function(){
9642             var d = this.dom, doc = document;
9643             if(d == doc || d == doc.body){
9644                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9645                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9646                 return {left: l, top: t};
9647             }else{
9648                 return {left: d.scrollLeft, top: d.scrollTop};
9649             }
9650         },
9651
9652         /**
9653          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9654          * are convert to standard 6 digit hex color.
9655          * @param {String} attr The css attribute
9656          * @param {String} defaultValue The default value to use when a valid color isn't found
9657          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9658          * YUI color anims.
9659          */
9660         getColor : function(attr, defaultValue, prefix){
9661             var v = this.getStyle(attr);
9662             if(!v || v == "transparent" || v == "inherit") {
9663                 return defaultValue;
9664             }
9665             var color = typeof prefix == "undefined" ? "#" : prefix;
9666             if(v.substr(0, 4) == "rgb("){
9667                 var rvs = v.slice(4, v.length -1).split(",");
9668                 for(var i = 0; i < 3; i++){
9669                     var h = parseInt(rvs[i]).toString(16);
9670                     if(h < 16){
9671                         h = "0" + h;
9672                     }
9673                     color += h;
9674                 }
9675             } else {
9676                 if(v.substr(0, 1) == "#"){
9677                     if(v.length == 4) {
9678                         for(var i = 1; i < 4; i++){
9679                             var c = v.charAt(i);
9680                             color +=  c + c;
9681                         }
9682                     }else if(v.length == 7){
9683                         color += v.substr(1);
9684                     }
9685                 }
9686             }
9687             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9688         },
9689
9690         /**
9691          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9692          * gradient background, rounded corners and a 4-way shadow.
9693          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9694          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9695          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9696          * @return {Roo.Element} this
9697          */
9698         boxWrap : function(cls){
9699             cls = cls || 'x-box';
9700             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9701             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9702             return el;
9703         },
9704
9705         /**
9706          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9707          * @param {String} namespace The namespace in which to look for the attribute
9708          * @param {String} name The attribute name
9709          * @return {String} The attribute value
9710          */
9711         getAttributeNS : Roo.isIE ? function(ns, name){
9712             var d = this.dom;
9713             var type = typeof d[ns+":"+name];
9714             if(type != 'undefined' && type != 'unknown'){
9715                 return d[ns+":"+name];
9716             }
9717             return d[name];
9718         } : function(ns, name){
9719             var d = this.dom;
9720             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9721         },
9722         
9723         
9724         /**
9725          * Sets or Returns the value the dom attribute value
9726          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9727          * @param {String} value (optional) The value to set the attribute to
9728          * @return {String} The attribute value
9729          */
9730         attr : function(name){
9731             if (arguments.length > 1) {
9732                 this.dom.setAttribute(name, arguments[1]);
9733                 return arguments[1];
9734             }
9735             if (typeof(name) == 'object') {
9736                 for(var i in name) {
9737                     this.attr(i, name[i]);
9738                 }
9739                 return name;
9740             }
9741             
9742             
9743             if (!this.dom.hasAttribute(name)) {
9744                 return undefined;
9745             }
9746             return this.dom.getAttribute(name);
9747         }
9748         
9749         
9750         
9751     };
9752
9753     var ep = El.prototype;
9754
9755     /**
9756      * Appends an event handler (Shorthand for addListener)
9757      * @param {String}   eventName     The type of event to append
9758      * @param {Function} fn        The method the event invokes
9759      * @param {Object} scope       (optional) The scope (this object) of the fn
9760      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9761      * @method
9762      */
9763     ep.on = ep.addListener;
9764         // backwards compat
9765     ep.mon = ep.addListener;
9766
9767     /**
9768      * Removes an event handler from this element (shorthand for removeListener)
9769      * @param {String} eventName the type of event to remove
9770      * @param {Function} fn the method the event invokes
9771      * @return {Roo.Element} this
9772      * @method
9773      */
9774     ep.un = ep.removeListener;
9775
9776     /**
9777      * true to automatically adjust width and height settings for box-model issues (default to true)
9778      */
9779     ep.autoBoxAdjust = true;
9780
9781     // private
9782     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9783
9784     // private
9785     El.addUnits = function(v, defaultUnit){
9786         if(v === "" || v == "auto"){
9787             return v;
9788         }
9789         if(v === undefined){
9790             return '';
9791         }
9792         if(typeof v == "number" || !El.unitPattern.test(v)){
9793             return v + (defaultUnit || 'px');
9794         }
9795         return v;
9796     };
9797
9798     // special markup used throughout Roo when box wrapping elements
9799     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>';
9800     /**
9801      * Visibility mode constant - Use visibility to hide element
9802      * @static
9803      * @type Number
9804      */
9805     El.VISIBILITY = 1;
9806     /**
9807      * Visibility mode constant - Use display to hide element
9808      * @static
9809      * @type Number
9810      */
9811     El.DISPLAY = 2;
9812
9813     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9814     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9815     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9816
9817
9818
9819     /**
9820      * @private
9821      */
9822     El.cache = {};
9823
9824     var docEl;
9825
9826     /**
9827      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9828      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9829      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9830      * @return {Element} The Element object
9831      * @static
9832      */
9833     El.get = function(el){
9834         var ex, elm, id;
9835         if(!el){ return null; }
9836         if(typeof el == "string"){ // element id
9837             if(!(elm = document.getElementById(el))){
9838                 return null;
9839             }
9840             if(ex = El.cache[el]){
9841                 ex.dom = elm;
9842             }else{
9843                 ex = El.cache[el] = new El(elm);
9844             }
9845             return ex;
9846         }else if(el.tagName){ // dom element
9847             if(!(id = el.id)){
9848                 id = Roo.id(el);
9849             }
9850             if(ex = El.cache[id]){
9851                 ex.dom = el;
9852             }else{
9853                 ex = El.cache[id] = new El(el);
9854             }
9855             return ex;
9856         }else if(el instanceof El){
9857             if(el != docEl){
9858                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9859                                                               // catch case where it hasn't been appended
9860                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9861             }
9862             return el;
9863         }else if(el.isComposite){
9864             return el;
9865         }else if(el instanceof Array){
9866             return El.select(el);
9867         }else if(el == document){
9868             // create a bogus element object representing the document object
9869             if(!docEl){
9870                 var f = function(){};
9871                 f.prototype = El.prototype;
9872                 docEl = new f();
9873                 docEl.dom = document;
9874             }
9875             return docEl;
9876         }
9877         return null;
9878     };
9879
9880     // private
9881     El.uncache = function(el){
9882         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9883             if(a[i]){
9884                 delete El.cache[a[i].id || a[i]];
9885             }
9886         }
9887     };
9888
9889     // private
9890     // Garbage collection - uncache elements/purge listeners on orphaned elements
9891     // so we don't hold a reference and cause the browser to retain them
9892     El.garbageCollect = function(){
9893         if(!Roo.enableGarbageCollector){
9894             clearInterval(El.collectorThread);
9895             return;
9896         }
9897         for(var eid in El.cache){
9898             var el = El.cache[eid], d = el.dom;
9899             // -------------------------------------------------------
9900             // Determining what is garbage:
9901             // -------------------------------------------------------
9902             // !d
9903             // dom node is null, definitely garbage
9904             // -------------------------------------------------------
9905             // !d.parentNode
9906             // no parentNode == direct orphan, definitely garbage
9907             // -------------------------------------------------------
9908             // !d.offsetParent && !document.getElementById(eid)
9909             // display none elements have no offsetParent so we will
9910             // also try to look it up by it's id. However, check
9911             // offsetParent first so we don't do unneeded lookups.
9912             // This enables collection of elements that are not orphans
9913             // directly, but somewhere up the line they have an orphan
9914             // parent.
9915             // -------------------------------------------------------
9916             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9917                 delete El.cache[eid];
9918                 if(d && Roo.enableListenerCollection){
9919                     E.purgeElement(d);
9920                 }
9921             }
9922         }
9923     }
9924     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9925
9926
9927     // dom is optional
9928     El.Flyweight = function(dom){
9929         this.dom = dom;
9930     };
9931     El.Flyweight.prototype = El.prototype;
9932
9933     El._flyweights = {};
9934     /**
9935      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9936      * the dom node can be overwritten by other code.
9937      * @param {String/HTMLElement} el The dom node or id
9938      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9939      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9940      * @static
9941      * @return {Element} The shared Element object
9942      */
9943     El.fly = function(el, named){
9944         named = named || '_global';
9945         el = Roo.getDom(el);
9946         if(!el){
9947             return null;
9948         }
9949         if(!El._flyweights[named]){
9950             El._flyweights[named] = new El.Flyweight();
9951         }
9952         El._flyweights[named].dom = el;
9953         return El._flyweights[named];
9954     };
9955
9956     /**
9957      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9958      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9959      * Shorthand of {@link Roo.Element#get}
9960      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9961      * @return {Element} The Element object
9962      * @member Roo
9963      * @method get
9964      */
9965     Roo.get = El.get;
9966     /**
9967      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9968      * the dom node can be overwritten by other code.
9969      * Shorthand of {@link Roo.Element#fly}
9970      * @param {String/HTMLElement} el The dom node or id
9971      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9972      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9973      * @static
9974      * @return {Element} The shared Element object
9975      * @member Roo
9976      * @method fly
9977      */
9978     Roo.fly = El.fly;
9979
9980     // speedy lookup for elements never to box adjust
9981     var noBoxAdjust = Roo.isStrict ? {
9982         select:1
9983     } : {
9984         input:1, select:1, textarea:1
9985     };
9986     if(Roo.isIE || Roo.isGecko){
9987         noBoxAdjust['button'] = 1;
9988     }
9989
9990
9991     Roo.EventManager.on(window, 'unload', function(){
9992         delete El.cache;
9993         delete El._flyweights;
9994     });
9995 })();
9996
9997
9998
9999
10000 if(Roo.DomQuery){
10001     Roo.Element.selectorFunction = Roo.DomQuery.select;
10002 }
10003
10004 Roo.Element.select = function(selector, unique, root){
10005     var els;
10006     if(typeof selector == "string"){
10007         els = Roo.Element.selectorFunction(selector, root);
10008     }else if(selector.length !== undefined){
10009         els = selector;
10010     }else{
10011         throw "Invalid selector";
10012     }
10013     if(unique === true){
10014         return new Roo.CompositeElement(els);
10015     }else{
10016         return new Roo.CompositeElementLite(els);
10017     }
10018 };
10019 /**
10020  * Selects elements based on the passed CSS selector to enable working on them as 1.
10021  * @param {String/Array} selector The CSS selector or an array of elements
10022  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10023  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10024  * @return {CompositeElementLite/CompositeElement}
10025  * @member Roo
10026  * @method select
10027  */
10028 Roo.select = Roo.Element.select;
10029
10030
10031
10032
10033
10034
10035
10036
10037
10038
10039
10040
10041
10042
10043 /*
10044  * Based on:
10045  * Ext JS Library 1.1.1
10046  * Copyright(c) 2006-2007, Ext JS, LLC.
10047  *
10048  * Originally Released Under LGPL - original licence link has changed is not relivant.
10049  *
10050  * Fork - LGPL
10051  * <script type="text/javascript">
10052  */
10053
10054
10055
10056 //Notifies Element that fx methods are available
10057 Roo.enableFx = true;
10058
10059 /**
10060  * @class Roo.Fx
10061  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10062  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10063  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10064  * Element effects to work.</p><br/>
10065  *
10066  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10067  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10068  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10069  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10070  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10071  * expected results and should be done with care.</p><br/>
10072  *
10073  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10074  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10075 <pre>
10076 Value  Description
10077 -----  -----------------------------
10078 tl     The top left corner
10079 t      The center of the top edge
10080 tr     The top right corner
10081 l      The center of the left edge
10082 r      The center of the right edge
10083 bl     The bottom left corner
10084 b      The center of the bottom edge
10085 br     The bottom right corner
10086 </pre>
10087  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10088  * below are common options that can be passed to any Fx method.</b>
10089  * @cfg {Function} callback A function called when the effect is finished
10090  * @cfg {Object} scope The scope of the effect function
10091  * @cfg {String} easing A valid Easing value for the effect
10092  * @cfg {String} afterCls A css class to apply after the effect
10093  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10094  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10095  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10096  * effects that end with the element being visually hidden, ignored otherwise)
10097  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10098  * a function which returns such a specification that will be applied to the Element after the effect finishes
10099  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10100  * @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
10101  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10102  */
10103 Roo.Fx = {
10104         /**
10105          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10106          * origin for the slide effect.  This function automatically handles wrapping the element with
10107          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10108          * Usage:
10109          *<pre><code>
10110 // default: slide the element in from the top
10111 el.slideIn();
10112
10113 // custom: slide the element in from the right with a 2-second duration
10114 el.slideIn('r', { duration: 2 });
10115
10116 // common config options shown with default values
10117 el.slideIn('t', {
10118     easing: 'easeOut',
10119     duration: .5
10120 });
10121 </code></pre>
10122          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10123          * @param {Object} options (optional) Object literal with any of the Fx config options
10124          * @return {Roo.Element} The Element
10125          */
10126     slideIn : function(anchor, o){
10127         var el = this.getFxEl();
10128         o = o || {};
10129
10130         el.queueFx(o, function(){
10131
10132             anchor = anchor || "t";
10133
10134             // fix display to visibility
10135             this.fixDisplay();
10136
10137             // restore values after effect
10138             var r = this.getFxRestore();
10139             var b = this.getBox();
10140             // fixed size for slide
10141             this.setSize(b);
10142
10143             // wrap if needed
10144             var wrap = this.fxWrap(r.pos, o, "hidden");
10145
10146             var st = this.dom.style;
10147             st.visibility = "visible";
10148             st.position = "absolute";
10149
10150             // clear out temp styles after slide and unwrap
10151             var after = function(){
10152                 el.fxUnwrap(wrap, r.pos, o);
10153                 st.width = r.width;
10154                 st.height = r.height;
10155                 el.afterFx(o);
10156             };
10157             // time to calc the positions
10158             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10159
10160             switch(anchor.toLowerCase()){
10161                 case "t":
10162                     wrap.setSize(b.width, 0);
10163                     st.left = st.bottom = "0";
10164                     a = {height: bh};
10165                 break;
10166                 case "l":
10167                     wrap.setSize(0, b.height);
10168                     st.right = st.top = "0";
10169                     a = {width: bw};
10170                 break;
10171                 case "r":
10172                     wrap.setSize(0, b.height);
10173                     wrap.setX(b.right);
10174                     st.left = st.top = "0";
10175                     a = {width: bw, points: pt};
10176                 break;
10177                 case "b":
10178                     wrap.setSize(b.width, 0);
10179                     wrap.setY(b.bottom);
10180                     st.left = st.top = "0";
10181                     a = {height: bh, points: pt};
10182                 break;
10183                 case "tl":
10184                     wrap.setSize(0, 0);
10185                     st.right = st.bottom = "0";
10186                     a = {width: bw, height: bh};
10187                 break;
10188                 case "bl":
10189                     wrap.setSize(0, 0);
10190                     wrap.setY(b.y+b.height);
10191                     st.right = st.top = "0";
10192                     a = {width: bw, height: bh, points: pt};
10193                 break;
10194                 case "br":
10195                     wrap.setSize(0, 0);
10196                     wrap.setXY([b.right, b.bottom]);
10197                     st.left = st.top = "0";
10198                     a = {width: bw, height: bh, points: pt};
10199                 break;
10200                 case "tr":
10201                     wrap.setSize(0, 0);
10202                     wrap.setX(b.x+b.width);
10203                     st.left = st.bottom = "0";
10204                     a = {width: bw, height: bh, points: pt};
10205                 break;
10206             }
10207             this.dom.style.visibility = "visible";
10208             wrap.show();
10209
10210             arguments.callee.anim = wrap.fxanim(a,
10211                 o,
10212                 'motion',
10213                 .5,
10214                 'easeOut', after);
10215         });
10216         return this;
10217     },
10218     
10219         /**
10220          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10221          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10222          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10223          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10224          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10225          * Usage:
10226          *<pre><code>
10227 // default: slide the element out to the top
10228 el.slideOut();
10229
10230 // custom: slide the element out to the right with a 2-second duration
10231 el.slideOut('r', { duration: 2 });
10232
10233 // common config options shown with default values
10234 el.slideOut('t', {
10235     easing: 'easeOut',
10236     duration: .5,
10237     remove: false,
10238     useDisplay: false
10239 });
10240 </code></pre>
10241          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10242          * @param {Object} options (optional) Object literal with any of the Fx config options
10243          * @return {Roo.Element} The Element
10244          */
10245     slideOut : function(anchor, o){
10246         var el = this.getFxEl();
10247         o = o || {};
10248
10249         el.queueFx(o, function(){
10250
10251             anchor = anchor || "t";
10252
10253             // restore values after effect
10254             var r = this.getFxRestore();
10255             
10256             var b = this.getBox();
10257             // fixed size for slide
10258             this.setSize(b);
10259
10260             // wrap if needed
10261             var wrap = this.fxWrap(r.pos, o, "visible");
10262
10263             var st = this.dom.style;
10264             st.visibility = "visible";
10265             st.position = "absolute";
10266
10267             wrap.setSize(b);
10268
10269             var after = function(){
10270                 if(o.useDisplay){
10271                     el.setDisplayed(false);
10272                 }else{
10273                     el.hide();
10274                 }
10275
10276                 el.fxUnwrap(wrap, r.pos, o);
10277
10278                 st.width = r.width;
10279                 st.height = r.height;
10280
10281                 el.afterFx(o);
10282             };
10283
10284             var a, zero = {to: 0};
10285             switch(anchor.toLowerCase()){
10286                 case "t":
10287                     st.left = st.bottom = "0";
10288                     a = {height: zero};
10289                 break;
10290                 case "l":
10291                     st.right = st.top = "0";
10292                     a = {width: zero};
10293                 break;
10294                 case "r":
10295                     st.left = st.top = "0";
10296                     a = {width: zero, points: {to:[b.right, b.y]}};
10297                 break;
10298                 case "b":
10299                     st.left = st.top = "0";
10300                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10301                 break;
10302                 case "tl":
10303                     st.right = st.bottom = "0";
10304                     a = {width: zero, height: zero};
10305                 break;
10306                 case "bl":
10307                     st.right = st.top = "0";
10308                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10309                 break;
10310                 case "br":
10311                     st.left = st.top = "0";
10312                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10313                 break;
10314                 case "tr":
10315                     st.left = st.bottom = "0";
10316                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10317                 break;
10318             }
10319
10320             arguments.callee.anim = wrap.fxanim(a,
10321                 o,
10322                 'motion',
10323                 .5,
10324                 "easeOut", after);
10325         });
10326         return this;
10327     },
10328
10329         /**
10330          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10331          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10332          * The element must be removed from the DOM using the 'remove' config option if desired.
10333          * Usage:
10334          *<pre><code>
10335 // default
10336 el.puff();
10337
10338 // common config options shown with default values
10339 el.puff({
10340     easing: 'easeOut',
10341     duration: .5,
10342     remove: false,
10343     useDisplay: false
10344 });
10345 </code></pre>
10346          * @param {Object} options (optional) Object literal with any of the Fx config options
10347          * @return {Roo.Element} The Element
10348          */
10349     puff : function(o){
10350         var el = this.getFxEl();
10351         o = o || {};
10352
10353         el.queueFx(o, function(){
10354             this.clearOpacity();
10355             this.show();
10356
10357             // restore values after effect
10358             var r = this.getFxRestore();
10359             var st = this.dom.style;
10360
10361             var after = function(){
10362                 if(o.useDisplay){
10363                     el.setDisplayed(false);
10364                 }else{
10365                     el.hide();
10366                 }
10367
10368                 el.clearOpacity();
10369
10370                 el.setPositioning(r.pos);
10371                 st.width = r.width;
10372                 st.height = r.height;
10373                 st.fontSize = '';
10374                 el.afterFx(o);
10375             };
10376
10377             var width = this.getWidth();
10378             var height = this.getHeight();
10379
10380             arguments.callee.anim = this.fxanim({
10381                     width : {to: this.adjustWidth(width * 2)},
10382                     height : {to: this.adjustHeight(height * 2)},
10383                     points : {by: [-(width * .5), -(height * .5)]},
10384                     opacity : {to: 0},
10385                     fontSize: {to:200, unit: "%"}
10386                 },
10387                 o,
10388                 'motion',
10389                 .5,
10390                 "easeOut", after);
10391         });
10392         return this;
10393     },
10394
10395         /**
10396          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10397          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10398          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10399          * Usage:
10400          *<pre><code>
10401 // default
10402 el.switchOff();
10403
10404 // all config options shown with default values
10405 el.switchOff({
10406     easing: 'easeIn',
10407     duration: .3,
10408     remove: false,
10409     useDisplay: false
10410 });
10411 </code></pre>
10412          * @param {Object} options (optional) Object literal with any of the Fx config options
10413          * @return {Roo.Element} The Element
10414          */
10415     switchOff : function(o){
10416         var el = this.getFxEl();
10417         o = o || {};
10418
10419         el.queueFx(o, function(){
10420             this.clearOpacity();
10421             this.clip();
10422
10423             // restore values after effect
10424             var r = this.getFxRestore();
10425             var st = this.dom.style;
10426
10427             var after = function(){
10428                 if(o.useDisplay){
10429                     el.setDisplayed(false);
10430                 }else{
10431                     el.hide();
10432                 }
10433
10434                 el.clearOpacity();
10435                 el.setPositioning(r.pos);
10436                 st.width = r.width;
10437                 st.height = r.height;
10438
10439                 el.afterFx(o);
10440             };
10441
10442             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10443                 this.clearOpacity();
10444                 (function(){
10445                     this.fxanim({
10446                         height:{to:1},
10447                         points:{by:[0, this.getHeight() * .5]}
10448                     }, o, 'motion', 0.3, 'easeIn', after);
10449                 }).defer(100, this);
10450             });
10451         });
10452         return this;
10453     },
10454
10455     /**
10456      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10457      * changed using the "attr" config option) and then fading back to the original color. If no original
10458      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10459      * Usage:
10460 <pre><code>
10461 // default: highlight background to yellow
10462 el.highlight();
10463
10464 // custom: highlight foreground text to blue for 2 seconds
10465 el.highlight("0000ff", { attr: 'color', duration: 2 });
10466
10467 // common config options shown with default values
10468 el.highlight("ffff9c", {
10469     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10470     endColor: (current color) or "ffffff",
10471     easing: 'easeIn',
10472     duration: 1
10473 });
10474 </code></pre>
10475      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10476      * @param {Object} options (optional) Object literal with any of the Fx config options
10477      * @return {Roo.Element} The Element
10478      */ 
10479     highlight : function(color, o){
10480         var el = this.getFxEl();
10481         o = o || {};
10482
10483         el.queueFx(o, function(){
10484             color = color || "ffff9c";
10485             attr = o.attr || "backgroundColor";
10486
10487             this.clearOpacity();
10488             this.show();
10489
10490             var origColor = this.getColor(attr);
10491             var restoreColor = this.dom.style[attr];
10492             endColor = (o.endColor || origColor) || "ffffff";
10493
10494             var after = function(){
10495                 el.dom.style[attr] = restoreColor;
10496                 el.afterFx(o);
10497             };
10498
10499             var a = {};
10500             a[attr] = {from: color, to: endColor};
10501             arguments.callee.anim = this.fxanim(a,
10502                 o,
10503                 'color',
10504                 1,
10505                 'easeIn', after);
10506         });
10507         return this;
10508     },
10509
10510    /**
10511     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10512     * Usage:
10513 <pre><code>
10514 // default: a single light blue ripple
10515 el.frame();
10516
10517 // custom: 3 red ripples lasting 3 seconds total
10518 el.frame("ff0000", 3, { duration: 3 });
10519
10520 // common config options shown with default values
10521 el.frame("C3DAF9", 1, {
10522     duration: 1 //duration of entire animation (not each individual ripple)
10523     // Note: Easing is not configurable and will be ignored if included
10524 });
10525 </code></pre>
10526     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10527     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10528     * @param {Object} options (optional) Object literal with any of the Fx config options
10529     * @return {Roo.Element} The Element
10530     */
10531     frame : function(color, count, o){
10532         var el = this.getFxEl();
10533         o = o || {};
10534
10535         el.queueFx(o, function(){
10536             color = color || "#C3DAF9";
10537             if(color.length == 6){
10538                 color = "#" + color;
10539             }
10540             count = count || 1;
10541             duration = o.duration || 1;
10542             this.show();
10543
10544             var b = this.getBox();
10545             var animFn = function(){
10546                 var proxy = this.createProxy({
10547
10548                      style:{
10549                         visbility:"hidden",
10550                         position:"absolute",
10551                         "z-index":"35000", // yee haw
10552                         border:"0px solid " + color
10553                      }
10554                   });
10555                 var scale = Roo.isBorderBox ? 2 : 1;
10556                 proxy.animate({
10557                     top:{from:b.y, to:b.y - 20},
10558                     left:{from:b.x, to:b.x - 20},
10559                     borderWidth:{from:0, to:10},
10560                     opacity:{from:1, to:0},
10561                     height:{from:b.height, to:(b.height + (20*scale))},
10562                     width:{from:b.width, to:(b.width + (20*scale))}
10563                 }, duration, function(){
10564                     proxy.remove();
10565                 });
10566                 if(--count > 0){
10567                      animFn.defer((duration/2)*1000, this);
10568                 }else{
10569                     el.afterFx(o);
10570                 }
10571             };
10572             animFn.call(this);
10573         });
10574         return this;
10575     },
10576
10577    /**
10578     * Creates a pause before any subsequent queued effects begin.  If there are
10579     * no effects queued after the pause it will have no effect.
10580     * Usage:
10581 <pre><code>
10582 el.pause(1);
10583 </code></pre>
10584     * @param {Number} seconds The length of time to pause (in seconds)
10585     * @return {Roo.Element} The Element
10586     */
10587     pause : function(seconds){
10588         var el = this.getFxEl();
10589         var o = {};
10590
10591         el.queueFx(o, function(){
10592             setTimeout(function(){
10593                 el.afterFx(o);
10594             }, seconds * 1000);
10595         });
10596         return this;
10597     },
10598
10599    /**
10600     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10601     * using the "endOpacity" config option.
10602     * Usage:
10603 <pre><code>
10604 // default: fade in from opacity 0 to 100%
10605 el.fadeIn();
10606
10607 // custom: fade in from opacity 0 to 75% over 2 seconds
10608 el.fadeIn({ endOpacity: .75, duration: 2});
10609
10610 // common config options shown with default values
10611 el.fadeIn({
10612     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10613     easing: 'easeOut',
10614     duration: .5
10615 });
10616 </code></pre>
10617     * @param {Object} options (optional) Object literal with any of the Fx config options
10618     * @return {Roo.Element} The Element
10619     */
10620     fadeIn : function(o){
10621         var el = this.getFxEl();
10622         o = o || {};
10623         el.queueFx(o, function(){
10624             this.setOpacity(0);
10625             this.fixDisplay();
10626             this.dom.style.visibility = 'visible';
10627             var to = o.endOpacity || 1;
10628             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10629                 o, null, .5, "easeOut", function(){
10630                 if(to == 1){
10631                     this.clearOpacity();
10632                 }
10633                 el.afterFx(o);
10634             });
10635         });
10636         return this;
10637     },
10638
10639    /**
10640     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10641     * using the "endOpacity" config option.
10642     * Usage:
10643 <pre><code>
10644 // default: fade out from the element's current opacity to 0
10645 el.fadeOut();
10646
10647 // custom: fade out from the element's current opacity to 25% over 2 seconds
10648 el.fadeOut({ endOpacity: .25, duration: 2});
10649
10650 // common config options shown with default values
10651 el.fadeOut({
10652     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10653     easing: 'easeOut',
10654     duration: .5
10655     remove: false,
10656     useDisplay: false
10657 });
10658 </code></pre>
10659     * @param {Object} options (optional) Object literal with any of the Fx config options
10660     * @return {Roo.Element} The Element
10661     */
10662     fadeOut : function(o){
10663         var el = this.getFxEl();
10664         o = o || {};
10665         el.queueFx(o, function(){
10666             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10667                 o, null, .5, "easeOut", function(){
10668                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10669                      this.dom.style.display = "none";
10670                 }else{
10671                      this.dom.style.visibility = "hidden";
10672                 }
10673                 this.clearOpacity();
10674                 el.afterFx(o);
10675             });
10676         });
10677         return this;
10678     },
10679
10680    /**
10681     * Animates the transition of an element's dimensions from a starting height/width
10682     * to an ending height/width.
10683     * Usage:
10684 <pre><code>
10685 // change height and width to 100x100 pixels
10686 el.scale(100, 100);
10687
10688 // common config options shown with default values.  The height and width will default to
10689 // the element's existing values if passed as null.
10690 el.scale(
10691     [element's width],
10692     [element's height], {
10693     easing: 'easeOut',
10694     duration: .35
10695 });
10696 </code></pre>
10697     * @param {Number} width  The new width (pass undefined to keep the original width)
10698     * @param {Number} height  The new height (pass undefined to keep the original height)
10699     * @param {Object} options (optional) Object literal with any of the Fx config options
10700     * @return {Roo.Element} The Element
10701     */
10702     scale : function(w, h, o){
10703         this.shift(Roo.apply({}, o, {
10704             width: w,
10705             height: h
10706         }));
10707         return this;
10708     },
10709
10710    /**
10711     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10712     * Any of these properties not specified in the config object will not be changed.  This effect 
10713     * requires that at least one new dimension, position or opacity setting must be passed in on
10714     * the config object in order for the function to have any effect.
10715     * Usage:
10716 <pre><code>
10717 // slide the element horizontally to x position 200 while changing the height and opacity
10718 el.shift({ x: 200, height: 50, opacity: .8 });
10719
10720 // common config options shown with default values.
10721 el.shift({
10722     width: [element's width],
10723     height: [element's height],
10724     x: [element's x position],
10725     y: [element's y position],
10726     opacity: [element's opacity],
10727     easing: 'easeOut',
10728     duration: .35
10729 });
10730 </code></pre>
10731     * @param {Object} options  Object literal with any of the Fx config options
10732     * @return {Roo.Element} The Element
10733     */
10734     shift : function(o){
10735         var el = this.getFxEl();
10736         o = o || {};
10737         el.queueFx(o, function(){
10738             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10739             if(w !== undefined){
10740                 a.width = {to: this.adjustWidth(w)};
10741             }
10742             if(h !== undefined){
10743                 a.height = {to: this.adjustHeight(h)};
10744             }
10745             if(x !== undefined || y !== undefined){
10746                 a.points = {to: [
10747                     x !== undefined ? x : this.getX(),
10748                     y !== undefined ? y : this.getY()
10749                 ]};
10750             }
10751             if(op !== undefined){
10752                 a.opacity = {to: op};
10753             }
10754             if(o.xy !== undefined){
10755                 a.points = {to: o.xy};
10756             }
10757             arguments.callee.anim = this.fxanim(a,
10758                 o, 'motion', .35, "easeOut", function(){
10759                 el.afterFx(o);
10760             });
10761         });
10762         return this;
10763     },
10764
10765         /**
10766          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10767          * ending point of the effect.
10768          * Usage:
10769          *<pre><code>
10770 // default: slide the element downward while fading out
10771 el.ghost();
10772
10773 // custom: slide the element out to the right with a 2-second duration
10774 el.ghost('r', { duration: 2 });
10775
10776 // common config options shown with default values
10777 el.ghost('b', {
10778     easing: 'easeOut',
10779     duration: .5
10780     remove: false,
10781     useDisplay: false
10782 });
10783 </code></pre>
10784          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10785          * @param {Object} options (optional) Object literal with any of the Fx config options
10786          * @return {Roo.Element} The Element
10787          */
10788     ghost : function(anchor, o){
10789         var el = this.getFxEl();
10790         o = o || {};
10791
10792         el.queueFx(o, function(){
10793             anchor = anchor || "b";
10794
10795             // restore values after effect
10796             var r = this.getFxRestore();
10797             var w = this.getWidth(),
10798                 h = this.getHeight();
10799
10800             var st = this.dom.style;
10801
10802             var after = function(){
10803                 if(o.useDisplay){
10804                     el.setDisplayed(false);
10805                 }else{
10806                     el.hide();
10807                 }
10808
10809                 el.clearOpacity();
10810                 el.setPositioning(r.pos);
10811                 st.width = r.width;
10812                 st.height = r.height;
10813
10814                 el.afterFx(o);
10815             };
10816
10817             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10818             switch(anchor.toLowerCase()){
10819                 case "t":
10820                     pt.by = [0, -h];
10821                 break;
10822                 case "l":
10823                     pt.by = [-w, 0];
10824                 break;
10825                 case "r":
10826                     pt.by = [w, 0];
10827                 break;
10828                 case "b":
10829                     pt.by = [0, h];
10830                 break;
10831                 case "tl":
10832                     pt.by = [-w, -h];
10833                 break;
10834                 case "bl":
10835                     pt.by = [-w, h];
10836                 break;
10837                 case "br":
10838                     pt.by = [w, h];
10839                 break;
10840                 case "tr":
10841                     pt.by = [w, -h];
10842                 break;
10843             }
10844
10845             arguments.callee.anim = this.fxanim(a,
10846                 o,
10847                 'motion',
10848                 .5,
10849                 "easeOut", after);
10850         });
10851         return this;
10852     },
10853
10854         /**
10855          * Ensures that all effects queued after syncFx is called on the element are
10856          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10857          * @return {Roo.Element} The Element
10858          */
10859     syncFx : function(){
10860         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10861             block : false,
10862             concurrent : true,
10863             stopFx : false
10864         });
10865         return this;
10866     },
10867
10868         /**
10869          * Ensures that all effects queued after sequenceFx is called on the element are
10870          * run in sequence.  This is the opposite of {@link #syncFx}.
10871          * @return {Roo.Element} The Element
10872          */
10873     sequenceFx : function(){
10874         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10875             block : false,
10876             concurrent : false,
10877             stopFx : false
10878         });
10879         return this;
10880     },
10881
10882         /* @private */
10883     nextFx : function(){
10884         var ef = this.fxQueue[0];
10885         if(ef){
10886             ef.call(this);
10887         }
10888     },
10889
10890         /**
10891          * Returns true if the element has any effects actively running or queued, else returns false.
10892          * @return {Boolean} True if element has active effects, else false
10893          */
10894     hasActiveFx : function(){
10895         return this.fxQueue && this.fxQueue[0];
10896     },
10897
10898         /**
10899          * Stops any running effects and clears the element's internal effects queue if it contains
10900          * any additional effects that haven't started yet.
10901          * @return {Roo.Element} The Element
10902          */
10903     stopFx : function(){
10904         if(this.hasActiveFx()){
10905             var cur = this.fxQueue[0];
10906             if(cur && cur.anim && cur.anim.isAnimated()){
10907                 this.fxQueue = [cur]; // clear out others
10908                 cur.anim.stop(true);
10909             }
10910         }
10911         return this;
10912     },
10913
10914         /* @private */
10915     beforeFx : function(o){
10916         if(this.hasActiveFx() && !o.concurrent){
10917            if(o.stopFx){
10918                this.stopFx();
10919                return true;
10920            }
10921            return false;
10922         }
10923         return true;
10924     },
10925
10926         /**
10927          * Returns true if the element is currently blocking so that no other effect can be queued
10928          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10929          * used to ensure that an effect initiated by a user action runs to completion prior to the
10930          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10931          * @return {Boolean} True if blocking, else false
10932          */
10933     hasFxBlock : function(){
10934         var q = this.fxQueue;
10935         return q && q[0] && q[0].block;
10936     },
10937
10938         /* @private */
10939     queueFx : function(o, fn){
10940         if(!this.fxQueue){
10941             this.fxQueue = [];
10942         }
10943         if(!this.hasFxBlock()){
10944             Roo.applyIf(o, this.fxDefaults);
10945             if(!o.concurrent){
10946                 var run = this.beforeFx(o);
10947                 fn.block = o.block;
10948                 this.fxQueue.push(fn);
10949                 if(run){
10950                     this.nextFx();
10951                 }
10952             }else{
10953                 fn.call(this);
10954             }
10955         }
10956         return this;
10957     },
10958
10959         /* @private */
10960     fxWrap : function(pos, o, vis){
10961         var wrap;
10962         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10963             var wrapXY;
10964             if(o.fixPosition){
10965                 wrapXY = this.getXY();
10966             }
10967             var div = document.createElement("div");
10968             div.style.visibility = vis;
10969             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10970             wrap.setPositioning(pos);
10971             if(wrap.getStyle("position") == "static"){
10972                 wrap.position("relative");
10973             }
10974             this.clearPositioning('auto');
10975             wrap.clip();
10976             wrap.dom.appendChild(this.dom);
10977             if(wrapXY){
10978                 wrap.setXY(wrapXY);
10979             }
10980         }
10981         return wrap;
10982     },
10983
10984         /* @private */
10985     fxUnwrap : function(wrap, pos, o){
10986         this.clearPositioning();
10987         this.setPositioning(pos);
10988         if(!o.wrap){
10989             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10990             wrap.remove();
10991         }
10992     },
10993
10994         /* @private */
10995     getFxRestore : function(){
10996         var st = this.dom.style;
10997         return {pos: this.getPositioning(), width: st.width, height : st.height};
10998     },
10999
11000         /* @private */
11001     afterFx : function(o){
11002         if(o.afterStyle){
11003             this.applyStyles(o.afterStyle);
11004         }
11005         if(o.afterCls){
11006             this.addClass(o.afterCls);
11007         }
11008         if(o.remove === true){
11009             this.remove();
11010         }
11011         Roo.callback(o.callback, o.scope, [this]);
11012         if(!o.concurrent){
11013             this.fxQueue.shift();
11014             this.nextFx();
11015         }
11016     },
11017
11018         /* @private */
11019     getFxEl : function(){ // support for composite element fx
11020         return Roo.get(this.dom);
11021     },
11022
11023         /* @private */
11024     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11025         animType = animType || 'run';
11026         opt = opt || {};
11027         var anim = Roo.lib.Anim[animType](
11028             this.dom, args,
11029             (opt.duration || defaultDur) || .35,
11030             (opt.easing || defaultEase) || 'easeOut',
11031             function(){
11032                 Roo.callback(cb, this);
11033             },
11034             this
11035         );
11036         opt.anim = anim;
11037         return anim;
11038     }
11039 };
11040
11041 // backwords compat
11042 Roo.Fx.resize = Roo.Fx.scale;
11043
11044 //When included, Roo.Fx is automatically applied to Element so that all basic
11045 //effects are available directly via the Element API
11046 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11047  * Based on:
11048  * Ext JS Library 1.1.1
11049  * Copyright(c) 2006-2007, Ext JS, LLC.
11050  *
11051  * Originally Released Under LGPL - original licence link has changed is not relivant.
11052  *
11053  * Fork - LGPL
11054  * <script type="text/javascript">
11055  */
11056
11057
11058 /**
11059  * @class Roo.CompositeElement
11060  * Standard composite class. Creates a Roo.Element for every element in the collection.
11061  * <br><br>
11062  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11063  * actions will be performed on all the elements in this collection.</b>
11064  * <br><br>
11065  * All methods return <i>this</i> and can be chained.
11066  <pre><code>
11067  var els = Roo.select("#some-el div.some-class", true);
11068  // or select directly from an existing element
11069  var el = Roo.get('some-el');
11070  el.select('div.some-class', true);
11071
11072  els.setWidth(100); // all elements become 100 width
11073  els.hide(true); // all elements fade out and hide
11074  // or
11075  els.setWidth(100).hide(true);
11076  </code></pre>
11077  */
11078 Roo.CompositeElement = function(els){
11079     this.elements = [];
11080     this.addElements(els);
11081 };
11082 Roo.CompositeElement.prototype = {
11083     isComposite: true,
11084     addElements : function(els){
11085         if(!els) {
11086             return this;
11087         }
11088         if(typeof els == "string"){
11089             els = Roo.Element.selectorFunction(els);
11090         }
11091         var yels = this.elements;
11092         var index = yels.length-1;
11093         for(var i = 0, len = els.length; i < len; i++) {
11094                 yels[++index] = Roo.get(els[i]);
11095         }
11096         return this;
11097     },
11098
11099     /**
11100     * Clears this composite and adds the elements returned by the passed selector.
11101     * @param {String/Array} els A string CSS selector, an array of elements or an element
11102     * @return {CompositeElement} this
11103     */
11104     fill : function(els){
11105         this.elements = [];
11106         this.add(els);
11107         return this;
11108     },
11109
11110     /**
11111     * Filters this composite to only elements that match the passed selector.
11112     * @param {String} selector A string CSS selector
11113     * @param {Boolean} inverse return inverse filter (not matches)
11114     * @return {CompositeElement} this
11115     */
11116     filter : function(selector, inverse){
11117         var els = [];
11118         inverse = inverse || false;
11119         this.each(function(el){
11120             var match = inverse ? !el.is(selector) : el.is(selector);
11121             if(match){
11122                 els[els.length] = el.dom;
11123             }
11124         });
11125         this.fill(els);
11126         return this;
11127     },
11128
11129     invoke : function(fn, args){
11130         var els = this.elements;
11131         for(var i = 0, len = els.length; i < len; i++) {
11132                 Roo.Element.prototype[fn].apply(els[i], args);
11133         }
11134         return this;
11135     },
11136     /**
11137     * Adds elements to this composite.
11138     * @param {String/Array} els A string CSS selector, an array of elements or an element
11139     * @return {CompositeElement} this
11140     */
11141     add : function(els){
11142         if(typeof els == "string"){
11143             this.addElements(Roo.Element.selectorFunction(els));
11144         }else if(els.length !== undefined){
11145             this.addElements(els);
11146         }else{
11147             this.addElements([els]);
11148         }
11149         return this;
11150     },
11151     /**
11152     * Calls the passed function passing (el, this, index) for each element in this composite.
11153     * @param {Function} fn The function to call
11154     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11155     * @return {CompositeElement} this
11156     */
11157     each : function(fn, scope){
11158         var els = this.elements;
11159         for(var i = 0, len = els.length; i < len; i++){
11160             if(fn.call(scope || els[i], els[i], this, i) === false) {
11161                 break;
11162             }
11163         }
11164         return this;
11165     },
11166
11167     /**
11168      * Returns the Element object at the specified index
11169      * @param {Number} index
11170      * @return {Roo.Element}
11171      */
11172     item : function(index){
11173         return this.elements[index] || null;
11174     },
11175
11176     /**
11177      * Returns the first Element
11178      * @return {Roo.Element}
11179      */
11180     first : function(){
11181         return this.item(0);
11182     },
11183
11184     /**
11185      * Returns the last Element
11186      * @return {Roo.Element}
11187      */
11188     last : function(){
11189         return this.item(this.elements.length-1);
11190     },
11191
11192     /**
11193      * Returns the number of elements in this composite
11194      * @return Number
11195      */
11196     getCount : function(){
11197         return this.elements.length;
11198     },
11199
11200     /**
11201      * Returns true if this composite contains the passed element
11202      * @return Boolean
11203      */
11204     contains : function(el){
11205         return this.indexOf(el) !== -1;
11206     },
11207
11208     /**
11209      * Returns true if this composite contains the passed element
11210      * @return Boolean
11211      */
11212     indexOf : function(el){
11213         return this.elements.indexOf(Roo.get(el));
11214     },
11215
11216
11217     /**
11218     * Removes the specified element(s).
11219     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11220     * or an array of any of those.
11221     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11222     * @return {CompositeElement} this
11223     */
11224     removeElement : function(el, removeDom){
11225         if(el instanceof Array){
11226             for(var i = 0, len = el.length; i < len; i++){
11227                 this.removeElement(el[i]);
11228             }
11229             return this;
11230         }
11231         var index = typeof el == 'number' ? el : this.indexOf(el);
11232         if(index !== -1){
11233             if(removeDom){
11234                 var d = this.elements[index];
11235                 if(d.dom){
11236                     d.remove();
11237                 }else{
11238                     d.parentNode.removeChild(d);
11239                 }
11240             }
11241             this.elements.splice(index, 1);
11242         }
11243         return this;
11244     },
11245
11246     /**
11247     * Replaces the specified element with the passed element.
11248     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11249     * to replace.
11250     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11251     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11252     * @return {CompositeElement} this
11253     */
11254     replaceElement : function(el, replacement, domReplace){
11255         var index = typeof el == 'number' ? el : this.indexOf(el);
11256         if(index !== -1){
11257             if(domReplace){
11258                 this.elements[index].replaceWith(replacement);
11259             }else{
11260                 this.elements.splice(index, 1, Roo.get(replacement))
11261             }
11262         }
11263         return this;
11264     },
11265
11266     /**
11267      * Removes all elements.
11268      */
11269     clear : function(){
11270         this.elements = [];
11271     }
11272 };
11273 (function(){
11274     Roo.CompositeElement.createCall = function(proto, fnName){
11275         if(!proto[fnName]){
11276             proto[fnName] = function(){
11277                 return this.invoke(fnName, arguments);
11278             };
11279         }
11280     };
11281     for(var fnName in Roo.Element.prototype){
11282         if(typeof Roo.Element.prototype[fnName] == "function"){
11283             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11284         }
11285     };
11286 })();
11287 /*
11288  * Based on:
11289  * Ext JS Library 1.1.1
11290  * Copyright(c) 2006-2007, Ext JS, LLC.
11291  *
11292  * Originally Released Under LGPL - original licence link has changed is not relivant.
11293  *
11294  * Fork - LGPL
11295  * <script type="text/javascript">
11296  */
11297
11298 /**
11299  * @class Roo.CompositeElementLite
11300  * @extends Roo.CompositeElement
11301  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11302  <pre><code>
11303  var els = Roo.select("#some-el div.some-class");
11304  // or select directly from an existing element
11305  var el = Roo.get('some-el');
11306  el.select('div.some-class');
11307
11308  els.setWidth(100); // all elements become 100 width
11309  els.hide(true); // all elements fade out and hide
11310  // or
11311  els.setWidth(100).hide(true);
11312  </code></pre><br><br>
11313  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11314  * actions will be performed on all the elements in this collection.</b>
11315  */
11316 Roo.CompositeElementLite = function(els){
11317     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11318     this.el = new Roo.Element.Flyweight();
11319 };
11320 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11321     addElements : function(els){
11322         if(els){
11323             if(els instanceof Array){
11324                 this.elements = this.elements.concat(els);
11325             }else{
11326                 var yels = this.elements;
11327                 var index = yels.length-1;
11328                 for(var i = 0, len = els.length; i < len; i++) {
11329                     yels[++index] = els[i];
11330                 }
11331             }
11332         }
11333         return this;
11334     },
11335     invoke : function(fn, args){
11336         var els = this.elements;
11337         var el = this.el;
11338         for(var i = 0, len = els.length; i < len; i++) {
11339             el.dom = els[i];
11340                 Roo.Element.prototype[fn].apply(el, args);
11341         }
11342         return this;
11343     },
11344     /**
11345      * Returns a flyweight Element of the dom element object at the specified index
11346      * @param {Number} index
11347      * @return {Roo.Element}
11348      */
11349     item : function(index){
11350         if(!this.elements[index]){
11351             return null;
11352         }
11353         this.el.dom = this.elements[index];
11354         return this.el;
11355     },
11356
11357     // fixes scope with flyweight
11358     addListener : function(eventName, handler, scope, opt){
11359         var els = this.elements;
11360         for(var i = 0, len = els.length; i < len; i++) {
11361             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11362         }
11363         return this;
11364     },
11365
11366     /**
11367     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11368     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11369     * a reference to the dom node, use el.dom.</b>
11370     * @param {Function} fn The function to call
11371     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11372     * @return {CompositeElement} this
11373     */
11374     each : function(fn, scope){
11375         var els = this.elements;
11376         var el = this.el;
11377         for(var i = 0, len = els.length; i < len; i++){
11378             el.dom = els[i];
11379                 if(fn.call(scope || el, el, this, i) === false){
11380                 break;
11381             }
11382         }
11383         return this;
11384     },
11385
11386     indexOf : function(el){
11387         return this.elements.indexOf(Roo.getDom(el));
11388     },
11389
11390     replaceElement : function(el, replacement, domReplace){
11391         var index = typeof el == 'number' ? el : this.indexOf(el);
11392         if(index !== -1){
11393             replacement = Roo.getDom(replacement);
11394             if(domReplace){
11395                 var d = this.elements[index];
11396                 d.parentNode.insertBefore(replacement, d);
11397                 d.parentNode.removeChild(d);
11398             }
11399             this.elements.splice(index, 1, replacement);
11400         }
11401         return this;
11402     }
11403 });
11404 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11405
11406 /*
11407  * Based on:
11408  * Ext JS Library 1.1.1
11409  * Copyright(c) 2006-2007, Ext JS, LLC.
11410  *
11411  * Originally Released Under LGPL - original licence link has changed is not relivant.
11412  *
11413  * Fork - LGPL
11414  * <script type="text/javascript">
11415  */
11416
11417  
11418
11419 /**
11420  * @class Roo.data.Connection
11421  * @extends Roo.util.Observable
11422  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11423  * either to a configured URL, or to a URL specified at request time.<br><br>
11424  * <p>
11425  * Requests made by this class are asynchronous, and will return immediately. No data from
11426  * the server will be available to the statement immediately following the {@link #request} call.
11427  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11428  * <p>
11429  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11430  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11431  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11432  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11433  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11434  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11435  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11436  * standard DOM methods.
11437  * @constructor
11438  * @param {Object} config a configuration object.
11439  */
11440 Roo.data.Connection = function(config){
11441     Roo.apply(this, config);
11442     this.addEvents({
11443         /**
11444          * @event beforerequest
11445          * Fires before a network request is made to retrieve a data object.
11446          * @param {Connection} conn This Connection object.
11447          * @param {Object} options The options config object passed to the {@link #request} method.
11448          */
11449         "beforerequest" : true,
11450         /**
11451          * @event requestcomplete
11452          * Fires if the request was successfully completed.
11453          * @param {Connection} conn This Connection object.
11454          * @param {Object} response The XHR object containing the response data.
11455          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11456          * @param {Object} options The options config object passed to the {@link #request} method.
11457          */
11458         "requestcomplete" : true,
11459         /**
11460          * @event requestexception
11461          * Fires if an error HTTP status was returned from the server.
11462          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11463          * @param {Connection} conn This Connection object.
11464          * @param {Object} response The XHR object containing the response data.
11465          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11466          * @param {Object} options The options config object passed to the {@link #request} method.
11467          */
11468         "requestexception" : true
11469     });
11470     Roo.data.Connection.superclass.constructor.call(this);
11471 };
11472
11473 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11474     /**
11475      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11476      */
11477     /**
11478      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11479      * extra parameters to each request made by this object. (defaults to undefined)
11480      */
11481     /**
11482      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11483      *  to each request made by this object. (defaults to undefined)
11484      */
11485     /**
11486      * @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)
11487      */
11488     /**
11489      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11490      */
11491     timeout : 30000,
11492     /**
11493      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11494      * @type Boolean
11495      */
11496     autoAbort:false,
11497
11498     /**
11499      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11500      * @type Boolean
11501      */
11502     disableCaching: true,
11503
11504     /**
11505      * Sends an HTTP request to a remote server.
11506      * @param {Object} options An object which may contain the following properties:<ul>
11507      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11508      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11509      * request, a url encoded string or a function to call to get either.</li>
11510      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11511      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11512      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11513      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11514      * <li>options {Object} The parameter to the request call.</li>
11515      * <li>success {Boolean} True if the request succeeded.</li>
11516      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11517      * </ul></li>
11518      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11519      * The callback is passed the following parameters:<ul>
11520      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11521      * <li>options {Object} The parameter to the request call.</li>
11522      * </ul></li>
11523      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11524      * The callback is passed the following parameters:<ul>
11525      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11526      * <li>options {Object} The parameter to the request call.</li>
11527      * </ul></li>
11528      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11529      * for the callback function. Defaults to the browser window.</li>
11530      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11531      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11532      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11533      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11534      * params for the post data. Any params will be appended to the URL.</li>
11535      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11536      * </ul>
11537      * @return {Number} transactionId
11538      */
11539     request : function(o){
11540         if(this.fireEvent("beforerequest", this, o) !== false){
11541             var p = o.params;
11542
11543             if(typeof p == "function"){
11544                 p = p.call(o.scope||window, o);
11545             }
11546             if(typeof p == "object"){
11547                 p = Roo.urlEncode(o.params);
11548             }
11549             if(this.extraParams){
11550                 var extras = Roo.urlEncode(this.extraParams);
11551                 p = p ? (p + '&' + extras) : extras;
11552             }
11553
11554             var url = o.url || this.url;
11555             if(typeof url == 'function'){
11556                 url = url.call(o.scope||window, o);
11557             }
11558
11559             if(o.form){
11560                 var form = Roo.getDom(o.form);
11561                 url = url || form.action;
11562
11563                 var enctype = form.getAttribute("enctype");
11564                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11565                     return this.doFormUpload(o, p, url);
11566                 }
11567                 var f = Roo.lib.Ajax.serializeForm(form);
11568                 p = p ? (p + '&' + f) : f;
11569             }
11570
11571             var hs = o.headers;
11572             if(this.defaultHeaders){
11573                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11574                 if(!o.headers){
11575                     o.headers = hs;
11576                 }
11577             }
11578
11579             var cb = {
11580                 success: this.handleResponse,
11581                 failure: this.handleFailure,
11582                 scope: this,
11583                 argument: {options: o},
11584                 timeout : o.timeout || this.timeout
11585             };
11586
11587             var method = o.method||this.method||(p ? "POST" : "GET");
11588
11589             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11590                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11591             }
11592
11593             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11594                 if(o.autoAbort){
11595                     this.abort();
11596                 }
11597             }else if(this.autoAbort !== false){
11598                 this.abort();
11599             }
11600
11601             if((method == 'GET' && p) || o.xmlData){
11602                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11603                 p = '';
11604             }
11605             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11606             return this.transId;
11607         }else{
11608             Roo.callback(o.callback, o.scope, [o, null, null]);
11609             return null;
11610         }
11611     },
11612
11613     /**
11614      * Determine whether this object has a request outstanding.
11615      * @param {Number} transactionId (Optional) defaults to the last transaction
11616      * @return {Boolean} True if there is an outstanding request.
11617      */
11618     isLoading : function(transId){
11619         if(transId){
11620             return Roo.lib.Ajax.isCallInProgress(transId);
11621         }else{
11622             return this.transId ? true : false;
11623         }
11624     },
11625
11626     /**
11627      * Aborts any outstanding request.
11628      * @param {Number} transactionId (Optional) defaults to the last transaction
11629      */
11630     abort : function(transId){
11631         if(transId || this.isLoading()){
11632             Roo.lib.Ajax.abort(transId || this.transId);
11633         }
11634     },
11635
11636     // private
11637     handleResponse : function(response){
11638         this.transId = false;
11639         var options = response.argument.options;
11640         response.argument = options ? options.argument : null;
11641         this.fireEvent("requestcomplete", this, response, options);
11642         Roo.callback(options.success, options.scope, [response, options]);
11643         Roo.callback(options.callback, options.scope, [options, true, response]);
11644     },
11645
11646     // private
11647     handleFailure : function(response, e){
11648         this.transId = false;
11649         var options = response.argument.options;
11650         response.argument = options ? options.argument : null;
11651         this.fireEvent("requestexception", this, response, options, e);
11652         Roo.callback(options.failure, options.scope, [response, options]);
11653         Roo.callback(options.callback, options.scope, [options, false, response]);
11654     },
11655
11656     // private
11657     doFormUpload : function(o, ps, url){
11658         var id = Roo.id();
11659         var frame = document.createElement('iframe');
11660         frame.id = id;
11661         frame.name = id;
11662         frame.className = 'x-hidden';
11663         if(Roo.isIE){
11664             frame.src = Roo.SSL_SECURE_URL;
11665         }
11666         document.body.appendChild(frame);
11667
11668         if(Roo.isIE){
11669            document.frames[id].name = id;
11670         }
11671
11672         var form = Roo.getDom(o.form);
11673         form.target = id;
11674         form.method = 'POST';
11675         form.enctype = form.encoding = 'multipart/form-data';
11676         if(url){
11677             form.action = url;
11678         }
11679
11680         var hiddens, hd;
11681         if(ps){ // add dynamic params
11682             hiddens = [];
11683             ps = Roo.urlDecode(ps, false);
11684             for(var k in ps){
11685                 if(ps.hasOwnProperty(k)){
11686                     hd = document.createElement('input');
11687                     hd.type = 'hidden';
11688                     hd.name = k;
11689                     hd.value = ps[k];
11690                     form.appendChild(hd);
11691                     hiddens.push(hd);
11692                 }
11693             }
11694         }
11695
11696         function cb(){
11697             var r = {  // bogus response object
11698                 responseText : '',
11699                 responseXML : null
11700             };
11701
11702             r.argument = o ? o.argument : null;
11703
11704             try { //
11705                 var doc;
11706                 if(Roo.isIE){
11707                     doc = frame.contentWindow.document;
11708                 }else {
11709                     doc = (frame.contentDocument || window.frames[id].document);
11710                 }
11711                 if(doc && doc.body){
11712                     r.responseText = doc.body.innerHTML;
11713                 }
11714                 if(doc && doc.XMLDocument){
11715                     r.responseXML = doc.XMLDocument;
11716                 }else {
11717                     r.responseXML = doc;
11718                 }
11719             }
11720             catch(e) {
11721                 // ignore
11722             }
11723
11724             Roo.EventManager.removeListener(frame, 'load', cb, this);
11725
11726             this.fireEvent("requestcomplete", this, r, o);
11727             Roo.callback(o.success, o.scope, [r, o]);
11728             Roo.callback(o.callback, o.scope, [o, true, r]);
11729
11730             setTimeout(function(){document.body.removeChild(frame);}, 100);
11731         }
11732
11733         Roo.EventManager.on(frame, 'load', cb, this);
11734         form.submit();
11735
11736         if(hiddens){ // remove dynamic params
11737             for(var i = 0, len = hiddens.length; i < len; i++){
11738                 form.removeChild(hiddens[i]);
11739             }
11740         }
11741     }
11742 });
11743 /*
11744  * Based on:
11745  * Ext JS Library 1.1.1
11746  * Copyright(c) 2006-2007, Ext JS, LLC.
11747  *
11748  * Originally Released Under LGPL - original licence link has changed is not relivant.
11749  *
11750  * Fork - LGPL
11751  * <script type="text/javascript">
11752  */
11753  
11754 /**
11755  * Global Ajax request class.
11756  * 
11757  * @class Roo.Ajax
11758  * @extends Roo.data.Connection
11759  * @static
11760  * 
11761  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11762  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11763  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11764  * @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)
11765  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11766  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11767  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11768  */
11769 Roo.Ajax = new Roo.data.Connection({
11770     // fix up the docs
11771     /**
11772      * @scope Roo.Ajax
11773      * @type {Boolear} 
11774      */
11775     autoAbort : false,
11776
11777     /**
11778      * Serialize the passed form into a url encoded string
11779      * @scope Roo.Ajax
11780      * @param {String/HTMLElement} form
11781      * @return {String}
11782      */
11783     serializeForm : function(form){
11784         return Roo.lib.Ajax.serializeForm(form);
11785     }
11786 });/*
11787  * Based on:
11788  * Ext JS Library 1.1.1
11789  * Copyright(c) 2006-2007, Ext JS, LLC.
11790  *
11791  * Originally Released Under LGPL - original licence link has changed is not relivant.
11792  *
11793  * Fork - LGPL
11794  * <script type="text/javascript">
11795  */
11796
11797  
11798 /**
11799  * @class Roo.UpdateManager
11800  * @extends Roo.util.Observable
11801  * Provides AJAX-style update for Element object.<br><br>
11802  * Usage:<br>
11803  * <pre><code>
11804  * // Get it from a Roo.Element object
11805  * var el = Roo.get("foo");
11806  * var mgr = el.getUpdateManager();
11807  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11808  * ...
11809  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11810  * <br>
11811  * // or directly (returns the same UpdateManager instance)
11812  * var mgr = new Roo.UpdateManager("myElementId");
11813  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11814  * mgr.on("update", myFcnNeedsToKnow);
11815  * <br>
11816    // short handed call directly from the element object
11817    Roo.get("foo").load({
11818         url: "bar.php",
11819         scripts:true,
11820         params: "for=bar",
11821         text: "Loading Foo..."
11822    });
11823  * </code></pre>
11824  * @constructor
11825  * Create new UpdateManager directly.
11826  * @param {String/HTMLElement/Roo.Element} el The element to update
11827  * @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).
11828  */
11829 Roo.UpdateManager = function(el, forceNew){
11830     el = Roo.get(el);
11831     if(!forceNew && el.updateManager){
11832         return el.updateManager;
11833     }
11834     /**
11835      * The Element object
11836      * @type Roo.Element
11837      */
11838     this.el = el;
11839     /**
11840      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11841      * @type String
11842      */
11843     this.defaultUrl = null;
11844
11845     this.addEvents({
11846         /**
11847          * @event beforeupdate
11848          * Fired before an update is made, return false from your handler and the update is cancelled.
11849          * @param {Roo.Element} el
11850          * @param {String/Object/Function} url
11851          * @param {String/Object} params
11852          */
11853         "beforeupdate": true,
11854         /**
11855          * @event update
11856          * Fired after successful update is made.
11857          * @param {Roo.Element} el
11858          * @param {Object} oResponseObject The response Object
11859          */
11860         "update": true,
11861         /**
11862          * @event failure
11863          * Fired on update failure.
11864          * @param {Roo.Element} el
11865          * @param {Object} oResponseObject The response Object
11866          */
11867         "failure": true
11868     });
11869     var d = Roo.UpdateManager.defaults;
11870     /**
11871      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11872      * @type String
11873      */
11874     this.sslBlankUrl = d.sslBlankUrl;
11875     /**
11876      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11877      * @type Boolean
11878      */
11879     this.disableCaching = d.disableCaching;
11880     /**
11881      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11882      * @type String
11883      */
11884     this.indicatorText = d.indicatorText;
11885     /**
11886      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11887      * @type String
11888      */
11889     this.showLoadIndicator = d.showLoadIndicator;
11890     /**
11891      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11892      * @type Number
11893      */
11894     this.timeout = d.timeout;
11895
11896     /**
11897      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11898      * @type Boolean
11899      */
11900     this.loadScripts = d.loadScripts;
11901
11902     /**
11903      * Transaction object of current executing transaction
11904      */
11905     this.transaction = null;
11906
11907     /**
11908      * @private
11909      */
11910     this.autoRefreshProcId = null;
11911     /**
11912      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11913      * @type Function
11914      */
11915     this.refreshDelegate = this.refresh.createDelegate(this);
11916     /**
11917      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11918      * @type Function
11919      */
11920     this.updateDelegate = this.update.createDelegate(this);
11921     /**
11922      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11923      * @type Function
11924      */
11925     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11926     /**
11927      * @private
11928      */
11929     this.successDelegate = this.processSuccess.createDelegate(this);
11930     /**
11931      * @private
11932      */
11933     this.failureDelegate = this.processFailure.createDelegate(this);
11934
11935     if(!this.renderer){
11936      /**
11937       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11938       */
11939     this.renderer = new Roo.UpdateManager.BasicRenderer();
11940     }
11941     
11942     Roo.UpdateManager.superclass.constructor.call(this);
11943 };
11944
11945 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11946     /**
11947      * Get the Element this UpdateManager is bound to
11948      * @return {Roo.Element} The element
11949      */
11950     getEl : function(){
11951         return this.el;
11952     },
11953     /**
11954      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11955      * @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:
11956 <pre><code>
11957 um.update({<br/>
11958     url: "your-url.php",<br/>
11959     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11960     callback: yourFunction,<br/>
11961     scope: yourObject, //(optional scope)  <br/>
11962     discardUrl: false, <br/>
11963     nocache: false,<br/>
11964     text: "Loading...",<br/>
11965     timeout: 30,<br/>
11966     scripts: false<br/>
11967 });
11968 </code></pre>
11969      * The only required property is url. The optional properties nocache, text and scripts
11970      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11971      * @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}
11972      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11973      * @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.
11974      */
11975     update : function(url, params, callback, discardUrl){
11976         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11977             var method = this.method,
11978                 cfg;
11979             if(typeof url == "object"){ // must be config object
11980                 cfg = url;
11981                 url = cfg.url;
11982                 params = params || cfg.params;
11983                 callback = callback || cfg.callback;
11984                 discardUrl = discardUrl || cfg.discardUrl;
11985                 if(callback && cfg.scope){
11986                     callback = callback.createDelegate(cfg.scope);
11987                 }
11988                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11989                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11990                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11991                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11992                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11993             }
11994             this.showLoading();
11995             if(!discardUrl){
11996                 this.defaultUrl = url;
11997             }
11998             if(typeof url == "function"){
11999                 url = url.call(this);
12000             }
12001
12002             method = method || (params ? "POST" : "GET");
12003             if(method == "GET"){
12004                 url = this.prepareUrl(url);
12005             }
12006
12007             var o = Roo.apply(cfg ||{}, {
12008                 url : url,
12009                 params: params,
12010                 success: this.successDelegate,
12011                 failure: this.failureDelegate,
12012                 callback: undefined,
12013                 timeout: (this.timeout*1000),
12014                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12015             });
12016             Roo.log("updated manager called with timeout of " + o.timeout);
12017             this.transaction = Roo.Ajax.request(o);
12018         }
12019     },
12020
12021     /**
12022      * 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.
12023      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12024      * @param {String/HTMLElement} form The form Id or form element
12025      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12026      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12027      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12028      */
12029     formUpdate : function(form, url, reset, callback){
12030         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12031             if(typeof url == "function"){
12032                 url = url.call(this);
12033             }
12034             form = Roo.getDom(form);
12035             this.transaction = Roo.Ajax.request({
12036                 form: form,
12037                 url:url,
12038                 success: this.successDelegate,
12039                 failure: this.failureDelegate,
12040                 timeout: (this.timeout*1000),
12041                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12042             });
12043             this.showLoading.defer(1, this);
12044         }
12045     },
12046
12047     /**
12048      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12049      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12050      */
12051     refresh : function(callback){
12052         if(this.defaultUrl == null){
12053             return;
12054         }
12055         this.update(this.defaultUrl, null, callback, true);
12056     },
12057
12058     /**
12059      * Set this element to auto refresh.
12060      * @param {Number} interval How often to update (in seconds).
12061      * @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)
12062      * @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}
12063      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12064      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12065      */
12066     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12067         if(refreshNow){
12068             this.update(url || this.defaultUrl, params, callback, true);
12069         }
12070         if(this.autoRefreshProcId){
12071             clearInterval(this.autoRefreshProcId);
12072         }
12073         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12074     },
12075
12076     /**
12077      * Stop auto refresh on this element.
12078      */
12079      stopAutoRefresh : function(){
12080         if(this.autoRefreshProcId){
12081             clearInterval(this.autoRefreshProcId);
12082             delete this.autoRefreshProcId;
12083         }
12084     },
12085
12086     isAutoRefreshing : function(){
12087        return this.autoRefreshProcId ? true : false;
12088     },
12089     /**
12090      * Called to update the element to "Loading" state. Override to perform custom action.
12091      */
12092     showLoading : function(){
12093         if(this.showLoadIndicator){
12094             this.el.update(this.indicatorText);
12095         }
12096     },
12097
12098     /**
12099      * Adds unique parameter to query string if disableCaching = true
12100      * @private
12101      */
12102     prepareUrl : function(url){
12103         if(this.disableCaching){
12104             var append = "_dc=" + (new Date().getTime());
12105             if(url.indexOf("?") !== -1){
12106                 url += "&" + append;
12107             }else{
12108                 url += "?" + append;
12109             }
12110         }
12111         return url;
12112     },
12113
12114     /**
12115      * @private
12116      */
12117     processSuccess : function(response){
12118         this.transaction = null;
12119         if(response.argument.form && response.argument.reset){
12120             try{ // put in try/catch since some older FF releases had problems with this
12121                 response.argument.form.reset();
12122             }catch(e){}
12123         }
12124         if(this.loadScripts){
12125             this.renderer.render(this.el, response, this,
12126                 this.updateComplete.createDelegate(this, [response]));
12127         }else{
12128             this.renderer.render(this.el, response, this);
12129             this.updateComplete(response);
12130         }
12131     },
12132
12133     updateComplete : function(response){
12134         this.fireEvent("update", this.el, response);
12135         if(typeof response.argument.callback == "function"){
12136             response.argument.callback(this.el, true, response);
12137         }
12138     },
12139
12140     /**
12141      * @private
12142      */
12143     processFailure : function(response){
12144         this.transaction = null;
12145         this.fireEvent("failure", this.el, response);
12146         if(typeof response.argument.callback == "function"){
12147             response.argument.callback(this.el, false, response);
12148         }
12149     },
12150
12151     /**
12152      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12153      * @param {Object} renderer The object implementing the render() method
12154      */
12155     setRenderer : function(renderer){
12156         this.renderer = renderer;
12157     },
12158
12159     getRenderer : function(){
12160        return this.renderer;
12161     },
12162
12163     /**
12164      * Set the defaultUrl used for updates
12165      * @param {String/Function} defaultUrl The url or a function to call to get the url
12166      */
12167     setDefaultUrl : function(defaultUrl){
12168         this.defaultUrl = defaultUrl;
12169     },
12170
12171     /**
12172      * Aborts the executing transaction
12173      */
12174     abort : function(){
12175         if(this.transaction){
12176             Roo.Ajax.abort(this.transaction);
12177         }
12178     },
12179
12180     /**
12181      * Returns true if an update is in progress
12182      * @return {Boolean}
12183      */
12184     isUpdating : function(){
12185         if(this.transaction){
12186             return Roo.Ajax.isLoading(this.transaction);
12187         }
12188         return false;
12189     }
12190 });
12191
12192 /**
12193  * @class Roo.UpdateManager.defaults
12194  * @static (not really - but it helps the doc tool)
12195  * The defaults collection enables customizing the default properties of UpdateManager
12196  */
12197    Roo.UpdateManager.defaults = {
12198        /**
12199          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12200          * @type Number
12201          */
12202          timeout : 30,
12203
12204          /**
12205          * True to process scripts by default (Defaults to false).
12206          * @type Boolean
12207          */
12208         loadScripts : false,
12209
12210         /**
12211         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12212         * @type String
12213         */
12214         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12215         /**
12216          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12217          * @type Boolean
12218          */
12219         disableCaching : false,
12220         /**
12221          * Whether to show indicatorText when loading (Defaults to true).
12222          * @type Boolean
12223          */
12224         showLoadIndicator : true,
12225         /**
12226          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12227          * @type String
12228          */
12229         indicatorText : '<div class="loading-indicator">Loading...</div>'
12230    };
12231
12232 /**
12233  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12234  *Usage:
12235  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12236  * @param {String/HTMLElement/Roo.Element} el The element to update
12237  * @param {String} url The url
12238  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12239  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12240  * @static
12241  * @deprecated
12242  * @member Roo.UpdateManager
12243  */
12244 Roo.UpdateManager.updateElement = function(el, url, params, options){
12245     var um = Roo.get(el, true).getUpdateManager();
12246     Roo.apply(um, options);
12247     um.update(url, params, options ? options.callback : null);
12248 };
12249 // alias for backwards compat
12250 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12251 /**
12252  * @class Roo.UpdateManager.BasicRenderer
12253  * Default Content renderer. Updates the elements innerHTML with the responseText.
12254  */
12255 Roo.UpdateManager.BasicRenderer = function(){};
12256
12257 Roo.UpdateManager.BasicRenderer.prototype = {
12258     /**
12259      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12260      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12261      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12262      * @param {Roo.Element} el The element being rendered
12263      * @param {Object} response The YUI Connect response object
12264      * @param {UpdateManager} updateManager The calling update manager
12265      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12266      */
12267      render : function(el, response, updateManager, callback){
12268         el.update(response.responseText, updateManager.loadScripts, callback);
12269     }
12270 };
12271 /*
12272  * Based on:
12273  * Roo JS
12274  * (c)) Alan Knowles
12275  * Licence : LGPL
12276  */
12277
12278
12279 /**
12280  * @class Roo.DomTemplate
12281  * @extends Roo.Template
12282  * An effort at a dom based template engine..
12283  *
12284  * Similar to XTemplate, except it uses dom parsing to create the template..
12285  *
12286  * Supported features:
12287  *
12288  *  Tags:
12289
12290 <pre><code>
12291       {a_variable} - output encoded.
12292       {a_variable.format:("Y-m-d")} - call a method on the variable
12293       {a_variable:raw} - unencoded output
12294       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12295       {a_variable:this.method_on_template(...)} - call a method on the template object.
12296  
12297 </code></pre>
12298  *  The tpl tag:
12299 <pre><code>
12300         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12301         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12302         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12303         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12304   
12305 </code></pre>
12306  *      
12307  */
12308 Roo.DomTemplate = function()
12309 {
12310      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12311      if (this.html) {
12312         this.compile();
12313      }
12314 };
12315
12316
12317 Roo.extend(Roo.DomTemplate, Roo.Template, {
12318     /**
12319      * id counter for sub templates.
12320      */
12321     id : 0,
12322     /**
12323      * flag to indicate if dom parser is inside a pre,
12324      * it will strip whitespace if not.
12325      */
12326     inPre : false,
12327     
12328     /**
12329      * The various sub templates
12330      */
12331     tpls : false,
12332     
12333     
12334     
12335     /**
12336      *
12337      * basic tag replacing syntax
12338      * WORD:WORD()
12339      *
12340      * // you can fake an object call by doing this
12341      *  x.t:(test,tesT) 
12342      * 
12343      */
12344     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12345     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12346     
12347     iterChild : function (node, method) {
12348         
12349         var oldPre = this.inPre;
12350         if (node.tagName == 'PRE') {
12351             this.inPre = true;
12352         }
12353         for( var i = 0; i < node.childNodes.length; i++) {
12354             method.call(this, node.childNodes[i]);
12355         }
12356         this.inPre = oldPre;
12357     },
12358     
12359     
12360     
12361     /**
12362      * compile the template
12363      *
12364      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12365      *
12366      */
12367     compile: function()
12368     {
12369         var s = this.html;
12370         
12371         // covert the html into DOM...
12372         var doc = false;
12373         var div =false;
12374         try {
12375             doc = document.implementation.createHTMLDocument("");
12376             doc.documentElement.innerHTML =   this.html  ;
12377             div = doc.documentElement;
12378         } catch (e) {
12379             // old IE... - nasty -- it causes all sorts of issues.. with
12380             // images getting pulled from server..
12381             div = document.createElement('div');
12382             div.innerHTML = this.html;
12383         }
12384         //doc.documentElement.innerHTML = htmlBody
12385          
12386         
12387         
12388         this.tpls = [];
12389         var _t = this;
12390         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12391         
12392         var tpls = this.tpls;
12393         
12394         // create a top level template from the snippet..
12395         
12396         //Roo.log(div.innerHTML);
12397         
12398         var tpl = {
12399             uid : 'master',
12400             id : this.id++,
12401             attr : false,
12402             value : false,
12403             body : div.innerHTML,
12404             
12405             forCall : false,
12406             execCall : false,
12407             dom : div,
12408             isTop : true
12409             
12410         };
12411         tpls.unshift(tpl);
12412         
12413         
12414         // compile them...
12415         this.tpls = [];
12416         Roo.each(tpls, function(tp){
12417             this.compileTpl(tp);
12418             this.tpls[tp.id] = tp;
12419         }, this);
12420         
12421         this.master = tpls[0];
12422         return this;
12423         
12424         
12425     },
12426     
12427     compileNode : function(node, istop) {
12428         // test for
12429         //Roo.log(node);
12430         
12431         
12432         // skip anything not a tag..
12433         if (node.nodeType != 1) {
12434             if (node.nodeType == 3 && !this.inPre) {
12435                 // reduce white space..
12436                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12437                 
12438             }
12439             return;
12440         }
12441         
12442         var tpl = {
12443             uid : false,
12444             id : false,
12445             attr : false,
12446             value : false,
12447             body : '',
12448             
12449             forCall : false,
12450             execCall : false,
12451             dom : false,
12452             isTop : istop
12453             
12454             
12455         };
12456         
12457         
12458         switch(true) {
12459             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12460             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12461             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12462             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12463             // no default..
12464         }
12465         
12466         
12467         if (!tpl.attr) {
12468             // just itterate children..
12469             this.iterChild(node,this.compileNode);
12470             return;
12471         }
12472         tpl.uid = this.id++;
12473         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12474         node.removeAttribute('roo-'+ tpl.attr);
12475         if (tpl.attr != 'name') {
12476             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12477             node.parentNode.replaceChild(placeholder,  node);
12478         } else {
12479             
12480             var placeholder =  document.createElement('span');
12481             placeholder.className = 'roo-tpl-' + tpl.value;
12482             node.parentNode.replaceChild(placeholder,  node);
12483         }
12484         
12485         // parent now sees '{domtplXXXX}
12486         this.iterChild(node,this.compileNode);
12487         
12488         // we should now have node body...
12489         var div = document.createElement('div');
12490         div.appendChild(node);
12491         tpl.dom = node;
12492         // this has the unfortunate side effect of converting tagged attributes
12493         // eg. href="{...}" into %7C...%7D
12494         // this has been fixed by searching for those combo's although it's a bit hacky..
12495         
12496         
12497         tpl.body = div.innerHTML;
12498         
12499         
12500          
12501         tpl.id = tpl.uid;
12502         switch(tpl.attr) {
12503             case 'for' :
12504                 switch (tpl.value) {
12505                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12506                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12507                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12508                 }
12509                 break;
12510             
12511             case 'exec':
12512                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12513                 break;
12514             
12515             case 'if':     
12516                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12517                 break;
12518             
12519             case 'name':
12520                 tpl.id  = tpl.value; // replace non characters???
12521                 break;
12522             
12523         }
12524         
12525         
12526         this.tpls.push(tpl);
12527         
12528         
12529         
12530     },
12531     
12532     
12533     
12534     
12535     /**
12536      * Compile a segment of the template into a 'sub-template'
12537      *
12538      * 
12539      * 
12540      *
12541      */
12542     compileTpl : function(tpl)
12543     {
12544         var fm = Roo.util.Format;
12545         var useF = this.disableFormats !== true;
12546         
12547         var sep = Roo.isGecko ? "+\n" : ",\n";
12548         
12549         var undef = function(str) {
12550             Roo.debug && Roo.log("Property not found :"  + str);
12551             return '';
12552         };
12553           
12554         //Roo.log(tpl.body);
12555         
12556         
12557         
12558         var fn = function(m, lbrace, name, format, args)
12559         {
12560             //Roo.log("ARGS");
12561             //Roo.log(arguments);
12562             args = args ? args.replace(/\\'/g,"'") : args;
12563             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12564             if (typeof(format) == 'undefined') {
12565                 format =  'htmlEncode'; 
12566             }
12567             if (format == 'raw' ) {
12568                 format = false;
12569             }
12570             
12571             if(name.substr(0, 6) == 'domtpl'){
12572                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12573             }
12574             
12575             // build an array of options to determine if value is undefined..
12576             
12577             // basically get 'xxxx.yyyy' then do
12578             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12579             //    (function () { Roo.log("Property not found"); return ''; })() :
12580             //    ......
12581             
12582             var udef_ar = [];
12583             var lookfor = '';
12584             Roo.each(name.split('.'), function(st) {
12585                 lookfor += (lookfor.length ? '.': '') + st;
12586                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12587             });
12588             
12589             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12590             
12591             
12592             if(format && useF){
12593                 
12594                 args = args ? ',' + args : "";
12595                  
12596                 if(format.substr(0, 5) != "this."){
12597                     format = "fm." + format + '(';
12598                 }else{
12599                     format = 'this.call("'+ format.substr(5) + '", ';
12600                     args = ", values";
12601                 }
12602                 
12603                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12604             }
12605              
12606             if (args && args.length) {
12607                 // called with xxyx.yuu:(test,test)
12608                 // change to ()
12609                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12610             }
12611             // raw.. - :raw modifier..
12612             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12613             
12614         };
12615         var body;
12616         // branched to use + in gecko and [].join() in others
12617         if(Roo.isGecko){
12618             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12619                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12620                     "';};};";
12621         }else{
12622             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12623             body.push(tpl.body.replace(/(\r\n|\n)/g,
12624                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12625             body.push("'].join('');};};");
12626             body = body.join('');
12627         }
12628         
12629         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12630        
12631         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12632         eval(body);
12633         
12634         return this;
12635     },
12636      
12637     /**
12638      * same as applyTemplate, except it's done to one of the subTemplates
12639      * when using named templates, you can do:
12640      *
12641      * var str = pl.applySubTemplate('your-name', values);
12642      *
12643      * 
12644      * @param {Number} id of the template
12645      * @param {Object} values to apply to template
12646      * @param {Object} parent (normaly the instance of this object)
12647      */
12648     applySubTemplate : function(id, values, parent)
12649     {
12650         
12651         
12652         var t = this.tpls[id];
12653         
12654         
12655         try { 
12656             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12657                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12658                 return '';
12659             }
12660         } catch(e) {
12661             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12662             Roo.log(values);
12663           
12664             return '';
12665         }
12666         try { 
12667             
12668             if(t.execCall && t.execCall.call(this, values, parent)){
12669                 return '';
12670             }
12671         } catch(e) {
12672             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12673             Roo.log(values);
12674             return '';
12675         }
12676         
12677         try {
12678             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12679             parent = t.target ? values : parent;
12680             if(t.forCall && vs instanceof Array){
12681                 var buf = [];
12682                 for(var i = 0, len = vs.length; i < len; i++){
12683                     try {
12684                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12685                     } catch (e) {
12686                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12687                         Roo.log(e.body);
12688                         //Roo.log(t.compiled);
12689                         Roo.log(vs[i]);
12690                     }   
12691                 }
12692                 return buf.join('');
12693             }
12694         } catch (e) {
12695             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12696             Roo.log(values);
12697             return '';
12698         }
12699         try {
12700             return t.compiled.call(this, vs, parent);
12701         } catch (e) {
12702             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12703             Roo.log(e.body);
12704             //Roo.log(t.compiled);
12705             Roo.log(values);
12706             return '';
12707         }
12708     },
12709
12710    
12711
12712     applyTemplate : function(values){
12713         return this.master.compiled.call(this, values, {});
12714         //var s = this.subs;
12715     },
12716
12717     apply : function(){
12718         return this.applyTemplate.apply(this, arguments);
12719     }
12720
12721  });
12722
12723 Roo.DomTemplate.from = function(el){
12724     el = Roo.getDom(el);
12725     return new Roo.Domtemplate(el.value || el.innerHTML);
12726 };/*
12727  * Based on:
12728  * Ext JS Library 1.1.1
12729  * Copyright(c) 2006-2007, Ext JS, LLC.
12730  *
12731  * Originally Released Under LGPL - original licence link has changed is not relivant.
12732  *
12733  * Fork - LGPL
12734  * <script type="text/javascript">
12735  */
12736
12737 /**
12738  * @class Roo.util.DelayedTask
12739  * Provides a convenient method of performing setTimeout where a new
12740  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12741  * You can use this class to buffer
12742  * the keypress events for a certain number of milliseconds, and perform only if they stop
12743  * for that amount of time.
12744  * @constructor The parameters to this constructor serve as defaults and are not required.
12745  * @param {Function} fn (optional) The default function to timeout
12746  * @param {Object} scope (optional) The default scope of that timeout
12747  * @param {Array} args (optional) The default Array of arguments
12748  */
12749 Roo.util.DelayedTask = function(fn, scope, args){
12750     var id = null, d, t;
12751
12752     var call = function(){
12753         var now = new Date().getTime();
12754         if(now - t >= d){
12755             clearInterval(id);
12756             id = null;
12757             fn.apply(scope, args || []);
12758         }
12759     };
12760     /**
12761      * Cancels any pending timeout and queues a new one
12762      * @param {Number} delay The milliseconds to delay
12763      * @param {Function} newFn (optional) Overrides function passed to constructor
12764      * @param {Object} newScope (optional) Overrides scope passed to constructor
12765      * @param {Array} newArgs (optional) Overrides args passed to constructor
12766      */
12767     this.delay = function(delay, newFn, newScope, newArgs){
12768         if(id && delay != d){
12769             this.cancel();
12770         }
12771         d = delay;
12772         t = new Date().getTime();
12773         fn = newFn || fn;
12774         scope = newScope || scope;
12775         args = newArgs || args;
12776         if(!id){
12777             id = setInterval(call, d);
12778         }
12779     };
12780
12781     /**
12782      * Cancel the last queued timeout
12783      */
12784     this.cancel = function(){
12785         if(id){
12786             clearInterval(id);
12787             id = null;
12788         }
12789     };
12790 };/*
12791  * Based on:
12792  * Ext JS Library 1.1.1
12793  * Copyright(c) 2006-2007, Ext JS, LLC.
12794  *
12795  * Originally Released Under LGPL - original licence link has changed is not relivant.
12796  *
12797  * Fork - LGPL
12798  * <script type="text/javascript">
12799  */
12800  
12801  
12802 Roo.util.TaskRunner = function(interval){
12803     interval = interval || 10;
12804     var tasks = [], removeQueue = [];
12805     var id = 0;
12806     var running = false;
12807
12808     var stopThread = function(){
12809         running = false;
12810         clearInterval(id);
12811         id = 0;
12812     };
12813
12814     var startThread = function(){
12815         if(!running){
12816             running = true;
12817             id = setInterval(runTasks, interval);
12818         }
12819     };
12820
12821     var removeTask = function(task){
12822         removeQueue.push(task);
12823         if(task.onStop){
12824             task.onStop();
12825         }
12826     };
12827
12828     var runTasks = function(){
12829         if(removeQueue.length > 0){
12830             for(var i = 0, len = removeQueue.length; i < len; i++){
12831                 tasks.remove(removeQueue[i]);
12832             }
12833             removeQueue = [];
12834             if(tasks.length < 1){
12835                 stopThread();
12836                 return;
12837             }
12838         }
12839         var now = new Date().getTime();
12840         for(var i = 0, len = tasks.length; i < len; ++i){
12841             var t = tasks[i];
12842             var itime = now - t.taskRunTime;
12843             if(t.interval <= itime){
12844                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12845                 t.taskRunTime = now;
12846                 if(rt === false || t.taskRunCount === t.repeat){
12847                     removeTask(t);
12848                     return;
12849                 }
12850             }
12851             if(t.duration && t.duration <= (now - t.taskStartTime)){
12852                 removeTask(t);
12853             }
12854         }
12855     };
12856
12857     /**
12858      * Queues a new task.
12859      * @param {Object} task
12860      */
12861     this.start = function(task){
12862         tasks.push(task);
12863         task.taskStartTime = new Date().getTime();
12864         task.taskRunTime = 0;
12865         task.taskRunCount = 0;
12866         startThread();
12867         return task;
12868     };
12869
12870     this.stop = function(task){
12871         removeTask(task);
12872         return task;
12873     };
12874
12875     this.stopAll = function(){
12876         stopThread();
12877         for(var i = 0, len = tasks.length; i < len; i++){
12878             if(tasks[i].onStop){
12879                 tasks[i].onStop();
12880             }
12881         }
12882         tasks = [];
12883         removeQueue = [];
12884     };
12885 };
12886
12887 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12888  * Based on:
12889  * Ext JS Library 1.1.1
12890  * Copyright(c) 2006-2007, Ext JS, LLC.
12891  *
12892  * Originally Released Under LGPL - original licence link has changed is not relivant.
12893  *
12894  * Fork - LGPL
12895  * <script type="text/javascript">
12896  */
12897
12898  
12899 /**
12900  * @class Roo.util.MixedCollection
12901  * @extends Roo.util.Observable
12902  * A Collection class that maintains both numeric indexes and keys and exposes events.
12903  * @constructor
12904  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12905  * collection (defaults to false)
12906  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12907  * and return the key value for that item.  This is used when available to look up the key on items that
12908  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12909  * equivalent to providing an implementation for the {@link #getKey} method.
12910  */
12911 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12912     this.items = [];
12913     this.map = {};
12914     this.keys = [];
12915     this.length = 0;
12916     this.addEvents({
12917         /**
12918          * @event clear
12919          * Fires when the collection is cleared.
12920          */
12921         "clear" : true,
12922         /**
12923          * @event add
12924          * Fires when an item is added to the collection.
12925          * @param {Number} index The index at which the item was added.
12926          * @param {Object} o The item added.
12927          * @param {String} key The key associated with the added item.
12928          */
12929         "add" : true,
12930         /**
12931          * @event replace
12932          * Fires when an item is replaced in the collection.
12933          * @param {String} key he key associated with the new added.
12934          * @param {Object} old The item being replaced.
12935          * @param {Object} new The new item.
12936          */
12937         "replace" : true,
12938         /**
12939          * @event remove
12940          * Fires when an item is removed from the collection.
12941          * @param {Object} o The item being removed.
12942          * @param {String} key (optional) The key associated with the removed item.
12943          */
12944         "remove" : true,
12945         "sort" : true
12946     });
12947     this.allowFunctions = allowFunctions === true;
12948     if(keyFn){
12949         this.getKey = keyFn;
12950     }
12951     Roo.util.MixedCollection.superclass.constructor.call(this);
12952 };
12953
12954 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12955     allowFunctions : false,
12956     
12957 /**
12958  * Adds an item to the collection.
12959  * @param {String} key The key to associate with the item
12960  * @param {Object} o The item to add.
12961  * @return {Object} The item added.
12962  */
12963     add : function(key, o){
12964         if(arguments.length == 1){
12965             o = arguments[0];
12966             key = this.getKey(o);
12967         }
12968         if(typeof key == "undefined" || key === null){
12969             this.length++;
12970             this.items.push(o);
12971             this.keys.push(null);
12972         }else{
12973             var old = this.map[key];
12974             if(old){
12975                 return this.replace(key, o);
12976             }
12977             this.length++;
12978             this.items.push(o);
12979             this.map[key] = o;
12980             this.keys.push(key);
12981         }
12982         this.fireEvent("add", this.length-1, o, key);
12983         return o;
12984     },
12985        
12986 /**
12987   * MixedCollection has a generic way to fetch keys if you implement getKey.
12988 <pre><code>
12989 // normal way
12990 var mc = new Roo.util.MixedCollection();
12991 mc.add(someEl.dom.id, someEl);
12992 mc.add(otherEl.dom.id, otherEl);
12993 //and so on
12994
12995 // using getKey
12996 var mc = new Roo.util.MixedCollection();
12997 mc.getKey = function(el){
12998    return el.dom.id;
12999 };
13000 mc.add(someEl);
13001 mc.add(otherEl);
13002
13003 // or via the constructor
13004 var mc = new Roo.util.MixedCollection(false, function(el){
13005    return el.dom.id;
13006 });
13007 mc.add(someEl);
13008 mc.add(otherEl);
13009 </code></pre>
13010  * @param o {Object} The item for which to find the key.
13011  * @return {Object} The key for the passed item.
13012  */
13013     getKey : function(o){
13014          return o.id; 
13015     },
13016    
13017 /**
13018  * Replaces an item in the collection.
13019  * @param {String} key The key associated with the item to replace, or the item to replace.
13020  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13021  * @return {Object}  The new item.
13022  */
13023     replace : function(key, o){
13024         if(arguments.length == 1){
13025             o = arguments[0];
13026             key = this.getKey(o);
13027         }
13028         var old = this.item(key);
13029         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13030              return this.add(key, o);
13031         }
13032         var index = this.indexOfKey(key);
13033         this.items[index] = o;
13034         this.map[key] = o;
13035         this.fireEvent("replace", key, old, o);
13036         return o;
13037     },
13038    
13039 /**
13040  * Adds all elements of an Array or an Object to the collection.
13041  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13042  * an Array of values, each of which are added to the collection.
13043  */
13044     addAll : function(objs){
13045         if(arguments.length > 1 || objs instanceof Array){
13046             var args = arguments.length > 1 ? arguments : objs;
13047             for(var i = 0, len = args.length; i < len; i++){
13048                 this.add(args[i]);
13049             }
13050         }else{
13051             for(var key in objs){
13052                 if(this.allowFunctions || typeof objs[key] != "function"){
13053                     this.add(key, objs[key]);
13054                 }
13055             }
13056         }
13057     },
13058    
13059 /**
13060  * Executes the specified function once for every item in the collection, passing each
13061  * item as the first and only parameter. returning false from the function will stop the iteration.
13062  * @param {Function} fn The function to execute for each item.
13063  * @param {Object} scope (optional) The scope in which to execute the function.
13064  */
13065     each : function(fn, scope){
13066         var items = [].concat(this.items); // each safe for removal
13067         for(var i = 0, len = items.length; i < len; i++){
13068             if(fn.call(scope || items[i], items[i], i, len) === false){
13069                 break;
13070             }
13071         }
13072     },
13073    
13074 /**
13075  * Executes the specified function once for every key in the collection, passing each
13076  * key, and its associated item as the first two parameters.
13077  * @param {Function} fn The function to execute for each item.
13078  * @param {Object} scope (optional) The scope in which to execute the function.
13079  */
13080     eachKey : function(fn, scope){
13081         for(var i = 0, len = this.keys.length; i < len; i++){
13082             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13083         }
13084     },
13085    
13086 /**
13087  * Returns the first item in the collection which elicits a true return value from the
13088  * passed selection function.
13089  * @param {Function} fn The selection function to execute for each item.
13090  * @param {Object} scope (optional) The scope in which to execute the function.
13091  * @return {Object} The first item in the collection which returned true from the selection function.
13092  */
13093     find : function(fn, scope){
13094         for(var i = 0, len = this.items.length; i < len; i++){
13095             if(fn.call(scope || window, this.items[i], this.keys[i])){
13096                 return this.items[i];
13097             }
13098         }
13099         return null;
13100     },
13101    
13102 /**
13103  * Inserts an item at the specified index in the collection.
13104  * @param {Number} index The index to insert the item at.
13105  * @param {String} key The key to associate with the new item, or the item itself.
13106  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13107  * @return {Object} The item inserted.
13108  */
13109     insert : function(index, key, o){
13110         if(arguments.length == 2){
13111             o = arguments[1];
13112             key = this.getKey(o);
13113         }
13114         if(index >= this.length){
13115             return this.add(key, o);
13116         }
13117         this.length++;
13118         this.items.splice(index, 0, o);
13119         if(typeof key != "undefined" && key != null){
13120             this.map[key] = o;
13121         }
13122         this.keys.splice(index, 0, key);
13123         this.fireEvent("add", index, o, key);
13124         return o;
13125     },
13126    
13127 /**
13128  * Removed an item from the collection.
13129  * @param {Object} o The item to remove.
13130  * @return {Object} The item removed.
13131  */
13132     remove : function(o){
13133         return this.removeAt(this.indexOf(o));
13134     },
13135    
13136 /**
13137  * Remove an item from a specified index in the collection.
13138  * @param {Number} index The index within the collection of the item to remove.
13139  */
13140     removeAt : function(index){
13141         if(index < this.length && index >= 0){
13142             this.length--;
13143             var o = this.items[index];
13144             this.items.splice(index, 1);
13145             var key = this.keys[index];
13146             if(typeof key != "undefined"){
13147                 delete this.map[key];
13148             }
13149             this.keys.splice(index, 1);
13150             this.fireEvent("remove", o, key);
13151         }
13152     },
13153    
13154 /**
13155  * Removed an item associated with the passed key fom the collection.
13156  * @param {String} key The key of the item to remove.
13157  */
13158     removeKey : function(key){
13159         return this.removeAt(this.indexOfKey(key));
13160     },
13161    
13162 /**
13163  * Returns the number of items in the collection.
13164  * @return {Number} the number of items in the collection.
13165  */
13166     getCount : function(){
13167         return this.length; 
13168     },
13169    
13170 /**
13171  * Returns index within the collection of the passed Object.
13172  * @param {Object} o The item to find the index of.
13173  * @return {Number} index of the item.
13174  */
13175     indexOf : function(o){
13176         if(!this.items.indexOf){
13177             for(var i = 0, len = this.items.length; i < len; i++){
13178                 if(this.items[i] == o) {
13179                     return i;
13180                 }
13181             }
13182             return -1;
13183         }else{
13184             return this.items.indexOf(o);
13185         }
13186     },
13187    
13188 /**
13189  * Returns index within the collection of the passed key.
13190  * @param {String} key The key to find the index of.
13191  * @return {Number} index of the key.
13192  */
13193     indexOfKey : function(key){
13194         if(!this.keys.indexOf){
13195             for(var i = 0, len = this.keys.length; i < len; i++){
13196                 if(this.keys[i] == key) {
13197                     return i;
13198                 }
13199             }
13200             return -1;
13201         }else{
13202             return this.keys.indexOf(key);
13203         }
13204     },
13205    
13206 /**
13207  * Returns the item associated with the passed key OR index. Key has priority over index.
13208  * @param {String/Number} key The key or index of the item.
13209  * @return {Object} The item associated with the passed key.
13210  */
13211     item : function(key){
13212         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13213         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13214     },
13215     
13216 /**
13217  * Returns the item at the specified index.
13218  * @param {Number} index The index of the item.
13219  * @return {Object}
13220  */
13221     itemAt : function(index){
13222         return this.items[index];
13223     },
13224     
13225 /**
13226  * Returns the item associated with the passed key.
13227  * @param {String/Number} key The key of the item.
13228  * @return {Object} The item associated with the passed key.
13229  */
13230     key : function(key){
13231         return this.map[key];
13232     },
13233    
13234 /**
13235  * Returns true if the collection contains the passed Object as an item.
13236  * @param {Object} o  The Object to look for in the collection.
13237  * @return {Boolean} True if the collection contains the Object as an item.
13238  */
13239     contains : function(o){
13240         return this.indexOf(o) != -1;
13241     },
13242    
13243 /**
13244  * Returns true if the collection contains the passed Object as a key.
13245  * @param {String} key The key to look for in the collection.
13246  * @return {Boolean} True if the collection contains the Object as a key.
13247  */
13248     containsKey : function(key){
13249         return typeof this.map[key] != "undefined";
13250     },
13251    
13252 /**
13253  * Removes all items from the collection.
13254  */
13255     clear : function(){
13256         this.length = 0;
13257         this.items = [];
13258         this.keys = [];
13259         this.map = {};
13260         this.fireEvent("clear");
13261     },
13262    
13263 /**
13264  * Returns the first item in the collection.
13265  * @return {Object} the first item in the collection..
13266  */
13267     first : function(){
13268         return this.items[0]; 
13269     },
13270    
13271 /**
13272  * Returns the last item in the collection.
13273  * @return {Object} the last item in the collection..
13274  */
13275     last : function(){
13276         return this.items[this.length-1];   
13277     },
13278     
13279     _sort : function(property, dir, fn){
13280         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13281         fn = fn || function(a, b){
13282             return a-b;
13283         };
13284         var c = [], k = this.keys, items = this.items;
13285         for(var i = 0, len = items.length; i < len; i++){
13286             c[c.length] = {key: k[i], value: items[i], index: i};
13287         }
13288         c.sort(function(a, b){
13289             var v = fn(a[property], b[property]) * dsc;
13290             if(v == 0){
13291                 v = (a.index < b.index ? -1 : 1);
13292             }
13293             return v;
13294         });
13295         for(var i = 0, len = c.length; i < len; i++){
13296             items[i] = c[i].value;
13297             k[i] = c[i].key;
13298         }
13299         this.fireEvent("sort", this);
13300     },
13301     
13302     /**
13303      * Sorts this collection with the passed comparison function
13304      * @param {String} direction (optional) "ASC" or "DESC"
13305      * @param {Function} fn (optional) comparison function
13306      */
13307     sort : function(dir, fn){
13308         this._sort("value", dir, fn);
13309     },
13310     
13311     /**
13312      * Sorts this collection by keys
13313      * @param {String} direction (optional) "ASC" or "DESC"
13314      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13315      */
13316     keySort : function(dir, fn){
13317         this._sort("key", dir, fn || function(a, b){
13318             return String(a).toUpperCase()-String(b).toUpperCase();
13319         });
13320     },
13321     
13322     /**
13323      * Returns a range of items in this collection
13324      * @param {Number} startIndex (optional) defaults to 0
13325      * @param {Number} endIndex (optional) default to the last item
13326      * @return {Array} An array of items
13327      */
13328     getRange : function(start, end){
13329         var items = this.items;
13330         if(items.length < 1){
13331             return [];
13332         }
13333         start = start || 0;
13334         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13335         var r = [];
13336         if(start <= end){
13337             for(var i = start; i <= end; i++) {
13338                     r[r.length] = items[i];
13339             }
13340         }else{
13341             for(var i = start; i >= end; i--) {
13342                     r[r.length] = items[i];
13343             }
13344         }
13345         return r;
13346     },
13347         
13348     /**
13349      * Filter the <i>objects</i> in this collection by a specific property. 
13350      * Returns a new collection that has been filtered.
13351      * @param {String} property A property on your objects
13352      * @param {String/RegExp} value Either string that the property values 
13353      * should start with or a RegExp to test against the property
13354      * @return {MixedCollection} The new filtered collection
13355      */
13356     filter : function(property, value){
13357         if(!value.exec){ // not a regex
13358             value = String(value);
13359             if(value.length == 0){
13360                 return this.clone();
13361             }
13362             value = new RegExp("^" + Roo.escapeRe(value), "i");
13363         }
13364         return this.filterBy(function(o){
13365             return o && value.test(o[property]);
13366         });
13367         },
13368     
13369     /**
13370      * Filter by a function. * Returns a new collection that has been filtered.
13371      * The passed function will be called with each 
13372      * object in the collection. If the function returns true, the value is included 
13373      * otherwise it is filtered.
13374      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13375      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13376      * @return {MixedCollection} The new filtered collection
13377      */
13378     filterBy : function(fn, scope){
13379         var r = new Roo.util.MixedCollection();
13380         r.getKey = this.getKey;
13381         var k = this.keys, it = this.items;
13382         for(var i = 0, len = it.length; i < len; i++){
13383             if(fn.call(scope||this, it[i], k[i])){
13384                                 r.add(k[i], it[i]);
13385                         }
13386         }
13387         return r;
13388     },
13389     
13390     /**
13391      * Creates a duplicate of this collection
13392      * @return {MixedCollection}
13393      */
13394     clone : function(){
13395         var r = new Roo.util.MixedCollection();
13396         var k = this.keys, it = this.items;
13397         for(var i = 0, len = it.length; i < len; i++){
13398             r.add(k[i], it[i]);
13399         }
13400         r.getKey = this.getKey;
13401         return r;
13402     }
13403 });
13404 /**
13405  * Returns the item associated with the passed key or index.
13406  * @method
13407  * @param {String/Number} key The key or index of the item.
13408  * @return {Object} The item associated with the passed key.
13409  */
13410 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13411  * Based on:
13412  * Ext JS Library 1.1.1
13413  * Copyright(c) 2006-2007, Ext JS, LLC.
13414  *
13415  * Originally Released Under LGPL - original licence link has changed is not relivant.
13416  *
13417  * Fork - LGPL
13418  * <script type="text/javascript">
13419  */
13420 /**
13421  * @class Roo.util.JSON
13422  * Modified version of Douglas Crockford"s json.js that doesn"t
13423  * mess with the Object prototype 
13424  * http://www.json.org/js.html
13425  * @singleton
13426  */
13427 Roo.util.JSON = new (function(){
13428     var useHasOwn = {}.hasOwnProperty ? true : false;
13429     
13430     // crashes Safari in some instances
13431     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13432     
13433     var pad = function(n) {
13434         return n < 10 ? "0" + n : n;
13435     };
13436     
13437     var m = {
13438         "\b": '\\b',
13439         "\t": '\\t',
13440         "\n": '\\n',
13441         "\f": '\\f',
13442         "\r": '\\r',
13443         '"' : '\\"',
13444         "\\": '\\\\'
13445     };
13446
13447     var encodeString = function(s){
13448         if (/["\\\x00-\x1f]/.test(s)) {
13449             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13450                 var c = m[b];
13451                 if(c){
13452                     return c;
13453                 }
13454                 c = b.charCodeAt();
13455                 return "\\u00" +
13456                     Math.floor(c / 16).toString(16) +
13457                     (c % 16).toString(16);
13458             }) + '"';
13459         }
13460         return '"' + s + '"';
13461     };
13462     
13463     var encodeArray = function(o){
13464         var a = ["["], b, i, l = o.length, v;
13465             for (i = 0; i < l; i += 1) {
13466                 v = o[i];
13467                 switch (typeof v) {
13468                     case "undefined":
13469                     case "function":
13470                     case "unknown":
13471                         break;
13472                     default:
13473                         if (b) {
13474                             a.push(',');
13475                         }
13476                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13477                         b = true;
13478                 }
13479             }
13480             a.push("]");
13481             return a.join("");
13482     };
13483     
13484     var encodeDate = function(o){
13485         return '"' + o.getFullYear() + "-" +
13486                 pad(o.getMonth() + 1) + "-" +
13487                 pad(o.getDate()) + "T" +
13488                 pad(o.getHours()) + ":" +
13489                 pad(o.getMinutes()) + ":" +
13490                 pad(o.getSeconds()) + '"';
13491     };
13492     
13493     /**
13494      * Encodes an Object, Array or other value
13495      * @param {Mixed} o The variable to encode
13496      * @return {String} The JSON string
13497      */
13498     this.encode = function(o)
13499     {
13500         // should this be extended to fully wrap stringify..
13501         
13502         if(typeof o == "undefined" || o === null){
13503             return "null";
13504         }else if(o instanceof Array){
13505             return encodeArray(o);
13506         }else if(o instanceof Date){
13507             return encodeDate(o);
13508         }else if(typeof o == "string"){
13509             return encodeString(o);
13510         }else if(typeof o == "number"){
13511             return isFinite(o) ? String(o) : "null";
13512         }else if(typeof o == "boolean"){
13513             return String(o);
13514         }else {
13515             var a = ["{"], b, i, v;
13516             for (i in o) {
13517                 if(!useHasOwn || o.hasOwnProperty(i)) {
13518                     v = o[i];
13519                     switch (typeof v) {
13520                     case "undefined":
13521                     case "function":
13522                     case "unknown":
13523                         break;
13524                     default:
13525                         if(b){
13526                             a.push(',');
13527                         }
13528                         a.push(this.encode(i), ":",
13529                                 v === null ? "null" : this.encode(v));
13530                         b = true;
13531                     }
13532                 }
13533             }
13534             a.push("}");
13535             return a.join("");
13536         }
13537     };
13538     
13539     /**
13540      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13541      * @param {String} json The JSON string
13542      * @return {Object} The resulting object
13543      */
13544     this.decode = function(json){
13545         
13546         return  /** eval:var:json */ eval("(" + json + ')');
13547     };
13548 })();
13549 /** 
13550  * Shorthand for {@link Roo.util.JSON#encode}
13551  * @member Roo encode 
13552  * @method */
13553 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13554 /** 
13555  * Shorthand for {@link Roo.util.JSON#decode}
13556  * @member Roo decode 
13557  * @method */
13558 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13559 /*
13560  * Based on:
13561  * Ext JS Library 1.1.1
13562  * Copyright(c) 2006-2007, Ext JS, LLC.
13563  *
13564  * Originally Released Under LGPL - original licence link has changed is not relivant.
13565  *
13566  * Fork - LGPL
13567  * <script type="text/javascript">
13568  */
13569  
13570 /**
13571  * @class Roo.util.Format
13572  * Reusable data formatting functions
13573  * @singleton
13574  */
13575 Roo.util.Format = function(){
13576     var trimRe = /^\s+|\s+$/g;
13577     return {
13578         /**
13579          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13580          * @param {String} value The string to truncate
13581          * @param {Number} length The maximum length to allow before truncating
13582          * @return {String} The converted text
13583          */
13584         ellipsis : function(value, len){
13585             if(value && value.length > len){
13586                 return value.substr(0, len-3)+"...";
13587             }
13588             return value;
13589         },
13590
13591         /**
13592          * Checks a reference and converts it to empty string if it is undefined
13593          * @param {Mixed} value Reference to check
13594          * @return {Mixed} Empty string if converted, otherwise the original value
13595          */
13596         undef : function(value){
13597             return typeof value != "undefined" ? value : "";
13598         },
13599
13600         /**
13601          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13602          * @param {String} value The string to encode
13603          * @return {String} The encoded text
13604          */
13605         htmlEncode : function(value){
13606             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13607         },
13608
13609         /**
13610          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13611          * @param {String} value The string to decode
13612          * @return {String} The decoded text
13613          */
13614         htmlDecode : function(value){
13615             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13616         },
13617
13618         /**
13619          * Trims any whitespace from either side of a string
13620          * @param {String} value The text to trim
13621          * @return {String} The trimmed text
13622          */
13623         trim : function(value){
13624             return String(value).replace(trimRe, "");
13625         },
13626
13627         /**
13628          * Returns a substring from within an original string
13629          * @param {String} value The original text
13630          * @param {Number} start The start index of the substring
13631          * @param {Number} length The length of the substring
13632          * @return {String} The substring
13633          */
13634         substr : function(value, start, length){
13635             return String(value).substr(start, length);
13636         },
13637
13638         /**
13639          * Converts a string to all lower case letters
13640          * @param {String} value The text to convert
13641          * @return {String} The converted text
13642          */
13643         lowercase : function(value){
13644             return String(value).toLowerCase();
13645         },
13646
13647         /**
13648          * Converts a string to all upper case letters
13649          * @param {String} value The text to convert
13650          * @return {String} The converted text
13651          */
13652         uppercase : function(value){
13653             return String(value).toUpperCase();
13654         },
13655
13656         /**
13657          * Converts the first character only of a string to upper case
13658          * @param {String} value The text to convert
13659          * @return {String} The converted text
13660          */
13661         capitalize : function(value){
13662             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13663         },
13664
13665         // private
13666         call : function(value, fn){
13667             if(arguments.length > 2){
13668                 var args = Array.prototype.slice.call(arguments, 2);
13669                 args.unshift(value);
13670                  
13671                 return /** eval:var:value */  eval(fn).apply(window, args);
13672             }else{
13673                 /** eval:var:value */
13674                 return /** eval:var:value */ eval(fn).call(window, value);
13675             }
13676         },
13677
13678        
13679         /**
13680          * safer version of Math.toFixed..??/
13681          * @param {Number/String} value The numeric value to format
13682          * @param {Number/String} value Decimal places 
13683          * @return {String} The formatted currency string
13684          */
13685         toFixed : function(v, n)
13686         {
13687             // why not use to fixed - precision is buggered???
13688             if (!n) {
13689                 return Math.round(v-0);
13690             }
13691             var fact = Math.pow(10,n+1);
13692             v = (Math.round((v-0)*fact))/fact;
13693             var z = (''+fact).substring(2);
13694             if (v == Math.floor(v)) {
13695                 return Math.floor(v) + '.' + z;
13696             }
13697             
13698             // now just padd decimals..
13699             var ps = String(v).split('.');
13700             var fd = (ps[1] + z);
13701             var r = fd.substring(0,n); 
13702             var rm = fd.substring(n); 
13703             if (rm < 5) {
13704                 return ps[0] + '.' + r;
13705             }
13706             r*=1; // turn it into a number;
13707             r++;
13708             if (String(r).length != n) {
13709                 ps[0]*=1;
13710                 ps[0]++;
13711                 r = String(r).substring(1); // chop the end off.
13712             }
13713             
13714             return ps[0] + '.' + r;
13715              
13716         },
13717         
13718         /**
13719          * Format a number as US currency
13720          * @param {Number/String} value The numeric value to format
13721          * @return {String} The formatted currency string
13722          */
13723         usMoney : function(v){
13724             return '$' + Roo.util.Format.number(v);
13725         },
13726         
13727         /**
13728          * Format a number
13729          * eventually this should probably emulate php's number_format
13730          * @param {Number/String} value The numeric value to format
13731          * @param {Number} decimals number of decimal places
13732          * @return {String} The formatted currency string
13733          */
13734         number : function(v,decimals)
13735         {
13736             // multiply and round.
13737             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13738             var mul = Math.pow(10, decimals);
13739             var zero = String(mul).substring(1);
13740             v = (Math.round((v-0)*mul))/mul;
13741             
13742             // if it's '0' number.. then
13743             
13744             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13745             v = String(v);
13746             var ps = v.split('.');
13747             var whole = ps[0];
13748             
13749             
13750             var r = /(\d+)(\d{3})/;
13751             // add comma's
13752             while (r.test(whole)) {
13753                 whole = whole.replace(r, '$1' + ',' + '$2');
13754             }
13755             
13756             
13757             var sub = ps[1] ?
13758                     // has decimals..
13759                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13760                     // does not have decimals
13761                     (decimals ? ('.' + zero) : '');
13762             
13763             
13764             return whole + sub ;
13765         },
13766         
13767         /**
13768          * Parse a value into a formatted date using the specified format pattern.
13769          * @param {Mixed} value The value to format
13770          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13771          * @return {String} The formatted date string
13772          */
13773         date : function(v, format){
13774             if(!v){
13775                 return "";
13776             }
13777             if(!(v instanceof Date)){
13778                 v = new Date(Date.parse(v));
13779             }
13780             return v.dateFormat(format || Roo.util.Format.defaults.date);
13781         },
13782
13783         /**
13784          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13785          * @param {String} format Any valid date format string
13786          * @return {Function} The date formatting function
13787          */
13788         dateRenderer : function(format){
13789             return function(v){
13790                 return Roo.util.Format.date(v, format);  
13791             };
13792         },
13793
13794         // private
13795         stripTagsRE : /<\/?[^>]+>/gi,
13796         
13797         /**
13798          * Strips all HTML tags
13799          * @param {Mixed} value The text from which to strip tags
13800          * @return {String} The stripped text
13801          */
13802         stripTags : function(v){
13803             return !v ? v : String(v).replace(this.stripTagsRE, "");
13804         }
13805     };
13806 }();
13807 Roo.util.Format.defaults = {
13808     date : 'd/M/Y'
13809 };/*
13810  * Based on:
13811  * Ext JS Library 1.1.1
13812  * Copyright(c) 2006-2007, Ext JS, LLC.
13813  *
13814  * Originally Released Under LGPL - original licence link has changed is not relivant.
13815  *
13816  * Fork - LGPL
13817  * <script type="text/javascript">
13818  */
13819
13820
13821  
13822
13823 /**
13824  * @class Roo.MasterTemplate
13825  * @extends Roo.Template
13826  * Provides a template that can have child templates. The syntax is:
13827 <pre><code>
13828 var t = new Roo.MasterTemplate(
13829         '&lt;select name="{name}"&gt;',
13830                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13831         '&lt;/select&gt;'
13832 );
13833 t.add('options', {value: 'foo', text: 'bar'});
13834 // or you can add multiple child elements in one shot
13835 t.addAll('options', [
13836     {value: 'foo', text: 'bar'},
13837     {value: 'foo2', text: 'bar2'},
13838     {value: 'foo3', text: 'bar3'}
13839 ]);
13840 // then append, applying the master template values
13841 t.append('my-form', {name: 'my-select'});
13842 </code></pre>
13843 * A name attribute for the child template is not required if you have only one child
13844 * template or you want to refer to them by index.
13845  */
13846 Roo.MasterTemplate = function(){
13847     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13848     this.originalHtml = this.html;
13849     var st = {};
13850     var m, re = this.subTemplateRe;
13851     re.lastIndex = 0;
13852     var subIndex = 0;
13853     while(m = re.exec(this.html)){
13854         var name = m[1], content = m[2];
13855         st[subIndex] = {
13856             name: name,
13857             index: subIndex,
13858             buffer: [],
13859             tpl : new Roo.Template(content)
13860         };
13861         if(name){
13862             st[name] = st[subIndex];
13863         }
13864         st[subIndex].tpl.compile();
13865         st[subIndex].tpl.call = this.call.createDelegate(this);
13866         subIndex++;
13867     }
13868     this.subCount = subIndex;
13869     this.subs = st;
13870 };
13871 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13872     /**
13873     * The regular expression used to match sub templates
13874     * @type RegExp
13875     * @property
13876     */
13877     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13878
13879     /**
13880      * Applies the passed values to a child template.
13881      * @param {String/Number} name (optional) The name or index of the child template
13882      * @param {Array/Object} values The values to be applied to the template
13883      * @return {MasterTemplate} this
13884      */
13885      add : function(name, values){
13886         if(arguments.length == 1){
13887             values = arguments[0];
13888             name = 0;
13889         }
13890         var s = this.subs[name];
13891         s.buffer[s.buffer.length] = s.tpl.apply(values);
13892         return this;
13893     },
13894
13895     /**
13896      * Applies all the passed values to a child template.
13897      * @param {String/Number} name (optional) The name or index of the child template
13898      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13899      * @param {Boolean} reset (optional) True to reset the template first
13900      * @return {MasterTemplate} this
13901      */
13902     fill : function(name, values, reset){
13903         var a = arguments;
13904         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13905             values = a[0];
13906             name = 0;
13907             reset = a[1];
13908         }
13909         if(reset){
13910             this.reset();
13911         }
13912         for(var i = 0, len = values.length; i < len; i++){
13913             this.add(name, values[i]);
13914         }
13915         return this;
13916     },
13917
13918     /**
13919      * Resets the template for reuse
13920      * @return {MasterTemplate} this
13921      */
13922      reset : function(){
13923         var s = this.subs;
13924         for(var i = 0; i < this.subCount; i++){
13925             s[i].buffer = [];
13926         }
13927         return this;
13928     },
13929
13930     applyTemplate : function(values){
13931         var s = this.subs;
13932         var replaceIndex = -1;
13933         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13934             return s[++replaceIndex].buffer.join("");
13935         });
13936         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13937     },
13938
13939     apply : function(){
13940         return this.applyTemplate.apply(this, arguments);
13941     },
13942
13943     compile : function(){return this;}
13944 });
13945
13946 /**
13947  * Alias for fill().
13948  * @method
13949  */
13950 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13951  /**
13952  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13953  * var tpl = Roo.MasterTemplate.from('element-id');
13954  * @param {String/HTMLElement} el
13955  * @param {Object} config
13956  * @static
13957  */
13958 Roo.MasterTemplate.from = function(el, config){
13959     el = Roo.getDom(el);
13960     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13961 };/*
13962  * Based on:
13963  * Ext JS Library 1.1.1
13964  * Copyright(c) 2006-2007, Ext JS, LLC.
13965  *
13966  * Originally Released Under LGPL - original licence link has changed is not relivant.
13967  *
13968  * Fork - LGPL
13969  * <script type="text/javascript">
13970  */
13971
13972  
13973 /**
13974  * @class Roo.util.CSS
13975  * Utility class for manipulating CSS rules
13976  * @singleton
13977  */
13978 Roo.util.CSS = function(){
13979         var rules = null;
13980         var doc = document;
13981
13982     var camelRe = /(-[a-z])/gi;
13983     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13984
13985    return {
13986    /**
13987     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13988     * tag and appended to the HEAD of the document.
13989     * @param {String|Object} cssText The text containing the css rules
13990     * @param {String} id An id to add to the stylesheet for later removal
13991     * @return {StyleSheet}
13992     */
13993     createStyleSheet : function(cssText, id){
13994         var ss;
13995         var head = doc.getElementsByTagName("head")[0];
13996         var nrules = doc.createElement("style");
13997         nrules.setAttribute("type", "text/css");
13998         if(id){
13999             nrules.setAttribute("id", id);
14000         }
14001         if (typeof(cssText) != 'string') {
14002             // support object maps..
14003             // not sure if this a good idea.. 
14004             // perhaps it should be merged with the general css handling
14005             // and handle js style props.
14006             var cssTextNew = [];
14007             for(var n in cssText) {
14008                 var citems = [];
14009                 for(var k in cssText[n]) {
14010                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14011                 }
14012                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14013                 
14014             }
14015             cssText = cssTextNew.join("\n");
14016             
14017         }
14018        
14019        
14020        if(Roo.isIE){
14021            head.appendChild(nrules);
14022            ss = nrules.styleSheet;
14023            ss.cssText = cssText;
14024        }else{
14025            try{
14026                 nrules.appendChild(doc.createTextNode(cssText));
14027            }catch(e){
14028                nrules.cssText = cssText; 
14029            }
14030            head.appendChild(nrules);
14031            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14032        }
14033        this.cacheStyleSheet(ss);
14034        return ss;
14035    },
14036
14037    /**
14038     * Removes a style or link tag by id
14039     * @param {String} id The id of the tag
14040     */
14041    removeStyleSheet : function(id){
14042        var existing = doc.getElementById(id);
14043        if(existing){
14044            existing.parentNode.removeChild(existing);
14045        }
14046    },
14047
14048    /**
14049     * Dynamically swaps an existing stylesheet reference for a new one
14050     * @param {String} id The id of an existing link tag to remove
14051     * @param {String} url The href of the new stylesheet to include
14052     */
14053    swapStyleSheet : function(id, url){
14054        this.removeStyleSheet(id);
14055        var ss = doc.createElement("link");
14056        ss.setAttribute("rel", "stylesheet");
14057        ss.setAttribute("type", "text/css");
14058        ss.setAttribute("id", id);
14059        ss.setAttribute("href", url);
14060        doc.getElementsByTagName("head")[0].appendChild(ss);
14061    },
14062    
14063    /**
14064     * Refresh the rule cache if you have dynamically added stylesheets
14065     * @return {Object} An object (hash) of rules indexed by selector
14066     */
14067    refreshCache : function(){
14068        return this.getRules(true);
14069    },
14070
14071    // private
14072    cacheStyleSheet : function(stylesheet){
14073        if(!rules){
14074            rules = {};
14075        }
14076        try{// try catch for cross domain access issue
14077            var ssRules = stylesheet.cssRules || stylesheet.rules;
14078            for(var j = ssRules.length-1; j >= 0; --j){
14079                rules[ssRules[j].selectorText] = ssRules[j];
14080            }
14081        }catch(e){}
14082    },
14083    
14084    /**
14085     * Gets all css rules for the document
14086     * @param {Boolean} refreshCache true to refresh the internal cache
14087     * @return {Object} An object (hash) of rules indexed by selector
14088     */
14089    getRules : function(refreshCache){
14090                 if(rules == null || refreshCache){
14091                         rules = {};
14092                         var ds = doc.styleSheets;
14093                         for(var i =0, len = ds.length; i < len; i++){
14094                             try{
14095                         this.cacheStyleSheet(ds[i]);
14096                     }catch(e){} 
14097                 }
14098                 }
14099                 return rules;
14100         },
14101         
14102         /**
14103     * Gets an an individual CSS rule by selector(s)
14104     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14105     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14106     * @return {CSSRule} The CSS rule or null if one is not found
14107     */
14108    getRule : function(selector, refreshCache){
14109                 var rs = this.getRules(refreshCache);
14110                 if(!(selector instanceof Array)){
14111                     return rs[selector];
14112                 }
14113                 for(var i = 0; i < selector.length; i++){
14114                         if(rs[selector[i]]){
14115                                 return rs[selector[i]];
14116                         }
14117                 }
14118                 return null;
14119         },
14120         
14121         
14122         /**
14123     * Updates a rule property
14124     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14125     * @param {String} property The css property
14126     * @param {String} value The new value for the property
14127     * @return {Boolean} true If a rule was found and updated
14128     */
14129    updateRule : function(selector, property, value){
14130                 if(!(selector instanceof Array)){
14131                         var rule = this.getRule(selector);
14132                         if(rule){
14133                                 rule.style[property.replace(camelRe, camelFn)] = value;
14134                                 return true;
14135                         }
14136                 }else{
14137                         for(var i = 0; i < selector.length; i++){
14138                                 if(this.updateRule(selector[i], property, value)){
14139                                         return true;
14140                                 }
14141                         }
14142                 }
14143                 return false;
14144         }
14145    };   
14146 }();/*
14147  * Based on:
14148  * Ext JS Library 1.1.1
14149  * Copyright(c) 2006-2007, Ext JS, LLC.
14150  *
14151  * Originally Released Under LGPL - original licence link has changed is not relivant.
14152  *
14153  * Fork - LGPL
14154  * <script type="text/javascript">
14155  */
14156
14157  
14158
14159 /**
14160  * @class Roo.util.ClickRepeater
14161  * @extends Roo.util.Observable
14162  * 
14163  * A wrapper class which can be applied to any element. Fires a "click" event while the
14164  * mouse is pressed. The interval between firings may be specified in the config but
14165  * defaults to 10 milliseconds.
14166  * 
14167  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14168  * 
14169  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14170  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14171  * Similar to an autorepeat key delay.
14172  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14173  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14174  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14175  *           "interval" and "delay" are ignored. "immediate" is honored.
14176  * @cfg {Boolean} preventDefault True to prevent the default click event
14177  * @cfg {Boolean} stopDefault True to stop the default click event
14178  * 
14179  * @history
14180  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14181  *     2007-02-02 jvs Renamed to ClickRepeater
14182  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14183  *
14184  *  @constructor
14185  * @param {String/HTMLElement/Element} el The element to listen on
14186  * @param {Object} config
14187  **/
14188 Roo.util.ClickRepeater = function(el, config)
14189 {
14190     this.el = Roo.get(el);
14191     this.el.unselectable();
14192
14193     Roo.apply(this, config);
14194
14195     this.addEvents({
14196     /**
14197      * @event mousedown
14198      * Fires when the mouse button is depressed.
14199      * @param {Roo.util.ClickRepeater} this
14200      */
14201         "mousedown" : true,
14202     /**
14203      * @event click
14204      * Fires on a specified interval during the time the element is pressed.
14205      * @param {Roo.util.ClickRepeater} this
14206      */
14207         "click" : true,
14208     /**
14209      * @event mouseup
14210      * Fires when the mouse key is released.
14211      * @param {Roo.util.ClickRepeater} this
14212      */
14213         "mouseup" : true
14214     });
14215
14216     this.el.on("mousedown", this.handleMouseDown, this);
14217     if(this.preventDefault || this.stopDefault){
14218         this.el.on("click", function(e){
14219             if(this.preventDefault){
14220                 e.preventDefault();
14221             }
14222             if(this.stopDefault){
14223                 e.stopEvent();
14224             }
14225         }, this);
14226     }
14227
14228     // allow inline handler
14229     if(this.handler){
14230         this.on("click", this.handler,  this.scope || this);
14231     }
14232
14233     Roo.util.ClickRepeater.superclass.constructor.call(this);
14234 };
14235
14236 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14237     interval : 20,
14238     delay: 250,
14239     preventDefault : true,
14240     stopDefault : false,
14241     timer : 0,
14242
14243     // private
14244     handleMouseDown : function(){
14245         clearTimeout(this.timer);
14246         this.el.blur();
14247         if(this.pressClass){
14248             this.el.addClass(this.pressClass);
14249         }
14250         this.mousedownTime = new Date();
14251
14252         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14253         this.el.on("mouseout", this.handleMouseOut, this);
14254
14255         this.fireEvent("mousedown", this);
14256         this.fireEvent("click", this);
14257         
14258         this.timer = this.click.defer(this.delay || this.interval, this);
14259     },
14260
14261     // private
14262     click : function(){
14263         this.fireEvent("click", this);
14264         this.timer = this.click.defer(this.getInterval(), this);
14265     },
14266
14267     // private
14268     getInterval: function(){
14269         if(!this.accelerate){
14270             return this.interval;
14271         }
14272         var pressTime = this.mousedownTime.getElapsed();
14273         if(pressTime < 500){
14274             return 400;
14275         }else if(pressTime < 1700){
14276             return 320;
14277         }else if(pressTime < 2600){
14278             return 250;
14279         }else if(pressTime < 3500){
14280             return 180;
14281         }else if(pressTime < 4400){
14282             return 140;
14283         }else if(pressTime < 5300){
14284             return 80;
14285         }else if(pressTime < 6200){
14286             return 50;
14287         }else{
14288             return 10;
14289         }
14290     },
14291
14292     // private
14293     handleMouseOut : function(){
14294         clearTimeout(this.timer);
14295         if(this.pressClass){
14296             this.el.removeClass(this.pressClass);
14297         }
14298         this.el.on("mouseover", this.handleMouseReturn, this);
14299     },
14300
14301     // private
14302     handleMouseReturn : function(){
14303         this.el.un("mouseover", this.handleMouseReturn);
14304         if(this.pressClass){
14305             this.el.addClass(this.pressClass);
14306         }
14307         this.click();
14308     },
14309
14310     // private
14311     handleMouseUp : function(){
14312         clearTimeout(this.timer);
14313         this.el.un("mouseover", this.handleMouseReturn);
14314         this.el.un("mouseout", this.handleMouseOut);
14315         Roo.get(document).un("mouseup", this.handleMouseUp);
14316         this.el.removeClass(this.pressClass);
14317         this.fireEvent("mouseup", this);
14318     }
14319 });/*
14320  * Based on:
14321  * Ext JS Library 1.1.1
14322  * Copyright(c) 2006-2007, Ext JS, LLC.
14323  *
14324  * Originally Released Under LGPL - original licence link has changed is not relivant.
14325  *
14326  * Fork - LGPL
14327  * <script type="text/javascript">
14328  */
14329
14330  
14331 /**
14332  * @class Roo.KeyNav
14333  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14334  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14335  * way to implement custom navigation schemes for any UI component.</p>
14336  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14337  * pageUp, pageDown, del, home, end.  Usage:</p>
14338  <pre><code>
14339 var nav = new Roo.KeyNav("my-element", {
14340     "left" : function(e){
14341         this.moveLeft(e.ctrlKey);
14342     },
14343     "right" : function(e){
14344         this.moveRight(e.ctrlKey);
14345     },
14346     "enter" : function(e){
14347         this.save();
14348     },
14349     scope : this
14350 });
14351 </code></pre>
14352  * @constructor
14353  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14354  * @param {Object} config The config
14355  */
14356 Roo.KeyNav = function(el, config){
14357     this.el = Roo.get(el);
14358     Roo.apply(this, config);
14359     if(!this.disabled){
14360         this.disabled = true;
14361         this.enable();
14362     }
14363 };
14364
14365 Roo.KeyNav.prototype = {
14366     /**
14367      * @cfg {Boolean} disabled
14368      * True to disable this KeyNav instance (defaults to false)
14369      */
14370     disabled : false,
14371     /**
14372      * @cfg {String} defaultEventAction
14373      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14374      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14375      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14376      */
14377     defaultEventAction: "stopEvent",
14378     /**
14379      * @cfg {Boolean} forceKeyDown
14380      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14381      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14382      * handle keydown instead of keypress.
14383      */
14384     forceKeyDown : false,
14385
14386     // private
14387     prepareEvent : function(e){
14388         var k = e.getKey();
14389         var h = this.keyToHandler[k];
14390         //if(h && this[h]){
14391         //    e.stopPropagation();
14392         //}
14393         if(Roo.isSafari && h && k >= 37 && k <= 40){
14394             e.stopEvent();
14395         }
14396     },
14397
14398     // private
14399     relay : function(e){
14400         var k = e.getKey();
14401         var h = this.keyToHandler[k];
14402         if(h && this[h]){
14403             if(this.doRelay(e, this[h], h) !== true){
14404                 e[this.defaultEventAction]();
14405             }
14406         }
14407     },
14408
14409     // private
14410     doRelay : function(e, h, hname){
14411         return h.call(this.scope || this, e);
14412     },
14413
14414     // possible handlers
14415     enter : false,
14416     left : false,
14417     right : false,
14418     up : false,
14419     down : false,
14420     tab : false,
14421     esc : false,
14422     pageUp : false,
14423     pageDown : false,
14424     del : false,
14425     home : false,
14426     end : false,
14427
14428     // quick lookup hash
14429     keyToHandler : {
14430         37 : "left",
14431         39 : "right",
14432         38 : "up",
14433         40 : "down",
14434         33 : "pageUp",
14435         34 : "pageDown",
14436         46 : "del",
14437         36 : "home",
14438         35 : "end",
14439         13 : "enter",
14440         27 : "esc",
14441         9  : "tab"
14442     },
14443
14444         /**
14445          * Enable this KeyNav
14446          */
14447         enable: function(){
14448                 if(this.disabled){
14449             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14450             // the EventObject will normalize Safari automatically
14451             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14452                 this.el.on("keydown", this.relay,  this);
14453             }else{
14454                 this.el.on("keydown", this.prepareEvent,  this);
14455                 this.el.on("keypress", this.relay,  this);
14456             }
14457                     this.disabled = false;
14458                 }
14459         },
14460
14461         /**
14462          * Disable this KeyNav
14463          */
14464         disable: function(){
14465                 if(!this.disabled){
14466                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14467                 this.el.un("keydown", this.relay);
14468             }else{
14469                 this.el.un("keydown", this.prepareEvent);
14470                 this.el.un("keypress", this.relay);
14471             }
14472                     this.disabled = true;
14473                 }
14474         }
14475 };/*
14476  * Based on:
14477  * Ext JS Library 1.1.1
14478  * Copyright(c) 2006-2007, Ext JS, LLC.
14479  *
14480  * Originally Released Under LGPL - original licence link has changed is not relivant.
14481  *
14482  * Fork - LGPL
14483  * <script type="text/javascript">
14484  */
14485
14486  
14487 /**
14488  * @class Roo.KeyMap
14489  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14490  * The constructor accepts the same config object as defined by {@link #addBinding}.
14491  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14492  * combination it will call the function with this signature (if the match is a multi-key
14493  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14494  * A KeyMap can also handle a string representation of keys.<br />
14495  * Usage:
14496  <pre><code>
14497 // map one key by key code
14498 var map = new Roo.KeyMap("my-element", {
14499     key: 13, // or Roo.EventObject.ENTER
14500     fn: myHandler,
14501     scope: myObject
14502 });
14503
14504 // map multiple keys to one action by string
14505 var map = new Roo.KeyMap("my-element", {
14506     key: "a\r\n\t",
14507     fn: myHandler,
14508     scope: myObject
14509 });
14510
14511 // map multiple keys to multiple actions by strings and array of codes
14512 var map = new Roo.KeyMap("my-element", [
14513     {
14514         key: [10,13],
14515         fn: function(){ alert("Return was pressed"); }
14516     }, {
14517         key: "abc",
14518         fn: function(){ alert('a, b or c was pressed'); }
14519     }, {
14520         key: "\t",
14521         ctrl:true,
14522         shift:true,
14523         fn: function(){ alert('Control + shift + tab was pressed.'); }
14524     }
14525 ]);
14526 </code></pre>
14527  * <b>Note: A KeyMap starts enabled</b>
14528  * @constructor
14529  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14530  * @param {Object} config The config (see {@link #addBinding})
14531  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14532  */
14533 Roo.KeyMap = function(el, config, eventName){
14534     this.el  = Roo.get(el);
14535     this.eventName = eventName || "keydown";
14536     this.bindings = [];
14537     if(config){
14538         this.addBinding(config);
14539     }
14540     this.enable();
14541 };
14542
14543 Roo.KeyMap.prototype = {
14544     /**
14545      * True to stop the event from bubbling and prevent the default browser action if the
14546      * key was handled by the KeyMap (defaults to false)
14547      * @type Boolean
14548      */
14549     stopEvent : false,
14550
14551     /**
14552      * Add a new binding to this KeyMap. The following config object properties are supported:
14553      * <pre>
14554 Property    Type             Description
14555 ----------  ---------------  ----------------------------------------------------------------------
14556 key         String/Array     A single keycode or an array of keycodes to handle
14557 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14558 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14559 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14560 fn          Function         The function to call when KeyMap finds the expected key combination
14561 scope       Object           The scope of the callback function
14562 </pre>
14563      *
14564      * Usage:
14565      * <pre><code>
14566 // Create a KeyMap
14567 var map = new Roo.KeyMap(document, {
14568     key: Roo.EventObject.ENTER,
14569     fn: handleKey,
14570     scope: this
14571 });
14572
14573 //Add a new binding to the existing KeyMap later
14574 map.addBinding({
14575     key: 'abc',
14576     shift: true,
14577     fn: handleKey,
14578     scope: this
14579 });
14580 </code></pre>
14581      * @param {Object/Array} config A single KeyMap config or an array of configs
14582      */
14583         addBinding : function(config){
14584         if(config instanceof Array){
14585             for(var i = 0, len = config.length; i < len; i++){
14586                 this.addBinding(config[i]);
14587             }
14588             return;
14589         }
14590         var keyCode = config.key,
14591             shift = config.shift, 
14592             ctrl = config.ctrl, 
14593             alt = config.alt,
14594             fn = config.fn,
14595             scope = config.scope;
14596         if(typeof keyCode == "string"){
14597             var ks = [];
14598             var keyString = keyCode.toUpperCase();
14599             for(var j = 0, len = keyString.length; j < len; j++){
14600                 ks.push(keyString.charCodeAt(j));
14601             }
14602             keyCode = ks;
14603         }
14604         var keyArray = keyCode instanceof Array;
14605         var handler = function(e){
14606             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14607                 var k = e.getKey();
14608                 if(keyArray){
14609                     for(var i = 0, len = keyCode.length; i < len; i++){
14610                         if(keyCode[i] == k){
14611                           if(this.stopEvent){
14612                               e.stopEvent();
14613                           }
14614                           fn.call(scope || window, k, e);
14615                           return;
14616                         }
14617                     }
14618                 }else{
14619                     if(k == keyCode){
14620                         if(this.stopEvent){
14621                            e.stopEvent();
14622                         }
14623                         fn.call(scope || window, k, e);
14624                     }
14625                 }
14626             }
14627         };
14628         this.bindings.push(handler);  
14629         },
14630
14631     /**
14632      * Shorthand for adding a single key listener
14633      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14634      * following options:
14635      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14636      * @param {Function} fn The function to call
14637      * @param {Object} scope (optional) The scope of the function
14638      */
14639     on : function(key, fn, scope){
14640         var keyCode, shift, ctrl, alt;
14641         if(typeof key == "object" && !(key instanceof Array)){
14642             keyCode = key.key;
14643             shift = key.shift;
14644             ctrl = key.ctrl;
14645             alt = key.alt;
14646         }else{
14647             keyCode = key;
14648         }
14649         this.addBinding({
14650             key: keyCode,
14651             shift: shift,
14652             ctrl: ctrl,
14653             alt: alt,
14654             fn: fn,
14655             scope: scope
14656         })
14657     },
14658
14659     // private
14660     handleKeyDown : function(e){
14661             if(this.enabled){ //just in case
14662             var b = this.bindings;
14663             for(var i = 0, len = b.length; i < len; i++){
14664                 b[i].call(this, e);
14665             }
14666             }
14667         },
14668         
14669         /**
14670          * Returns true if this KeyMap is enabled
14671          * @return {Boolean} 
14672          */
14673         isEnabled : function(){
14674             return this.enabled;  
14675         },
14676         
14677         /**
14678          * Enables this KeyMap
14679          */
14680         enable: function(){
14681                 if(!this.enabled){
14682                     this.el.on(this.eventName, this.handleKeyDown, this);
14683                     this.enabled = true;
14684                 }
14685         },
14686
14687         /**
14688          * Disable this KeyMap
14689          */
14690         disable: function(){
14691                 if(this.enabled){
14692                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14693                     this.enabled = false;
14694                 }
14695         }
14696 };/*
14697  * Based on:
14698  * Ext JS Library 1.1.1
14699  * Copyright(c) 2006-2007, Ext JS, LLC.
14700  *
14701  * Originally Released Under LGPL - original licence link has changed is not relivant.
14702  *
14703  * Fork - LGPL
14704  * <script type="text/javascript">
14705  */
14706
14707  
14708 /**
14709  * @class Roo.util.TextMetrics
14710  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14711  * wide, in pixels, a given block of text will be.
14712  * @singleton
14713  */
14714 Roo.util.TextMetrics = function(){
14715     var shared;
14716     return {
14717         /**
14718          * Measures the size of the specified text
14719          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14720          * that can affect the size of the rendered text
14721          * @param {String} text The text to measure
14722          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14723          * in order to accurately measure the text height
14724          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14725          */
14726         measure : function(el, text, fixedWidth){
14727             if(!shared){
14728                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14729             }
14730             shared.bind(el);
14731             shared.setFixedWidth(fixedWidth || 'auto');
14732             return shared.getSize(text);
14733         },
14734
14735         /**
14736          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14737          * the overhead of multiple calls to initialize the style properties on each measurement.
14738          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14739          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14740          * in order to accurately measure the text height
14741          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14742          */
14743         createInstance : function(el, fixedWidth){
14744             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14745         }
14746     };
14747 }();
14748
14749  
14750
14751 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14752     var ml = new Roo.Element(document.createElement('div'));
14753     document.body.appendChild(ml.dom);
14754     ml.position('absolute');
14755     ml.setLeftTop(-1000, -1000);
14756     ml.hide();
14757
14758     if(fixedWidth){
14759         ml.setWidth(fixedWidth);
14760     }
14761      
14762     var instance = {
14763         /**
14764          * Returns the size of the specified text based on the internal element's style and width properties
14765          * @memberOf Roo.util.TextMetrics.Instance#
14766          * @param {String} text The text to measure
14767          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14768          */
14769         getSize : function(text){
14770             ml.update(text);
14771             var s = ml.getSize();
14772             ml.update('');
14773             return s;
14774         },
14775
14776         /**
14777          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14778          * that can affect the size of the rendered text
14779          * @memberOf Roo.util.TextMetrics.Instance#
14780          * @param {String/HTMLElement} el The element, dom node or id
14781          */
14782         bind : function(el){
14783             ml.setStyle(
14784                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14785             );
14786         },
14787
14788         /**
14789          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14790          * to set a fixed width in order to accurately measure the text height.
14791          * @memberOf Roo.util.TextMetrics.Instance#
14792          * @param {Number} width The width to set on the element
14793          */
14794         setFixedWidth : function(width){
14795             ml.setWidth(width);
14796         },
14797
14798         /**
14799          * Returns the measured width of the specified text
14800          * @memberOf Roo.util.TextMetrics.Instance#
14801          * @param {String} text The text to measure
14802          * @return {Number} width The width in pixels
14803          */
14804         getWidth : function(text){
14805             ml.dom.style.width = 'auto';
14806             return this.getSize(text).width;
14807         },
14808
14809         /**
14810          * Returns the measured height of the specified text.  For multiline text, be sure to call
14811          * {@link #setFixedWidth} if necessary.
14812          * @memberOf Roo.util.TextMetrics.Instance#
14813          * @param {String} text The text to measure
14814          * @return {Number} height The height in pixels
14815          */
14816         getHeight : function(text){
14817             return this.getSize(text).height;
14818         }
14819     };
14820
14821     instance.bind(bindTo);
14822
14823     return instance;
14824 };
14825
14826 // backwards compat
14827 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14828  * Based on:
14829  * Ext JS Library 1.1.1
14830  * Copyright(c) 2006-2007, Ext JS, LLC.
14831  *
14832  * Originally Released Under LGPL - original licence link has changed is not relivant.
14833  *
14834  * Fork - LGPL
14835  * <script type="text/javascript">
14836  */
14837
14838 /**
14839  * @class Roo.state.Provider
14840  * Abstract base class for state provider implementations. This class provides methods
14841  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14842  * Provider interface.
14843  */
14844 Roo.state.Provider = function(){
14845     /**
14846      * @event statechange
14847      * Fires when a state change occurs.
14848      * @param {Provider} this This state provider
14849      * @param {String} key The state key which was changed
14850      * @param {String} value The encoded value for the state
14851      */
14852     this.addEvents({
14853         "statechange": true
14854     });
14855     this.state = {};
14856     Roo.state.Provider.superclass.constructor.call(this);
14857 };
14858 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14859     /**
14860      * Returns the current value for a key
14861      * @param {String} name The key name
14862      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14863      * @return {Mixed} The state data
14864      */
14865     get : function(name, defaultValue){
14866         return typeof this.state[name] == "undefined" ?
14867             defaultValue : this.state[name];
14868     },
14869     
14870     /**
14871      * Clears a value from the state
14872      * @param {String} name The key name
14873      */
14874     clear : function(name){
14875         delete this.state[name];
14876         this.fireEvent("statechange", this, name, null);
14877     },
14878     
14879     /**
14880      * Sets the value for a key
14881      * @param {String} name The key name
14882      * @param {Mixed} value The value to set
14883      */
14884     set : function(name, value){
14885         this.state[name] = value;
14886         this.fireEvent("statechange", this, name, value);
14887     },
14888     
14889     /**
14890      * Decodes a string previously encoded with {@link #encodeValue}.
14891      * @param {String} value The value to decode
14892      * @return {Mixed} The decoded value
14893      */
14894     decodeValue : function(cookie){
14895         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14896         var matches = re.exec(unescape(cookie));
14897         if(!matches || !matches[1]) {
14898             return; // non state cookie
14899         }
14900         var type = matches[1];
14901         var v = matches[2];
14902         switch(type){
14903             case "n":
14904                 return parseFloat(v);
14905             case "d":
14906                 return new Date(Date.parse(v));
14907             case "b":
14908                 return (v == "1");
14909             case "a":
14910                 var all = [];
14911                 var values = v.split("^");
14912                 for(var i = 0, len = values.length; i < len; i++){
14913                     all.push(this.decodeValue(values[i]));
14914                 }
14915                 return all;
14916            case "o":
14917                 var all = {};
14918                 var values = v.split("^");
14919                 for(var i = 0, len = values.length; i < len; i++){
14920                     var kv = values[i].split("=");
14921                     all[kv[0]] = this.decodeValue(kv[1]);
14922                 }
14923                 return all;
14924            default:
14925                 return v;
14926         }
14927     },
14928     
14929     /**
14930      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14931      * @param {Mixed} value The value to encode
14932      * @return {String} The encoded value
14933      */
14934     encodeValue : function(v){
14935         var enc;
14936         if(typeof v == "number"){
14937             enc = "n:" + v;
14938         }else if(typeof v == "boolean"){
14939             enc = "b:" + (v ? "1" : "0");
14940         }else if(v instanceof Date){
14941             enc = "d:" + v.toGMTString();
14942         }else if(v instanceof Array){
14943             var flat = "";
14944             for(var i = 0, len = v.length; i < len; i++){
14945                 flat += this.encodeValue(v[i]);
14946                 if(i != len-1) {
14947                     flat += "^";
14948                 }
14949             }
14950             enc = "a:" + flat;
14951         }else if(typeof v == "object"){
14952             var flat = "";
14953             for(var key in v){
14954                 if(typeof v[key] != "function"){
14955                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14956                 }
14957             }
14958             enc = "o:" + flat.substring(0, flat.length-1);
14959         }else{
14960             enc = "s:" + v;
14961         }
14962         return escape(enc);        
14963     }
14964 });
14965
14966 /*
14967  * Based on:
14968  * Ext JS Library 1.1.1
14969  * Copyright(c) 2006-2007, Ext JS, LLC.
14970  *
14971  * Originally Released Under LGPL - original licence link has changed is not relivant.
14972  *
14973  * Fork - LGPL
14974  * <script type="text/javascript">
14975  */
14976 /**
14977  * @class Roo.state.Manager
14978  * This is the global state manager. By default all components that are "state aware" check this class
14979  * for state information if you don't pass them a custom state provider. In order for this class
14980  * to be useful, it must be initialized with a provider when your application initializes.
14981  <pre><code>
14982 // in your initialization function
14983 init : function(){
14984    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14985    ...
14986    // supposed you have a {@link Roo.BorderLayout}
14987    var layout = new Roo.BorderLayout(...);
14988    layout.restoreState();
14989    // or a {Roo.BasicDialog}
14990    var dialog = new Roo.BasicDialog(...);
14991    dialog.restoreState();
14992  </code></pre>
14993  * @singleton
14994  */
14995 Roo.state.Manager = function(){
14996     var provider = new Roo.state.Provider();
14997     
14998     return {
14999         /**
15000          * Configures the default state provider for your application
15001          * @param {Provider} stateProvider The state provider to set
15002          */
15003         setProvider : function(stateProvider){
15004             provider = stateProvider;
15005         },
15006         
15007         /**
15008          * Returns the current value for a key
15009          * @param {String} name The key name
15010          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15011          * @return {Mixed} The state data
15012          */
15013         get : function(key, defaultValue){
15014             return provider.get(key, defaultValue);
15015         },
15016         
15017         /**
15018          * Sets the value for a key
15019          * @param {String} name The key name
15020          * @param {Mixed} value The state data
15021          */
15022          set : function(key, value){
15023             provider.set(key, value);
15024         },
15025         
15026         /**
15027          * Clears a value from the state
15028          * @param {String} name The key name
15029          */
15030         clear : function(key){
15031             provider.clear(key);
15032         },
15033         
15034         /**
15035          * Gets the currently configured state provider
15036          * @return {Provider} The state provider
15037          */
15038         getProvider : function(){
15039             return provider;
15040         }
15041     };
15042 }();
15043 /*
15044  * Based on:
15045  * Ext JS Library 1.1.1
15046  * Copyright(c) 2006-2007, Ext JS, LLC.
15047  *
15048  * Originally Released Under LGPL - original licence link has changed is not relivant.
15049  *
15050  * Fork - LGPL
15051  * <script type="text/javascript">
15052  */
15053 /**
15054  * @class Roo.state.CookieProvider
15055  * @extends Roo.state.Provider
15056  * The default Provider implementation which saves state via cookies.
15057  * <br />Usage:
15058  <pre><code>
15059    var cp = new Roo.state.CookieProvider({
15060        path: "/cgi-bin/",
15061        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15062        domain: "roojs.com"
15063    })
15064    Roo.state.Manager.setProvider(cp);
15065  </code></pre>
15066  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15067  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15068  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15069  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15070  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15071  * domain the page is running on including the 'www' like 'www.roojs.com')
15072  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15073  * @constructor
15074  * Create a new CookieProvider
15075  * @param {Object} config The configuration object
15076  */
15077 Roo.state.CookieProvider = function(config){
15078     Roo.state.CookieProvider.superclass.constructor.call(this);
15079     this.path = "/";
15080     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15081     this.domain = null;
15082     this.secure = false;
15083     Roo.apply(this, config);
15084     this.state = this.readCookies();
15085 };
15086
15087 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15088     // private
15089     set : function(name, value){
15090         if(typeof value == "undefined" || value === null){
15091             this.clear(name);
15092             return;
15093         }
15094         this.setCookie(name, value);
15095         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15096     },
15097
15098     // private
15099     clear : function(name){
15100         this.clearCookie(name);
15101         Roo.state.CookieProvider.superclass.clear.call(this, name);
15102     },
15103
15104     // private
15105     readCookies : function(){
15106         var cookies = {};
15107         var c = document.cookie + ";";
15108         var re = /\s?(.*?)=(.*?);/g;
15109         var matches;
15110         while((matches = re.exec(c)) != null){
15111             var name = matches[1];
15112             var value = matches[2];
15113             if(name && name.substring(0,3) == "ys-"){
15114                 cookies[name.substr(3)] = this.decodeValue(value);
15115             }
15116         }
15117         return cookies;
15118     },
15119
15120     // private
15121     setCookie : function(name, value){
15122         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15123            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15124            ((this.path == null) ? "" : ("; path=" + this.path)) +
15125            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15126            ((this.secure == true) ? "; secure" : "");
15127     },
15128
15129     // private
15130     clearCookie : function(name){
15131         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15132            ((this.path == null) ? "" : ("; path=" + this.path)) +
15133            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15134            ((this.secure == true) ? "; secure" : "");
15135     }
15136 });/*
15137  * Based on:
15138  * Ext JS Library 1.1.1
15139  * Copyright(c) 2006-2007, Ext JS, LLC.
15140  *
15141  * Originally Released Under LGPL - original licence link has changed is not relivant.
15142  *
15143  * Fork - LGPL
15144  * <script type="text/javascript">
15145  */
15146  
15147
15148 /**
15149  * @class Roo.ComponentMgr
15150  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15151  * @singleton
15152  */
15153 Roo.ComponentMgr = function(){
15154     var all = new Roo.util.MixedCollection();
15155
15156     return {
15157         /**
15158          * Registers a component.
15159          * @param {Roo.Component} c The component
15160          */
15161         register : function(c){
15162             all.add(c);
15163         },
15164
15165         /**
15166          * Unregisters a component.
15167          * @param {Roo.Component} c The component
15168          */
15169         unregister : function(c){
15170             all.remove(c);
15171         },
15172
15173         /**
15174          * Returns a component by id
15175          * @param {String} id The component id
15176          */
15177         get : function(id){
15178             return all.get(id);
15179         },
15180
15181         /**
15182          * Registers a function that will be called when a specified component is added to ComponentMgr
15183          * @param {String} id The component id
15184          * @param {Funtction} fn The callback function
15185          * @param {Object} scope The scope of the callback
15186          */
15187         onAvailable : function(id, fn, scope){
15188             all.on("add", function(index, o){
15189                 if(o.id == id){
15190                     fn.call(scope || o, o);
15191                     all.un("add", fn, scope);
15192                 }
15193             });
15194         }
15195     };
15196 }();/*
15197  * Based on:
15198  * Ext JS Library 1.1.1
15199  * Copyright(c) 2006-2007, Ext JS, LLC.
15200  *
15201  * Originally Released Under LGPL - original licence link has changed is not relivant.
15202  *
15203  * Fork - LGPL
15204  * <script type="text/javascript">
15205  */
15206  
15207 /**
15208  * @class Roo.Component
15209  * @extends Roo.util.Observable
15210  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15211  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15212  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15213  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15214  * All visual components (widgets) that require rendering into a layout should subclass Component.
15215  * @constructor
15216  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15217  * 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
15218  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15219  */
15220 Roo.Component = function(config){
15221     config = config || {};
15222     if(config.tagName || config.dom || typeof config == "string"){ // element object
15223         config = {el: config, id: config.id || config};
15224     }
15225     this.initialConfig = config;
15226
15227     Roo.apply(this, config);
15228     this.addEvents({
15229         /**
15230          * @event disable
15231          * Fires after the component is disabled.
15232              * @param {Roo.Component} this
15233              */
15234         disable : true,
15235         /**
15236          * @event enable
15237          * Fires after the component is enabled.
15238              * @param {Roo.Component} this
15239              */
15240         enable : true,
15241         /**
15242          * @event beforeshow
15243          * Fires before the component is shown.  Return false to stop the show.
15244              * @param {Roo.Component} this
15245              */
15246         beforeshow : true,
15247         /**
15248          * @event show
15249          * Fires after the component is shown.
15250              * @param {Roo.Component} this
15251              */
15252         show : true,
15253         /**
15254          * @event beforehide
15255          * Fires before the component is hidden. Return false to stop the hide.
15256              * @param {Roo.Component} this
15257              */
15258         beforehide : true,
15259         /**
15260          * @event hide
15261          * Fires after the component is hidden.
15262              * @param {Roo.Component} this
15263              */
15264         hide : true,
15265         /**
15266          * @event beforerender
15267          * Fires before the component is rendered. Return false to stop the render.
15268              * @param {Roo.Component} this
15269              */
15270         beforerender : true,
15271         /**
15272          * @event render
15273          * Fires after the component is rendered.
15274              * @param {Roo.Component} this
15275              */
15276         render : true,
15277         /**
15278          * @event beforedestroy
15279          * Fires before the component is destroyed. Return false to stop the destroy.
15280              * @param {Roo.Component} this
15281              */
15282         beforedestroy : true,
15283         /**
15284          * @event destroy
15285          * Fires after the component is destroyed.
15286              * @param {Roo.Component} this
15287              */
15288         destroy : true
15289     });
15290     if(!this.id){
15291         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15292     }
15293     Roo.ComponentMgr.register(this);
15294     Roo.Component.superclass.constructor.call(this);
15295     this.initComponent();
15296     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15297         this.render(this.renderTo);
15298         delete this.renderTo;
15299     }
15300 };
15301
15302 /** @private */
15303 Roo.Component.AUTO_ID = 1000;
15304
15305 Roo.extend(Roo.Component, Roo.util.Observable, {
15306     /**
15307      * @scope Roo.Component.prototype
15308      * @type {Boolean}
15309      * true if this component is hidden. Read-only.
15310      */
15311     hidden : false,
15312     /**
15313      * @type {Boolean}
15314      * true if this component is disabled. Read-only.
15315      */
15316     disabled : false,
15317     /**
15318      * @type {Boolean}
15319      * true if this component has been rendered. Read-only.
15320      */
15321     rendered : false,
15322     
15323     /** @cfg {String} disableClass
15324      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15325      */
15326     disabledClass : "x-item-disabled",
15327         /** @cfg {Boolean} allowDomMove
15328          * Whether the component can move the Dom node when rendering (defaults to true).
15329          */
15330     allowDomMove : true,
15331     /** @cfg {String} hideMode (display|visibility)
15332      * How this component should hidden. Supported values are
15333      * "visibility" (css visibility), "offsets" (negative offset position) and
15334      * "display" (css display) - defaults to "display".
15335      */
15336     hideMode: 'display',
15337
15338     /** @private */
15339     ctype : "Roo.Component",
15340
15341     /**
15342      * @cfg {String} actionMode 
15343      * which property holds the element that used for  hide() / show() / disable() / enable()
15344      * default is 'el' 
15345      */
15346     actionMode : "el",
15347
15348     /** @private */
15349     getActionEl : function(){
15350         return this[this.actionMode];
15351     },
15352
15353     initComponent : Roo.emptyFn,
15354     /**
15355      * If this is a lazy rendering component, render it to its container element.
15356      * @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.
15357      */
15358     render : function(container, position){
15359         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15360             if(!container && this.el){
15361                 this.el = Roo.get(this.el);
15362                 container = this.el.dom.parentNode;
15363                 this.allowDomMove = false;
15364             }
15365             this.container = Roo.get(container);
15366             this.rendered = true;
15367             if(position !== undefined){
15368                 if(typeof position == 'number'){
15369                     position = this.container.dom.childNodes[position];
15370                 }else{
15371                     position = Roo.getDom(position);
15372                 }
15373             }
15374             this.onRender(this.container, position || null);
15375             if(this.cls){
15376                 this.el.addClass(this.cls);
15377                 delete this.cls;
15378             }
15379             if(this.style){
15380                 this.el.applyStyles(this.style);
15381                 delete this.style;
15382             }
15383             this.fireEvent("render", this);
15384             this.afterRender(this.container);
15385             if(this.hidden){
15386                 this.hide();
15387             }
15388             if(this.disabled){
15389                 this.disable();
15390             }
15391         }
15392         return this;
15393     },
15394
15395     /** @private */
15396     // default function is not really useful
15397     onRender : function(ct, position){
15398         if(this.el){
15399             this.el = Roo.get(this.el);
15400             if(this.allowDomMove !== false){
15401                 ct.dom.insertBefore(this.el.dom, position);
15402             }
15403         }
15404     },
15405
15406     /** @private */
15407     getAutoCreate : function(){
15408         var cfg = typeof this.autoCreate == "object" ?
15409                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15410         if(this.id && !cfg.id){
15411             cfg.id = this.id;
15412         }
15413         return cfg;
15414     },
15415
15416     /** @private */
15417     afterRender : Roo.emptyFn,
15418
15419     /**
15420      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15421      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15422      */
15423     destroy : function(){
15424         if(this.fireEvent("beforedestroy", this) !== false){
15425             this.purgeListeners();
15426             this.beforeDestroy();
15427             if(this.rendered){
15428                 this.el.removeAllListeners();
15429                 this.el.remove();
15430                 if(this.actionMode == "container"){
15431                     this.container.remove();
15432                 }
15433             }
15434             this.onDestroy();
15435             Roo.ComponentMgr.unregister(this);
15436             this.fireEvent("destroy", this);
15437         }
15438     },
15439
15440         /** @private */
15441     beforeDestroy : function(){
15442
15443     },
15444
15445         /** @private */
15446         onDestroy : function(){
15447
15448     },
15449
15450     /**
15451      * Returns the underlying {@link Roo.Element}.
15452      * @return {Roo.Element} The element
15453      */
15454     getEl : function(){
15455         return this.el;
15456     },
15457
15458     /**
15459      * Returns the id of this component.
15460      * @return {String}
15461      */
15462     getId : function(){
15463         return this.id;
15464     },
15465
15466     /**
15467      * Try to focus this component.
15468      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15469      * @return {Roo.Component} this
15470      */
15471     focus : function(selectText){
15472         if(this.rendered){
15473             this.el.focus();
15474             if(selectText === true){
15475                 this.el.dom.select();
15476             }
15477         }
15478         return this;
15479     },
15480
15481     /** @private */
15482     blur : function(){
15483         if(this.rendered){
15484             this.el.blur();
15485         }
15486         return this;
15487     },
15488
15489     /**
15490      * Disable this component.
15491      * @return {Roo.Component} this
15492      */
15493     disable : function(){
15494         if(this.rendered){
15495             this.onDisable();
15496         }
15497         this.disabled = true;
15498         this.fireEvent("disable", this);
15499         return this;
15500     },
15501
15502         // private
15503     onDisable : function(){
15504         this.getActionEl().addClass(this.disabledClass);
15505         this.el.dom.disabled = true;
15506     },
15507
15508     /**
15509      * Enable this component.
15510      * @return {Roo.Component} this
15511      */
15512     enable : function(){
15513         if(this.rendered){
15514             this.onEnable();
15515         }
15516         this.disabled = false;
15517         this.fireEvent("enable", this);
15518         return this;
15519     },
15520
15521         // private
15522     onEnable : function(){
15523         this.getActionEl().removeClass(this.disabledClass);
15524         this.el.dom.disabled = false;
15525     },
15526
15527     /**
15528      * Convenience function for setting disabled/enabled by boolean.
15529      * @param {Boolean} disabled
15530      */
15531     setDisabled : function(disabled){
15532         this[disabled ? "disable" : "enable"]();
15533     },
15534
15535     /**
15536      * Show this component.
15537      * @return {Roo.Component} this
15538      */
15539     show: function(){
15540         if(this.fireEvent("beforeshow", this) !== false){
15541             this.hidden = false;
15542             if(this.rendered){
15543                 this.onShow();
15544             }
15545             this.fireEvent("show", this);
15546         }
15547         return this;
15548     },
15549
15550     // private
15551     onShow : function(){
15552         var ae = this.getActionEl();
15553         if(this.hideMode == 'visibility'){
15554             ae.dom.style.visibility = "visible";
15555         }else if(this.hideMode == 'offsets'){
15556             ae.removeClass('x-hidden');
15557         }else{
15558             ae.dom.style.display = "";
15559         }
15560     },
15561
15562     /**
15563      * Hide this component.
15564      * @return {Roo.Component} this
15565      */
15566     hide: function(){
15567         if(this.fireEvent("beforehide", this) !== false){
15568             this.hidden = true;
15569             if(this.rendered){
15570                 this.onHide();
15571             }
15572             this.fireEvent("hide", this);
15573         }
15574         return this;
15575     },
15576
15577     // private
15578     onHide : function(){
15579         var ae = this.getActionEl();
15580         if(this.hideMode == 'visibility'){
15581             ae.dom.style.visibility = "hidden";
15582         }else if(this.hideMode == 'offsets'){
15583             ae.addClass('x-hidden');
15584         }else{
15585             ae.dom.style.display = "none";
15586         }
15587     },
15588
15589     /**
15590      * Convenience function to hide or show this component by boolean.
15591      * @param {Boolean} visible True to show, false to hide
15592      * @return {Roo.Component} this
15593      */
15594     setVisible: function(visible){
15595         if(visible) {
15596             this.show();
15597         }else{
15598             this.hide();
15599         }
15600         return this;
15601     },
15602
15603     /**
15604      * Returns true if this component is visible.
15605      */
15606     isVisible : function(){
15607         return this.getActionEl().isVisible();
15608     },
15609
15610     cloneConfig : function(overrides){
15611         overrides = overrides || {};
15612         var id = overrides.id || Roo.id();
15613         var cfg = Roo.applyIf(overrides, this.initialConfig);
15614         cfg.id = id; // prevent dup id
15615         return new this.constructor(cfg);
15616     }
15617 });/*
15618  * Based on:
15619  * Ext JS Library 1.1.1
15620  * Copyright(c) 2006-2007, Ext JS, LLC.
15621  *
15622  * Originally Released Under LGPL - original licence link has changed is not relivant.
15623  *
15624  * Fork - LGPL
15625  * <script type="text/javascript">
15626  */
15627
15628 /**
15629  * @class Roo.BoxComponent
15630  * @extends Roo.Component
15631  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15632  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15633  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15634  * layout containers.
15635  * @constructor
15636  * @param {Roo.Element/String/Object} config The configuration options.
15637  */
15638 Roo.BoxComponent = function(config){
15639     Roo.Component.call(this, config);
15640     this.addEvents({
15641         /**
15642          * @event resize
15643          * Fires after the component is resized.
15644              * @param {Roo.Component} this
15645              * @param {Number} adjWidth The box-adjusted width that was set
15646              * @param {Number} adjHeight The box-adjusted height that was set
15647              * @param {Number} rawWidth The width that was originally specified
15648              * @param {Number} rawHeight The height that was originally specified
15649              */
15650         resize : true,
15651         /**
15652          * @event move
15653          * Fires after the component is moved.
15654              * @param {Roo.Component} this
15655              * @param {Number} x The new x position
15656              * @param {Number} y The new y position
15657              */
15658         move : true
15659     });
15660 };
15661
15662 Roo.extend(Roo.BoxComponent, Roo.Component, {
15663     // private, set in afterRender to signify that the component has been rendered
15664     boxReady : false,
15665     // private, used to defer height settings to subclasses
15666     deferHeight: false,
15667     /** @cfg {Number} width
15668      * width (optional) size of component
15669      */
15670      /** @cfg {Number} height
15671      * height (optional) size of component
15672      */
15673      
15674     /**
15675      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15676      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15677      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15678      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15679      * @return {Roo.BoxComponent} this
15680      */
15681     setSize : function(w, h){
15682         // support for standard size objects
15683         if(typeof w == 'object'){
15684             h = w.height;
15685             w = w.width;
15686         }
15687         // not rendered
15688         if(!this.boxReady){
15689             this.width = w;
15690             this.height = h;
15691             return this;
15692         }
15693
15694         // prevent recalcs when not needed
15695         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15696             return this;
15697         }
15698         this.lastSize = {width: w, height: h};
15699
15700         var adj = this.adjustSize(w, h);
15701         var aw = adj.width, ah = adj.height;
15702         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15703             var rz = this.getResizeEl();
15704             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15705                 rz.setSize(aw, ah);
15706             }else if(!this.deferHeight && ah !== undefined){
15707                 rz.setHeight(ah);
15708             }else if(aw !== undefined){
15709                 rz.setWidth(aw);
15710             }
15711             this.onResize(aw, ah, w, h);
15712             this.fireEvent('resize', this, aw, ah, w, h);
15713         }
15714         return this;
15715     },
15716
15717     /**
15718      * Gets the current size of the component's underlying element.
15719      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15720      */
15721     getSize : function(){
15722         return this.el.getSize();
15723     },
15724
15725     /**
15726      * Gets the current XY position of the component's underlying element.
15727      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15728      * @return {Array} The XY position of the element (e.g., [100, 200])
15729      */
15730     getPosition : function(local){
15731         if(local === true){
15732             return [this.el.getLeft(true), this.el.getTop(true)];
15733         }
15734         return this.xy || this.el.getXY();
15735     },
15736
15737     /**
15738      * Gets the current box measurements of the component's underlying element.
15739      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15740      * @returns {Object} box An object in the format {x, y, width, height}
15741      */
15742     getBox : function(local){
15743         var s = this.el.getSize();
15744         if(local){
15745             s.x = this.el.getLeft(true);
15746             s.y = this.el.getTop(true);
15747         }else{
15748             var xy = this.xy || this.el.getXY();
15749             s.x = xy[0];
15750             s.y = xy[1];
15751         }
15752         return s;
15753     },
15754
15755     /**
15756      * Sets the current box measurements of the component's underlying element.
15757      * @param {Object} box An object in the format {x, y, width, height}
15758      * @returns {Roo.BoxComponent} this
15759      */
15760     updateBox : function(box){
15761         this.setSize(box.width, box.height);
15762         this.setPagePosition(box.x, box.y);
15763         return this;
15764     },
15765
15766     // protected
15767     getResizeEl : function(){
15768         return this.resizeEl || this.el;
15769     },
15770
15771     // protected
15772     getPositionEl : function(){
15773         return this.positionEl || this.el;
15774     },
15775
15776     /**
15777      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15778      * This method fires the move event.
15779      * @param {Number} left The new left
15780      * @param {Number} top The new top
15781      * @returns {Roo.BoxComponent} this
15782      */
15783     setPosition : function(x, y){
15784         this.x = x;
15785         this.y = y;
15786         if(!this.boxReady){
15787             return this;
15788         }
15789         var adj = this.adjustPosition(x, y);
15790         var ax = adj.x, ay = adj.y;
15791
15792         var el = this.getPositionEl();
15793         if(ax !== undefined || ay !== undefined){
15794             if(ax !== undefined && ay !== undefined){
15795                 el.setLeftTop(ax, ay);
15796             }else if(ax !== undefined){
15797                 el.setLeft(ax);
15798             }else if(ay !== undefined){
15799                 el.setTop(ay);
15800             }
15801             this.onPosition(ax, ay);
15802             this.fireEvent('move', this, ax, ay);
15803         }
15804         return this;
15805     },
15806
15807     /**
15808      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15809      * This method fires the move event.
15810      * @param {Number} x The new x position
15811      * @param {Number} y The new y position
15812      * @returns {Roo.BoxComponent} this
15813      */
15814     setPagePosition : function(x, y){
15815         this.pageX = x;
15816         this.pageY = y;
15817         if(!this.boxReady){
15818             return;
15819         }
15820         if(x === undefined || y === undefined){ // cannot translate undefined points
15821             return;
15822         }
15823         var p = this.el.translatePoints(x, y);
15824         this.setPosition(p.left, p.top);
15825         return this;
15826     },
15827
15828     // private
15829     onRender : function(ct, position){
15830         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15831         if(this.resizeEl){
15832             this.resizeEl = Roo.get(this.resizeEl);
15833         }
15834         if(this.positionEl){
15835             this.positionEl = Roo.get(this.positionEl);
15836         }
15837     },
15838
15839     // private
15840     afterRender : function(){
15841         Roo.BoxComponent.superclass.afterRender.call(this);
15842         this.boxReady = true;
15843         this.setSize(this.width, this.height);
15844         if(this.x || this.y){
15845             this.setPosition(this.x, this.y);
15846         }
15847         if(this.pageX || this.pageY){
15848             this.setPagePosition(this.pageX, this.pageY);
15849         }
15850     },
15851
15852     /**
15853      * Force the component's size to recalculate based on the underlying element's current height and width.
15854      * @returns {Roo.BoxComponent} this
15855      */
15856     syncSize : function(){
15857         delete this.lastSize;
15858         this.setSize(this.el.getWidth(), this.el.getHeight());
15859         return this;
15860     },
15861
15862     /**
15863      * Called after the component is resized, this method is empty by default but can be implemented by any
15864      * subclass that needs to perform custom logic after a resize occurs.
15865      * @param {Number} adjWidth The box-adjusted width that was set
15866      * @param {Number} adjHeight The box-adjusted height that was set
15867      * @param {Number} rawWidth The width that was originally specified
15868      * @param {Number} rawHeight The height that was originally specified
15869      */
15870     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15871
15872     },
15873
15874     /**
15875      * Called after the component is moved, this method is empty by default but can be implemented by any
15876      * subclass that needs to perform custom logic after a move occurs.
15877      * @param {Number} x The new x position
15878      * @param {Number} y The new y position
15879      */
15880     onPosition : function(x, y){
15881
15882     },
15883
15884     // private
15885     adjustSize : function(w, h){
15886         if(this.autoWidth){
15887             w = 'auto';
15888         }
15889         if(this.autoHeight){
15890             h = 'auto';
15891         }
15892         return {width : w, height: h};
15893     },
15894
15895     // private
15896     adjustPosition : function(x, y){
15897         return {x : x, y: y};
15898     }
15899 });/*
15900  * Original code for Roojs - LGPL
15901  * <script type="text/javascript">
15902  */
15903  
15904 /**
15905  * @class Roo.XComponent
15906  * A delayed Element creator...
15907  * Or a way to group chunks of interface together.
15908  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15909  *  used in conjunction with XComponent.build() it will create an instance of each element,
15910  *  then call addxtype() to build the User interface.
15911  * 
15912  * Mypart.xyx = new Roo.XComponent({
15913
15914     parent : 'Mypart.xyz', // empty == document.element.!!
15915     order : '001',
15916     name : 'xxxx'
15917     region : 'xxxx'
15918     disabled : function() {} 
15919      
15920     tree : function() { // return an tree of xtype declared components
15921         var MODULE = this;
15922         return 
15923         {
15924             xtype : 'NestedLayoutPanel',
15925             // technicall
15926         }
15927      ]
15928  *})
15929  *
15930  *
15931  * It can be used to build a big heiracy, with parent etc.
15932  * or you can just use this to render a single compoent to a dom element
15933  * MYPART.render(Roo.Element | String(id) | dom_element )
15934  *
15935  *
15936  * Usage patterns.
15937  *
15938  * Classic Roo
15939  *
15940  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15941  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15942  *
15943  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15944  *
15945  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15946  * - if mulitple topModules exist, the last one is defined as the top module.
15947  *
15948  * Embeded Roo
15949  * 
15950  * When the top level or multiple modules are to embedded into a existing HTML page,
15951  * the parent element can container '#id' of the element where the module will be drawn.
15952  *
15953  * Bootstrap Roo
15954  *
15955  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15956  * it relies more on a include mechanism, where sub modules are included into an outer page.
15957  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15958  * 
15959  * Bootstrap Roo Included elements
15960  *
15961  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15962  * hence confusing the component builder as it thinks there are multiple top level elements. 
15963  *
15964  * 
15965  * 
15966  * @extends Roo.util.Observable
15967  * @constructor
15968  * @param cfg {Object} configuration of component
15969  * 
15970  */
15971 Roo.XComponent = function(cfg) {
15972     Roo.apply(this, cfg);
15973     this.addEvents({ 
15974         /**
15975              * @event built
15976              * Fires when this the componnt is built
15977              * @param {Roo.XComponent} c the component
15978              */
15979         'built' : true
15980         
15981     });
15982     this.region = this.region || 'center'; // default..
15983     Roo.XComponent.register(this);
15984     this.modules = false;
15985     this.el = false; // where the layout goes..
15986     
15987     
15988 }
15989 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15990     /**
15991      * @property el
15992      * The created element (with Roo.factory())
15993      * @type {Roo.Layout}
15994      */
15995     el  : false,
15996     
15997     /**
15998      * @property el
15999      * for BC  - use el in new code
16000      * @type {Roo.Layout}
16001      */
16002     panel : false,
16003     
16004     /**
16005      * @property layout
16006      * for BC  - use el in new code
16007      * @type {Roo.Layout}
16008      */
16009     layout : false,
16010     
16011      /**
16012      * @cfg {Function|boolean} disabled
16013      * If this module is disabled by some rule, return true from the funtion
16014      */
16015     disabled : false,
16016     
16017     /**
16018      * @cfg {String} parent 
16019      * Name of parent element which it get xtype added to..
16020      */
16021     parent: false,
16022     
16023     /**
16024      * @cfg {String} order
16025      * Used to set the order in which elements are created (usefull for multiple tabs)
16026      */
16027     
16028     order : false,
16029     /**
16030      * @cfg {String} name
16031      * String to display while loading.
16032      */
16033     name : false,
16034     /**
16035      * @cfg {String} region
16036      * Region to render component to (defaults to center)
16037      */
16038     region : 'center',
16039     
16040     /**
16041      * @cfg {Array} items
16042      * A single item array - the first element is the root of the tree..
16043      * It's done this way to stay compatible with the Xtype system...
16044      */
16045     items : false,
16046     
16047     /**
16048      * @property _tree
16049      * The method that retuns the tree of parts that make up this compoennt 
16050      * @type {function}
16051      */
16052     _tree  : false,
16053     
16054      /**
16055      * render
16056      * render element to dom or tree
16057      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16058      */
16059     
16060     render : function(el)
16061     {
16062         
16063         el = el || false;
16064         var hp = this.parent ? 1 : 0;
16065         Roo.debug &&  Roo.log(this);
16066         
16067         var tree = this._tree ? this._tree() : this.tree();
16068
16069         
16070         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16071             // if parent is a '#.....' string, then let's use that..
16072             var ename = this.parent.substr(1);
16073             this.parent = false;
16074             Roo.debug && Roo.log(ename);
16075             switch (ename) {
16076                 case 'bootstrap-body':
16077                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16078                         // this is the BorderLayout standard?
16079                        this.parent = { el : true };
16080                        break;
16081                     }
16082                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16083                         // need to insert stuff...
16084                         this.parent =  {
16085                              el : new Roo.bootstrap.layout.Border({
16086                                  el : document.body, 
16087                      
16088                                  center: {
16089                                     titlebar: false,
16090                                     autoScroll:false,
16091                                     closeOnTab: true,
16092                                     tabPosition: 'top',
16093                                       //resizeTabs: true,
16094                                     alwaysShowTabs: true,
16095                                     hideTabs: false
16096                                      //minTabWidth: 140
16097                                  }
16098                              })
16099                         
16100                          };
16101                          break;
16102                     }
16103                          
16104                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16105                         this.parent = { el :  new  Roo.bootstrap.Body() };
16106                         Roo.debug && Roo.log("setting el to doc body");
16107                          
16108                     } else {
16109                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16110                     }
16111                     break;
16112                 case 'bootstrap':
16113                     this.parent = { el : true};
16114                     // fall through
16115                 default:
16116                     el = Roo.get(ename);
16117                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16118                         this.parent = { el : true};
16119                     }
16120                     
16121                     break;
16122             }
16123                 
16124             
16125             if (!el && !this.parent) {
16126                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16127                 return;
16128             }
16129         }
16130         
16131         Roo.debug && Roo.log("EL:");
16132         Roo.debug && Roo.log(el);
16133         Roo.debug && Roo.log("this.parent.el:");
16134         Roo.debug && Roo.log(this.parent.el);
16135         
16136
16137         // altertive root elements ??? - we need a better way to indicate these.
16138         var is_alt = Roo.XComponent.is_alt ||
16139                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16140                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16141                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16142         
16143         
16144         
16145         if (!this.parent && is_alt) {
16146             //el = Roo.get(document.body);
16147             this.parent = { el : true };
16148         }
16149             
16150             
16151         
16152         if (!this.parent) {
16153             
16154             Roo.debug && Roo.log("no parent - creating one");
16155             
16156             el = el ? Roo.get(el) : false;      
16157             
16158             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16159                 
16160                 this.parent =  {
16161                     el : new Roo.bootstrap.layout.Border({
16162                         el: el || document.body,
16163                     
16164                         center: {
16165                             titlebar: false,
16166                             autoScroll:false,
16167                             closeOnTab: true,
16168                             tabPosition: 'top',
16169                              //resizeTabs: true,
16170                             alwaysShowTabs: false,
16171                             hideTabs: true,
16172                             minTabWidth: 140,
16173                             overflow: 'visible'
16174                          }
16175                      })
16176                 };
16177             } else {
16178             
16179                 // it's a top level one..
16180                 this.parent =  {
16181                     el : new Roo.BorderLayout(el || document.body, {
16182                         center: {
16183                             titlebar: false,
16184                             autoScroll:false,
16185                             closeOnTab: true,
16186                             tabPosition: 'top',
16187                              //resizeTabs: true,
16188                             alwaysShowTabs: el && hp? false :  true,
16189                             hideTabs: el || !hp ? true :  false,
16190                             minTabWidth: 140
16191                          }
16192                     })
16193                 };
16194             }
16195         }
16196         
16197         if (!this.parent.el) {
16198                 // probably an old style ctor, which has been disabled.
16199                 return;
16200
16201         }
16202                 // The 'tree' method is  '_tree now' 
16203             
16204         tree.region = tree.region || this.region;
16205         var is_body = false;
16206         if (this.parent.el === true) {
16207             // bootstrap... - body..
16208             if (el) {
16209                 tree.el = el;
16210             }
16211             this.parent.el = Roo.factory(tree);
16212             is_body = true;
16213         }
16214         
16215         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16216         this.fireEvent('built', this);
16217         
16218         this.panel = this.el;
16219         this.layout = this.panel.layout;
16220         this.parentLayout = this.parent.layout  || false;  
16221          
16222     }
16223     
16224 });
16225
16226 Roo.apply(Roo.XComponent, {
16227     /**
16228      * @property  hideProgress
16229      * true to disable the building progress bar.. usefull on single page renders.
16230      * @type Boolean
16231      */
16232     hideProgress : false,
16233     /**
16234      * @property  buildCompleted
16235      * True when the builder has completed building the interface.
16236      * @type Boolean
16237      */
16238     buildCompleted : false,
16239      
16240     /**
16241      * @property  topModule
16242      * the upper most module - uses document.element as it's constructor.
16243      * @type Object
16244      */
16245      
16246     topModule  : false,
16247       
16248     /**
16249      * @property  modules
16250      * array of modules to be created by registration system.
16251      * @type {Array} of Roo.XComponent
16252      */
16253     
16254     modules : [],
16255     /**
16256      * @property  elmodules
16257      * array of modules to be created by which use #ID 
16258      * @type {Array} of Roo.XComponent
16259      */
16260      
16261     elmodules : [],
16262
16263      /**
16264      * @property  is_alt
16265      * Is an alternative Root - normally used by bootstrap or other systems,
16266      *    where the top element in the tree can wrap 'body' 
16267      * @type {boolean}  (default false)
16268      */
16269      
16270     is_alt : false,
16271     /**
16272      * @property  build_from_html
16273      * Build elements from html - used by bootstrap HTML stuff 
16274      *    - this is cleared after build is completed
16275      * @type {boolean}    (default false)
16276      */
16277      
16278     build_from_html : false,
16279     /**
16280      * Register components to be built later.
16281      *
16282      * This solves the following issues
16283      * - Building is not done on page load, but after an authentication process has occured.
16284      * - Interface elements are registered on page load
16285      * - Parent Interface elements may not be loaded before child, so this handles that..
16286      * 
16287      *
16288      * example:
16289      * 
16290      * MyApp.register({
16291           order : '000001',
16292           module : 'Pman.Tab.projectMgr',
16293           region : 'center',
16294           parent : 'Pman.layout',
16295           disabled : false,  // or use a function..
16296         })
16297      
16298      * * @param {Object} details about module
16299      */
16300     register : function(obj) {
16301                 
16302         Roo.XComponent.event.fireEvent('register', obj);
16303         switch(typeof(obj.disabled) ) {
16304                 
16305             case 'undefined':
16306                 break;
16307             
16308             case 'function':
16309                 if ( obj.disabled() ) {
16310                         return;
16311                 }
16312                 break;
16313             
16314             default:
16315                 if (obj.disabled) {
16316                         return;
16317                 }
16318                 break;
16319         }
16320                 
16321         this.modules.push(obj);
16322          
16323     },
16324     /**
16325      * convert a string to an object..
16326      * eg. 'AAA.BBB' -> finds AAA.BBB
16327
16328      */
16329     
16330     toObject : function(str)
16331     {
16332         if (!str || typeof(str) == 'object') {
16333             return str;
16334         }
16335         if (str.substring(0,1) == '#') {
16336             return str;
16337         }
16338
16339         var ar = str.split('.');
16340         var rt, o;
16341         rt = ar.shift();
16342             /** eval:var:o */
16343         try {
16344             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16345         } catch (e) {
16346             throw "Module not found : " + str;
16347         }
16348         
16349         if (o === false) {
16350             throw "Module not found : " + str;
16351         }
16352         Roo.each(ar, function(e) {
16353             if (typeof(o[e]) == 'undefined') {
16354                 throw "Module not found : " + str;
16355             }
16356             o = o[e];
16357         });
16358         
16359         return o;
16360         
16361     },
16362     
16363     
16364     /**
16365      * move modules into their correct place in the tree..
16366      * 
16367      */
16368     preBuild : function ()
16369     {
16370         var _t = this;
16371         Roo.each(this.modules , function (obj)
16372         {
16373             Roo.XComponent.event.fireEvent('beforebuild', obj);
16374             
16375             var opar = obj.parent;
16376             try { 
16377                 obj.parent = this.toObject(opar);
16378             } catch(e) {
16379                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16380                 return;
16381             }
16382             
16383             if (!obj.parent) {
16384                 Roo.debug && Roo.log("GOT top level module");
16385                 Roo.debug && Roo.log(obj);
16386                 obj.modules = new Roo.util.MixedCollection(false, 
16387                     function(o) { return o.order + '' }
16388                 );
16389                 this.topModule = obj;
16390                 return;
16391             }
16392                         // parent is a string (usually a dom element name..)
16393             if (typeof(obj.parent) == 'string') {
16394                 this.elmodules.push(obj);
16395                 return;
16396             }
16397             if (obj.parent.constructor != Roo.XComponent) {
16398                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16399             }
16400             if (!obj.parent.modules) {
16401                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16402                     function(o) { return o.order + '' }
16403                 );
16404             }
16405             if (obj.parent.disabled) {
16406                 obj.disabled = true;
16407             }
16408             obj.parent.modules.add(obj);
16409         }, this);
16410     },
16411     
16412      /**
16413      * make a list of modules to build.
16414      * @return {Array} list of modules. 
16415      */ 
16416     
16417     buildOrder : function()
16418     {
16419         var _this = this;
16420         var cmp = function(a,b) {   
16421             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16422         };
16423         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16424             throw "No top level modules to build";
16425         }
16426         
16427         // make a flat list in order of modules to build.
16428         var mods = this.topModule ? [ this.topModule ] : [];
16429                 
16430         
16431         // elmodules (is a list of DOM based modules )
16432         Roo.each(this.elmodules, function(e) {
16433             mods.push(e);
16434             if (!this.topModule &&
16435                 typeof(e.parent) == 'string' &&
16436                 e.parent.substring(0,1) == '#' &&
16437                 Roo.get(e.parent.substr(1))
16438                ) {
16439                 
16440                 _this.topModule = e;
16441             }
16442             
16443         });
16444
16445         
16446         // add modules to their parents..
16447         var addMod = function(m) {
16448             Roo.debug && Roo.log("build Order: add: " + m.name);
16449                 
16450             mods.push(m);
16451             if (m.modules && !m.disabled) {
16452                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16453                 m.modules.keySort('ASC',  cmp );
16454                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16455     
16456                 m.modules.each(addMod);
16457             } else {
16458                 Roo.debug && Roo.log("build Order: no child modules");
16459             }
16460             // not sure if this is used any more..
16461             if (m.finalize) {
16462                 m.finalize.name = m.name + " (clean up) ";
16463                 mods.push(m.finalize);
16464             }
16465             
16466         }
16467         if (this.topModule && this.topModule.modules) { 
16468             this.topModule.modules.keySort('ASC',  cmp );
16469             this.topModule.modules.each(addMod);
16470         } 
16471         return mods;
16472     },
16473     
16474      /**
16475      * Build the registered modules.
16476      * @param {Object} parent element.
16477      * @param {Function} optional method to call after module has been added.
16478      * 
16479      */ 
16480    
16481     build : function(opts) 
16482     {
16483         
16484         if (typeof(opts) != 'undefined') {
16485             Roo.apply(this,opts);
16486         }
16487         
16488         this.preBuild();
16489         var mods = this.buildOrder();
16490       
16491         //this.allmods = mods;
16492         //Roo.debug && Roo.log(mods);
16493         //return;
16494         if (!mods.length) { // should not happen
16495             throw "NO modules!!!";
16496         }
16497         
16498         
16499         var msg = "Building Interface...";
16500         // flash it up as modal - so we store the mask!?
16501         if (!this.hideProgress && Roo.MessageBox) {
16502             Roo.MessageBox.show({ title: 'loading' });
16503             Roo.MessageBox.show({
16504                title: "Please wait...",
16505                msg: msg,
16506                width:450,
16507                progress:true,
16508                closable:false,
16509                modal: false
16510               
16511             });
16512         }
16513         var total = mods.length;
16514         
16515         var _this = this;
16516         var progressRun = function() {
16517             if (!mods.length) {
16518                 Roo.debug && Roo.log('hide?');
16519                 if (!this.hideProgress && Roo.MessageBox) {
16520                     Roo.MessageBox.hide();
16521                 }
16522                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16523                 
16524                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16525                 
16526                 // THE END...
16527                 return false;   
16528             }
16529             
16530             var m = mods.shift();
16531             
16532             
16533             Roo.debug && Roo.log(m);
16534             // not sure if this is supported any more.. - modules that are are just function
16535             if (typeof(m) == 'function') { 
16536                 m.call(this);
16537                 return progressRun.defer(10, _this);
16538             } 
16539             
16540             
16541             msg = "Building Interface " + (total  - mods.length) + 
16542                     " of " + total + 
16543                     (m.name ? (' - ' + m.name) : '');
16544                         Roo.debug && Roo.log(msg);
16545             if (!_this.hideProgress &&  Roo.MessageBox) { 
16546                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16547             }
16548             
16549          
16550             // is the module disabled?
16551             var disabled = (typeof(m.disabled) == 'function') ?
16552                 m.disabled.call(m.module.disabled) : m.disabled;    
16553             
16554             
16555             if (disabled) {
16556                 return progressRun(); // we do not update the display!
16557             }
16558             
16559             // now build 
16560             
16561                         
16562                         
16563             m.render();
16564             // it's 10 on top level, and 1 on others??? why...
16565             return progressRun.defer(10, _this);
16566              
16567         }
16568         progressRun.defer(1, _this);
16569      
16570         
16571         
16572     },
16573         
16574         
16575         /**
16576          * Event Object.
16577          *
16578          *
16579          */
16580         event: false, 
16581     /**
16582          * wrapper for event.on - aliased later..  
16583          * Typically use to register a event handler for register:
16584          *
16585          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16586          *
16587          */
16588     on : false
16589    
16590     
16591     
16592 });
16593
16594 Roo.XComponent.event = new Roo.util.Observable({
16595                 events : { 
16596                         /**
16597                          * @event register
16598                          * Fires when an Component is registered,
16599                          * set the disable property on the Component to stop registration.
16600                          * @param {Roo.XComponent} c the component being registerd.
16601                          * 
16602                          */
16603                         'register' : true,
16604             /**
16605                          * @event beforebuild
16606                          * Fires before each Component is built
16607                          * can be used to apply permissions.
16608                          * @param {Roo.XComponent} c the component being registerd.
16609                          * 
16610                          */
16611                         'beforebuild' : true,
16612                         /**
16613                          * @event buildcomplete
16614                          * Fires on the top level element when all elements have been built
16615                          * @param {Roo.XComponent} the top level component.
16616                          */
16617                         'buildcomplete' : true
16618                         
16619                 }
16620 });
16621
16622 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16623  //
16624  /**
16625  * marked - a markdown parser
16626  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16627  * https://github.com/chjj/marked
16628  */
16629
16630
16631 /**
16632  *
16633  * Roo.Markdown - is a very crude wrapper around marked..
16634  *
16635  * usage:
16636  * 
16637  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16638  * 
16639  * Note: move the sample code to the bottom of this
16640  * file before uncommenting it.
16641  *
16642  */
16643
16644 Roo.Markdown = {};
16645 Roo.Markdown.toHtml = function(text) {
16646     
16647     var c = new Roo.Markdown.marked.setOptions({
16648             renderer: new Roo.Markdown.marked.Renderer(),
16649             gfm: true,
16650             tables: true,
16651             breaks: false,
16652             pedantic: false,
16653             sanitize: false,
16654             smartLists: true,
16655             smartypants: false
16656           });
16657     // A FEW HACKS!!?
16658     
16659     text = text.replace(/\\\n/g,' ');
16660     return Roo.Markdown.marked(text);
16661 };
16662 //
16663 // converter
16664 //
16665 // Wraps all "globals" so that the only thing
16666 // exposed is makeHtml().
16667 //
16668 (function() {
16669     
16670     /**
16671      * Block-Level Grammar
16672      */
16673     
16674     var block = {
16675       newline: /^\n+/,
16676       code: /^( {4}[^\n]+\n*)+/,
16677       fences: noop,
16678       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16679       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16680       nptable: noop,
16681       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16682       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16683       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16684       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16685       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16686       table: noop,
16687       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16688       text: /^[^\n]+/
16689     };
16690     
16691     block.bullet = /(?:[*+-]|\d+\.)/;
16692     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16693     block.item = replace(block.item, 'gm')
16694       (/bull/g, block.bullet)
16695       ();
16696     
16697     block.list = replace(block.list)
16698       (/bull/g, block.bullet)
16699       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16700       ('def', '\\n+(?=' + block.def.source + ')')
16701       ();
16702     
16703     block.blockquote = replace(block.blockquote)
16704       ('def', block.def)
16705       ();
16706     
16707     block._tag = '(?!(?:'
16708       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16709       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16710       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16711     
16712     block.html = replace(block.html)
16713       ('comment', /<!--[\s\S]*?-->/)
16714       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16715       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16716       (/tag/g, block._tag)
16717       ();
16718     
16719     block.paragraph = replace(block.paragraph)
16720       ('hr', block.hr)
16721       ('heading', block.heading)
16722       ('lheading', block.lheading)
16723       ('blockquote', block.blockquote)
16724       ('tag', '<' + block._tag)
16725       ('def', block.def)
16726       ();
16727     
16728     /**
16729      * Normal Block Grammar
16730      */
16731     
16732     block.normal = merge({}, block);
16733     
16734     /**
16735      * GFM Block Grammar
16736      */
16737     
16738     block.gfm = merge({}, block.normal, {
16739       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16740       paragraph: /^/,
16741       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16742     });
16743     
16744     block.gfm.paragraph = replace(block.paragraph)
16745       ('(?!', '(?!'
16746         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16747         + block.list.source.replace('\\1', '\\3') + '|')
16748       ();
16749     
16750     /**
16751      * GFM + Tables Block Grammar
16752      */
16753     
16754     block.tables = merge({}, block.gfm, {
16755       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16756       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16757     });
16758     
16759     /**
16760      * Block Lexer
16761      */
16762     
16763     function Lexer(options) {
16764       this.tokens = [];
16765       this.tokens.links = {};
16766       this.options = options || marked.defaults;
16767       this.rules = block.normal;
16768     
16769       if (this.options.gfm) {
16770         if (this.options.tables) {
16771           this.rules = block.tables;
16772         } else {
16773           this.rules = block.gfm;
16774         }
16775       }
16776     }
16777     
16778     /**
16779      * Expose Block Rules
16780      */
16781     
16782     Lexer.rules = block;
16783     
16784     /**
16785      * Static Lex Method
16786      */
16787     
16788     Lexer.lex = function(src, options) {
16789       var lexer = new Lexer(options);
16790       return lexer.lex(src);
16791     };
16792     
16793     /**
16794      * Preprocessing
16795      */
16796     
16797     Lexer.prototype.lex = function(src) {
16798       src = src
16799         .replace(/\r\n|\r/g, '\n')
16800         .replace(/\t/g, '    ')
16801         .replace(/\u00a0/g, ' ')
16802         .replace(/\u2424/g, '\n');
16803     
16804       return this.token(src, true);
16805     };
16806     
16807     /**
16808      * Lexing
16809      */
16810     
16811     Lexer.prototype.token = function(src, top, bq) {
16812       var src = src.replace(/^ +$/gm, '')
16813         , next
16814         , loose
16815         , cap
16816         , bull
16817         , b
16818         , item
16819         , space
16820         , i
16821         , l;
16822     
16823       while (src) {
16824         // newline
16825         if (cap = this.rules.newline.exec(src)) {
16826           src = src.substring(cap[0].length);
16827           if (cap[0].length > 1) {
16828             this.tokens.push({
16829               type: 'space'
16830             });
16831           }
16832         }
16833     
16834         // code
16835         if (cap = this.rules.code.exec(src)) {
16836           src = src.substring(cap[0].length);
16837           cap = cap[0].replace(/^ {4}/gm, '');
16838           this.tokens.push({
16839             type: 'code',
16840             text: !this.options.pedantic
16841               ? cap.replace(/\n+$/, '')
16842               : cap
16843           });
16844           continue;
16845         }
16846     
16847         // fences (gfm)
16848         if (cap = this.rules.fences.exec(src)) {
16849           src = src.substring(cap[0].length);
16850           this.tokens.push({
16851             type: 'code',
16852             lang: cap[2],
16853             text: cap[3] || ''
16854           });
16855           continue;
16856         }
16857     
16858         // heading
16859         if (cap = this.rules.heading.exec(src)) {
16860           src = src.substring(cap[0].length);
16861           this.tokens.push({
16862             type: 'heading',
16863             depth: cap[1].length,
16864             text: cap[2]
16865           });
16866           continue;
16867         }
16868     
16869         // table no leading pipe (gfm)
16870         if (top && (cap = this.rules.nptable.exec(src))) {
16871           src = src.substring(cap[0].length);
16872     
16873           item = {
16874             type: 'table',
16875             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16876             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16877             cells: cap[3].replace(/\n$/, '').split('\n')
16878           };
16879     
16880           for (i = 0; i < item.align.length; i++) {
16881             if (/^ *-+: *$/.test(item.align[i])) {
16882               item.align[i] = 'right';
16883             } else if (/^ *:-+: *$/.test(item.align[i])) {
16884               item.align[i] = 'center';
16885             } else if (/^ *:-+ *$/.test(item.align[i])) {
16886               item.align[i] = 'left';
16887             } else {
16888               item.align[i] = null;
16889             }
16890           }
16891     
16892           for (i = 0; i < item.cells.length; i++) {
16893             item.cells[i] = item.cells[i].split(/ *\| */);
16894           }
16895     
16896           this.tokens.push(item);
16897     
16898           continue;
16899         }
16900     
16901         // lheading
16902         if (cap = this.rules.lheading.exec(src)) {
16903           src = src.substring(cap[0].length);
16904           this.tokens.push({
16905             type: 'heading',
16906             depth: cap[2] === '=' ? 1 : 2,
16907             text: cap[1]
16908           });
16909           continue;
16910         }
16911     
16912         // hr
16913         if (cap = this.rules.hr.exec(src)) {
16914           src = src.substring(cap[0].length);
16915           this.tokens.push({
16916             type: 'hr'
16917           });
16918           continue;
16919         }
16920     
16921         // blockquote
16922         if (cap = this.rules.blockquote.exec(src)) {
16923           src = src.substring(cap[0].length);
16924     
16925           this.tokens.push({
16926             type: 'blockquote_start'
16927           });
16928     
16929           cap = cap[0].replace(/^ *> ?/gm, '');
16930     
16931           // Pass `top` to keep the current
16932           // "toplevel" state. This is exactly
16933           // how markdown.pl works.
16934           this.token(cap, top, true);
16935     
16936           this.tokens.push({
16937             type: 'blockquote_end'
16938           });
16939     
16940           continue;
16941         }
16942     
16943         // list
16944         if (cap = this.rules.list.exec(src)) {
16945           src = src.substring(cap[0].length);
16946           bull = cap[2];
16947     
16948           this.tokens.push({
16949             type: 'list_start',
16950             ordered: bull.length > 1
16951           });
16952     
16953           // Get each top-level item.
16954           cap = cap[0].match(this.rules.item);
16955     
16956           next = false;
16957           l = cap.length;
16958           i = 0;
16959     
16960           for (; i < l; i++) {
16961             item = cap[i];
16962     
16963             // Remove the list item's bullet
16964             // so it is seen as the next token.
16965             space = item.length;
16966             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16967     
16968             // Outdent whatever the
16969             // list item contains. Hacky.
16970             if (~item.indexOf('\n ')) {
16971               space -= item.length;
16972               item = !this.options.pedantic
16973                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16974                 : item.replace(/^ {1,4}/gm, '');
16975             }
16976     
16977             // Determine whether the next list item belongs here.
16978             // Backpedal if it does not belong in this list.
16979             if (this.options.smartLists && i !== l - 1) {
16980               b = block.bullet.exec(cap[i + 1])[0];
16981               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16982                 src = cap.slice(i + 1).join('\n') + src;
16983                 i = l - 1;
16984               }
16985             }
16986     
16987             // Determine whether item is loose or not.
16988             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16989             // for discount behavior.
16990             loose = next || /\n\n(?!\s*$)/.test(item);
16991             if (i !== l - 1) {
16992               next = item.charAt(item.length - 1) === '\n';
16993               if (!loose) { loose = next; }
16994             }
16995     
16996             this.tokens.push({
16997               type: loose
16998                 ? 'loose_item_start'
16999                 : 'list_item_start'
17000             });
17001     
17002             // Recurse.
17003             this.token(item, false, bq);
17004     
17005             this.tokens.push({
17006               type: 'list_item_end'
17007             });
17008           }
17009     
17010           this.tokens.push({
17011             type: 'list_end'
17012           });
17013     
17014           continue;
17015         }
17016     
17017         // html
17018         if (cap = this.rules.html.exec(src)) {
17019           src = src.substring(cap[0].length);
17020           this.tokens.push({
17021             type: this.options.sanitize
17022               ? 'paragraph'
17023               : 'html',
17024             pre: !this.options.sanitizer
17025               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17026             text: cap[0]
17027           });
17028           continue;
17029         }
17030     
17031         // def
17032         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17033           src = src.substring(cap[0].length);
17034           this.tokens.links[cap[1].toLowerCase()] = {
17035             href: cap[2],
17036             title: cap[3]
17037           };
17038           continue;
17039         }
17040     
17041         // table (gfm)
17042         if (top && (cap = this.rules.table.exec(src))) {
17043           src = src.substring(cap[0].length);
17044     
17045           item = {
17046             type: 'table',
17047             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17048             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17049             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17050           };
17051     
17052           for (i = 0; i < item.align.length; i++) {
17053             if (/^ *-+: *$/.test(item.align[i])) {
17054               item.align[i] = 'right';
17055             } else if (/^ *:-+: *$/.test(item.align[i])) {
17056               item.align[i] = 'center';
17057             } else if (/^ *:-+ *$/.test(item.align[i])) {
17058               item.align[i] = 'left';
17059             } else {
17060               item.align[i] = null;
17061             }
17062           }
17063     
17064           for (i = 0; i < item.cells.length; i++) {
17065             item.cells[i] = item.cells[i]
17066               .replace(/^ *\| *| *\| *$/g, '')
17067               .split(/ *\| */);
17068           }
17069     
17070           this.tokens.push(item);
17071     
17072           continue;
17073         }
17074     
17075         // top-level paragraph
17076         if (top && (cap = this.rules.paragraph.exec(src))) {
17077           src = src.substring(cap[0].length);
17078           this.tokens.push({
17079             type: 'paragraph',
17080             text: cap[1].charAt(cap[1].length - 1) === '\n'
17081               ? cap[1].slice(0, -1)
17082               : cap[1]
17083           });
17084           continue;
17085         }
17086     
17087         // text
17088         if (cap = this.rules.text.exec(src)) {
17089           // Top-level should never reach here.
17090           src = src.substring(cap[0].length);
17091           this.tokens.push({
17092             type: 'text',
17093             text: cap[0]
17094           });
17095           continue;
17096         }
17097     
17098         if (src) {
17099           throw new
17100             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17101         }
17102       }
17103     
17104       return this.tokens;
17105     };
17106     
17107     /**
17108      * Inline-Level Grammar
17109      */
17110     
17111     var inline = {
17112       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17113       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17114       url: noop,
17115       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17116       link: /^!?\[(inside)\]\(href\)/,
17117       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17118       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17119       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17120       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17121       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17122       br: /^ {2,}\n(?!\s*$)/,
17123       del: noop,
17124       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17125     };
17126     
17127     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17128     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17129     
17130     inline.link = replace(inline.link)
17131       ('inside', inline._inside)
17132       ('href', inline._href)
17133       ();
17134     
17135     inline.reflink = replace(inline.reflink)
17136       ('inside', inline._inside)
17137       ();
17138     
17139     /**
17140      * Normal Inline Grammar
17141      */
17142     
17143     inline.normal = merge({}, inline);
17144     
17145     /**
17146      * Pedantic Inline Grammar
17147      */
17148     
17149     inline.pedantic = merge({}, inline.normal, {
17150       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17151       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17152     });
17153     
17154     /**
17155      * GFM Inline Grammar
17156      */
17157     
17158     inline.gfm = merge({}, inline.normal, {
17159       escape: replace(inline.escape)('])', '~|])')(),
17160       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17161       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17162       text: replace(inline.text)
17163         (']|', '~]|')
17164         ('|', '|https?://|')
17165         ()
17166     });
17167     
17168     /**
17169      * GFM + Line Breaks Inline Grammar
17170      */
17171     
17172     inline.breaks = merge({}, inline.gfm, {
17173       br: replace(inline.br)('{2,}', '*')(),
17174       text: replace(inline.gfm.text)('{2,}', '*')()
17175     });
17176     
17177     /**
17178      * Inline Lexer & Compiler
17179      */
17180     
17181     function InlineLexer(links, options) {
17182       this.options = options || marked.defaults;
17183       this.links = links;
17184       this.rules = inline.normal;
17185       this.renderer = this.options.renderer || new Renderer;
17186       this.renderer.options = this.options;
17187     
17188       if (!this.links) {
17189         throw new
17190           Error('Tokens array requires a `links` property.');
17191       }
17192     
17193       if (this.options.gfm) {
17194         if (this.options.breaks) {
17195           this.rules = inline.breaks;
17196         } else {
17197           this.rules = inline.gfm;
17198         }
17199       } else if (this.options.pedantic) {
17200         this.rules = inline.pedantic;
17201       }
17202     }
17203     
17204     /**
17205      * Expose Inline Rules
17206      */
17207     
17208     InlineLexer.rules = inline;
17209     
17210     /**
17211      * Static Lexing/Compiling Method
17212      */
17213     
17214     InlineLexer.output = function(src, links, options) {
17215       var inline = new InlineLexer(links, options);
17216       return inline.output(src);
17217     };
17218     
17219     /**
17220      * Lexing/Compiling
17221      */
17222     
17223     InlineLexer.prototype.output = function(src) {
17224       var out = ''
17225         , link
17226         , text
17227         , href
17228         , cap;
17229     
17230       while (src) {
17231         // escape
17232         if (cap = this.rules.escape.exec(src)) {
17233           src = src.substring(cap[0].length);
17234           out += cap[1];
17235           continue;
17236         }
17237     
17238         // autolink
17239         if (cap = this.rules.autolink.exec(src)) {
17240           src = src.substring(cap[0].length);
17241           if (cap[2] === '@') {
17242             text = cap[1].charAt(6) === ':'
17243               ? this.mangle(cap[1].substring(7))
17244               : this.mangle(cap[1]);
17245             href = this.mangle('mailto:') + text;
17246           } else {
17247             text = escape(cap[1]);
17248             href = text;
17249           }
17250           out += this.renderer.link(href, null, text);
17251           continue;
17252         }
17253     
17254         // url (gfm)
17255         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17256           src = src.substring(cap[0].length);
17257           text = escape(cap[1]);
17258           href = text;
17259           out += this.renderer.link(href, null, text);
17260           continue;
17261         }
17262     
17263         // tag
17264         if (cap = this.rules.tag.exec(src)) {
17265           if (!this.inLink && /^<a /i.test(cap[0])) {
17266             this.inLink = true;
17267           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17268             this.inLink = false;
17269           }
17270           src = src.substring(cap[0].length);
17271           out += this.options.sanitize
17272             ? this.options.sanitizer
17273               ? this.options.sanitizer(cap[0])
17274               : escape(cap[0])
17275             : cap[0];
17276           continue;
17277         }
17278     
17279         // link
17280         if (cap = this.rules.link.exec(src)) {
17281           src = src.substring(cap[0].length);
17282           this.inLink = true;
17283           out += this.outputLink(cap, {
17284             href: cap[2],
17285             title: cap[3]
17286           });
17287           this.inLink = false;
17288           continue;
17289         }
17290     
17291         // reflink, nolink
17292         if ((cap = this.rules.reflink.exec(src))
17293             || (cap = this.rules.nolink.exec(src))) {
17294           src = src.substring(cap[0].length);
17295           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17296           link = this.links[link.toLowerCase()];
17297           if (!link || !link.href) {
17298             out += cap[0].charAt(0);
17299             src = cap[0].substring(1) + src;
17300             continue;
17301           }
17302           this.inLink = true;
17303           out += this.outputLink(cap, link);
17304           this.inLink = false;
17305           continue;
17306         }
17307     
17308         // strong
17309         if (cap = this.rules.strong.exec(src)) {
17310           src = src.substring(cap[0].length);
17311           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17312           continue;
17313         }
17314     
17315         // em
17316         if (cap = this.rules.em.exec(src)) {
17317           src = src.substring(cap[0].length);
17318           out += this.renderer.em(this.output(cap[2] || cap[1]));
17319           continue;
17320         }
17321     
17322         // code
17323         if (cap = this.rules.code.exec(src)) {
17324           src = src.substring(cap[0].length);
17325           out += this.renderer.codespan(escape(cap[2], true));
17326           continue;
17327         }
17328     
17329         // br
17330         if (cap = this.rules.br.exec(src)) {
17331           src = src.substring(cap[0].length);
17332           out += this.renderer.br();
17333           continue;
17334         }
17335     
17336         // del (gfm)
17337         if (cap = this.rules.del.exec(src)) {
17338           src = src.substring(cap[0].length);
17339           out += this.renderer.del(this.output(cap[1]));
17340           continue;
17341         }
17342     
17343         // text
17344         if (cap = this.rules.text.exec(src)) {
17345           src = src.substring(cap[0].length);
17346           out += this.renderer.text(escape(this.smartypants(cap[0])));
17347           continue;
17348         }
17349     
17350         if (src) {
17351           throw new
17352             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17353         }
17354       }
17355     
17356       return out;
17357     };
17358     
17359     /**
17360      * Compile Link
17361      */
17362     
17363     InlineLexer.prototype.outputLink = function(cap, link) {
17364       var href = escape(link.href)
17365         , title = link.title ? escape(link.title) : null;
17366     
17367       return cap[0].charAt(0) !== '!'
17368         ? this.renderer.link(href, title, this.output(cap[1]))
17369         : this.renderer.image(href, title, escape(cap[1]));
17370     };
17371     
17372     /**
17373      * Smartypants Transformations
17374      */
17375     
17376     InlineLexer.prototype.smartypants = function(text) {
17377       if (!this.options.smartypants)  { return text; }
17378       return text
17379         // em-dashes
17380         .replace(/---/g, '\u2014')
17381         // en-dashes
17382         .replace(/--/g, '\u2013')
17383         // opening singles
17384         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17385         // closing singles & apostrophes
17386         .replace(/'/g, '\u2019')
17387         // opening doubles
17388         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17389         // closing doubles
17390         .replace(/"/g, '\u201d')
17391         // ellipses
17392         .replace(/\.{3}/g, '\u2026');
17393     };
17394     
17395     /**
17396      * Mangle Links
17397      */
17398     
17399     InlineLexer.prototype.mangle = function(text) {
17400       if (!this.options.mangle) { return text; }
17401       var out = ''
17402         , l = text.length
17403         , i = 0
17404         , ch;
17405     
17406       for (; i < l; i++) {
17407         ch = text.charCodeAt(i);
17408         if (Math.random() > 0.5) {
17409           ch = 'x' + ch.toString(16);
17410         }
17411         out += '&#' + ch + ';';
17412       }
17413     
17414       return out;
17415     };
17416     
17417     /**
17418      * Renderer
17419      */
17420     
17421     function Renderer(options) {
17422       this.options = options || {};
17423     }
17424     
17425     Renderer.prototype.code = function(code, lang, escaped) {
17426       if (this.options.highlight) {
17427         var out = this.options.highlight(code, lang);
17428         if (out != null && out !== code) {
17429           escaped = true;
17430           code = out;
17431         }
17432       } else {
17433             // hack!!! - it's already escapeD?
17434             escaped = true;
17435       }
17436     
17437       if (!lang) {
17438         return '<pre><code>'
17439           + (escaped ? code : escape(code, true))
17440           + '\n</code></pre>';
17441       }
17442     
17443       return '<pre><code class="'
17444         + this.options.langPrefix
17445         + escape(lang, true)
17446         + '">'
17447         + (escaped ? code : escape(code, true))
17448         + '\n</code></pre>\n';
17449     };
17450     
17451     Renderer.prototype.blockquote = function(quote) {
17452       return '<blockquote>\n' + quote + '</blockquote>\n';
17453     };
17454     
17455     Renderer.prototype.html = function(html) {
17456       return html;
17457     };
17458     
17459     Renderer.prototype.heading = function(text, level, raw) {
17460       return '<h'
17461         + level
17462         + ' id="'
17463         + this.options.headerPrefix
17464         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17465         + '">'
17466         + text
17467         + '</h'
17468         + level
17469         + '>\n';
17470     };
17471     
17472     Renderer.prototype.hr = function() {
17473       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17474     };
17475     
17476     Renderer.prototype.list = function(body, ordered) {
17477       var type = ordered ? 'ol' : 'ul';
17478       return '<' + type + '>\n' + body + '</' + type + '>\n';
17479     };
17480     
17481     Renderer.prototype.listitem = function(text) {
17482       return '<li>' + text + '</li>\n';
17483     };
17484     
17485     Renderer.prototype.paragraph = function(text) {
17486       return '<p>' + text + '</p>\n';
17487     };
17488     
17489     Renderer.prototype.table = function(header, body) {
17490       return '<table class="table table-striped">\n'
17491         + '<thead>\n'
17492         + header
17493         + '</thead>\n'
17494         + '<tbody>\n'
17495         + body
17496         + '</tbody>\n'
17497         + '</table>\n';
17498     };
17499     
17500     Renderer.prototype.tablerow = function(content) {
17501       return '<tr>\n' + content + '</tr>\n';
17502     };
17503     
17504     Renderer.prototype.tablecell = function(content, flags) {
17505       var type = flags.header ? 'th' : 'td';
17506       var tag = flags.align
17507         ? '<' + type + ' style="text-align:' + flags.align + '">'
17508         : '<' + type + '>';
17509       return tag + content + '</' + type + '>\n';
17510     };
17511     
17512     // span level renderer
17513     Renderer.prototype.strong = function(text) {
17514       return '<strong>' + text + '</strong>';
17515     };
17516     
17517     Renderer.prototype.em = function(text) {
17518       return '<em>' + text + '</em>';
17519     };
17520     
17521     Renderer.prototype.codespan = function(text) {
17522       return '<code>' + text + '</code>';
17523     };
17524     
17525     Renderer.prototype.br = function() {
17526       return this.options.xhtml ? '<br/>' : '<br>';
17527     };
17528     
17529     Renderer.prototype.del = function(text) {
17530       return '<del>' + text + '</del>';
17531     };
17532     
17533     Renderer.prototype.link = function(href, title, text) {
17534       if (this.options.sanitize) {
17535         try {
17536           var prot = decodeURIComponent(unescape(href))
17537             .replace(/[^\w:]/g, '')
17538             .toLowerCase();
17539         } catch (e) {
17540           return '';
17541         }
17542         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17543           return '';
17544         }
17545       }
17546       var out = '<a href="' + href + '"';
17547       if (title) {
17548         out += ' title="' + title + '"';
17549       }
17550       out += '>' + text + '</a>';
17551       return out;
17552     };
17553     
17554     Renderer.prototype.image = function(href, title, text) {
17555       var out = '<img src="' + href + '" alt="' + text + '"';
17556       if (title) {
17557         out += ' title="' + title + '"';
17558       }
17559       out += this.options.xhtml ? '/>' : '>';
17560       return out;
17561     };
17562     
17563     Renderer.prototype.text = function(text) {
17564       return text;
17565     };
17566     
17567     /**
17568      * Parsing & Compiling
17569      */
17570     
17571     function Parser(options) {
17572       this.tokens = [];
17573       this.token = null;
17574       this.options = options || marked.defaults;
17575       this.options.renderer = this.options.renderer || new Renderer;
17576       this.renderer = this.options.renderer;
17577       this.renderer.options = this.options;
17578     }
17579     
17580     /**
17581      * Static Parse Method
17582      */
17583     
17584     Parser.parse = function(src, options, renderer) {
17585       var parser = new Parser(options, renderer);
17586       return parser.parse(src);
17587     };
17588     
17589     /**
17590      * Parse Loop
17591      */
17592     
17593     Parser.prototype.parse = function(src) {
17594       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17595       this.tokens = src.reverse();
17596     
17597       var out = '';
17598       while (this.next()) {
17599         out += this.tok();
17600       }
17601     
17602       return out;
17603     };
17604     
17605     /**
17606      * Next Token
17607      */
17608     
17609     Parser.prototype.next = function() {
17610       return this.token = this.tokens.pop();
17611     };
17612     
17613     /**
17614      * Preview Next Token
17615      */
17616     
17617     Parser.prototype.peek = function() {
17618       return this.tokens[this.tokens.length - 1] || 0;
17619     };
17620     
17621     /**
17622      * Parse Text Tokens
17623      */
17624     
17625     Parser.prototype.parseText = function() {
17626       var body = this.token.text;
17627     
17628       while (this.peek().type === 'text') {
17629         body += '\n' + this.next().text;
17630       }
17631     
17632       return this.inline.output(body);
17633     };
17634     
17635     /**
17636      * Parse Current Token
17637      */
17638     
17639     Parser.prototype.tok = function() {
17640       switch (this.token.type) {
17641         case 'space': {
17642           return '';
17643         }
17644         case 'hr': {
17645           return this.renderer.hr();
17646         }
17647         case 'heading': {
17648           return this.renderer.heading(
17649             this.inline.output(this.token.text),
17650             this.token.depth,
17651             this.token.text);
17652         }
17653         case 'code': {
17654           return this.renderer.code(this.token.text,
17655             this.token.lang,
17656             this.token.escaped);
17657         }
17658         case 'table': {
17659           var header = ''
17660             , body = ''
17661             , i
17662             , row
17663             , cell
17664             , flags
17665             , j;
17666     
17667           // header
17668           cell = '';
17669           for (i = 0; i < this.token.header.length; i++) {
17670             flags = { header: true, align: this.token.align[i] };
17671             cell += this.renderer.tablecell(
17672               this.inline.output(this.token.header[i]),
17673               { header: true, align: this.token.align[i] }
17674             );
17675           }
17676           header += this.renderer.tablerow(cell);
17677     
17678           for (i = 0; i < this.token.cells.length; i++) {
17679             row = this.token.cells[i];
17680     
17681             cell = '';
17682             for (j = 0; j < row.length; j++) {
17683               cell += this.renderer.tablecell(
17684                 this.inline.output(row[j]),
17685                 { header: false, align: this.token.align[j] }
17686               );
17687             }
17688     
17689             body += this.renderer.tablerow(cell);
17690           }
17691           return this.renderer.table(header, body);
17692         }
17693         case 'blockquote_start': {
17694           var body = '';
17695     
17696           while (this.next().type !== 'blockquote_end') {
17697             body += this.tok();
17698           }
17699     
17700           return this.renderer.blockquote(body);
17701         }
17702         case 'list_start': {
17703           var body = ''
17704             , ordered = this.token.ordered;
17705     
17706           while (this.next().type !== 'list_end') {
17707             body += this.tok();
17708           }
17709     
17710           return this.renderer.list(body, ordered);
17711         }
17712         case 'list_item_start': {
17713           var body = '';
17714     
17715           while (this.next().type !== 'list_item_end') {
17716             body += this.token.type === 'text'
17717               ? this.parseText()
17718               : this.tok();
17719           }
17720     
17721           return this.renderer.listitem(body);
17722         }
17723         case 'loose_item_start': {
17724           var body = '';
17725     
17726           while (this.next().type !== 'list_item_end') {
17727             body += this.tok();
17728           }
17729     
17730           return this.renderer.listitem(body);
17731         }
17732         case 'html': {
17733           var html = !this.token.pre && !this.options.pedantic
17734             ? this.inline.output(this.token.text)
17735             : this.token.text;
17736           return this.renderer.html(html);
17737         }
17738         case 'paragraph': {
17739           return this.renderer.paragraph(this.inline.output(this.token.text));
17740         }
17741         case 'text': {
17742           return this.renderer.paragraph(this.parseText());
17743         }
17744       }
17745     };
17746     
17747     /**
17748      * Helpers
17749      */
17750     
17751     function escape(html, encode) {
17752       return html
17753         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17754         .replace(/</g, '&lt;')
17755         .replace(/>/g, '&gt;')
17756         .replace(/"/g, '&quot;')
17757         .replace(/'/g, '&#39;');
17758     }
17759     
17760     function unescape(html) {
17761         // explicitly match decimal, hex, and named HTML entities 
17762       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17763         n = n.toLowerCase();
17764         if (n === 'colon') { return ':'; }
17765         if (n.charAt(0) === '#') {
17766           return n.charAt(1) === 'x'
17767             ? String.fromCharCode(parseInt(n.substring(2), 16))
17768             : String.fromCharCode(+n.substring(1));
17769         }
17770         return '';
17771       });
17772     }
17773     
17774     function replace(regex, opt) {
17775       regex = regex.source;
17776       opt = opt || '';
17777       return function self(name, val) {
17778         if (!name) { return new RegExp(regex, opt); }
17779         val = val.source || val;
17780         val = val.replace(/(^|[^\[])\^/g, '$1');
17781         regex = regex.replace(name, val);
17782         return self;
17783       };
17784     }
17785     
17786     function noop() {}
17787     noop.exec = noop;
17788     
17789     function merge(obj) {
17790       var i = 1
17791         , target
17792         , key;
17793     
17794       for (; i < arguments.length; i++) {
17795         target = arguments[i];
17796         for (key in target) {
17797           if (Object.prototype.hasOwnProperty.call(target, key)) {
17798             obj[key] = target[key];
17799           }
17800         }
17801       }
17802     
17803       return obj;
17804     }
17805     
17806     
17807     /**
17808      * Marked
17809      */
17810     
17811     function marked(src, opt, callback) {
17812       if (callback || typeof opt === 'function') {
17813         if (!callback) {
17814           callback = opt;
17815           opt = null;
17816         }
17817     
17818         opt = merge({}, marked.defaults, opt || {});
17819     
17820         var highlight = opt.highlight
17821           , tokens
17822           , pending
17823           , i = 0;
17824     
17825         try {
17826           tokens = Lexer.lex(src, opt)
17827         } catch (e) {
17828           return callback(e);
17829         }
17830     
17831         pending = tokens.length;
17832     
17833         var done = function(err) {
17834           if (err) {
17835             opt.highlight = highlight;
17836             return callback(err);
17837           }
17838     
17839           var out;
17840     
17841           try {
17842             out = Parser.parse(tokens, opt);
17843           } catch (e) {
17844             err = e;
17845           }
17846     
17847           opt.highlight = highlight;
17848     
17849           return err
17850             ? callback(err)
17851             : callback(null, out);
17852         };
17853     
17854         if (!highlight || highlight.length < 3) {
17855           return done();
17856         }
17857     
17858         delete opt.highlight;
17859     
17860         if (!pending) { return done(); }
17861     
17862         for (; i < tokens.length; i++) {
17863           (function(token) {
17864             if (token.type !== 'code') {
17865               return --pending || done();
17866             }
17867             return highlight(token.text, token.lang, function(err, code) {
17868               if (err) { return done(err); }
17869               if (code == null || code === token.text) {
17870                 return --pending || done();
17871               }
17872               token.text = code;
17873               token.escaped = true;
17874               --pending || done();
17875             });
17876           })(tokens[i]);
17877         }
17878     
17879         return;
17880       }
17881       try {
17882         if (opt) { opt = merge({}, marked.defaults, opt); }
17883         return Parser.parse(Lexer.lex(src, opt), opt);
17884       } catch (e) {
17885         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17886         if ((opt || marked.defaults).silent) {
17887           return '<p>An error occured:</p><pre>'
17888             + escape(e.message + '', true)
17889             + '</pre>';
17890         }
17891         throw e;
17892       }
17893     }
17894     
17895     /**
17896      * Options
17897      */
17898     
17899     marked.options =
17900     marked.setOptions = function(opt) {
17901       merge(marked.defaults, opt);
17902       return marked;
17903     };
17904     
17905     marked.defaults = {
17906       gfm: true,
17907       tables: true,
17908       breaks: false,
17909       pedantic: false,
17910       sanitize: false,
17911       sanitizer: null,
17912       mangle: true,
17913       smartLists: false,
17914       silent: false,
17915       highlight: null,
17916       langPrefix: 'lang-',
17917       smartypants: false,
17918       headerPrefix: '',
17919       renderer: new Renderer,
17920       xhtml: false
17921     };
17922     
17923     /**
17924      * Expose
17925      */
17926     
17927     marked.Parser = Parser;
17928     marked.parser = Parser.parse;
17929     
17930     marked.Renderer = Renderer;
17931     
17932     marked.Lexer = Lexer;
17933     marked.lexer = Lexer.lex;
17934     
17935     marked.InlineLexer = InlineLexer;
17936     marked.inlineLexer = InlineLexer.output;
17937     
17938     marked.parse = marked;
17939     
17940     Roo.Markdown.marked = marked;
17941
17942 })();/*
17943  * Based on:
17944  * Ext JS Library 1.1.1
17945  * Copyright(c) 2006-2007, Ext JS, LLC.
17946  *
17947  * Originally Released Under LGPL - original licence link has changed is not relivant.
17948  *
17949  * Fork - LGPL
17950  * <script type="text/javascript">
17951  */
17952
17953
17954
17955 /*
17956  * These classes are derivatives of the similarly named classes in the YUI Library.
17957  * The original license:
17958  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17959  * Code licensed under the BSD License:
17960  * http://developer.yahoo.net/yui/license.txt
17961  */
17962
17963 (function() {
17964
17965 var Event=Roo.EventManager;
17966 var Dom=Roo.lib.Dom;
17967
17968 /**
17969  * @class Roo.dd.DragDrop
17970  * @extends Roo.util.Observable
17971  * Defines the interface and base operation of items that that can be
17972  * dragged or can be drop targets.  It was designed to be extended, overriding
17973  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17974  * Up to three html elements can be associated with a DragDrop instance:
17975  * <ul>
17976  * <li>linked element: the element that is passed into the constructor.
17977  * This is the element which defines the boundaries for interaction with
17978  * other DragDrop objects.</li>
17979  * <li>handle element(s): The drag operation only occurs if the element that
17980  * was clicked matches a handle element.  By default this is the linked
17981  * element, but there are times that you will want only a portion of the
17982  * linked element to initiate the drag operation, and the setHandleElId()
17983  * method provides a way to define this.</li>
17984  * <li>drag element: this represents the element that would be moved along
17985  * with the cursor during a drag operation.  By default, this is the linked
17986  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
17987  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17988  * </li>
17989  * </ul>
17990  * This class should not be instantiated until the onload event to ensure that
17991  * the associated elements are available.
17992  * The following would define a DragDrop obj that would interact with any
17993  * other DragDrop obj in the "group1" group:
17994  * <pre>
17995  *  dd = new Roo.dd.DragDrop("div1", "group1");
17996  * </pre>
17997  * Since none of the event handlers have been implemented, nothing would
17998  * actually happen if you were to run the code above.  Normally you would
17999  * override this class or one of the default implementations, but you can
18000  * also override the methods you want on an instance of the class...
18001  * <pre>
18002  *  dd.onDragDrop = function(e, id) {
18003  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18004  *  }
18005  * </pre>
18006  * @constructor
18007  * @param {String} id of the element that is linked to this instance
18008  * @param {String} sGroup the group of related DragDrop objects
18009  * @param {object} config an object containing configurable attributes
18010  *                Valid properties for DragDrop:
18011  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18012  */
18013 Roo.dd.DragDrop = function(id, sGroup, config) {
18014     if (id) {
18015         this.init(id, sGroup, config);
18016     }
18017     
18018 };
18019
18020 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18021
18022     /**
18023      * The id of the element associated with this object.  This is what we
18024      * refer to as the "linked element" because the size and position of
18025      * this element is used to determine when the drag and drop objects have
18026      * interacted.
18027      * @property id
18028      * @type String
18029      */
18030     id: null,
18031
18032     /**
18033      * Configuration attributes passed into the constructor
18034      * @property config
18035      * @type object
18036      */
18037     config: null,
18038
18039     /**
18040      * The id of the element that will be dragged.  By default this is same
18041      * as the linked element , but could be changed to another element. Ex:
18042      * Roo.dd.DDProxy
18043      * @property dragElId
18044      * @type String
18045      * @private
18046      */
18047     dragElId: null,
18048
18049     /**
18050      * the id of the element that initiates the drag operation.  By default
18051      * this is the linked element, but could be changed to be a child of this
18052      * element.  This lets us do things like only starting the drag when the
18053      * header element within the linked html element is clicked.
18054      * @property handleElId
18055      * @type String
18056      * @private
18057      */
18058     handleElId: null,
18059
18060     /**
18061      * An associative array of HTML tags that will be ignored if clicked.
18062      * @property invalidHandleTypes
18063      * @type {string: string}
18064      */
18065     invalidHandleTypes: null,
18066
18067     /**
18068      * An associative array of ids for elements that will be ignored if clicked
18069      * @property invalidHandleIds
18070      * @type {string: string}
18071      */
18072     invalidHandleIds: null,
18073
18074     /**
18075      * An indexted array of css class names for elements that will be ignored
18076      * if clicked.
18077      * @property invalidHandleClasses
18078      * @type string[]
18079      */
18080     invalidHandleClasses: null,
18081
18082     /**
18083      * The linked element's absolute X position at the time the drag was
18084      * started
18085      * @property startPageX
18086      * @type int
18087      * @private
18088      */
18089     startPageX: 0,
18090
18091     /**
18092      * The linked element's absolute X position at the time the drag was
18093      * started
18094      * @property startPageY
18095      * @type int
18096      * @private
18097      */
18098     startPageY: 0,
18099
18100     /**
18101      * The group defines a logical collection of DragDrop objects that are
18102      * related.  Instances only get events when interacting with other
18103      * DragDrop object in the same group.  This lets us define multiple
18104      * groups using a single DragDrop subclass if we want.
18105      * @property groups
18106      * @type {string: string}
18107      */
18108     groups: null,
18109
18110     /**
18111      * Individual drag/drop instances can be locked.  This will prevent
18112      * onmousedown start drag.
18113      * @property locked
18114      * @type boolean
18115      * @private
18116      */
18117     locked: false,
18118
18119     /**
18120      * Lock this instance
18121      * @method lock
18122      */
18123     lock: function() { this.locked = true; },
18124
18125     /**
18126      * Unlock this instace
18127      * @method unlock
18128      */
18129     unlock: function() { this.locked = false; },
18130
18131     /**
18132      * By default, all insances can be a drop target.  This can be disabled by
18133      * setting isTarget to false.
18134      * @method isTarget
18135      * @type boolean
18136      */
18137     isTarget: true,
18138
18139     /**
18140      * The padding configured for this drag and drop object for calculating
18141      * the drop zone intersection with this object.
18142      * @method padding
18143      * @type int[]
18144      */
18145     padding: null,
18146
18147     /**
18148      * Cached reference to the linked element
18149      * @property _domRef
18150      * @private
18151      */
18152     _domRef: null,
18153
18154     /**
18155      * Internal typeof flag
18156      * @property __ygDragDrop
18157      * @private
18158      */
18159     __ygDragDrop: true,
18160
18161     /**
18162      * Set to true when horizontal contraints are applied
18163      * @property constrainX
18164      * @type boolean
18165      * @private
18166      */
18167     constrainX: false,
18168
18169     /**
18170      * Set to true when vertical contraints are applied
18171      * @property constrainY
18172      * @type boolean
18173      * @private
18174      */
18175     constrainY: false,
18176
18177     /**
18178      * The left constraint
18179      * @property minX
18180      * @type int
18181      * @private
18182      */
18183     minX: 0,
18184
18185     /**
18186      * The right constraint
18187      * @property maxX
18188      * @type int
18189      * @private
18190      */
18191     maxX: 0,
18192
18193     /**
18194      * The up constraint
18195      * @property minY
18196      * @type int
18197      * @type int
18198      * @private
18199      */
18200     minY: 0,
18201
18202     /**
18203      * The down constraint
18204      * @property maxY
18205      * @type int
18206      * @private
18207      */
18208     maxY: 0,
18209
18210     /**
18211      * Maintain offsets when we resetconstraints.  Set to true when you want
18212      * the position of the element relative to its parent to stay the same
18213      * when the page changes
18214      *
18215      * @property maintainOffset
18216      * @type boolean
18217      */
18218     maintainOffset: false,
18219
18220     /**
18221      * Array of pixel locations the element will snap to if we specified a
18222      * horizontal graduation/interval.  This array is generated automatically
18223      * when you define a tick interval.
18224      * @property xTicks
18225      * @type int[]
18226      */
18227     xTicks: null,
18228
18229     /**
18230      * Array of pixel locations the element will snap to if we specified a
18231      * vertical graduation/interval.  This array is generated automatically
18232      * when you define a tick interval.
18233      * @property yTicks
18234      * @type int[]
18235      */
18236     yTicks: null,
18237
18238     /**
18239      * By default the drag and drop instance will only respond to the primary
18240      * button click (left button for a right-handed mouse).  Set to true to
18241      * allow drag and drop to start with any mouse click that is propogated
18242      * by the browser
18243      * @property primaryButtonOnly
18244      * @type boolean
18245      */
18246     primaryButtonOnly: true,
18247
18248     /**
18249      * The availabe property is false until the linked dom element is accessible.
18250      * @property available
18251      * @type boolean
18252      */
18253     available: false,
18254
18255     /**
18256      * By default, drags can only be initiated if the mousedown occurs in the
18257      * region the linked element is.  This is done in part to work around a
18258      * bug in some browsers that mis-report the mousedown if the previous
18259      * mouseup happened outside of the window.  This property is set to true
18260      * if outer handles are defined.
18261      *
18262      * @property hasOuterHandles
18263      * @type boolean
18264      * @default false
18265      */
18266     hasOuterHandles: false,
18267
18268     /**
18269      * Code that executes immediately before the startDrag event
18270      * @method b4StartDrag
18271      * @private
18272      */
18273     b4StartDrag: function(x, y) { },
18274
18275     /**
18276      * Abstract method called after a drag/drop object is clicked
18277      * and the drag or mousedown time thresholds have beeen met.
18278      * @method startDrag
18279      * @param {int} X click location
18280      * @param {int} Y click location
18281      */
18282     startDrag: function(x, y) { /* override this */ },
18283
18284     /**
18285      * Code that executes immediately before the onDrag event
18286      * @method b4Drag
18287      * @private
18288      */
18289     b4Drag: function(e) { },
18290
18291     /**
18292      * Abstract method called during the onMouseMove event while dragging an
18293      * object.
18294      * @method onDrag
18295      * @param {Event} e the mousemove event
18296      */
18297     onDrag: function(e) { /* override this */ },
18298
18299     /**
18300      * Abstract method called when this element fist begins hovering over
18301      * another DragDrop obj
18302      * @method onDragEnter
18303      * @param {Event} e the mousemove event
18304      * @param {String|DragDrop[]} id In POINT mode, the element
18305      * id this is hovering over.  In INTERSECT mode, an array of one or more
18306      * dragdrop items being hovered over.
18307      */
18308     onDragEnter: function(e, id) { /* override this */ },
18309
18310     /**
18311      * Code that executes immediately before the onDragOver event
18312      * @method b4DragOver
18313      * @private
18314      */
18315     b4DragOver: function(e) { },
18316
18317     /**
18318      * Abstract method called when this element is hovering over another
18319      * DragDrop obj
18320      * @method onDragOver
18321      * @param {Event} e the mousemove event
18322      * @param {String|DragDrop[]} id In POINT mode, the element
18323      * id this is hovering over.  In INTERSECT mode, an array of dd items
18324      * being hovered over.
18325      */
18326     onDragOver: function(e, id) { /* override this */ },
18327
18328     /**
18329      * Code that executes immediately before the onDragOut event
18330      * @method b4DragOut
18331      * @private
18332      */
18333     b4DragOut: function(e) { },
18334
18335     /**
18336      * Abstract method called when we are no longer hovering over an element
18337      * @method onDragOut
18338      * @param {Event} e the mousemove event
18339      * @param {String|DragDrop[]} id In POINT mode, the element
18340      * id this was hovering over.  In INTERSECT mode, an array of dd items
18341      * that the mouse is no longer over.
18342      */
18343     onDragOut: function(e, id) { /* override this */ },
18344
18345     /**
18346      * Code that executes immediately before the onDragDrop event
18347      * @method b4DragDrop
18348      * @private
18349      */
18350     b4DragDrop: function(e) { },
18351
18352     /**
18353      * Abstract method called when this item is dropped on another DragDrop
18354      * obj
18355      * @method onDragDrop
18356      * @param {Event} e the mouseup event
18357      * @param {String|DragDrop[]} id In POINT mode, the element
18358      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18359      * was dropped on.
18360      */
18361     onDragDrop: function(e, id) { /* override this */ },
18362
18363     /**
18364      * Abstract method called when this item is dropped on an area with no
18365      * drop target
18366      * @method onInvalidDrop
18367      * @param {Event} e the mouseup event
18368      */
18369     onInvalidDrop: function(e) { /* override this */ },
18370
18371     /**
18372      * Code that executes immediately before the endDrag event
18373      * @method b4EndDrag
18374      * @private
18375      */
18376     b4EndDrag: function(e) { },
18377
18378     /**
18379      * Fired when we are done dragging the object
18380      * @method endDrag
18381      * @param {Event} e the mouseup event
18382      */
18383     endDrag: function(e) { /* override this */ },
18384
18385     /**
18386      * Code executed immediately before the onMouseDown event
18387      * @method b4MouseDown
18388      * @param {Event} e the mousedown event
18389      * @private
18390      */
18391     b4MouseDown: function(e) {  },
18392
18393     /**
18394      * Event handler that fires when a drag/drop obj gets a mousedown
18395      * @method onMouseDown
18396      * @param {Event} e the mousedown event
18397      */
18398     onMouseDown: function(e) { /* override this */ },
18399
18400     /**
18401      * Event handler that fires when a drag/drop obj gets a mouseup
18402      * @method onMouseUp
18403      * @param {Event} e the mouseup event
18404      */
18405     onMouseUp: function(e) { /* override this */ },
18406
18407     /**
18408      * Override the onAvailable method to do what is needed after the initial
18409      * position was determined.
18410      * @method onAvailable
18411      */
18412     onAvailable: function () {
18413     },
18414
18415     /*
18416      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18417      * @type Object
18418      */
18419     defaultPadding : {left:0, right:0, top:0, bottom:0},
18420
18421     /*
18422      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18423  *
18424  * Usage:
18425  <pre><code>
18426  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18427                 { dragElId: "existingProxyDiv" });
18428  dd.startDrag = function(){
18429      this.constrainTo("parent-id");
18430  };
18431  </code></pre>
18432  * Or you can initalize it using the {@link Roo.Element} object:
18433  <pre><code>
18434  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18435      startDrag : function(){
18436          this.constrainTo("parent-id");
18437      }
18438  });
18439  </code></pre>
18440      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18441      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18442      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18443      * an object containing the sides to pad. For example: {right:10, bottom:10}
18444      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18445      */
18446     constrainTo : function(constrainTo, pad, inContent){
18447         if(typeof pad == "number"){
18448             pad = {left: pad, right:pad, top:pad, bottom:pad};
18449         }
18450         pad = pad || this.defaultPadding;
18451         var b = Roo.get(this.getEl()).getBox();
18452         var ce = Roo.get(constrainTo);
18453         var s = ce.getScroll();
18454         var c, cd = ce.dom;
18455         if(cd == document.body){
18456             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18457         }else{
18458             xy = ce.getXY();
18459             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18460         }
18461
18462
18463         var topSpace = b.y - c.y;
18464         var leftSpace = b.x - c.x;
18465
18466         this.resetConstraints();
18467         this.setXConstraint(leftSpace - (pad.left||0), // left
18468                 c.width - leftSpace - b.width - (pad.right||0) //right
18469         );
18470         this.setYConstraint(topSpace - (pad.top||0), //top
18471                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18472         );
18473     },
18474
18475     /**
18476      * Returns a reference to the linked element
18477      * @method getEl
18478      * @return {HTMLElement} the html element
18479      */
18480     getEl: function() {
18481         if (!this._domRef) {
18482             this._domRef = Roo.getDom(this.id);
18483         }
18484
18485         return this._domRef;
18486     },
18487
18488     /**
18489      * Returns a reference to the actual element to drag.  By default this is
18490      * the same as the html element, but it can be assigned to another
18491      * element. An example of this can be found in Roo.dd.DDProxy
18492      * @method getDragEl
18493      * @return {HTMLElement} the html element
18494      */
18495     getDragEl: function() {
18496         return Roo.getDom(this.dragElId);
18497     },
18498
18499     /**
18500      * Sets up the DragDrop object.  Must be called in the constructor of any
18501      * Roo.dd.DragDrop subclass
18502      * @method init
18503      * @param id the id of the linked element
18504      * @param {String} sGroup the group of related items
18505      * @param {object} config configuration attributes
18506      */
18507     init: function(id, sGroup, config) {
18508         this.initTarget(id, sGroup, config);
18509         if (!Roo.isTouch) {
18510             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18511         }
18512         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18513         // Event.on(this.id, "selectstart", Event.preventDefault);
18514     },
18515
18516     /**
18517      * Initializes Targeting functionality only... the object does not
18518      * get a mousedown handler.
18519      * @method initTarget
18520      * @param id the id of the linked element
18521      * @param {String} sGroup the group of related items
18522      * @param {object} config configuration attributes
18523      */
18524     initTarget: function(id, sGroup, config) {
18525
18526         // configuration attributes
18527         this.config = config || {};
18528
18529         // create a local reference to the drag and drop manager
18530         this.DDM = Roo.dd.DDM;
18531         // initialize the groups array
18532         this.groups = {};
18533
18534         // assume that we have an element reference instead of an id if the
18535         // parameter is not a string
18536         if (typeof id !== "string") {
18537             id = Roo.id(id);
18538         }
18539
18540         // set the id
18541         this.id = id;
18542
18543         // add to an interaction group
18544         this.addToGroup((sGroup) ? sGroup : "default");
18545
18546         // We don't want to register this as the handle with the manager
18547         // so we just set the id rather than calling the setter.
18548         this.handleElId = id;
18549
18550         // the linked element is the element that gets dragged by default
18551         this.setDragElId(id);
18552
18553         // by default, clicked anchors will not start drag operations.
18554         this.invalidHandleTypes = { A: "A" };
18555         this.invalidHandleIds = {};
18556         this.invalidHandleClasses = [];
18557
18558         this.applyConfig();
18559
18560         this.handleOnAvailable();
18561     },
18562
18563     /**
18564      * Applies the configuration parameters that were passed into the constructor.
18565      * This is supposed to happen at each level through the inheritance chain.  So
18566      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18567      * DragDrop in order to get all of the parameters that are available in
18568      * each object.
18569      * @method applyConfig
18570      */
18571     applyConfig: function() {
18572
18573         // configurable properties:
18574         //    padding, isTarget, maintainOffset, primaryButtonOnly
18575         this.padding           = this.config.padding || [0, 0, 0, 0];
18576         this.isTarget          = (this.config.isTarget !== false);
18577         this.maintainOffset    = (this.config.maintainOffset);
18578         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18579
18580     },
18581
18582     /**
18583      * Executed when the linked element is available
18584      * @method handleOnAvailable
18585      * @private
18586      */
18587     handleOnAvailable: function() {
18588         this.available = true;
18589         this.resetConstraints();
18590         this.onAvailable();
18591     },
18592
18593      /**
18594      * Configures the padding for the target zone in px.  Effectively expands
18595      * (or reduces) the virtual object size for targeting calculations.
18596      * Supports css-style shorthand; if only one parameter is passed, all sides
18597      * will have that padding, and if only two are passed, the top and bottom
18598      * will have the first param, the left and right the second.
18599      * @method setPadding
18600      * @param {int} iTop    Top pad
18601      * @param {int} iRight  Right pad
18602      * @param {int} iBot    Bot pad
18603      * @param {int} iLeft   Left pad
18604      */
18605     setPadding: function(iTop, iRight, iBot, iLeft) {
18606         // this.padding = [iLeft, iRight, iTop, iBot];
18607         if (!iRight && 0 !== iRight) {
18608             this.padding = [iTop, iTop, iTop, iTop];
18609         } else if (!iBot && 0 !== iBot) {
18610             this.padding = [iTop, iRight, iTop, iRight];
18611         } else {
18612             this.padding = [iTop, iRight, iBot, iLeft];
18613         }
18614     },
18615
18616     /**
18617      * Stores the initial placement of the linked element.
18618      * @method setInitialPosition
18619      * @param {int} diffX   the X offset, default 0
18620      * @param {int} diffY   the Y offset, default 0
18621      */
18622     setInitPosition: function(diffX, diffY) {
18623         var el = this.getEl();
18624
18625         if (!this.DDM.verifyEl(el)) {
18626             return;
18627         }
18628
18629         var dx = diffX || 0;
18630         var dy = diffY || 0;
18631
18632         var p = Dom.getXY( el );
18633
18634         this.initPageX = p[0] - dx;
18635         this.initPageY = p[1] - dy;
18636
18637         this.lastPageX = p[0];
18638         this.lastPageY = p[1];
18639
18640
18641         this.setStartPosition(p);
18642     },
18643
18644     /**
18645      * Sets the start position of the element.  This is set when the obj
18646      * is initialized, the reset when a drag is started.
18647      * @method setStartPosition
18648      * @param pos current position (from previous lookup)
18649      * @private
18650      */
18651     setStartPosition: function(pos) {
18652         var p = pos || Dom.getXY( this.getEl() );
18653         this.deltaSetXY = null;
18654
18655         this.startPageX = p[0];
18656         this.startPageY = p[1];
18657     },
18658
18659     /**
18660      * Add this instance to a group of related drag/drop objects.  All
18661      * instances belong to at least one group, and can belong to as many
18662      * groups as needed.
18663      * @method addToGroup
18664      * @param sGroup {string} the name of the group
18665      */
18666     addToGroup: function(sGroup) {
18667         this.groups[sGroup] = true;
18668         this.DDM.regDragDrop(this, sGroup);
18669     },
18670
18671     /**
18672      * Remove's this instance from the supplied interaction group
18673      * @method removeFromGroup
18674      * @param {string}  sGroup  The group to drop
18675      */
18676     removeFromGroup: function(sGroup) {
18677         if (this.groups[sGroup]) {
18678             delete this.groups[sGroup];
18679         }
18680
18681         this.DDM.removeDDFromGroup(this, sGroup);
18682     },
18683
18684     /**
18685      * Allows you to specify that an element other than the linked element
18686      * will be moved with the cursor during a drag
18687      * @method setDragElId
18688      * @param id {string} the id of the element that will be used to initiate the drag
18689      */
18690     setDragElId: function(id) {
18691         this.dragElId = id;
18692     },
18693
18694     /**
18695      * Allows you to specify a child of the linked element that should be
18696      * used to initiate the drag operation.  An example of this would be if
18697      * you have a content div with text and links.  Clicking anywhere in the
18698      * content area would normally start the drag operation.  Use this method
18699      * to specify that an element inside of the content div is the element
18700      * that starts the drag operation.
18701      * @method setHandleElId
18702      * @param id {string} the id of the element that will be used to
18703      * initiate the drag.
18704      */
18705     setHandleElId: function(id) {
18706         if (typeof id !== "string") {
18707             id = Roo.id(id);
18708         }
18709         this.handleElId = id;
18710         this.DDM.regHandle(this.id, id);
18711     },
18712
18713     /**
18714      * Allows you to set an element outside of the linked element as a drag
18715      * handle
18716      * @method setOuterHandleElId
18717      * @param id the id of the element that will be used to initiate the drag
18718      */
18719     setOuterHandleElId: function(id) {
18720         if (typeof id !== "string") {
18721             id = Roo.id(id);
18722         }
18723         Event.on(id, "mousedown",
18724                 this.handleMouseDown, this);
18725         this.setHandleElId(id);
18726
18727         this.hasOuterHandles = true;
18728     },
18729
18730     /**
18731      * Remove all drag and drop hooks for this element
18732      * @method unreg
18733      */
18734     unreg: function() {
18735         Event.un(this.id, "mousedown",
18736                 this.handleMouseDown);
18737         Event.un(this.id, "touchstart",
18738                 this.handleMouseDown);
18739         this._domRef = null;
18740         this.DDM._remove(this);
18741     },
18742
18743     destroy : function(){
18744         this.unreg();
18745     },
18746
18747     /**
18748      * Returns true if this instance is locked, or the drag drop mgr is locked
18749      * (meaning that all drag/drop is disabled on the page.)
18750      * @method isLocked
18751      * @return {boolean} true if this obj or all drag/drop is locked, else
18752      * false
18753      */
18754     isLocked: function() {
18755         return (this.DDM.isLocked() || this.locked);
18756     },
18757
18758     /**
18759      * Fired when this object is clicked
18760      * @method handleMouseDown
18761      * @param {Event} e
18762      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18763      * @private
18764      */
18765     handleMouseDown: function(e, oDD){
18766      
18767         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18768             //Roo.log('not touch/ button !=0');
18769             return;
18770         }
18771         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18772             return; // double touch..
18773         }
18774         
18775
18776         if (this.isLocked()) {
18777             //Roo.log('locked');
18778             return;
18779         }
18780
18781         this.DDM.refreshCache(this.groups);
18782 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18783         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18784         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18785             //Roo.log('no outer handes or not over target');
18786                 // do nothing.
18787         } else {
18788 //            Roo.log('check validator');
18789             if (this.clickValidator(e)) {
18790 //                Roo.log('validate success');
18791                 // set the initial element position
18792                 this.setStartPosition();
18793
18794
18795                 this.b4MouseDown(e);
18796                 this.onMouseDown(e);
18797
18798                 this.DDM.handleMouseDown(e, this);
18799
18800                 this.DDM.stopEvent(e);
18801             } else {
18802
18803
18804             }
18805         }
18806     },
18807
18808     clickValidator: function(e) {
18809         var target = e.getTarget();
18810         return ( this.isValidHandleChild(target) &&
18811                     (this.id == this.handleElId ||
18812                         this.DDM.handleWasClicked(target, this.id)) );
18813     },
18814
18815     /**
18816      * Allows you to specify a tag name that should not start a drag operation
18817      * when clicked.  This is designed to facilitate embedding links within a
18818      * drag handle that do something other than start the drag.
18819      * @method addInvalidHandleType
18820      * @param {string} tagName the type of element to exclude
18821      */
18822     addInvalidHandleType: function(tagName) {
18823         var type = tagName.toUpperCase();
18824         this.invalidHandleTypes[type] = type;
18825     },
18826
18827     /**
18828      * Lets you to specify an element id for a child of a drag handle
18829      * that should not initiate a drag
18830      * @method addInvalidHandleId
18831      * @param {string} id the element id of the element you wish to ignore
18832      */
18833     addInvalidHandleId: function(id) {
18834         if (typeof id !== "string") {
18835             id = Roo.id(id);
18836         }
18837         this.invalidHandleIds[id] = id;
18838     },
18839
18840     /**
18841      * Lets you specify a css class of elements that will not initiate a drag
18842      * @method addInvalidHandleClass
18843      * @param {string} cssClass the class of the elements you wish to ignore
18844      */
18845     addInvalidHandleClass: function(cssClass) {
18846         this.invalidHandleClasses.push(cssClass);
18847     },
18848
18849     /**
18850      * Unsets an excluded tag name set by addInvalidHandleType
18851      * @method removeInvalidHandleType
18852      * @param {string} tagName the type of element to unexclude
18853      */
18854     removeInvalidHandleType: function(tagName) {
18855         var type = tagName.toUpperCase();
18856         // this.invalidHandleTypes[type] = null;
18857         delete this.invalidHandleTypes[type];
18858     },
18859
18860     /**
18861      * Unsets an invalid handle id
18862      * @method removeInvalidHandleId
18863      * @param {string} id the id of the element to re-enable
18864      */
18865     removeInvalidHandleId: function(id) {
18866         if (typeof id !== "string") {
18867             id = Roo.id(id);
18868         }
18869         delete this.invalidHandleIds[id];
18870     },
18871
18872     /**
18873      * Unsets an invalid css class
18874      * @method removeInvalidHandleClass
18875      * @param {string} cssClass the class of the element(s) you wish to
18876      * re-enable
18877      */
18878     removeInvalidHandleClass: function(cssClass) {
18879         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18880             if (this.invalidHandleClasses[i] == cssClass) {
18881                 delete this.invalidHandleClasses[i];
18882             }
18883         }
18884     },
18885
18886     /**
18887      * Checks the tag exclusion list to see if this click should be ignored
18888      * @method isValidHandleChild
18889      * @param {HTMLElement} node the HTMLElement to evaluate
18890      * @return {boolean} true if this is a valid tag type, false if not
18891      */
18892     isValidHandleChild: function(node) {
18893
18894         var valid = true;
18895         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18896         var nodeName;
18897         try {
18898             nodeName = node.nodeName.toUpperCase();
18899         } catch(e) {
18900             nodeName = node.nodeName;
18901         }
18902         valid = valid && !this.invalidHandleTypes[nodeName];
18903         valid = valid && !this.invalidHandleIds[node.id];
18904
18905         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18906             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18907         }
18908
18909
18910         return valid;
18911
18912     },
18913
18914     /**
18915      * Create the array of horizontal tick marks if an interval was specified
18916      * in setXConstraint().
18917      * @method setXTicks
18918      * @private
18919      */
18920     setXTicks: function(iStartX, iTickSize) {
18921         this.xTicks = [];
18922         this.xTickSize = iTickSize;
18923
18924         var tickMap = {};
18925
18926         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18927             if (!tickMap[i]) {
18928                 this.xTicks[this.xTicks.length] = i;
18929                 tickMap[i] = true;
18930             }
18931         }
18932
18933         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18934             if (!tickMap[i]) {
18935                 this.xTicks[this.xTicks.length] = i;
18936                 tickMap[i] = true;
18937             }
18938         }
18939
18940         this.xTicks.sort(this.DDM.numericSort) ;
18941     },
18942
18943     /**
18944      * Create the array of vertical tick marks if an interval was specified in
18945      * setYConstraint().
18946      * @method setYTicks
18947      * @private
18948      */
18949     setYTicks: function(iStartY, iTickSize) {
18950         this.yTicks = [];
18951         this.yTickSize = iTickSize;
18952
18953         var tickMap = {};
18954
18955         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18956             if (!tickMap[i]) {
18957                 this.yTicks[this.yTicks.length] = i;
18958                 tickMap[i] = true;
18959             }
18960         }
18961
18962         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18963             if (!tickMap[i]) {
18964                 this.yTicks[this.yTicks.length] = i;
18965                 tickMap[i] = true;
18966             }
18967         }
18968
18969         this.yTicks.sort(this.DDM.numericSort) ;
18970     },
18971
18972     /**
18973      * By default, the element can be dragged any place on the screen.  Use
18974      * this method to limit the horizontal travel of the element.  Pass in
18975      * 0,0 for the parameters if you want to lock the drag to the y axis.
18976      * @method setXConstraint
18977      * @param {int} iLeft the number of pixels the element can move to the left
18978      * @param {int} iRight the number of pixels the element can move to the
18979      * right
18980      * @param {int} iTickSize optional parameter for specifying that the
18981      * element
18982      * should move iTickSize pixels at a time.
18983      */
18984     setXConstraint: function(iLeft, iRight, iTickSize) {
18985         this.leftConstraint = iLeft;
18986         this.rightConstraint = iRight;
18987
18988         this.minX = this.initPageX - iLeft;
18989         this.maxX = this.initPageX + iRight;
18990         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18991
18992         this.constrainX = true;
18993     },
18994
18995     /**
18996      * Clears any constraints applied to this instance.  Also clears ticks
18997      * since they can't exist independent of a constraint at this time.
18998      * @method clearConstraints
18999      */
19000     clearConstraints: function() {
19001         this.constrainX = false;
19002         this.constrainY = false;
19003         this.clearTicks();
19004     },
19005
19006     /**
19007      * Clears any tick interval defined for this instance
19008      * @method clearTicks
19009      */
19010     clearTicks: function() {
19011         this.xTicks = null;
19012         this.yTicks = null;
19013         this.xTickSize = 0;
19014         this.yTickSize = 0;
19015     },
19016
19017     /**
19018      * By default, the element can be dragged any place on the screen.  Set
19019      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19020      * parameters if you want to lock the drag to the x axis.
19021      * @method setYConstraint
19022      * @param {int} iUp the number of pixels the element can move up
19023      * @param {int} iDown the number of pixels the element can move down
19024      * @param {int} iTickSize optional parameter for specifying that the
19025      * element should move iTickSize pixels at a time.
19026      */
19027     setYConstraint: function(iUp, iDown, iTickSize) {
19028         this.topConstraint = iUp;
19029         this.bottomConstraint = iDown;
19030
19031         this.minY = this.initPageY - iUp;
19032         this.maxY = this.initPageY + iDown;
19033         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19034
19035         this.constrainY = true;
19036
19037     },
19038
19039     /**
19040      * resetConstraints must be called if you manually reposition a dd element.
19041      * @method resetConstraints
19042      * @param {boolean} maintainOffset
19043      */
19044     resetConstraints: function() {
19045
19046
19047         // Maintain offsets if necessary
19048         if (this.initPageX || this.initPageX === 0) {
19049             // figure out how much this thing has moved
19050             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19051             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19052
19053             this.setInitPosition(dx, dy);
19054
19055         // This is the first time we have detected the element's position
19056         } else {
19057             this.setInitPosition();
19058         }
19059
19060         if (this.constrainX) {
19061             this.setXConstraint( this.leftConstraint,
19062                                  this.rightConstraint,
19063                                  this.xTickSize        );
19064         }
19065
19066         if (this.constrainY) {
19067             this.setYConstraint( this.topConstraint,
19068                                  this.bottomConstraint,
19069                                  this.yTickSize         );
19070         }
19071     },
19072
19073     /**
19074      * Normally the drag element is moved pixel by pixel, but we can specify
19075      * that it move a number of pixels at a time.  This method resolves the
19076      * location when we have it set up like this.
19077      * @method getTick
19078      * @param {int} val where we want to place the object
19079      * @param {int[]} tickArray sorted array of valid points
19080      * @return {int} the closest tick
19081      * @private
19082      */
19083     getTick: function(val, tickArray) {
19084
19085         if (!tickArray) {
19086             // If tick interval is not defined, it is effectively 1 pixel,
19087             // so we return the value passed to us.
19088             return val;
19089         } else if (tickArray[0] >= val) {
19090             // The value is lower than the first tick, so we return the first
19091             // tick.
19092             return tickArray[0];
19093         } else {
19094             for (var i=0, len=tickArray.length; i<len; ++i) {
19095                 var next = i + 1;
19096                 if (tickArray[next] && tickArray[next] >= val) {
19097                     var diff1 = val - tickArray[i];
19098                     var diff2 = tickArray[next] - val;
19099                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19100                 }
19101             }
19102
19103             // The value is larger than the last tick, so we return the last
19104             // tick.
19105             return tickArray[tickArray.length - 1];
19106         }
19107     },
19108
19109     /**
19110      * toString method
19111      * @method toString
19112      * @return {string} string representation of the dd obj
19113      */
19114     toString: function() {
19115         return ("DragDrop " + this.id);
19116     }
19117
19118 });
19119
19120 })();
19121 /*
19122  * Based on:
19123  * Ext JS Library 1.1.1
19124  * Copyright(c) 2006-2007, Ext JS, LLC.
19125  *
19126  * Originally Released Under LGPL - original licence link has changed is not relivant.
19127  *
19128  * Fork - LGPL
19129  * <script type="text/javascript">
19130  */
19131
19132
19133 /**
19134  * The drag and drop utility provides a framework for building drag and drop
19135  * applications.  In addition to enabling drag and drop for specific elements,
19136  * the drag and drop elements are tracked by the manager class, and the
19137  * interactions between the various elements are tracked during the drag and
19138  * the implementing code is notified about these important moments.
19139  */
19140
19141 // Only load the library once.  Rewriting the manager class would orphan
19142 // existing drag and drop instances.
19143 if (!Roo.dd.DragDropMgr) {
19144
19145 /**
19146  * @class Roo.dd.DragDropMgr
19147  * DragDropMgr is a singleton that tracks the element interaction for
19148  * all DragDrop items in the window.  Generally, you will not call
19149  * this class directly, but it does have helper methods that could
19150  * be useful in your DragDrop implementations.
19151  * @singleton
19152  */
19153 Roo.dd.DragDropMgr = function() {
19154
19155     var Event = Roo.EventManager;
19156
19157     return {
19158
19159         /**
19160          * Two dimensional Array of registered DragDrop objects.  The first
19161          * dimension is the DragDrop item group, the second the DragDrop
19162          * object.
19163          * @property ids
19164          * @type {string: string}
19165          * @private
19166          * @static
19167          */
19168         ids: {},
19169
19170         /**
19171          * Array of element ids defined as drag handles.  Used to determine
19172          * if the element that generated the mousedown event is actually the
19173          * handle and not the html element itself.
19174          * @property handleIds
19175          * @type {string: string}
19176          * @private
19177          * @static
19178          */
19179         handleIds: {},
19180
19181         /**
19182          * the DragDrop object that is currently being dragged
19183          * @property dragCurrent
19184          * @type DragDrop
19185          * @private
19186          * @static
19187          **/
19188         dragCurrent: null,
19189
19190         /**
19191          * the DragDrop object(s) that are being hovered over
19192          * @property dragOvers
19193          * @type Array
19194          * @private
19195          * @static
19196          */
19197         dragOvers: {},
19198
19199         /**
19200          * the X distance between the cursor and the object being dragged
19201          * @property deltaX
19202          * @type int
19203          * @private
19204          * @static
19205          */
19206         deltaX: 0,
19207
19208         /**
19209          * the Y distance between the cursor and the object being dragged
19210          * @property deltaY
19211          * @type int
19212          * @private
19213          * @static
19214          */
19215         deltaY: 0,
19216
19217         /**
19218          * Flag to determine if we should prevent the default behavior of the
19219          * events we define. By default this is true, but this can be set to
19220          * false if you need the default behavior (not recommended)
19221          * @property preventDefault
19222          * @type boolean
19223          * @static
19224          */
19225         preventDefault: true,
19226
19227         /**
19228          * Flag to determine if we should stop the propagation of the events
19229          * we generate. This is true by default but you may want to set it to
19230          * false if the html element contains other features that require the
19231          * mouse click.
19232          * @property stopPropagation
19233          * @type boolean
19234          * @static
19235          */
19236         stopPropagation: true,
19237
19238         /**
19239          * Internal flag that is set to true when drag and drop has been
19240          * intialized
19241          * @property initialized
19242          * @private
19243          * @static
19244          */
19245         initalized: false,
19246
19247         /**
19248          * All drag and drop can be disabled.
19249          * @property locked
19250          * @private
19251          * @static
19252          */
19253         locked: false,
19254
19255         /**
19256          * Called the first time an element is registered.
19257          * @method init
19258          * @private
19259          * @static
19260          */
19261         init: function() {
19262             this.initialized = true;
19263         },
19264
19265         /**
19266          * In point mode, drag and drop interaction is defined by the
19267          * location of the cursor during the drag/drop
19268          * @property POINT
19269          * @type int
19270          * @static
19271          */
19272         POINT: 0,
19273
19274         /**
19275          * In intersect mode, drag and drop interactio nis defined by the
19276          * overlap of two or more drag and drop objects.
19277          * @property INTERSECT
19278          * @type int
19279          * @static
19280          */
19281         INTERSECT: 1,
19282
19283         /**
19284          * The current drag and drop mode.  Default: POINT
19285          * @property mode
19286          * @type int
19287          * @static
19288          */
19289         mode: 0,
19290
19291         /**
19292          * Runs method on all drag and drop objects
19293          * @method _execOnAll
19294          * @private
19295          * @static
19296          */
19297         _execOnAll: function(sMethod, args) {
19298             for (var i in this.ids) {
19299                 for (var j in this.ids[i]) {
19300                     var oDD = this.ids[i][j];
19301                     if (! this.isTypeOfDD(oDD)) {
19302                         continue;
19303                     }
19304                     oDD[sMethod].apply(oDD, args);
19305                 }
19306             }
19307         },
19308
19309         /**
19310          * Drag and drop initialization.  Sets up the global event handlers
19311          * @method _onLoad
19312          * @private
19313          * @static
19314          */
19315         _onLoad: function() {
19316
19317             this.init();
19318
19319             if (!Roo.isTouch) {
19320                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19321                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19322             }
19323             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19324             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19325             
19326             Event.on(window,   "unload",    this._onUnload, this, true);
19327             Event.on(window,   "resize",    this._onResize, this, true);
19328             // Event.on(window,   "mouseout",    this._test);
19329
19330         },
19331
19332         /**
19333          * Reset constraints on all drag and drop objs
19334          * @method _onResize
19335          * @private
19336          * @static
19337          */
19338         _onResize: function(e) {
19339             this._execOnAll("resetConstraints", []);
19340         },
19341
19342         /**
19343          * Lock all drag and drop functionality
19344          * @method lock
19345          * @static
19346          */
19347         lock: function() { this.locked = true; },
19348
19349         /**
19350          * Unlock all drag and drop functionality
19351          * @method unlock
19352          * @static
19353          */
19354         unlock: function() { this.locked = false; },
19355
19356         /**
19357          * Is drag and drop locked?
19358          * @method isLocked
19359          * @return {boolean} True if drag and drop is locked, false otherwise.
19360          * @static
19361          */
19362         isLocked: function() { return this.locked; },
19363
19364         /**
19365          * Location cache that is set for all drag drop objects when a drag is
19366          * initiated, cleared when the drag is finished.
19367          * @property locationCache
19368          * @private
19369          * @static
19370          */
19371         locationCache: {},
19372
19373         /**
19374          * Set useCache to false if you want to force object the lookup of each
19375          * drag and drop linked element constantly during a drag.
19376          * @property useCache
19377          * @type boolean
19378          * @static
19379          */
19380         useCache: true,
19381
19382         /**
19383          * The number of pixels that the mouse needs to move after the
19384          * mousedown before the drag is initiated.  Default=3;
19385          * @property clickPixelThresh
19386          * @type int
19387          * @static
19388          */
19389         clickPixelThresh: 3,
19390
19391         /**
19392          * The number of milliseconds after the mousedown event to initiate the
19393          * drag if we don't get a mouseup event. Default=1000
19394          * @property clickTimeThresh
19395          * @type int
19396          * @static
19397          */
19398         clickTimeThresh: 350,
19399
19400         /**
19401          * Flag that indicates that either the drag pixel threshold or the
19402          * mousdown time threshold has been met
19403          * @property dragThreshMet
19404          * @type boolean
19405          * @private
19406          * @static
19407          */
19408         dragThreshMet: false,
19409
19410         /**
19411          * Timeout used for the click time threshold
19412          * @property clickTimeout
19413          * @type Object
19414          * @private
19415          * @static
19416          */
19417         clickTimeout: null,
19418
19419         /**
19420          * The X position of the mousedown event stored for later use when a
19421          * drag threshold is met.
19422          * @property startX
19423          * @type int
19424          * @private
19425          * @static
19426          */
19427         startX: 0,
19428
19429         /**
19430          * The Y position of the mousedown event stored for later use when a
19431          * drag threshold is met.
19432          * @property startY
19433          * @type int
19434          * @private
19435          * @static
19436          */
19437         startY: 0,
19438
19439         /**
19440          * Each DragDrop instance must be registered with the DragDropMgr.
19441          * This is executed in DragDrop.init()
19442          * @method regDragDrop
19443          * @param {DragDrop} oDD the DragDrop object to register
19444          * @param {String} sGroup the name of the group this element belongs to
19445          * @static
19446          */
19447         regDragDrop: function(oDD, sGroup) {
19448             if (!this.initialized) { this.init(); }
19449
19450             if (!this.ids[sGroup]) {
19451                 this.ids[sGroup] = {};
19452             }
19453             this.ids[sGroup][oDD.id] = oDD;
19454         },
19455
19456         /**
19457          * Removes the supplied dd instance from the supplied group. Executed
19458          * by DragDrop.removeFromGroup, so don't call this function directly.
19459          * @method removeDDFromGroup
19460          * @private
19461          * @static
19462          */
19463         removeDDFromGroup: function(oDD, sGroup) {
19464             if (!this.ids[sGroup]) {
19465                 this.ids[sGroup] = {};
19466             }
19467
19468             var obj = this.ids[sGroup];
19469             if (obj && obj[oDD.id]) {
19470                 delete obj[oDD.id];
19471             }
19472         },
19473
19474         /**
19475          * Unregisters a drag and drop item.  This is executed in
19476          * DragDrop.unreg, use that method instead of calling this directly.
19477          * @method _remove
19478          * @private
19479          * @static
19480          */
19481         _remove: function(oDD) {
19482             for (var g in oDD.groups) {
19483                 if (g && this.ids[g][oDD.id]) {
19484                     delete this.ids[g][oDD.id];
19485                 }
19486             }
19487             delete this.handleIds[oDD.id];
19488         },
19489
19490         /**
19491          * Each DragDrop handle element must be registered.  This is done
19492          * automatically when executing DragDrop.setHandleElId()
19493          * @method regHandle
19494          * @param {String} sDDId the DragDrop id this element is a handle for
19495          * @param {String} sHandleId the id of the element that is the drag
19496          * handle
19497          * @static
19498          */
19499         regHandle: function(sDDId, sHandleId) {
19500             if (!this.handleIds[sDDId]) {
19501                 this.handleIds[sDDId] = {};
19502             }
19503             this.handleIds[sDDId][sHandleId] = sHandleId;
19504         },
19505
19506         /**
19507          * Utility function to determine if a given element has been
19508          * registered as a drag drop item.
19509          * @method isDragDrop
19510          * @param {String} id the element id to check
19511          * @return {boolean} true if this element is a DragDrop item,
19512          * false otherwise
19513          * @static
19514          */
19515         isDragDrop: function(id) {
19516             return ( this.getDDById(id) ) ? true : false;
19517         },
19518
19519         /**
19520          * Returns the drag and drop instances that are in all groups the
19521          * passed in instance belongs to.
19522          * @method getRelated
19523          * @param {DragDrop} p_oDD the obj to get related data for
19524          * @param {boolean} bTargetsOnly if true, only return targetable objs
19525          * @return {DragDrop[]} the related instances
19526          * @static
19527          */
19528         getRelated: function(p_oDD, bTargetsOnly) {
19529             var oDDs = [];
19530             for (var i in p_oDD.groups) {
19531                 for (j in this.ids[i]) {
19532                     var dd = this.ids[i][j];
19533                     if (! this.isTypeOfDD(dd)) {
19534                         continue;
19535                     }
19536                     if (!bTargetsOnly || dd.isTarget) {
19537                         oDDs[oDDs.length] = dd;
19538                     }
19539                 }
19540             }
19541
19542             return oDDs;
19543         },
19544
19545         /**
19546          * Returns true if the specified dd target is a legal target for
19547          * the specifice drag obj
19548          * @method isLegalTarget
19549          * @param {DragDrop} the drag obj
19550          * @param {DragDrop} the target
19551          * @return {boolean} true if the target is a legal target for the
19552          * dd obj
19553          * @static
19554          */
19555         isLegalTarget: function (oDD, oTargetDD) {
19556             var targets = this.getRelated(oDD, true);
19557             for (var i=0, len=targets.length;i<len;++i) {
19558                 if (targets[i].id == oTargetDD.id) {
19559                     return true;
19560                 }
19561             }
19562
19563             return false;
19564         },
19565
19566         /**
19567          * My goal is to be able to transparently determine if an object is
19568          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19569          * returns "object", oDD.constructor.toString() always returns
19570          * "DragDrop" and not the name of the subclass.  So for now it just
19571          * evaluates a well-known variable in DragDrop.
19572          * @method isTypeOfDD
19573          * @param {Object} the object to evaluate
19574          * @return {boolean} true if typeof oDD = DragDrop
19575          * @static
19576          */
19577         isTypeOfDD: function (oDD) {
19578             return (oDD && oDD.__ygDragDrop);
19579         },
19580
19581         /**
19582          * Utility function to determine if a given element has been
19583          * registered as a drag drop handle for the given Drag Drop object.
19584          * @method isHandle
19585          * @param {String} id the element id to check
19586          * @return {boolean} true if this element is a DragDrop handle, false
19587          * otherwise
19588          * @static
19589          */
19590         isHandle: function(sDDId, sHandleId) {
19591             return ( this.handleIds[sDDId] &&
19592                             this.handleIds[sDDId][sHandleId] );
19593         },
19594
19595         /**
19596          * Returns the DragDrop instance for a given id
19597          * @method getDDById
19598          * @param {String} id the id of the DragDrop object
19599          * @return {DragDrop} the drag drop object, null if it is not found
19600          * @static
19601          */
19602         getDDById: function(id) {
19603             for (var i in this.ids) {
19604                 if (this.ids[i][id]) {
19605                     return this.ids[i][id];
19606                 }
19607             }
19608             return null;
19609         },
19610
19611         /**
19612          * Fired after a registered DragDrop object gets the mousedown event.
19613          * Sets up the events required to track the object being dragged
19614          * @method handleMouseDown
19615          * @param {Event} e the event
19616          * @param oDD the DragDrop object being dragged
19617          * @private
19618          * @static
19619          */
19620         handleMouseDown: function(e, oDD) {
19621             if(Roo.QuickTips){
19622                 Roo.QuickTips.disable();
19623             }
19624             this.currentTarget = e.getTarget();
19625
19626             this.dragCurrent = oDD;
19627
19628             var el = oDD.getEl();
19629
19630             // track start position
19631             this.startX = e.getPageX();
19632             this.startY = e.getPageY();
19633
19634             this.deltaX = this.startX - el.offsetLeft;
19635             this.deltaY = this.startY - el.offsetTop;
19636
19637             this.dragThreshMet = false;
19638
19639             this.clickTimeout = setTimeout(
19640                     function() {
19641                         var DDM = Roo.dd.DDM;
19642                         DDM.startDrag(DDM.startX, DDM.startY);
19643                     },
19644                     this.clickTimeThresh );
19645         },
19646
19647         /**
19648          * Fired when either the drag pixel threshol or the mousedown hold
19649          * time threshold has been met.
19650          * @method startDrag
19651          * @param x {int} the X position of the original mousedown
19652          * @param y {int} the Y position of the original mousedown
19653          * @static
19654          */
19655         startDrag: function(x, y) {
19656             clearTimeout(this.clickTimeout);
19657             if (this.dragCurrent) {
19658                 this.dragCurrent.b4StartDrag(x, y);
19659                 this.dragCurrent.startDrag(x, y);
19660             }
19661             this.dragThreshMet = true;
19662         },
19663
19664         /**
19665          * Internal function to handle the mouseup event.  Will be invoked
19666          * from the context of the document.
19667          * @method handleMouseUp
19668          * @param {Event} e the event
19669          * @private
19670          * @static
19671          */
19672         handleMouseUp: function(e) {
19673
19674             if(Roo.QuickTips){
19675                 Roo.QuickTips.enable();
19676             }
19677             if (! this.dragCurrent) {
19678                 return;
19679             }
19680
19681             clearTimeout(this.clickTimeout);
19682
19683             if (this.dragThreshMet) {
19684                 this.fireEvents(e, true);
19685             } else {
19686             }
19687
19688             this.stopDrag(e);
19689
19690             this.stopEvent(e);
19691         },
19692
19693         /**
19694          * Utility to stop event propagation and event default, if these
19695          * features are turned on.
19696          * @method stopEvent
19697          * @param {Event} e the event as returned by this.getEvent()
19698          * @static
19699          */
19700         stopEvent: function(e){
19701             if(this.stopPropagation) {
19702                 e.stopPropagation();
19703             }
19704
19705             if (this.preventDefault) {
19706                 e.preventDefault();
19707             }
19708         },
19709
19710         /**
19711          * Internal function to clean up event handlers after the drag
19712          * operation is complete
19713          * @method stopDrag
19714          * @param {Event} e the event
19715          * @private
19716          * @static
19717          */
19718         stopDrag: function(e) {
19719             // Fire the drag end event for the item that was dragged
19720             if (this.dragCurrent) {
19721                 if (this.dragThreshMet) {
19722                     this.dragCurrent.b4EndDrag(e);
19723                     this.dragCurrent.endDrag(e);
19724                 }
19725
19726                 this.dragCurrent.onMouseUp(e);
19727             }
19728
19729             this.dragCurrent = null;
19730             this.dragOvers = {};
19731         },
19732
19733         /**
19734          * Internal function to handle the mousemove event.  Will be invoked
19735          * from the context of the html element.
19736          *
19737          * @TODO figure out what we can do about mouse events lost when the
19738          * user drags objects beyond the window boundary.  Currently we can
19739          * detect this in internet explorer by verifying that the mouse is
19740          * down during the mousemove event.  Firefox doesn't give us the
19741          * button state on the mousemove event.
19742          * @method handleMouseMove
19743          * @param {Event} e the event
19744          * @private
19745          * @static
19746          */
19747         handleMouseMove: function(e) {
19748             if (! this.dragCurrent) {
19749                 return true;
19750             }
19751
19752             // var button = e.which || e.button;
19753
19754             // check for IE mouseup outside of page boundary
19755             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19756                 this.stopEvent(e);
19757                 return this.handleMouseUp(e);
19758             }
19759
19760             if (!this.dragThreshMet) {
19761                 var diffX = Math.abs(this.startX - e.getPageX());
19762                 var diffY = Math.abs(this.startY - e.getPageY());
19763                 if (diffX > this.clickPixelThresh ||
19764                             diffY > this.clickPixelThresh) {
19765                     this.startDrag(this.startX, this.startY);
19766                 }
19767             }
19768
19769             if (this.dragThreshMet) {
19770                 this.dragCurrent.b4Drag(e);
19771                 this.dragCurrent.onDrag(e);
19772                 if(!this.dragCurrent.moveOnly){
19773                     this.fireEvents(e, false);
19774                 }
19775             }
19776
19777             this.stopEvent(e);
19778
19779             return true;
19780         },
19781
19782         /**
19783          * Iterates over all of the DragDrop elements to find ones we are
19784          * hovering over or dropping on
19785          * @method fireEvents
19786          * @param {Event} e the event
19787          * @param {boolean} isDrop is this a drop op or a mouseover op?
19788          * @private
19789          * @static
19790          */
19791         fireEvents: function(e, isDrop) {
19792             var dc = this.dragCurrent;
19793
19794             // If the user did the mouse up outside of the window, we could
19795             // get here even though we have ended the drag.
19796             if (!dc || dc.isLocked()) {
19797                 return;
19798             }
19799
19800             var pt = e.getPoint();
19801
19802             // cache the previous dragOver array
19803             var oldOvers = [];
19804
19805             var outEvts   = [];
19806             var overEvts  = [];
19807             var dropEvts  = [];
19808             var enterEvts = [];
19809
19810             // Check to see if the object(s) we were hovering over is no longer
19811             // being hovered over so we can fire the onDragOut event
19812             for (var i in this.dragOvers) {
19813
19814                 var ddo = this.dragOvers[i];
19815
19816                 if (! this.isTypeOfDD(ddo)) {
19817                     continue;
19818                 }
19819
19820                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19821                     outEvts.push( ddo );
19822                 }
19823
19824                 oldOvers[i] = true;
19825                 delete this.dragOvers[i];
19826             }
19827
19828             for (var sGroup in dc.groups) {
19829
19830                 if ("string" != typeof sGroup) {
19831                     continue;
19832                 }
19833
19834                 for (i in this.ids[sGroup]) {
19835                     var oDD = this.ids[sGroup][i];
19836                     if (! this.isTypeOfDD(oDD)) {
19837                         continue;
19838                     }
19839
19840                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19841                         if (this.isOverTarget(pt, oDD, this.mode)) {
19842                             // look for drop interactions
19843                             if (isDrop) {
19844                                 dropEvts.push( oDD );
19845                             // look for drag enter and drag over interactions
19846                             } else {
19847
19848                                 // initial drag over: dragEnter fires
19849                                 if (!oldOvers[oDD.id]) {
19850                                     enterEvts.push( oDD );
19851                                 // subsequent drag overs: dragOver fires
19852                                 } else {
19853                                     overEvts.push( oDD );
19854                                 }
19855
19856                                 this.dragOvers[oDD.id] = oDD;
19857                             }
19858                         }
19859                     }
19860                 }
19861             }
19862
19863             if (this.mode) {
19864                 if (outEvts.length) {
19865                     dc.b4DragOut(e, outEvts);
19866                     dc.onDragOut(e, outEvts);
19867                 }
19868
19869                 if (enterEvts.length) {
19870                     dc.onDragEnter(e, enterEvts);
19871                 }
19872
19873                 if (overEvts.length) {
19874                     dc.b4DragOver(e, overEvts);
19875                     dc.onDragOver(e, overEvts);
19876                 }
19877
19878                 if (dropEvts.length) {
19879                     dc.b4DragDrop(e, dropEvts);
19880                     dc.onDragDrop(e, dropEvts);
19881                 }
19882
19883             } else {
19884                 // fire dragout events
19885                 var len = 0;
19886                 for (i=0, len=outEvts.length; i<len; ++i) {
19887                     dc.b4DragOut(e, outEvts[i].id);
19888                     dc.onDragOut(e, outEvts[i].id);
19889                 }
19890
19891                 // fire enter events
19892                 for (i=0,len=enterEvts.length; i<len; ++i) {
19893                     // dc.b4DragEnter(e, oDD.id);
19894                     dc.onDragEnter(e, enterEvts[i].id);
19895                 }
19896
19897                 // fire over events
19898                 for (i=0,len=overEvts.length; i<len; ++i) {
19899                     dc.b4DragOver(e, overEvts[i].id);
19900                     dc.onDragOver(e, overEvts[i].id);
19901                 }
19902
19903                 // fire drop events
19904                 for (i=0, len=dropEvts.length; i<len; ++i) {
19905                     dc.b4DragDrop(e, dropEvts[i].id);
19906                     dc.onDragDrop(e, dropEvts[i].id);
19907                 }
19908
19909             }
19910
19911             // notify about a drop that did not find a target
19912             if (isDrop && !dropEvts.length) {
19913                 dc.onInvalidDrop(e);
19914             }
19915
19916         },
19917
19918         /**
19919          * Helper function for getting the best match from the list of drag
19920          * and drop objects returned by the drag and drop events when we are
19921          * in INTERSECT mode.  It returns either the first object that the
19922          * cursor is over, or the object that has the greatest overlap with
19923          * the dragged element.
19924          * @method getBestMatch
19925          * @param  {DragDrop[]} dds The array of drag and drop objects
19926          * targeted
19927          * @return {DragDrop}       The best single match
19928          * @static
19929          */
19930         getBestMatch: function(dds) {
19931             var winner = null;
19932             // Return null if the input is not what we expect
19933             //if (!dds || !dds.length || dds.length == 0) {
19934                // winner = null;
19935             // If there is only one item, it wins
19936             //} else if (dds.length == 1) {
19937
19938             var len = dds.length;
19939
19940             if (len == 1) {
19941                 winner = dds[0];
19942             } else {
19943                 // Loop through the targeted items
19944                 for (var i=0; i<len; ++i) {
19945                     var dd = dds[i];
19946                     // If the cursor is over the object, it wins.  If the
19947                     // cursor is over multiple matches, the first one we come
19948                     // to wins.
19949                     if (dd.cursorIsOver) {
19950                         winner = dd;
19951                         break;
19952                     // Otherwise the object with the most overlap wins
19953                     } else {
19954                         if (!winner ||
19955                             winner.overlap.getArea() < dd.overlap.getArea()) {
19956                             winner = dd;
19957                         }
19958                     }
19959                 }
19960             }
19961
19962             return winner;
19963         },
19964
19965         /**
19966          * Refreshes the cache of the top-left and bottom-right points of the
19967          * drag and drop objects in the specified group(s).  This is in the
19968          * format that is stored in the drag and drop instance, so typical
19969          * usage is:
19970          * <code>
19971          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19972          * </code>
19973          * Alternatively:
19974          * <code>
19975          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19976          * </code>
19977          * @TODO this really should be an indexed array.  Alternatively this
19978          * method could accept both.
19979          * @method refreshCache
19980          * @param {Object} groups an associative array of groups to refresh
19981          * @static
19982          */
19983         refreshCache: function(groups) {
19984             for (var sGroup in groups) {
19985                 if ("string" != typeof sGroup) {
19986                     continue;
19987                 }
19988                 for (var i in this.ids[sGroup]) {
19989                     var oDD = this.ids[sGroup][i];
19990
19991                     if (this.isTypeOfDD(oDD)) {
19992                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19993                         var loc = this.getLocation(oDD);
19994                         if (loc) {
19995                             this.locationCache[oDD.id] = loc;
19996                         } else {
19997                             delete this.locationCache[oDD.id];
19998                             // this will unregister the drag and drop object if
19999                             // the element is not in a usable state
20000                             // oDD.unreg();
20001                         }
20002                     }
20003                 }
20004             }
20005         },
20006
20007         /**
20008          * This checks to make sure an element exists and is in the DOM.  The
20009          * main purpose is to handle cases where innerHTML is used to remove
20010          * drag and drop objects from the DOM.  IE provides an 'unspecified
20011          * error' when trying to access the offsetParent of such an element
20012          * @method verifyEl
20013          * @param {HTMLElement} el the element to check
20014          * @return {boolean} true if the element looks usable
20015          * @static
20016          */
20017         verifyEl: function(el) {
20018             if (el) {
20019                 var parent;
20020                 if(Roo.isIE){
20021                     try{
20022                         parent = el.offsetParent;
20023                     }catch(e){}
20024                 }else{
20025                     parent = el.offsetParent;
20026                 }
20027                 if (parent) {
20028                     return true;
20029                 }
20030             }
20031
20032             return false;
20033         },
20034
20035         /**
20036          * Returns a Region object containing the drag and drop element's position
20037          * and size, including the padding configured for it
20038          * @method getLocation
20039          * @param {DragDrop} oDD the drag and drop object to get the
20040          *                       location for
20041          * @return {Roo.lib.Region} a Region object representing the total area
20042          *                             the element occupies, including any padding
20043          *                             the instance is configured for.
20044          * @static
20045          */
20046         getLocation: function(oDD) {
20047             if (! this.isTypeOfDD(oDD)) {
20048                 return null;
20049             }
20050
20051             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20052
20053             try {
20054                 pos= Roo.lib.Dom.getXY(el);
20055             } catch (e) { }
20056
20057             if (!pos) {
20058                 return null;
20059             }
20060
20061             x1 = pos[0];
20062             x2 = x1 + el.offsetWidth;
20063             y1 = pos[1];
20064             y2 = y1 + el.offsetHeight;
20065
20066             t = y1 - oDD.padding[0];
20067             r = x2 + oDD.padding[1];
20068             b = y2 + oDD.padding[2];
20069             l = x1 - oDD.padding[3];
20070
20071             return new Roo.lib.Region( t, r, b, l );
20072         },
20073
20074         /**
20075          * Checks the cursor location to see if it over the target
20076          * @method isOverTarget
20077          * @param {Roo.lib.Point} pt The point to evaluate
20078          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20079          * @return {boolean} true if the mouse is over the target
20080          * @private
20081          * @static
20082          */
20083         isOverTarget: function(pt, oTarget, intersect) {
20084             // use cache if available
20085             var loc = this.locationCache[oTarget.id];
20086             if (!loc || !this.useCache) {
20087                 loc = this.getLocation(oTarget);
20088                 this.locationCache[oTarget.id] = loc;
20089
20090             }
20091
20092             if (!loc) {
20093                 return false;
20094             }
20095
20096             oTarget.cursorIsOver = loc.contains( pt );
20097
20098             // DragDrop is using this as a sanity check for the initial mousedown
20099             // in this case we are done.  In POINT mode, if the drag obj has no
20100             // contraints, we are also done. Otherwise we need to evaluate the
20101             // location of the target as related to the actual location of the
20102             // dragged element.
20103             var dc = this.dragCurrent;
20104             if (!dc || !dc.getTargetCoord ||
20105                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20106                 return oTarget.cursorIsOver;
20107             }
20108
20109             oTarget.overlap = null;
20110
20111             // Get the current location of the drag element, this is the
20112             // location of the mouse event less the delta that represents
20113             // where the original mousedown happened on the element.  We
20114             // need to consider constraints and ticks as well.
20115             var pos = dc.getTargetCoord(pt.x, pt.y);
20116
20117             var el = dc.getDragEl();
20118             var curRegion = new Roo.lib.Region( pos.y,
20119                                                    pos.x + el.offsetWidth,
20120                                                    pos.y + el.offsetHeight,
20121                                                    pos.x );
20122
20123             var overlap = curRegion.intersect(loc);
20124
20125             if (overlap) {
20126                 oTarget.overlap = overlap;
20127                 return (intersect) ? true : oTarget.cursorIsOver;
20128             } else {
20129                 return false;
20130             }
20131         },
20132
20133         /**
20134          * unload event handler
20135          * @method _onUnload
20136          * @private
20137          * @static
20138          */
20139         _onUnload: function(e, me) {
20140             Roo.dd.DragDropMgr.unregAll();
20141         },
20142
20143         /**
20144          * Cleans up the drag and drop events and objects.
20145          * @method unregAll
20146          * @private
20147          * @static
20148          */
20149         unregAll: function() {
20150
20151             if (this.dragCurrent) {
20152                 this.stopDrag();
20153                 this.dragCurrent = null;
20154             }
20155
20156             this._execOnAll("unreg", []);
20157
20158             for (i in this.elementCache) {
20159                 delete this.elementCache[i];
20160             }
20161
20162             this.elementCache = {};
20163             this.ids = {};
20164         },
20165
20166         /**
20167          * A cache of DOM elements
20168          * @property elementCache
20169          * @private
20170          * @static
20171          */
20172         elementCache: {},
20173
20174         /**
20175          * Get the wrapper for the DOM element specified
20176          * @method getElWrapper
20177          * @param {String} id the id of the element to get
20178          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20179          * @private
20180          * @deprecated This wrapper isn't that useful
20181          * @static
20182          */
20183         getElWrapper: function(id) {
20184             var oWrapper = this.elementCache[id];
20185             if (!oWrapper || !oWrapper.el) {
20186                 oWrapper = this.elementCache[id] =
20187                     new this.ElementWrapper(Roo.getDom(id));
20188             }
20189             return oWrapper;
20190         },
20191
20192         /**
20193          * Returns the actual DOM element
20194          * @method getElement
20195          * @param {String} id the id of the elment to get
20196          * @return {Object} The element
20197          * @deprecated use Roo.getDom instead
20198          * @static
20199          */
20200         getElement: function(id) {
20201             return Roo.getDom(id);
20202         },
20203
20204         /**
20205          * Returns the style property for the DOM element (i.e.,
20206          * document.getElById(id).style)
20207          * @method getCss
20208          * @param {String} id the id of the elment to get
20209          * @return {Object} The style property of the element
20210          * @deprecated use Roo.getDom instead
20211          * @static
20212          */
20213         getCss: function(id) {
20214             var el = Roo.getDom(id);
20215             return (el) ? el.style : null;
20216         },
20217
20218         /**
20219          * Inner class for cached elements
20220          * @class DragDropMgr.ElementWrapper
20221          * @for DragDropMgr
20222          * @private
20223          * @deprecated
20224          */
20225         ElementWrapper: function(el) {
20226                 /**
20227                  * The element
20228                  * @property el
20229                  */
20230                 this.el = el || null;
20231                 /**
20232                  * The element id
20233                  * @property id
20234                  */
20235                 this.id = this.el && el.id;
20236                 /**
20237                  * A reference to the style property
20238                  * @property css
20239                  */
20240                 this.css = this.el && el.style;
20241             },
20242
20243         /**
20244          * Returns the X position of an html element
20245          * @method getPosX
20246          * @param el the element for which to get the position
20247          * @return {int} the X coordinate
20248          * @for DragDropMgr
20249          * @deprecated use Roo.lib.Dom.getX instead
20250          * @static
20251          */
20252         getPosX: function(el) {
20253             return Roo.lib.Dom.getX(el);
20254         },
20255
20256         /**
20257          * Returns the Y position of an html element
20258          * @method getPosY
20259          * @param el the element for which to get the position
20260          * @return {int} the Y coordinate
20261          * @deprecated use Roo.lib.Dom.getY instead
20262          * @static
20263          */
20264         getPosY: function(el) {
20265             return Roo.lib.Dom.getY(el);
20266         },
20267
20268         /**
20269          * Swap two nodes.  In IE, we use the native method, for others we
20270          * emulate the IE behavior
20271          * @method swapNode
20272          * @param n1 the first node to swap
20273          * @param n2 the other node to swap
20274          * @static
20275          */
20276         swapNode: function(n1, n2) {
20277             if (n1.swapNode) {
20278                 n1.swapNode(n2);
20279             } else {
20280                 var p = n2.parentNode;
20281                 var s = n2.nextSibling;
20282
20283                 if (s == n1) {
20284                     p.insertBefore(n1, n2);
20285                 } else if (n2 == n1.nextSibling) {
20286                     p.insertBefore(n2, n1);
20287                 } else {
20288                     n1.parentNode.replaceChild(n2, n1);
20289                     p.insertBefore(n1, s);
20290                 }
20291             }
20292         },
20293
20294         /**
20295          * Returns the current scroll position
20296          * @method getScroll
20297          * @private
20298          * @static
20299          */
20300         getScroll: function () {
20301             var t, l, dde=document.documentElement, db=document.body;
20302             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20303                 t = dde.scrollTop;
20304                 l = dde.scrollLeft;
20305             } else if (db) {
20306                 t = db.scrollTop;
20307                 l = db.scrollLeft;
20308             } else {
20309
20310             }
20311             return { top: t, left: l };
20312         },
20313
20314         /**
20315          * Returns the specified element style property
20316          * @method getStyle
20317          * @param {HTMLElement} el          the element
20318          * @param {string}      styleProp   the style property
20319          * @return {string} The value of the style property
20320          * @deprecated use Roo.lib.Dom.getStyle
20321          * @static
20322          */
20323         getStyle: function(el, styleProp) {
20324             return Roo.fly(el).getStyle(styleProp);
20325         },
20326
20327         /**
20328          * Gets the scrollTop
20329          * @method getScrollTop
20330          * @return {int} the document's scrollTop
20331          * @static
20332          */
20333         getScrollTop: function () { return this.getScroll().top; },
20334
20335         /**
20336          * Gets the scrollLeft
20337          * @method getScrollLeft
20338          * @return {int} the document's scrollTop
20339          * @static
20340          */
20341         getScrollLeft: function () { return this.getScroll().left; },
20342
20343         /**
20344          * Sets the x/y position of an element to the location of the
20345          * target element.
20346          * @method moveToEl
20347          * @param {HTMLElement} moveEl      The element to move
20348          * @param {HTMLElement} targetEl    The position reference element
20349          * @static
20350          */
20351         moveToEl: function (moveEl, targetEl) {
20352             var aCoord = Roo.lib.Dom.getXY(targetEl);
20353             Roo.lib.Dom.setXY(moveEl, aCoord);
20354         },
20355
20356         /**
20357          * Numeric array sort function
20358          * @method numericSort
20359          * @static
20360          */
20361         numericSort: function(a, b) { return (a - b); },
20362
20363         /**
20364          * Internal counter
20365          * @property _timeoutCount
20366          * @private
20367          * @static
20368          */
20369         _timeoutCount: 0,
20370
20371         /**
20372          * Trying to make the load order less important.  Without this we get
20373          * an error if this file is loaded before the Event Utility.
20374          * @method _addListeners
20375          * @private
20376          * @static
20377          */
20378         _addListeners: function() {
20379             var DDM = Roo.dd.DDM;
20380             if ( Roo.lib.Event && document ) {
20381                 DDM._onLoad();
20382             } else {
20383                 if (DDM._timeoutCount > 2000) {
20384                 } else {
20385                     setTimeout(DDM._addListeners, 10);
20386                     if (document && document.body) {
20387                         DDM._timeoutCount += 1;
20388                     }
20389                 }
20390             }
20391         },
20392
20393         /**
20394          * Recursively searches the immediate parent and all child nodes for
20395          * the handle element in order to determine wheter or not it was
20396          * clicked.
20397          * @method handleWasClicked
20398          * @param node the html element to inspect
20399          * @static
20400          */
20401         handleWasClicked: function(node, id) {
20402             if (this.isHandle(id, node.id)) {
20403                 return true;
20404             } else {
20405                 // check to see if this is a text node child of the one we want
20406                 var p = node.parentNode;
20407
20408                 while (p) {
20409                     if (this.isHandle(id, p.id)) {
20410                         return true;
20411                     } else {
20412                         p = p.parentNode;
20413                     }
20414                 }
20415             }
20416
20417             return false;
20418         }
20419
20420     };
20421
20422 }();
20423
20424 // shorter alias, save a few bytes
20425 Roo.dd.DDM = Roo.dd.DragDropMgr;
20426 Roo.dd.DDM._addListeners();
20427
20428 }/*
20429  * Based on:
20430  * Ext JS Library 1.1.1
20431  * Copyright(c) 2006-2007, Ext JS, LLC.
20432  *
20433  * Originally Released Under LGPL - original licence link has changed is not relivant.
20434  *
20435  * Fork - LGPL
20436  * <script type="text/javascript">
20437  */
20438
20439 /**
20440  * @class Roo.dd.DD
20441  * A DragDrop implementation where the linked element follows the
20442  * mouse cursor during a drag.
20443  * @extends Roo.dd.DragDrop
20444  * @constructor
20445  * @param {String} id the id of the linked element
20446  * @param {String} sGroup the group of related DragDrop items
20447  * @param {object} config an object containing configurable attributes
20448  *                Valid properties for DD:
20449  *                    scroll
20450  */
20451 Roo.dd.DD = function(id, sGroup, config) {
20452     if (id) {
20453         this.init(id, sGroup, config);
20454     }
20455 };
20456
20457 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20458
20459     /**
20460      * When set to true, the utility automatically tries to scroll the browser
20461      * window wehn a drag and drop element is dragged near the viewport boundary.
20462      * Defaults to true.
20463      * @property scroll
20464      * @type boolean
20465      */
20466     scroll: true,
20467
20468     /**
20469      * Sets the pointer offset to the distance between the linked element's top
20470      * left corner and the location the element was clicked
20471      * @method autoOffset
20472      * @param {int} iPageX the X coordinate of the click
20473      * @param {int} iPageY the Y coordinate of the click
20474      */
20475     autoOffset: function(iPageX, iPageY) {
20476         var x = iPageX - this.startPageX;
20477         var y = iPageY - this.startPageY;
20478         this.setDelta(x, y);
20479     },
20480
20481     /**
20482      * Sets the pointer offset.  You can call this directly to force the
20483      * offset to be in a particular location (e.g., pass in 0,0 to set it
20484      * to the center of the object)
20485      * @method setDelta
20486      * @param {int} iDeltaX the distance from the left
20487      * @param {int} iDeltaY the distance from the top
20488      */
20489     setDelta: function(iDeltaX, iDeltaY) {
20490         this.deltaX = iDeltaX;
20491         this.deltaY = iDeltaY;
20492     },
20493
20494     /**
20495      * Sets the drag element to the location of the mousedown or click event,
20496      * maintaining the cursor location relative to the location on the element
20497      * that was clicked.  Override this if you want to place the element in a
20498      * location other than where the cursor is.
20499      * @method setDragElPos
20500      * @param {int} iPageX the X coordinate of the mousedown or drag event
20501      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20502      */
20503     setDragElPos: function(iPageX, iPageY) {
20504         // the first time we do this, we are going to check to make sure
20505         // the element has css positioning
20506
20507         var el = this.getDragEl();
20508         this.alignElWithMouse(el, iPageX, iPageY);
20509     },
20510
20511     /**
20512      * Sets the element to the location of the mousedown or click event,
20513      * maintaining the cursor location relative to the location on the element
20514      * that was clicked.  Override this if you want to place the element in a
20515      * location other than where the cursor is.
20516      * @method alignElWithMouse
20517      * @param {HTMLElement} el the element to move
20518      * @param {int} iPageX the X coordinate of the mousedown or drag event
20519      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20520      */
20521     alignElWithMouse: function(el, iPageX, iPageY) {
20522         var oCoord = this.getTargetCoord(iPageX, iPageY);
20523         var fly = el.dom ? el : Roo.fly(el);
20524         if (!this.deltaSetXY) {
20525             var aCoord = [oCoord.x, oCoord.y];
20526             fly.setXY(aCoord);
20527             var newLeft = fly.getLeft(true);
20528             var newTop  = fly.getTop(true);
20529             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20530         } else {
20531             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20532         }
20533
20534         this.cachePosition(oCoord.x, oCoord.y);
20535         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20536         return oCoord;
20537     },
20538
20539     /**
20540      * Saves the most recent position so that we can reset the constraints and
20541      * tick marks on-demand.  We need to know this so that we can calculate the
20542      * number of pixels the element is offset from its original position.
20543      * @method cachePosition
20544      * @param iPageX the current x position (optional, this just makes it so we
20545      * don't have to look it up again)
20546      * @param iPageY the current y position (optional, this just makes it so we
20547      * don't have to look it up again)
20548      */
20549     cachePosition: function(iPageX, iPageY) {
20550         if (iPageX) {
20551             this.lastPageX = iPageX;
20552             this.lastPageY = iPageY;
20553         } else {
20554             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20555             this.lastPageX = aCoord[0];
20556             this.lastPageY = aCoord[1];
20557         }
20558     },
20559
20560     /**
20561      * Auto-scroll the window if the dragged object has been moved beyond the
20562      * visible window boundary.
20563      * @method autoScroll
20564      * @param {int} x the drag element's x position
20565      * @param {int} y the drag element's y position
20566      * @param {int} h the height of the drag element
20567      * @param {int} w the width of the drag element
20568      * @private
20569      */
20570     autoScroll: function(x, y, h, w) {
20571
20572         if (this.scroll) {
20573             // The client height
20574             var clientH = Roo.lib.Dom.getViewWidth();
20575
20576             // The client width
20577             var clientW = Roo.lib.Dom.getViewHeight();
20578
20579             // The amt scrolled down
20580             var st = this.DDM.getScrollTop();
20581
20582             // The amt scrolled right
20583             var sl = this.DDM.getScrollLeft();
20584
20585             // Location of the bottom of the element
20586             var bot = h + y;
20587
20588             // Location of the right of the element
20589             var right = w + x;
20590
20591             // The distance from the cursor to the bottom of the visible area,
20592             // adjusted so that we don't scroll if the cursor is beyond the
20593             // element drag constraints
20594             var toBot = (clientH + st - y - this.deltaY);
20595
20596             // The distance from the cursor to the right of the visible area
20597             var toRight = (clientW + sl - x - this.deltaX);
20598
20599
20600             // How close to the edge the cursor must be before we scroll
20601             // var thresh = (document.all) ? 100 : 40;
20602             var thresh = 40;
20603
20604             // How many pixels to scroll per autoscroll op.  This helps to reduce
20605             // clunky scrolling. IE is more sensitive about this ... it needs this
20606             // value to be higher.
20607             var scrAmt = (document.all) ? 80 : 30;
20608
20609             // Scroll down if we are near the bottom of the visible page and the
20610             // obj extends below the crease
20611             if ( bot > clientH && toBot < thresh ) {
20612                 window.scrollTo(sl, st + scrAmt);
20613             }
20614
20615             // Scroll up if the window is scrolled down and the top of the object
20616             // goes above the top border
20617             if ( y < st && st > 0 && y - st < thresh ) {
20618                 window.scrollTo(sl, st - scrAmt);
20619             }
20620
20621             // Scroll right if the obj is beyond the right border and the cursor is
20622             // near the border.
20623             if ( right > clientW && toRight < thresh ) {
20624                 window.scrollTo(sl + scrAmt, st);
20625             }
20626
20627             // Scroll left if the window has been scrolled to the right and the obj
20628             // extends past the left border
20629             if ( x < sl && sl > 0 && x - sl < thresh ) {
20630                 window.scrollTo(sl - scrAmt, st);
20631             }
20632         }
20633     },
20634
20635     /**
20636      * Finds the location the element should be placed if we want to move
20637      * it to where the mouse location less the click offset would place us.
20638      * @method getTargetCoord
20639      * @param {int} iPageX the X coordinate of the click
20640      * @param {int} iPageY the Y coordinate of the click
20641      * @return an object that contains the coordinates (Object.x and Object.y)
20642      * @private
20643      */
20644     getTargetCoord: function(iPageX, iPageY) {
20645
20646
20647         var x = iPageX - this.deltaX;
20648         var y = iPageY - this.deltaY;
20649
20650         if (this.constrainX) {
20651             if (x < this.minX) { x = this.minX; }
20652             if (x > this.maxX) { x = this.maxX; }
20653         }
20654
20655         if (this.constrainY) {
20656             if (y < this.minY) { y = this.minY; }
20657             if (y > this.maxY) { y = this.maxY; }
20658         }
20659
20660         x = this.getTick(x, this.xTicks);
20661         y = this.getTick(y, this.yTicks);
20662
20663
20664         return {x:x, y:y};
20665     },
20666
20667     /*
20668      * Sets up config options specific to this class. Overrides
20669      * Roo.dd.DragDrop, but all versions of this method through the
20670      * inheritance chain are called
20671      */
20672     applyConfig: function() {
20673         Roo.dd.DD.superclass.applyConfig.call(this);
20674         this.scroll = (this.config.scroll !== false);
20675     },
20676
20677     /*
20678      * Event that fires prior to the onMouseDown event.  Overrides
20679      * Roo.dd.DragDrop.
20680      */
20681     b4MouseDown: function(e) {
20682         // this.resetConstraints();
20683         this.autoOffset(e.getPageX(),
20684                             e.getPageY());
20685     },
20686
20687     /*
20688      * Event that fires prior to the onDrag event.  Overrides
20689      * Roo.dd.DragDrop.
20690      */
20691     b4Drag: function(e) {
20692         this.setDragElPos(e.getPageX(),
20693                             e.getPageY());
20694     },
20695
20696     toString: function() {
20697         return ("DD " + this.id);
20698     }
20699
20700     //////////////////////////////////////////////////////////////////////////
20701     // Debugging ygDragDrop events that can be overridden
20702     //////////////////////////////////////////////////////////////////////////
20703     /*
20704     startDrag: function(x, y) {
20705     },
20706
20707     onDrag: function(e) {
20708     },
20709
20710     onDragEnter: function(e, id) {
20711     },
20712
20713     onDragOver: function(e, id) {
20714     },
20715
20716     onDragOut: function(e, id) {
20717     },
20718
20719     onDragDrop: function(e, id) {
20720     },
20721
20722     endDrag: function(e) {
20723     }
20724
20725     */
20726
20727 });/*
20728  * Based on:
20729  * Ext JS Library 1.1.1
20730  * Copyright(c) 2006-2007, Ext JS, LLC.
20731  *
20732  * Originally Released Under LGPL - original licence link has changed is not relivant.
20733  *
20734  * Fork - LGPL
20735  * <script type="text/javascript">
20736  */
20737
20738 /**
20739  * @class Roo.dd.DDProxy
20740  * A DragDrop implementation that inserts an empty, bordered div into
20741  * the document that follows the cursor during drag operations.  At the time of
20742  * the click, the frame div is resized to the dimensions of the linked html
20743  * element, and moved to the exact location of the linked element.
20744  *
20745  * References to the "frame" element refer to the single proxy element that
20746  * was created to be dragged in place of all DDProxy elements on the
20747  * page.
20748  *
20749  * @extends Roo.dd.DD
20750  * @constructor
20751  * @param {String} id the id of the linked html element
20752  * @param {String} sGroup the group of related DragDrop objects
20753  * @param {object} config an object containing configurable attributes
20754  *                Valid properties for DDProxy in addition to those in DragDrop:
20755  *                   resizeFrame, centerFrame, dragElId
20756  */
20757 Roo.dd.DDProxy = function(id, sGroup, config) {
20758     if (id) {
20759         this.init(id, sGroup, config);
20760         this.initFrame();
20761     }
20762 };
20763
20764 /**
20765  * The default drag frame div id
20766  * @property Roo.dd.DDProxy.dragElId
20767  * @type String
20768  * @static
20769  */
20770 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20771
20772 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20773
20774     /**
20775      * By default we resize the drag frame to be the same size as the element
20776      * we want to drag (this is to get the frame effect).  We can turn it off
20777      * if we want a different behavior.
20778      * @property resizeFrame
20779      * @type boolean
20780      */
20781     resizeFrame: true,
20782
20783     /**
20784      * By default the frame is positioned exactly where the drag element is, so
20785      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20786      * you do not have constraints on the obj is to have the drag frame centered
20787      * around the cursor.  Set centerFrame to true for this effect.
20788      * @property centerFrame
20789      * @type boolean
20790      */
20791     centerFrame: false,
20792
20793     /**
20794      * Creates the proxy element if it does not yet exist
20795      * @method createFrame
20796      */
20797     createFrame: function() {
20798         var self = this;
20799         var body = document.body;
20800
20801         if (!body || !body.firstChild) {
20802             setTimeout( function() { self.createFrame(); }, 50 );
20803             return;
20804         }
20805
20806         var div = this.getDragEl();
20807
20808         if (!div) {
20809             div    = document.createElement("div");
20810             div.id = this.dragElId;
20811             var s  = div.style;
20812
20813             s.position   = "absolute";
20814             s.visibility = "hidden";
20815             s.cursor     = "move";
20816             s.border     = "2px solid #aaa";
20817             s.zIndex     = 999;
20818
20819             // appendChild can blow up IE if invoked prior to the window load event
20820             // while rendering a table.  It is possible there are other scenarios
20821             // that would cause this to happen as well.
20822             body.insertBefore(div, body.firstChild);
20823         }
20824     },
20825
20826     /**
20827      * Initialization for the drag frame element.  Must be called in the
20828      * constructor of all subclasses
20829      * @method initFrame
20830      */
20831     initFrame: function() {
20832         this.createFrame();
20833     },
20834
20835     applyConfig: function() {
20836         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20837
20838         this.resizeFrame = (this.config.resizeFrame !== false);
20839         this.centerFrame = (this.config.centerFrame);
20840         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20841     },
20842
20843     /**
20844      * Resizes the drag frame to the dimensions of the clicked object, positions
20845      * it over the object, and finally displays it
20846      * @method showFrame
20847      * @param {int} iPageX X click position
20848      * @param {int} iPageY Y click position
20849      * @private
20850      */
20851     showFrame: function(iPageX, iPageY) {
20852         var el = this.getEl();
20853         var dragEl = this.getDragEl();
20854         var s = dragEl.style;
20855
20856         this._resizeProxy();
20857
20858         if (this.centerFrame) {
20859             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20860                            Math.round(parseInt(s.height, 10)/2) );
20861         }
20862
20863         this.setDragElPos(iPageX, iPageY);
20864
20865         Roo.fly(dragEl).show();
20866     },
20867
20868     /**
20869      * The proxy is automatically resized to the dimensions of the linked
20870      * element when a drag is initiated, unless resizeFrame is set to false
20871      * @method _resizeProxy
20872      * @private
20873      */
20874     _resizeProxy: function() {
20875         if (this.resizeFrame) {
20876             var el = this.getEl();
20877             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20878         }
20879     },
20880
20881     // overrides Roo.dd.DragDrop
20882     b4MouseDown: function(e) {
20883         var x = e.getPageX();
20884         var y = e.getPageY();
20885         this.autoOffset(x, y);
20886         this.setDragElPos(x, y);
20887     },
20888
20889     // overrides Roo.dd.DragDrop
20890     b4StartDrag: function(x, y) {
20891         // show the drag frame
20892         this.showFrame(x, y);
20893     },
20894
20895     // overrides Roo.dd.DragDrop
20896     b4EndDrag: function(e) {
20897         Roo.fly(this.getDragEl()).hide();
20898     },
20899
20900     // overrides Roo.dd.DragDrop
20901     // By default we try to move the element to the last location of the frame.
20902     // This is so that the default behavior mirrors that of Roo.dd.DD.
20903     endDrag: function(e) {
20904
20905         var lel = this.getEl();
20906         var del = this.getDragEl();
20907
20908         // Show the drag frame briefly so we can get its position
20909         del.style.visibility = "";
20910
20911         this.beforeMove();
20912         // Hide the linked element before the move to get around a Safari
20913         // rendering bug.
20914         lel.style.visibility = "hidden";
20915         Roo.dd.DDM.moveToEl(lel, del);
20916         del.style.visibility = "hidden";
20917         lel.style.visibility = "";
20918
20919         this.afterDrag();
20920     },
20921
20922     beforeMove : function(){
20923
20924     },
20925
20926     afterDrag : function(){
20927
20928     },
20929
20930     toString: function() {
20931         return ("DDProxy " + this.id);
20932     }
20933
20934 });
20935 /*
20936  * Based on:
20937  * Ext JS Library 1.1.1
20938  * Copyright(c) 2006-2007, Ext JS, LLC.
20939  *
20940  * Originally Released Under LGPL - original licence link has changed is not relivant.
20941  *
20942  * Fork - LGPL
20943  * <script type="text/javascript">
20944  */
20945
20946  /**
20947  * @class Roo.dd.DDTarget
20948  * A DragDrop implementation that does not move, but can be a drop
20949  * target.  You would get the same result by simply omitting implementation
20950  * for the event callbacks, but this way we reduce the processing cost of the
20951  * event listener and the callbacks.
20952  * @extends Roo.dd.DragDrop
20953  * @constructor
20954  * @param {String} id the id of the element that is a drop target
20955  * @param {String} sGroup the group of related DragDrop objects
20956  * @param {object} config an object containing configurable attributes
20957  *                 Valid properties for DDTarget in addition to those in
20958  *                 DragDrop:
20959  *                    none
20960  */
20961 Roo.dd.DDTarget = function(id, sGroup, config) {
20962     if (id) {
20963         this.initTarget(id, sGroup, config);
20964     }
20965     if (config.listeners || config.events) { 
20966        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20967             listeners : config.listeners || {}, 
20968             events : config.events || {} 
20969         });    
20970     }
20971 };
20972
20973 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20974 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20975     toString: function() {
20976         return ("DDTarget " + this.id);
20977     }
20978 });
20979 /*
20980  * Based on:
20981  * Ext JS Library 1.1.1
20982  * Copyright(c) 2006-2007, Ext JS, LLC.
20983  *
20984  * Originally Released Under LGPL - original licence link has changed is not relivant.
20985  *
20986  * Fork - LGPL
20987  * <script type="text/javascript">
20988  */
20989  
20990
20991 /**
20992  * @class Roo.dd.ScrollManager
20993  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20994  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20995  * @singleton
20996  */
20997 Roo.dd.ScrollManager = function(){
20998     var ddm = Roo.dd.DragDropMgr;
20999     var els = {};
21000     var dragEl = null;
21001     var proc = {};
21002     
21003     
21004     
21005     var onStop = function(e){
21006         dragEl = null;
21007         clearProc();
21008     };
21009     
21010     var triggerRefresh = function(){
21011         if(ddm.dragCurrent){
21012              ddm.refreshCache(ddm.dragCurrent.groups);
21013         }
21014     };
21015     
21016     var doScroll = function(){
21017         if(ddm.dragCurrent){
21018             var dds = Roo.dd.ScrollManager;
21019             if(!dds.animate){
21020                 if(proc.el.scroll(proc.dir, dds.increment)){
21021                     triggerRefresh();
21022                 }
21023             }else{
21024                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21025             }
21026         }
21027     };
21028     
21029     var clearProc = function(){
21030         if(proc.id){
21031             clearInterval(proc.id);
21032         }
21033         proc.id = 0;
21034         proc.el = null;
21035         proc.dir = "";
21036     };
21037     
21038     var startProc = function(el, dir){
21039          Roo.log('scroll startproc');
21040         clearProc();
21041         proc.el = el;
21042         proc.dir = dir;
21043         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21044     };
21045     
21046     var onFire = function(e, isDrop){
21047        
21048         if(isDrop || !ddm.dragCurrent){ return; }
21049         var dds = Roo.dd.ScrollManager;
21050         if(!dragEl || dragEl != ddm.dragCurrent){
21051             dragEl = ddm.dragCurrent;
21052             // refresh regions on drag start
21053             dds.refreshCache();
21054         }
21055         
21056         var xy = Roo.lib.Event.getXY(e);
21057         var pt = new Roo.lib.Point(xy[0], xy[1]);
21058         for(var id in els){
21059             var el = els[id], r = el._region;
21060             if(r && r.contains(pt) && el.isScrollable()){
21061                 if(r.bottom - pt.y <= dds.thresh){
21062                     if(proc.el != el){
21063                         startProc(el, "down");
21064                     }
21065                     return;
21066                 }else if(r.right - pt.x <= dds.thresh){
21067                     if(proc.el != el){
21068                         startProc(el, "left");
21069                     }
21070                     return;
21071                 }else if(pt.y - r.top <= dds.thresh){
21072                     if(proc.el != el){
21073                         startProc(el, "up");
21074                     }
21075                     return;
21076                 }else if(pt.x - r.left <= dds.thresh){
21077                     if(proc.el != el){
21078                         startProc(el, "right");
21079                     }
21080                     return;
21081                 }
21082             }
21083         }
21084         clearProc();
21085     };
21086     
21087     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21088     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21089     
21090     return {
21091         /**
21092          * Registers new overflow element(s) to auto scroll
21093          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21094          */
21095         register : function(el){
21096             if(el instanceof Array){
21097                 for(var i = 0, len = el.length; i < len; i++) {
21098                         this.register(el[i]);
21099                 }
21100             }else{
21101                 el = Roo.get(el);
21102                 els[el.id] = el;
21103             }
21104             Roo.dd.ScrollManager.els = els;
21105         },
21106         
21107         /**
21108          * Unregisters overflow element(s) so they are no longer scrolled
21109          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21110          */
21111         unregister : function(el){
21112             if(el instanceof Array){
21113                 for(var i = 0, len = el.length; i < len; i++) {
21114                         this.unregister(el[i]);
21115                 }
21116             }else{
21117                 el = Roo.get(el);
21118                 delete els[el.id];
21119             }
21120         },
21121         
21122         /**
21123          * The number of pixels from the edge of a container the pointer needs to be to 
21124          * trigger scrolling (defaults to 25)
21125          * @type Number
21126          */
21127         thresh : 25,
21128         
21129         /**
21130          * The number of pixels to scroll in each scroll increment (defaults to 50)
21131          * @type Number
21132          */
21133         increment : 100,
21134         
21135         /**
21136          * The frequency of scrolls in milliseconds (defaults to 500)
21137          * @type Number
21138          */
21139         frequency : 500,
21140         
21141         /**
21142          * True to animate the scroll (defaults to true)
21143          * @type Boolean
21144          */
21145         animate: true,
21146         
21147         /**
21148          * The animation duration in seconds - 
21149          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21150          * @type Number
21151          */
21152         animDuration: .4,
21153         
21154         /**
21155          * Manually trigger a cache refresh.
21156          */
21157         refreshCache : function(){
21158             for(var id in els){
21159                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21160                     els[id]._region = els[id].getRegion();
21161                 }
21162             }
21163         }
21164     };
21165 }();/*
21166  * Based on:
21167  * Ext JS Library 1.1.1
21168  * Copyright(c) 2006-2007, Ext JS, LLC.
21169  *
21170  * Originally Released Under LGPL - original licence link has changed is not relivant.
21171  *
21172  * Fork - LGPL
21173  * <script type="text/javascript">
21174  */
21175  
21176
21177 /**
21178  * @class Roo.dd.Registry
21179  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21180  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21181  * @singleton
21182  */
21183 Roo.dd.Registry = function(){
21184     var elements = {}; 
21185     var handles = {}; 
21186     var autoIdSeed = 0;
21187
21188     var getId = function(el, autogen){
21189         if(typeof el == "string"){
21190             return el;
21191         }
21192         var id = el.id;
21193         if(!id && autogen !== false){
21194             id = "roodd-" + (++autoIdSeed);
21195             el.id = id;
21196         }
21197         return id;
21198     };
21199     
21200     return {
21201     /**
21202      * Register a drag drop element
21203      * @param {String|HTMLElement} element The id or DOM node to register
21204      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21205      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21206      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21207      * populated in the data object (if applicable):
21208      * <pre>
21209 Value      Description<br />
21210 ---------  ------------------------------------------<br />
21211 handles    Array of DOM nodes that trigger dragging<br />
21212            for the element being registered<br />
21213 isHandle   True if the element passed in triggers<br />
21214            dragging itself, else false
21215 </pre>
21216      */
21217         register : function(el, data){
21218             data = data || {};
21219             if(typeof el == "string"){
21220                 el = document.getElementById(el);
21221             }
21222             data.ddel = el;
21223             elements[getId(el)] = data;
21224             if(data.isHandle !== false){
21225                 handles[data.ddel.id] = data;
21226             }
21227             if(data.handles){
21228                 var hs = data.handles;
21229                 for(var i = 0, len = hs.length; i < len; i++){
21230                         handles[getId(hs[i])] = data;
21231                 }
21232             }
21233         },
21234
21235     /**
21236      * Unregister a drag drop element
21237      * @param {String|HTMLElement}  element The id or DOM node to unregister
21238      */
21239         unregister : function(el){
21240             var id = getId(el, false);
21241             var data = elements[id];
21242             if(data){
21243                 delete elements[id];
21244                 if(data.handles){
21245                     var hs = data.handles;
21246                     for(var i = 0, len = hs.length; i < len; i++){
21247                         delete handles[getId(hs[i], false)];
21248                     }
21249                 }
21250             }
21251         },
21252
21253     /**
21254      * Returns the handle registered for a DOM Node by id
21255      * @param {String|HTMLElement} id The DOM node or id to look up
21256      * @return {Object} handle The custom handle data
21257      */
21258         getHandle : function(id){
21259             if(typeof id != "string"){ // must be element?
21260                 id = id.id;
21261             }
21262             return handles[id];
21263         },
21264
21265     /**
21266      * Returns the handle that is registered for the DOM node that is the target of the event
21267      * @param {Event} e The event
21268      * @return {Object} handle The custom handle data
21269      */
21270         getHandleFromEvent : function(e){
21271             var t = Roo.lib.Event.getTarget(e);
21272             return t ? handles[t.id] : null;
21273         },
21274
21275     /**
21276      * Returns a custom data object that is registered for a DOM node by id
21277      * @param {String|HTMLElement} id The DOM node or id to look up
21278      * @return {Object} data The custom data
21279      */
21280         getTarget : function(id){
21281             if(typeof id != "string"){ // must be element?
21282                 id = id.id;
21283             }
21284             return elements[id];
21285         },
21286
21287     /**
21288      * Returns a custom data object that is registered for the DOM node that is the target of the event
21289      * @param {Event} e The event
21290      * @return {Object} data The custom data
21291      */
21292         getTargetFromEvent : function(e){
21293             var t = Roo.lib.Event.getTarget(e);
21294             return t ? elements[t.id] || handles[t.id] : null;
21295         }
21296     };
21297 }();/*
21298  * Based on:
21299  * Ext JS Library 1.1.1
21300  * Copyright(c) 2006-2007, Ext JS, LLC.
21301  *
21302  * Originally Released Under LGPL - original licence link has changed is not relivant.
21303  *
21304  * Fork - LGPL
21305  * <script type="text/javascript">
21306  */
21307  
21308
21309 /**
21310  * @class Roo.dd.StatusProxy
21311  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21312  * default drag proxy used by all Roo.dd components.
21313  * @constructor
21314  * @param {Object} config
21315  */
21316 Roo.dd.StatusProxy = function(config){
21317     Roo.apply(this, config);
21318     this.id = this.id || Roo.id();
21319     this.el = new Roo.Layer({
21320         dh: {
21321             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21322                 {tag: "div", cls: "x-dd-drop-icon"},
21323                 {tag: "div", cls: "x-dd-drag-ghost"}
21324             ]
21325         }, 
21326         shadow: !config || config.shadow !== false
21327     });
21328     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21329     this.dropStatus = this.dropNotAllowed;
21330 };
21331
21332 Roo.dd.StatusProxy.prototype = {
21333     /**
21334      * @cfg {String} dropAllowed
21335      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21336      */
21337     dropAllowed : "x-dd-drop-ok",
21338     /**
21339      * @cfg {String} dropNotAllowed
21340      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21341      */
21342     dropNotAllowed : "x-dd-drop-nodrop",
21343
21344     /**
21345      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21346      * over the current target element.
21347      * @param {String} cssClass The css class for the new drop status indicator image
21348      */
21349     setStatus : function(cssClass){
21350         cssClass = cssClass || this.dropNotAllowed;
21351         if(this.dropStatus != cssClass){
21352             this.el.replaceClass(this.dropStatus, cssClass);
21353             this.dropStatus = cssClass;
21354         }
21355     },
21356
21357     /**
21358      * Resets the status indicator to the default dropNotAllowed value
21359      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21360      */
21361     reset : function(clearGhost){
21362         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21363         this.dropStatus = this.dropNotAllowed;
21364         if(clearGhost){
21365             this.ghost.update("");
21366         }
21367     },
21368
21369     /**
21370      * Updates the contents of the ghost element
21371      * @param {String} html The html that will replace the current innerHTML of the ghost element
21372      */
21373     update : function(html){
21374         if(typeof html == "string"){
21375             this.ghost.update(html);
21376         }else{
21377             this.ghost.update("");
21378             html.style.margin = "0";
21379             this.ghost.dom.appendChild(html);
21380         }
21381         // ensure float = none set?? cant remember why though.
21382         var el = this.ghost.dom.firstChild;
21383                 if(el){
21384                         Roo.fly(el).setStyle('float', 'none');
21385                 }
21386     },
21387     
21388     /**
21389      * Returns the underlying proxy {@link Roo.Layer}
21390      * @return {Roo.Layer} el
21391     */
21392     getEl : function(){
21393         return this.el;
21394     },
21395
21396     /**
21397      * Returns the ghost element
21398      * @return {Roo.Element} el
21399      */
21400     getGhost : function(){
21401         return this.ghost;
21402     },
21403
21404     /**
21405      * Hides the proxy
21406      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21407      */
21408     hide : function(clear){
21409         this.el.hide();
21410         if(clear){
21411             this.reset(true);
21412         }
21413     },
21414
21415     /**
21416      * Stops the repair animation if it's currently running
21417      */
21418     stop : function(){
21419         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21420             this.anim.stop();
21421         }
21422     },
21423
21424     /**
21425      * Displays this proxy
21426      */
21427     show : function(){
21428         this.el.show();
21429     },
21430
21431     /**
21432      * Force the Layer to sync its shadow and shim positions to the element
21433      */
21434     sync : function(){
21435         this.el.sync();
21436     },
21437
21438     /**
21439      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21440      * invalid drop operation by the item being dragged.
21441      * @param {Array} xy The XY position of the element ([x, y])
21442      * @param {Function} callback The function to call after the repair is complete
21443      * @param {Object} scope The scope in which to execute the callback
21444      */
21445     repair : function(xy, callback, scope){
21446         this.callback = callback;
21447         this.scope = scope;
21448         if(xy && this.animRepair !== false){
21449             this.el.addClass("x-dd-drag-repair");
21450             this.el.hideUnders(true);
21451             this.anim = this.el.shift({
21452                 duration: this.repairDuration || .5,
21453                 easing: 'easeOut',
21454                 xy: xy,
21455                 stopFx: true,
21456                 callback: this.afterRepair,
21457                 scope: this
21458             });
21459         }else{
21460             this.afterRepair();
21461         }
21462     },
21463
21464     // private
21465     afterRepair : function(){
21466         this.hide(true);
21467         if(typeof this.callback == "function"){
21468             this.callback.call(this.scope || this);
21469         }
21470         this.callback = null;
21471         this.scope = null;
21472     }
21473 };/*
21474  * Based on:
21475  * Ext JS Library 1.1.1
21476  * Copyright(c) 2006-2007, Ext JS, LLC.
21477  *
21478  * Originally Released Under LGPL - original licence link has changed is not relivant.
21479  *
21480  * Fork - LGPL
21481  * <script type="text/javascript">
21482  */
21483
21484 /**
21485  * @class Roo.dd.DragSource
21486  * @extends Roo.dd.DDProxy
21487  * A simple class that provides the basic implementation needed to make any element draggable.
21488  * @constructor
21489  * @param {String/HTMLElement/Element} el The container element
21490  * @param {Object} config
21491  */
21492 Roo.dd.DragSource = function(el, config){
21493     this.el = Roo.get(el);
21494     this.dragData = {};
21495     
21496     Roo.apply(this, config);
21497     
21498     if(!this.proxy){
21499         this.proxy = new Roo.dd.StatusProxy();
21500     }
21501
21502     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21503           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21504     
21505     this.dragging = false;
21506 };
21507
21508 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21509     /**
21510      * @cfg {String} dropAllowed
21511      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21512      */
21513     dropAllowed : "x-dd-drop-ok",
21514     /**
21515      * @cfg {String} dropNotAllowed
21516      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21517      */
21518     dropNotAllowed : "x-dd-drop-nodrop",
21519
21520     /**
21521      * Returns the data object associated with this drag source
21522      * @return {Object} data An object containing arbitrary data
21523      */
21524     getDragData : function(e){
21525         return this.dragData;
21526     },
21527
21528     // private
21529     onDragEnter : function(e, id){
21530         var target = Roo.dd.DragDropMgr.getDDById(id);
21531         this.cachedTarget = target;
21532         if(this.beforeDragEnter(target, e, id) !== false){
21533             if(target.isNotifyTarget){
21534                 var status = target.notifyEnter(this, e, this.dragData);
21535                 this.proxy.setStatus(status);
21536             }else{
21537                 this.proxy.setStatus(this.dropAllowed);
21538             }
21539             
21540             if(this.afterDragEnter){
21541                 /**
21542                  * An empty function by default, but provided so that you can perform a custom action
21543                  * when the dragged item enters the drop target by providing an implementation.
21544                  * @param {Roo.dd.DragDrop} target The drop target
21545                  * @param {Event} e The event object
21546                  * @param {String} id The id of the dragged element
21547                  * @method afterDragEnter
21548                  */
21549                 this.afterDragEnter(target, e, id);
21550             }
21551         }
21552     },
21553
21554     /**
21555      * An empty function by default, but provided so that you can perform a custom action
21556      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21557      * @param {Roo.dd.DragDrop} target The drop target
21558      * @param {Event} e The event object
21559      * @param {String} id The id of the dragged element
21560      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21561      */
21562     beforeDragEnter : function(target, e, id){
21563         return true;
21564     },
21565
21566     // private
21567     alignElWithMouse: function() {
21568         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21569         this.proxy.sync();
21570     },
21571
21572     // private
21573     onDragOver : function(e, id){
21574         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21575         if(this.beforeDragOver(target, e, id) !== false){
21576             if(target.isNotifyTarget){
21577                 var status = target.notifyOver(this, e, this.dragData);
21578                 this.proxy.setStatus(status);
21579             }
21580
21581             if(this.afterDragOver){
21582                 /**
21583                  * An empty function by default, but provided so that you can perform a custom action
21584                  * while the dragged item is over the drop target by providing an implementation.
21585                  * @param {Roo.dd.DragDrop} target The drop target
21586                  * @param {Event} e The event object
21587                  * @param {String} id The id of the dragged element
21588                  * @method afterDragOver
21589                  */
21590                 this.afterDragOver(target, e, id);
21591             }
21592         }
21593     },
21594
21595     /**
21596      * An empty function by default, but provided so that you can perform a custom action
21597      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21598      * @param {Roo.dd.DragDrop} target The drop target
21599      * @param {Event} e The event object
21600      * @param {String} id The id of the dragged element
21601      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21602      */
21603     beforeDragOver : function(target, e, id){
21604         return true;
21605     },
21606
21607     // private
21608     onDragOut : function(e, id){
21609         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21610         if(this.beforeDragOut(target, e, id) !== false){
21611             if(target.isNotifyTarget){
21612                 target.notifyOut(this, e, this.dragData);
21613             }
21614             this.proxy.reset();
21615             if(this.afterDragOut){
21616                 /**
21617                  * An empty function by default, but provided so that you can perform a custom action
21618                  * after the dragged item is dragged out of the target without dropping.
21619                  * @param {Roo.dd.DragDrop} target The drop target
21620                  * @param {Event} e The event object
21621                  * @param {String} id The id of the dragged element
21622                  * @method afterDragOut
21623                  */
21624                 this.afterDragOut(target, e, id);
21625             }
21626         }
21627         this.cachedTarget = null;
21628     },
21629
21630     /**
21631      * An empty function by default, but provided so that you can perform a custom action before the dragged
21632      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21633      * @param {Roo.dd.DragDrop} target The drop target
21634      * @param {Event} e The event object
21635      * @param {String} id The id of the dragged element
21636      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21637      */
21638     beforeDragOut : function(target, e, id){
21639         return true;
21640     },
21641     
21642     // private
21643     onDragDrop : function(e, id){
21644         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21645         if(this.beforeDragDrop(target, e, id) !== false){
21646             if(target.isNotifyTarget){
21647                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21648                     this.onValidDrop(target, e, id);
21649                 }else{
21650                     this.onInvalidDrop(target, e, id);
21651                 }
21652             }else{
21653                 this.onValidDrop(target, e, id);
21654             }
21655             
21656             if(this.afterDragDrop){
21657                 /**
21658                  * An empty function by default, but provided so that you can perform a custom action
21659                  * after a valid drag drop has occurred by providing an implementation.
21660                  * @param {Roo.dd.DragDrop} target The drop target
21661                  * @param {Event} e The event object
21662                  * @param {String} id The id of the dropped element
21663                  * @method afterDragDrop
21664                  */
21665                 this.afterDragDrop(target, e, id);
21666             }
21667         }
21668         delete this.cachedTarget;
21669     },
21670
21671     /**
21672      * An empty function by default, but provided so that you can perform a custom action before the dragged
21673      * item is dropped onto the target and optionally cancel the onDragDrop.
21674      * @param {Roo.dd.DragDrop} target The drop target
21675      * @param {Event} e The event object
21676      * @param {String} id The id of the dragged element
21677      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21678      */
21679     beforeDragDrop : function(target, e, id){
21680         return true;
21681     },
21682
21683     // private
21684     onValidDrop : function(target, e, id){
21685         this.hideProxy();
21686         if(this.afterValidDrop){
21687             /**
21688              * An empty function by default, but provided so that you can perform a custom action
21689              * after a valid drop has occurred by providing an implementation.
21690              * @param {Object} target The target DD 
21691              * @param {Event} e The event object
21692              * @param {String} id The id of the dropped element
21693              * @method afterInvalidDrop
21694              */
21695             this.afterValidDrop(target, e, id);
21696         }
21697     },
21698
21699     // private
21700     getRepairXY : function(e, data){
21701         return this.el.getXY();  
21702     },
21703
21704     // private
21705     onInvalidDrop : function(target, e, id){
21706         this.beforeInvalidDrop(target, e, id);
21707         if(this.cachedTarget){
21708             if(this.cachedTarget.isNotifyTarget){
21709                 this.cachedTarget.notifyOut(this, e, this.dragData);
21710             }
21711             this.cacheTarget = null;
21712         }
21713         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21714
21715         if(this.afterInvalidDrop){
21716             /**
21717              * An empty function by default, but provided so that you can perform a custom action
21718              * after an invalid drop has occurred by providing an implementation.
21719              * @param {Event} e The event object
21720              * @param {String} id The id of the dropped element
21721              * @method afterInvalidDrop
21722              */
21723             this.afterInvalidDrop(e, id);
21724         }
21725     },
21726
21727     // private
21728     afterRepair : function(){
21729         if(Roo.enableFx){
21730             this.el.highlight(this.hlColor || "c3daf9");
21731         }
21732         this.dragging = false;
21733     },
21734
21735     /**
21736      * An empty function by default, but provided so that you can perform a custom action after an invalid
21737      * drop has occurred.
21738      * @param {Roo.dd.DragDrop} target The drop target
21739      * @param {Event} e The event object
21740      * @param {String} id The id of the dragged element
21741      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21742      */
21743     beforeInvalidDrop : function(target, e, id){
21744         return true;
21745     },
21746
21747     // private
21748     handleMouseDown : function(e){
21749         if(this.dragging) {
21750             return;
21751         }
21752         var data = this.getDragData(e);
21753         if(data && this.onBeforeDrag(data, e) !== false){
21754             this.dragData = data;
21755             this.proxy.stop();
21756             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21757         } 
21758     },
21759
21760     /**
21761      * An empty function by default, but provided so that you can perform a custom action before the initial
21762      * drag event begins and optionally cancel it.
21763      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21764      * @param {Event} e The event object
21765      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21766      */
21767     onBeforeDrag : function(data, e){
21768         return true;
21769     },
21770
21771     /**
21772      * An empty function by default, but provided so that you can perform a custom action once the initial
21773      * drag event has begun.  The drag cannot be canceled from this function.
21774      * @param {Number} x The x position of the click on the dragged object
21775      * @param {Number} y The y position of the click on the dragged object
21776      */
21777     onStartDrag : Roo.emptyFn,
21778
21779     // private - YUI override
21780     startDrag : function(x, y){
21781         this.proxy.reset();
21782         this.dragging = true;
21783         this.proxy.update("");
21784         this.onInitDrag(x, y);
21785         this.proxy.show();
21786     },
21787
21788     // private
21789     onInitDrag : function(x, y){
21790         var clone = this.el.dom.cloneNode(true);
21791         clone.id = Roo.id(); // prevent duplicate ids
21792         this.proxy.update(clone);
21793         this.onStartDrag(x, y);
21794         return true;
21795     },
21796
21797     /**
21798      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21799      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21800      */
21801     getProxy : function(){
21802         return this.proxy;  
21803     },
21804
21805     /**
21806      * Hides the drag source's {@link Roo.dd.StatusProxy}
21807      */
21808     hideProxy : function(){
21809         this.proxy.hide();  
21810         this.proxy.reset(true);
21811         this.dragging = false;
21812     },
21813
21814     // private
21815     triggerCacheRefresh : function(){
21816         Roo.dd.DDM.refreshCache(this.groups);
21817     },
21818
21819     // private - override to prevent hiding
21820     b4EndDrag: function(e) {
21821     },
21822
21823     // private - override to prevent moving
21824     endDrag : function(e){
21825         this.onEndDrag(this.dragData, e);
21826     },
21827
21828     // private
21829     onEndDrag : function(data, e){
21830     },
21831     
21832     // private - pin to cursor
21833     autoOffset : function(x, y) {
21834         this.setDelta(-12, -20);
21835     }    
21836 });/*
21837  * Based on:
21838  * Ext JS Library 1.1.1
21839  * Copyright(c) 2006-2007, Ext JS, LLC.
21840  *
21841  * Originally Released Under LGPL - original licence link has changed is not relivant.
21842  *
21843  * Fork - LGPL
21844  * <script type="text/javascript">
21845  */
21846
21847
21848 /**
21849  * @class Roo.dd.DropTarget
21850  * @extends Roo.dd.DDTarget
21851  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21852  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21853  * @constructor
21854  * @param {String/HTMLElement/Element} el The container element
21855  * @param {Object} config
21856  */
21857 Roo.dd.DropTarget = function(el, config){
21858     this.el = Roo.get(el);
21859     
21860     var listeners = false; ;
21861     if (config && config.listeners) {
21862         listeners= config.listeners;
21863         delete config.listeners;
21864     }
21865     Roo.apply(this, config);
21866     
21867     if(this.containerScroll){
21868         Roo.dd.ScrollManager.register(this.el);
21869     }
21870     this.addEvents( {
21871          /**
21872          * @scope Roo.dd.DropTarget
21873          */
21874          
21875          /**
21876          * @event enter
21877          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21878          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21879          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21880          * 
21881          * IMPORTANT : it should set this.overClass and this.dropAllowed
21882          * 
21883          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21884          * @param {Event} e The event
21885          * @param {Object} data An object containing arbitrary data supplied by the drag source
21886          */
21887         "enter" : true,
21888         
21889          /**
21890          * @event over
21891          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21892          * This method will be called on every mouse movement while the drag source is over the drop target.
21893          * This default implementation simply returns the dropAllowed config value.
21894          * 
21895          * IMPORTANT : it should set this.dropAllowed
21896          * 
21897          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21898          * @param {Event} e The event
21899          * @param {Object} data An object containing arbitrary data supplied by the drag source
21900          
21901          */
21902         "over" : true,
21903         /**
21904          * @event out
21905          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21906          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21907          * overClass (if any) from the drop element.
21908          * 
21909          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21910          * @param {Event} e The event
21911          * @param {Object} data An object containing arbitrary data supplied by the drag source
21912          */
21913          "out" : true,
21914          
21915         /**
21916          * @event drop
21917          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21918          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21919          * implementation that does something to process the drop event and returns true so that the drag source's
21920          * repair action does not run.
21921          * 
21922          * IMPORTANT : it should set this.success
21923          * 
21924          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21925          * @param {Event} e The event
21926          * @param {Object} data An object containing arbitrary data supplied by the drag source
21927         */
21928          "drop" : true
21929     });
21930             
21931      
21932     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21933         this.el.dom, 
21934         this.ddGroup || this.group,
21935         {
21936             isTarget: true,
21937             listeners : listeners || {} 
21938            
21939         
21940         }
21941     );
21942
21943 };
21944
21945 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21946     /**
21947      * @cfg {String} overClass
21948      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21949      */
21950      /**
21951      * @cfg {String} ddGroup
21952      * The drag drop group to handle drop events for
21953      */
21954      
21955     /**
21956      * @cfg {String} dropAllowed
21957      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21958      */
21959     dropAllowed : "x-dd-drop-ok",
21960     /**
21961      * @cfg {String} dropNotAllowed
21962      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21963      */
21964     dropNotAllowed : "x-dd-drop-nodrop",
21965     /**
21966      * @cfg {boolean} success
21967      * set this after drop listener.. 
21968      */
21969     success : false,
21970     /**
21971      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21972      * if the drop point is valid for over/enter..
21973      */
21974     valid : false,
21975     // private
21976     isTarget : true,
21977
21978     // private
21979     isNotifyTarget : true,
21980     
21981     /**
21982      * @hide
21983      */
21984     notifyEnter : function(dd, e, data)
21985     {
21986         this.valid = true;
21987         this.fireEvent('enter', dd, e, data);
21988         if(this.overClass){
21989             this.el.addClass(this.overClass);
21990         }
21991         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21992             this.valid ? this.dropAllowed : this.dropNotAllowed
21993         );
21994     },
21995
21996     /**
21997      * @hide
21998      */
21999     notifyOver : function(dd, e, data)
22000     {
22001         this.valid = true;
22002         this.fireEvent('over', dd, e, data);
22003         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22004             this.valid ? this.dropAllowed : this.dropNotAllowed
22005         );
22006     },
22007
22008     /**
22009      * @hide
22010      */
22011     notifyOut : function(dd, e, data)
22012     {
22013         this.fireEvent('out', dd, e, data);
22014         if(this.overClass){
22015             this.el.removeClass(this.overClass);
22016         }
22017     },
22018
22019     /**
22020      * @hide
22021      */
22022     notifyDrop : function(dd, e, data)
22023     {
22024         this.success = false;
22025         this.fireEvent('drop', dd, e, data);
22026         return this.success;
22027     }
22028 });/*
22029  * Based on:
22030  * Ext JS Library 1.1.1
22031  * Copyright(c) 2006-2007, Ext JS, LLC.
22032  *
22033  * Originally Released Under LGPL - original licence link has changed is not relivant.
22034  *
22035  * Fork - LGPL
22036  * <script type="text/javascript">
22037  */
22038
22039
22040 /**
22041  * @class Roo.dd.DragZone
22042  * @extends Roo.dd.DragSource
22043  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22044  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22045  * @constructor
22046  * @param {String/HTMLElement/Element} el The container element
22047  * @param {Object} config
22048  */
22049 Roo.dd.DragZone = function(el, config){
22050     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22051     if(this.containerScroll){
22052         Roo.dd.ScrollManager.register(this.el);
22053     }
22054 };
22055
22056 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22057     /**
22058      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22059      * for auto scrolling during drag operations.
22060      */
22061     /**
22062      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22063      * method after a failed drop (defaults to "c3daf9" - light blue)
22064      */
22065
22066     /**
22067      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22068      * for a valid target to drag based on the mouse down. Override this method
22069      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22070      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22071      * @param {EventObject} e The mouse down event
22072      * @return {Object} The dragData
22073      */
22074     getDragData : function(e){
22075         return Roo.dd.Registry.getHandleFromEvent(e);
22076     },
22077     
22078     /**
22079      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22080      * this.dragData.ddel
22081      * @param {Number} x The x position of the click on the dragged object
22082      * @param {Number} y The y position of the click on the dragged object
22083      * @return {Boolean} true to continue the drag, false to cancel
22084      */
22085     onInitDrag : function(x, y){
22086         this.proxy.update(this.dragData.ddel.cloneNode(true));
22087         this.onStartDrag(x, y);
22088         return true;
22089     },
22090     
22091     /**
22092      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22093      */
22094     afterRepair : function(){
22095         if(Roo.enableFx){
22096             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22097         }
22098         this.dragging = false;
22099     },
22100
22101     /**
22102      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22103      * the XY of this.dragData.ddel
22104      * @param {EventObject} e The mouse up event
22105      * @return {Array} The xy location (e.g. [100, 200])
22106      */
22107     getRepairXY : function(e){
22108         return Roo.Element.fly(this.dragData.ddel).getXY();  
22109     }
22110 });/*
22111  * Based on:
22112  * Ext JS Library 1.1.1
22113  * Copyright(c) 2006-2007, Ext JS, LLC.
22114  *
22115  * Originally Released Under LGPL - original licence link has changed is not relivant.
22116  *
22117  * Fork - LGPL
22118  * <script type="text/javascript">
22119  */
22120 /**
22121  * @class Roo.dd.DropZone
22122  * @extends Roo.dd.DropTarget
22123  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22124  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22125  * @constructor
22126  * @param {String/HTMLElement/Element} el The container element
22127  * @param {Object} config
22128  */
22129 Roo.dd.DropZone = function(el, config){
22130     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22131 };
22132
22133 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22134     /**
22135      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22136      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22137      * provide your own custom lookup.
22138      * @param {Event} e The event
22139      * @return {Object} data The custom data
22140      */
22141     getTargetFromEvent : function(e){
22142         return Roo.dd.Registry.getTargetFromEvent(e);
22143     },
22144
22145     /**
22146      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22147      * that it has registered.  This method has no default implementation and should be overridden to provide
22148      * node-specific processing if necessary.
22149      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22150      * {@link #getTargetFromEvent} for this node)
22151      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22152      * @param {Event} e The event
22153      * @param {Object} data An object containing arbitrary data supplied by the drag source
22154      */
22155     onNodeEnter : function(n, dd, e, data){
22156         
22157     },
22158
22159     /**
22160      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22161      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22162      * overridden to provide the proper feedback.
22163      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22164      * {@link #getTargetFromEvent} for this node)
22165      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22166      * @param {Event} e The event
22167      * @param {Object} data An object containing arbitrary data supplied by the drag source
22168      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22169      * underlying {@link Roo.dd.StatusProxy} can be updated
22170      */
22171     onNodeOver : function(n, dd, e, data){
22172         return this.dropAllowed;
22173     },
22174
22175     /**
22176      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22177      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22178      * node-specific processing if necessary.
22179      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22180      * {@link #getTargetFromEvent} for this node)
22181      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22182      * @param {Event} e The event
22183      * @param {Object} data An object containing arbitrary data supplied by the drag source
22184      */
22185     onNodeOut : function(n, dd, e, data){
22186         
22187     },
22188
22189     /**
22190      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22191      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22192      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22193      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22194      * {@link #getTargetFromEvent} for this node)
22195      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22196      * @param {Event} e The event
22197      * @param {Object} data An object containing arbitrary data supplied by the drag source
22198      * @return {Boolean} True if the drop was valid, else false
22199      */
22200     onNodeDrop : function(n, dd, e, data){
22201         return false;
22202     },
22203
22204     /**
22205      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22206      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22207      * it should be overridden to provide the proper feedback if necessary.
22208      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22209      * @param {Event} e The event
22210      * @param {Object} data An object containing arbitrary data supplied by the drag source
22211      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22212      * underlying {@link Roo.dd.StatusProxy} can be updated
22213      */
22214     onContainerOver : function(dd, e, data){
22215         return this.dropNotAllowed;
22216     },
22217
22218     /**
22219      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22220      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22221      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22222      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22223      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22224      * @param {Event} e The event
22225      * @param {Object} data An object containing arbitrary data supplied by the drag source
22226      * @return {Boolean} True if the drop was valid, else false
22227      */
22228     onContainerDrop : function(dd, e, data){
22229         return false;
22230     },
22231
22232     /**
22233      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22234      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22235      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22236      * you should override this method and provide a custom implementation.
22237      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22238      * @param {Event} e The event
22239      * @param {Object} data An object containing arbitrary data supplied by the drag source
22240      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22241      * underlying {@link Roo.dd.StatusProxy} can be updated
22242      */
22243     notifyEnter : function(dd, e, data){
22244         return this.dropNotAllowed;
22245     },
22246
22247     /**
22248      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22249      * This method will be called on every mouse movement while the drag source is over the drop zone.
22250      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22251      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22252      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22253      * registered node, it will call {@link #onContainerOver}.
22254      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22255      * @param {Event} e The event
22256      * @param {Object} data An object containing arbitrary data supplied by the drag source
22257      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22258      * underlying {@link Roo.dd.StatusProxy} can be updated
22259      */
22260     notifyOver : function(dd, e, data){
22261         var n = this.getTargetFromEvent(e);
22262         if(!n){ // not over valid drop target
22263             if(this.lastOverNode){
22264                 this.onNodeOut(this.lastOverNode, dd, e, data);
22265                 this.lastOverNode = null;
22266             }
22267             return this.onContainerOver(dd, e, data);
22268         }
22269         if(this.lastOverNode != n){
22270             if(this.lastOverNode){
22271                 this.onNodeOut(this.lastOverNode, dd, e, data);
22272             }
22273             this.onNodeEnter(n, dd, e, data);
22274             this.lastOverNode = n;
22275         }
22276         return this.onNodeOver(n, dd, e, data);
22277     },
22278
22279     /**
22280      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22281      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22282      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22283      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22284      * @param {Event} e The event
22285      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22286      */
22287     notifyOut : function(dd, e, data){
22288         if(this.lastOverNode){
22289             this.onNodeOut(this.lastOverNode, dd, e, data);
22290             this.lastOverNode = null;
22291         }
22292     },
22293
22294     /**
22295      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22296      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22297      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22298      * otherwise it will call {@link #onContainerDrop}.
22299      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22300      * @param {Event} e The event
22301      * @param {Object} data An object containing arbitrary data supplied by the drag source
22302      * @return {Boolean} True if the drop was valid, else false
22303      */
22304     notifyDrop : function(dd, e, data){
22305         if(this.lastOverNode){
22306             this.onNodeOut(this.lastOverNode, dd, e, data);
22307             this.lastOverNode = null;
22308         }
22309         var n = this.getTargetFromEvent(e);
22310         return n ?
22311             this.onNodeDrop(n, dd, e, data) :
22312             this.onContainerDrop(dd, e, data);
22313     },
22314
22315     // private
22316     triggerCacheRefresh : function(){
22317         Roo.dd.DDM.refreshCache(this.groups);
22318     }  
22319 });