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  * @static
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         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             
346             console.log(s);
347         },
348         /**
349          * 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.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * 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]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         },
672                 /**
673                  * Find the current bootstrap width Grid size
674                  * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675                  * @returns {String} (xs|sm|md|lg|xl)
676                  */
677                 
678                 getGridSize : function()
679                 {
680                         var w = Roo.lib.Dom.getViewWidth();
681                         switch(true) {
682                                 case w > 1200:
683                                         return 'xl';
684                                 case w > 992:
685                                         return 'lg';
686                                 case w > 768:
687                                         return 'md';
688                                 case w > 576:
689                                         return 'sm';
690                                 default:
691                                         return 'xs'
692                         }
693                         
694                 }
695         
696     });
697
698
699 })();
700
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
703                 "Roo.app", "Roo.ux",
704                 "Roo.bootstrap",
705                 "Roo.bootstrap.dash");
706 /*
707  * Based on:
708  * Ext JS Library 1.1.1
709  * Copyright(c) 2006-2007, Ext JS, LLC.
710  *
711  * Originally Released Under LGPL - original licence link has changed is not relivant.
712  *
713  * Fork - LGPL
714  * <script type="text/javascript">
715  */
716
717 (function() {    
718     // wrappedn so fnCleanup is not in global scope...
719     if(Roo.isIE) {
720         function fnCleanUp() {
721             var p = Function.prototype;
722             delete p.createSequence;
723             delete p.defer;
724             delete p.createDelegate;
725             delete p.createCallback;
726             delete p.createInterceptor;
727
728             window.detachEvent("onunload", fnCleanUp);
729         }
730         window.attachEvent("onunload", fnCleanUp);
731     }
732 })();
733
734
735 /**
736  * @class Function
737  * These functions are available on every Function object (any JavaScript function).
738  */
739 Roo.apply(Function.prototype, {
740      /**
741      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
742      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
743      * Will create a function that is bound to those 2 args.
744      * @return {Function} The new function
745     */
746     createCallback : function(/*args...*/){
747         // make args available, in function below
748         var args = arguments;
749         var method = this;
750         return function() {
751             return method.apply(window, args);
752         };
753     },
754
755     /**
756      * Creates a delegate (callback) that sets the scope to obj.
757      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
758      * Will create a function that is automatically scoped to this.
759      * @param {Object} obj (optional) The object for which the scope is set
760      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
761      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
762      *                                             if a number the args are inserted at the specified position
763      * @return {Function} The new function
764      */
765     createDelegate : function(obj, args, appendArgs){
766         var method = this;
767         return function() {
768             var callArgs = args || arguments;
769             if(appendArgs === true){
770                 callArgs = Array.prototype.slice.call(arguments, 0);
771                 callArgs = callArgs.concat(args);
772             }else if(typeof appendArgs == "number"){
773                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
774                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
775                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
776             }
777             return method.apply(obj || window, callArgs);
778         };
779     },
780
781     /**
782      * Calls this function after the number of millseconds specified.
783      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
784      * @param {Object} obj (optional) The object for which the scope is set
785      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
786      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
787      *                                             if a number the args are inserted at the specified position
788      * @return {Number} The timeout id that can be used with clearTimeout
789      */
790     defer : function(millis, obj, args, appendArgs){
791         var fn = this.createDelegate(obj, args, appendArgs);
792         if(millis){
793             return setTimeout(fn, millis);
794         }
795         fn();
796         return 0;
797     },
798     /**
799      * Create a combined function call sequence of the original function + the passed function.
800      * The resulting function returns the results of the original function.
801      * The passed fcn is called with the parameters of the original function
802      * @param {Function} fcn The function to sequence
803      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
804      * @return {Function} The new function
805      */
806     createSequence : function(fcn, scope){
807         if(typeof fcn != "function"){
808             return this;
809         }
810         var method = this;
811         return function() {
812             var retval = method.apply(this || window, arguments);
813             fcn.apply(scope || this || window, arguments);
814             return retval;
815         };
816     },
817
818     /**
819      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
820      * The resulting function returns the results of the original function.
821      * The passed fcn is called with the parameters of the original function.
822      * @addon
823      * @param {Function} fcn The function to call before the original
824      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
825      * @return {Function} The new function
826      */
827     createInterceptor : function(fcn, scope){
828         if(typeof fcn != "function"){
829             return this;
830         }
831         var method = this;
832         return function() {
833             fcn.target = this;
834             fcn.method = method;
835             if(fcn.apply(scope || this || window, arguments) === false){
836                 return;
837             }
838             return method.apply(this || window, arguments);
839         };
840     }
841 });
842 /*
843  * Based on:
844  * Ext JS Library 1.1.1
845  * Copyright(c) 2006-2007, Ext JS, LLC.
846  *
847  * Originally Released Under LGPL - original licence link has changed is not relivant.
848  *
849  * Fork - LGPL
850  * <script type="text/javascript">
851  */
852
853 Roo.applyIf(String, {
854     
855     /** @scope String */
856     
857     /**
858      * Escapes the passed string for ' and \
859      * @param {String} string The string to escape
860      * @return {String} The escaped string
861      * @static
862      */
863     escape : function(string) {
864         return string.replace(/('|\\)/g, "\\$1");
865     },
866
867     /**
868      * Pads the left side of a string with a specified character.  This is especially useful
869      * for normalizing number and date strings.  Example usage:
870      * <pre><code>
871 var s = String.leftPad('123', 5, '0');
872 // s now contains the string: '00123'
873 </code></pre>
874      * @param {String} string The original string
875      * @param {Number} size The total length of the output string
876      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
877      * @return {String} The padded string
878      * @static
879      */
880     leftPad : function (val, size, ch) {
881         var result = new String(val);
882         if(ch === null || ch === undefined || ch === '') {
883             ch = " ";
884         }
885         while (result.length < size) {
886             result = ch + result;
887         }
888         return result;
889     },
890
891     /**
892      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
893      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
894      * <pre><code>
895 var cls = 'my-class', text = 'Some text';
896 var s = String.format('<div class="{0}">{1}</div>', cls, text);
897 // s now contains the string: '<div class="my-class">Some text</div>'
898 </code></pre>
899      * @param {String} string The tokenized string to be formatted
900      * @param {String} value1 The value to replace token {0}
901      * @param {String} value2 Etc...
902      * @return {String} The formatted string
903      * @static
904      */
905     format : function(format){
906         var args = Array.prototype.slice.call(arguments, 1);
907         return format.replace(/\{(\d+)\}/g, function(m, i){
908             return Roo.util.Format.htmlEncode(args[i]);
909         });
910     }
911   
912     
913 });
914
915 /**
916  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
917  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
918  * they are already different, the first value passed in is returned.  Note that this method returns the new value
919  * but does not change the current string.
920  * <pre><code>
921 // alternate sort directions
922 sort = sort.toggle('ASC', 'DESC');
923
924 // instead of conditional logic:
925 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
926 </code></pre>
927  * @param {String} value The value to compare to the current string
928  * @param {String} other The new value to use if the string already equals the first value passed in
929  * @return {String} The new value
930  */
931  
932 String.prototype.toggle = function(value, other){
933     return this == value ? other : value;
934 };
935
936
937 /**
938   * Remove invalid unicode characters from a string 
939   *
940   * @return {String} The clean string
941   */
942 String.prototype.unicodeClean = function () {
943     return this.replace(/[\s\S]/g,
944         function(character) {
945             if (character.charCodeAt()< 256) {
946               return character;
947            }
948            try {
949                 encodeURIComponent(character);
950            } catch(e) { 
951               return '';
952            }
953            return character;
954         }
955     );
956 };
957   
958 /*
959  * Based on:
960  * Ext JS Library 1.1.1
961  * Copyright(c) 2006-2007, Ext JS, LLC.
962  *
963  * Originally Released Under LGPL - original licence link has changed is not relivant.
964  *
965  * Fork - LGPL
966  * <script type="text/javascript">
967  */
968
969  /**
970  * @class Number
971  */
972 Roo.applyIf(Number.prototype, {
973     /**
974      * Checks whether or not the current number is within a desired range.  If the number is already within the
975      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
976      * exceeded.  Note that this method returns the constrained value but does not change the current number.
977      * @param {Number} min The minimum number in the range
978      * @param {Number} max The maximum number in the range
979      * @return {Number} The constrained value if outside the range, otherwise the current value
980      */
981     constrain : function(min, max){
982         return Math.min(Math.max(this, min), max);
983     }
984 });/*
985  * Based on:
986  * Ext JS Library 1.1.1
987  * Copyright(c) 2006-2007, Ext JS, LLC.
988  *
989  * Originally Released Under LGPL - original licence link has changed is not relivant.
990  *
991  * Fork - LGPL
992  * <script type="text/javascript">
993  */
994  /**
995  * @class Array
996  */
997 Roo.applyIf(Array.prototype, {
998     /**
999      * 
1000      * Checks whether or not the specified object exists in the array.
1001      * @param {Object} o The object to check for
1002      * @return {Number} The index of o in the array (or -1 if it is not found)
1003      */
1004     indexOf : function(o){
1005        for (var i = 0, len = this.length; i < len; i++){
1006               if(this[i] == o) { return i; }
1007        }
1008            return -1;
1009     },
1010
1011     /**
1012      * Removes the specified object from the array.  If the object is not found nothing happens.
1013      * @param {Object} o The object to remove
1014      */
1015     remove : function(o){
1016        var index = this.indexOf(o);
1017        if(index != -1){
1018            this.splice(index, 1);
1019        }
1020     },
1021     /**
1022      * Map (JS 1.6 compatibility)
1023      * @param {Function} function  to call
1024      */
1025     map : function(fun )
1026     {
1027         var len = this.length >>> 0;
1028         if (typeof fun != "function") {
1029             throw new TypeError();
1030         }
1031         var res = new Array(len);
1032         var thisp = arguments[1];
1033         for (var i = 0; i < len; i++)
1034         {
1035             if (i in this) {
1036                 res[i] = fun.call(thisp, this[i], i, this);
1037             }
1038         }
1039
1040         return res;
1041     },
1042     /**
1043      * equals
1044      * @param {Array} o The array to compare to
1045      * @returns {Boolean} true if the same
1046      */
1047     equals : function(b)
1048     {
1049             // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1050         if (this === b) {
1051             return true;
1052         }
1053         if (b == null) {
1054             return false;
1055         }
1056         if (this.length !== b.length) {
1057             return false;
1058         }
1059           
1060         // sort?? a.sort().equals(b.sort());
1061           
1062         for (var i = 0; i < this.length; ++i) {
1063             if (this[i] !== b[i]) {
1064             return false;
1065             }
1066         }
1067         return true;
1068     } 
1069     
1070     
1071     
1072     
1073 });
1074
1075 Roo.applyIf(Array, {
1076  /**
1077      * from
1078      * @static
1079      * @param {Array} o Or Array like object (eg. nodelist)
1080      * @returns {Array} 
1081      */
1082     from : function(o)
1083     {
1084         var ret= [];
1085     
1086         for (var i =0; i < o.length; i++) { 
1087             ret[i] = o[i];
1088         }
1089         return ret;
1090       
1091     }
1092 });
1093 /*
1094  * Based on:
1095  * Ext JS Library 1.1.1
1096  * Copyright(c) 2006-2007, Ext JS, LLC.
1097  *
1098  * Originally Released Under LGPL - original licence link has changed is not relivant.
1099  *
1100  * Fork - LGPL
1101  * <script type="text/javascript">
1102  */
1103
1104 /**
1105  * @class Date
1106  *
1107  * The date parsing and format syntax is a subset of
1108  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1109  * supported will provide results equivalent to their PHP versions.
1110  *
1111  * Following is the list of all currently supported formats:
1112  *<pre>
1113 Sample date:
1114 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1115
1116 Format  Output      Description
1117 ------  ----------  --------------------------------------------------------------
1118   d      10         Day of the month, 2 digits with leading zeros
1119   D      Wed        A textual representation of a day, three letters
1120   j      10         Day of the month without leading zeros
1121   l      Wednesday  A full textual representation of the day of the week
1122   S      th         English ordinal day of month suffix, 2 chars (use with j)
1123   w      3          Numeric representation of the day of the week
1124   z      9          The julian date, or day of the year (0-365)
1125   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1126   F      January    A full textual representation of the month
1127   m      01         Numeric representation of a month, with leading zeros
1128   M      Jan        Month name abbreviation, three letters
1129   n      1          Numeric representation of a month, without leading zeros
1130   t      31         Number of days in the given month
1131   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1132   Y      2007       A full numeric representation of a year, 4 digits
1133   y      07         A two digit representation of a year
1134   a      pm         Lowercase Ante meridiem and Post meridiem
1135   A      PM         Uppercase Ante meridiem and Post meridiem
1136   g      3          12-hour format of an hour without leading zeros
1137   G      15         24-hour format of an hour without leading zeros
1138   h      03         12-hour format of an hour with leading zeros
1139   H      15         24-hour format of an hour with leading zeros
1140   i      05         Minutes with leading zeros
1141   s      01         Seconds, with leading zeros
1142   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1143   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1144   T      CST        Timezone setting of the machine running the code
1145   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1146 </pre>
1147  *
1148  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1149  * <pre><code>
1150 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1151 document.write(dt.format('Y-m-d'));                         //2007-01-10
1152 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1153 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
1154  </code></pre>
1155  *
1156  * Here are some standard date/time patterns that you might find helpful.  They
1157  * are not part of the source of Date.js, but to use them you can simply copy this
1158  * block of code into any script that is included after Date.js and they will also become
1159  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1160  * <pre><code>
1161 Date.patterns = {
1162     ISO8601Long:"Y-m-d H:i:s",
1163     ISO8601Short:"Y-m-d",
1164     ShortDate: "n/j/Y",
1165     LongDate: "l, F d, Y",
1166     FullDateTime: "l, F d, Y g:i:s A",
1167     MonthDay: "F d",
1168     ShortTime: "g:i A",
1169     LongTime: "g:i:s A",
1170     SortableDateTime: "Y-m-d\\TH:i:s",
1171     UniversalSortableDateTime: "Y-m-d H:i:sO",
1172     YearMonth: "F, Y"
1173 };
1174 </code></pre>
1175  *
1176  * Example usage:
1177  * <pre><code>
1178 var dt = new Date();
1179 document.write(dt.format(Date.patterns.ShortDate));
1180  </code></pre>
1181  */
1182
1183 /*
1184  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1185  * They generate precompiled functions from date formats instead of parsing and
1186  * processing the pattern every time you format a date.  These functions are available
1187  * on every Date object (any javascript function).
1188  *
1189  * The original article and download are here:
1190  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1191  *
1192  */
1193  
1194  
1195  // was in core
1196 /**
1197  Returns the number of milliseconds between this date and date
1198  @param {Date} date (optional) Defaults to now
1199  @return {Number} The diff in milliseconds
1200  @member Date getElapsed
1201  */
1202 Date.prototype.getElapsed = function(date) {
1203         return Math.abs((date || new Date()).getTime()-this.getTime());
1204 };
1205 // was in date file..
1206
1207
1208 // private
1209 Date.parseFunctions = {count:0};
1210 // private
1211 Date.parseRegexes = [];
1212 // private
1213 Date.formatFunctions = {count:0};
1214
1215 // private
1216 Date.prototype.dateFormat = function(format) {
1217     if (Date.formatFunctions[format] == null) {
1218         Date.createNewFormat(format);
1219     }
1220     var func = Date.formatFunctions[format];
1221     return this[func]();
1222 };
1223
1224
1225 /**
1226  * Formats a date given the supplied format string
1227  * @param {String} format The format string
1228  * @return {String} The formatted date
1229  * @method
1230  */
1231 Date.prototype.format = Date.prototype.dateFormat;
1232
1233 // private
1234 Date.createNewFormat = function(format) {
1235     var funcName = "format" + Date.formatFunctions.count++;
1236     Date.formatFunctions[format] = funcName;
1237     var code = "Date.prototype." + funcName + " = function(){return ";
1238     var special = false;
1239     var ch = '';
1240     for (var i = 0; i < format.length; ++i) {
1241         ch = format.charAt(i);
1242         if (!special && ch == "\\") {
1243             special = true;
1244         }
1245         else if (special) {
1246             special = false;
1247             code += "'" + String.escape(ch) + "' + ";
1248         }
1249         else {
1250             code += Date.getFormatCode(ch);
1251         }
1252     }
1253     /** eval:var:zzzzzzzzzzzzz */
1254     eval(code.substring(0, code.length - 3) + ";}");
1255 };
1256
1257 // private
1258 Date.getFormatCode = function(character) {
1259     switch (character) {
1260     case "d":
1261         return "String.leftPad(this.getDate(), 2, '0') + ";
1262     case "D":
1263         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1264     case "j":
1265         return "this.getDate() + ";
1266     case "l":
1267         return "Date.dayNames[this.getDay()] + ";
1268     case "S":
1269         return "this.getSuffix() + ";
1270     case "w":
1271         return "this.getDay() + ";
1272     case "z":
1273         return "this.getDayOfYear() + ";
1274     case "W":
1275         return "this.getWeekOfYear() + ";
1276     case "F":
1277         return "Date.monthNames[this.getMonth()] + ";
1278     case "m":
1279         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1280     case "M":
1281         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1282     case "n":
1283         return "(this.getMonth() + 1) + ";
1284     case "t":
1285         return "this.getDaysInMonth() + ";
1286     case "L":
1287         return "(this.isLeapYear() ? 1 : 0) + ";
1288     case "Y":
1289         return "this.getFullYear() + ";
1290     case "y":
1291         return "('' + this.getFullYear()).substring(2, 4) + ";
1292     case "a":
1293         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1294     case "A":
1295         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1296     case "g":
1297         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1298     case "G":
1299         return "this.getHours() + ";
1300     case "h":
1301         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1302     case "H":
1303         return "String.leftPad(this.getHours(), 2, '0') + ";
1304     case "i":
1305         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1306     case "s":
1307         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1308     case "O":
1309         return "this.getGMTOffset() + ";
1310     case "P":
1311         return "this.getGMTColonOffset() + ";
1312     case "T":
1313         return "this.getTimezone() + ";
1314     case "Z":
1315         return "(this.getTimezoneOffset() * -60) + ";
1316     default:
1317         return "'" + String.escape(character) + "' + ";
1318     }
1319 };
1320
1321 /**
1322  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1323  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1324  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1325  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1326  * string or the parse operation will fail.
1327  * Example Usage:
1328 <pre><code>
1329 //dt = Fri May 25 2007 (current date)
1330 var dt = new Date();
1331
1332 //dt = Thu May 25 2006 (today's month/day in 2006)
1333 dt = Date.parseDate("2006", "Y");
1334
1335 //dt = Sun Jan 15 2006 (all date parts specified)
1336 dt = Date.parseDate("2006-1-15", "Y-m-d");
1337
1338 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1339 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1340 </code></pre>
1341  * @param {String} input The unparsed date as a string
1342  * @param {String} format The format the date is in
1343  * @return {Date} The parsed date
1344  * @static
1345  */
1346 Date.parseDate = function(input, format) {
1347     if (Date.parseFunctions[format] == null) {
1348         Date.createParser(format);
1349     }
1350     var func = Date.parseFunctions[format];
1351     return Date[func](input);
1352 };
1353 /**
1354  * @private
1355  */
1356
1357 Date.createParser = function(format) {
1358     var funcName = "parse" + Date.parseFunctions.count++;
1359     var regexNum = Date.parseRegexes.length;
1360     var currentGroup = 1;
1361     Date.parseFunctions[format] = funcName;
1362
1363     var code = "Date." + funcName + " = function(input){\n"
1364         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1365         + "var d = new Date();\n"
1366         + "y = d.getFullYear();\n"
1367         + "m = d.getMonth();\n"
1368         + "d = d.getDate();\n"
1369         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1370         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1371         + "if (results && results.length > 0) {";
1372     var regex = "";
1373
1374     var special = false;
1375     var ch = '';
1376     for (var i = 0; i < format.length; ++i) {
1377         ch = format.charAt(i);
1378         if (!special && ch == "\\") {
1379             special = true;
1380         }
1381         else if (special) {
1382             special = false;
1383             regex += String.escape(ch);
1384         }
1385         else {
1386             var obj = Date.formatCodeToRegex(ch, currentGroup);
1387             currentGroup += obj.g;
1388             regex += obj.s;
1389             if (obj.g && obj.c) {
1390                 code += obj.c;
1391             }
1392         }
1393     }
1394
1395     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1396         + "{v = new Date(y, m, d, h, i, s);}\n"
1397         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1398         + "{v = new Date(y, m, d, h, i);}\n"
1399         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1400         + "{v = new Date(y, m, d, h);}\n"
1401         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1402         + "{v = new Date(y, m, d);}\n"
1403         + "else if (y >= 0 && m >= 0)\n"
1404         + "{v = new Date(y, m);}\n"
1405         + "else if (y >= 0)\n"
1406         + "{v = new Date(y);}\n"
1407         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1408         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1409         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1410         + ";}";
1411
1412     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1413     /** eval:var:zzzzzzzzzzzzz */
1414     eval(code);
1415 };
1416
1417 // private
1418 Date.formatCodeToRegex = function(character, currentGroup) {
1419     switch (character) {
1420     case "D":
1421         return {g:0,
1422         c:null,
1423         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1424     case "j":
1425         return {g:1,
1426             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1427             s:"(\\d{1,2})"}; // day of month without leading zeroes
1428     case "d":
1429         return {g:1,
1430             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1431             s:"(\\d{2})"}; // day of month with leading zeroes
1432     case "l":
1433         return {g:0,
1434             c:null,
1435             s:"(?:" + Date.dayNames.join("|") + ")"};
1436     case "S":
1437         return {g:0,
1438             c:null,
1439             s:"(?:st|nd|rd|th)"};
1440     case "w":
1441         return {g:0,
1442             c:null,
1443             s:"\\d"};
1444     case "z":
1445         return {g:0,
1446             c:null,
1447             s:"(?:\\d{1,3})"};
1448     case "W":
1449         return {g:0,
1450             c:null,
1451             s:"(?:\\d{2})"};
1452     case "F":
1453         return {g:1,
1454             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1455             s:"(" + Date.monthNames.join("|") + ")"};
1456     case "M":
1457         return {g:1,
1458             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1459             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1460     case "n":
1461         return {g:1,
1462             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1463             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1464     case "m":
1465         return {g:1,
1466             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1467             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1468     case "t":
1469         return {g:0,
1470             c:null,
1471             s:"\\d{1,2}"};
1472     case "L":
1473         return {g:0,
1474             c:null,
1475             s:"(?:1|0)"};
1476     case "Y":
1477         return {g:1,
1478             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1479             s:"(\\d{4})"};
1480     case "y":
1481         return {g:1,
1482             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1483                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1484             s:"(\\d{1,2})"};
1485     case "a":
1486         return {g:1,
1487             c:"if (results[" + currentGroup + "] == 'am') {\n"
1488                 + "if (h == 12) { h = 0; }\n"
1489                 + "} else { if (h < 12) { h += 12; }}",
1490             s:"(am|pm)"};
1491     case "A":
1492         return {g:1,
1493             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1494                 + "if (h == 12) { h = 0; }\n"
1495                 + "} else { if (h < 12) { h += 12; }}",
1496             s:"(AM|PM)"};
1497     case "g":
1498     case "G":
1499         return {g:1,
1500             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1501             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1502     case "h":
1503     case "H":
1504         return {g:1,
1505             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1506             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1507     case "i":
1508         return {g:1,
1509             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1510             s:"(\\d{2})"};
1511     case "s":
1512         return {g:1,
1513             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1514             s:"(\\d{2})"};
1515     case "O":
1516         return {g:1,
1517             c:[
1518                 "o = results[", currentGroup, "];\n",
1519                 "var sn = o.substring(0,1);\n", // get + / - sign
1520                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1521                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1522                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1523                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1524             ].join(""),
1525             s:"([+\-]\\d{2,4})"};
1526     
1527     
1528     case "P":
1529         return {g:1,
1530                 c:[
1531                    "o = results[", currentGroup, "];\n",
1532                    "var sn = o.substring(0,1);\n",
1533                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1534                    "var mn = o.substring(4,6) % 60;\n",
1535                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1536                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1537             ].join(""),
1538             s:"([+\-]\\d{4})"};
1539     case "T":
1540         return {g:0,
1541             c:null,
1542             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1543     case "Z":
1544         return {g:1,
1545             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1546                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1547             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1548     default:
1549         return {g:0,
1550             c:null,
1551             s:String.escape(character)};
1552     }
1553 };
1554
1555 /**
1556  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1557  * @return {String} The abbreviated timezone name (e.g. 'CST')
1558  */
1559 Date.prototype.getTimezone = function() {
1560     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1561 };
1562
1563 /**
1564  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1565  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1566  */
1567 Date.prototype.getGMTOffset = function() {
1568     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1569         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1570         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1571 };
1572
1573 /**
1574  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1575  * @return {String} 2-characters representing hours and 2-characters representing minutes
1576  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1577  */
1578 Date.prototype.getGMTColonOffset = function() {
1579         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1580                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1581                 + ":"
1582                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1583 }
1584
1585 /**
1586  * Get the numeric day number of the year, adjusted for leap year.
1587  * @return {Number} 0 through 364 (365 in leap years)
1588  */
1589 Date.prototype.getDayOfYear = function() {
1590     var num = 0;
1591     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1592     for (var i = 0; i < this.getMonth(); ++i) {
1593         num += Date.daysInMonth[i];
1594     }
1595     return num + this.getDate() - 1;
1596 };
1597
1598 /**
1599  * Get the string representation of the numeric week number of the year
1600  * (equivalent to the format specifier 'W').
1601  * @return {String} '00' through '52'
1602  */
1603 Date.prototype.getWeekOfYear = function() {
1604     // Skip to Thursday of this week
1605     var now = this.getDayOfYear() + (4 - this.getDay());
1606     // Find the first Thursday of the year
1607     var jan1 = new Date(this.getFullYear(), 0, 1);
1608     var then = (7 - jan1.getDay() + 4);
1609     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1610 };
1611
1612 /**
1613  * Whether or not the current date is in a leap year.
1614  * @return {Boolean} True if the current date is in a leap year, else false
1615  */
1616 Date.prototype.isLeapYear = function() {
1617     var year = this.getFullYear();
1618     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1619 };
1620
1621 /**
1622  * Get the first day of the current month, adjusted for leap year.  The returned value
1623  * is the numeric day index within the week (0-6) which can be used in conjunction with
1624  * the {@link #monthNames} array to retrieve the textual day name.
1625  * Example:
1626  *<pre><code>
1627 var dt = new Date('1/10/2007');
1628 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1629 </code></pre>
1630  * @return {Number} The day number (0-6)
1631  */
1632 Date.prototype.getFirstDayOfMonth = function() {
1633     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1634     return (day < 0) ? (day + 7) : day;
1635 };
1636
1637 /**
1638  * Get the last day of the current month, adjusted for leap year.  The returned value
1639  * is the numeric day index within the week (0-6) which can be used in conjunction with
1640  * the {@link #monthNames} array to retrieve the textual day name.
1641  * Example:
1642  *<pre><code>
1643 var dt = new Date('1/10/2007');
1644 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1645 </code></pre>
1646  * @return {Number} The day number (0-6)
1647  */
1648 Date.prototype.getLastDayOfMonth = function() {
1649     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1650     return (day < 0) ? (day + 7) : day;
1651 };
1652
1653
1654 /**
1655  * Get the first date of this date's month
1656  * @return {Date}
1657  */
1658 Date.prototype.getFirstDateOfMonth = function() {
1659     return new Date(this.getFullYear(), this.getMonth(), 1);
1660 };
1661
1662 /**
1663  * Get the last date of this date's month
1664  * @return {Date}
1665  */
1666 Date.prototype.getLastDateOfMonth = function() {
1667     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1668 };
1669 /**
1670  * Get the number of days in the current month, adjusted for leap year.
1671  * @return {Number} The number of days in the month
1672  */
1673 Date.prototype.getDaysInMonth = function() {
1674     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1675     return Date.daysInMonth[this.getMonth()];
1676 };
1677
1678 /**
1679  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1680  * @return {String} 'st, 'nd', 'rd' or 'th'
1681  */
1682 Date.prototype.getSuffix = function() {
1683     switch (this.getDate()) {
1684         case 1:
1685         case 21:
1686         case 31:
1687             return "st";
1688         case 2:
1689         case 22:
1690             return "nd";
1691         case 3:
1692         case 23:
1693             return "rd";
1694         default:
1695             return "th";
1696     }
1697 };
1698
1699 // private
1700 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1701
1702 /**
1703  * An array of textual month names.
1704  * Override these values for international dates, for example...
1705  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1706  * @type Array
1707  * @static
1708  */
1709 Date.monthNames =
1710    ["January",
1711     "February",
1712     "March",
1713     "April",
1714     "May",
1715     "June",
1716     "July",
1717     "August",
1718     "September",
1719     "October",
1720     "November",
1721     "December"];
1722
1723 /**
1724  * An array of textual day names.
1725  * Override these values for international dates, for example...
1726  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1727  * @type Array
1728  * @static
1729  */
1730 Date.dayNames =
1731    ["Sunday",
1732     "Monday",
1733     "Tuesday",
1734     "Wednesday",
1735     "Thursday",
1736     "Friday",
1737     "Saturday"];
1738
1739 // private
1740 Date.y2kYear = 50;
1741 // private
1742 Date.monthNumbers = {
1743     Jan:0,
1744     Feb:1,
1745     Mar:2,
1746     Apr:3,
1747     May:4,
1748     Jun:5,
1749     Jul:6,
1750     Aug:7,
1751     Sep:8,
1752     Oct:9,
1753     Nov:10,
1754     Dec:11};
1755
1756 /**
1757  * Creates and returns a new Date instance with the exact same date value as the called instance.
1758  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1759  * variable will also be changed.  When the intention is to create a new variable that will not
1760  * modify the original instance, you should create a clone.
1761  *
1762  * Example of correctly cloning a date:
1763  * <pre><code>
1764 //wrong way:
1765 var orig = new Date('10/1/2006');
1766 var copy = orig;
1767 copy.setDate(5);
1768 document.write(orig);  //returns 'Thu Oct 05 2006'!
1769
1770 //correct way:
1771 var orig = new Date('10/1/2006');
1772 var copy = orig.clone();
1773 copy.setDate(5);
1774 document.write(orig);  //returns 'Thu Oct 01 2006'
1775 </code></pre>
1776  * @return {Date} The new Date instance
1777  */
1778 Date.prototype.clone = function() {
1779         return new Date(this.getTime());
1780 };
1781
1782 /**
1783  * Clears any time information from this date
1784  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1785  @return {Date} this or the clone
1786  */
1787 Date.prototype.clearTime = function(clone){
1788     if(clone){
1789         return this.clone().clearTime();
1790     }
1791     this.setHours(0);
1792     this.setMinutes(0);
1793     this.setSeconds(0);
1794     this.setMilliseconds(0);
1795     return this;
1796 };
1797
1798 // private
1799 // safari setMonth is broken -- check that this is only donw once...
1800 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1801     Date.brokenSetMonth = Date.prototype.setMonth;
1802         Date.prototype.setMonth = function(num){
1803                 if(num <= -1){
1804                         var n = Math.ceil(-num);
1805                         var back_year = Math.ceil(n/12);
1806                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1807                         this.setFullYear(this.getFullYear() - back_year);
1808                         return Date.brokenSetMonth.call(this, month);
1809                 } else {
1810                         return Date.brokenSetMonth.apply(this, arguments);
1811                 }
1812         };
1813 }
1814
1815 /** Date interval constant 
1816 * @static 
1817 * @type String */
1818 Date.MILLI = "ms";
1819 /** Date interval constant 
1820 * @static 
1821 * @type String */
1822 Date.SECOND = "s";
1823 /** Date interval constant 
1824 * @static 
1825 * @type String */
1826 Date.MINUTE = "mi";
1827 /** Date interval constant 
1828 * @static 
1829 * @type String */
1830 Date.HOUR = "h";
1831 /** Date interval constant 
1832 * @static 
1833 * @type String */
1834 Date.DAY = "d";
1835 /** Date interval constant 
1836 * @static 
1837 * @type String */
1838 Date.MONTH = "mo";
1839 /** Date interval constant 
1840 * @static 
1841 * @type String */
1842 Date.YEAR = "y";
1843
1844 /**
1845  * Provides a convenient method of performing basic date arithmetic.  This method
1846  * does not modify the Date instance being called - it creates and returns
1847  * a new Date instance containing the resulting date value.
1848  *
1849  * Examples:
1850  * <pre><code>
1851 //Basic usage:
1852 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1853 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1854
1855 //Negative values will subtract correctly:
1856 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1857 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1858
1859 //You can even chain several calls together in one line!
1860 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1861 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1862  </code></pre>
1863  *
1864  * @param {String} interval   A valid date interval enum value
1865  * @param {Number} value      The amount to add to the current date
1866  * @return {Date} The new Date instance
1867  */
1868 Date.prototype.add = function(interval, value){
1869   var d = this.clone();
1870   if (!interval || value === 0) { return d; }
1871   switch(interval.toLowerCase()){
1872     case Date.MILLI:
1873       d.setMilliseconds(this.getMilliseconds() + value);
1874       break;
1875     case Date.SECOND:
1876       d.setSeconds(this.getSeconds() + value);
1877       break;
1878     case Date.MINUTE:
1879       d.setMinutes(this.getMinutes() + value);
1880       break;
1881     case Date.HOUR:
1882       d.setHours(this.getHours() + value);
1883       break;
1884     case Date.DAY:
1885       d.setDate(this.getDate() + value);
1886       break;
1887     case Date.MONTH:
1888       var day = this.getDate();
1889       if(day > 28){
1890           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1891       }
1892       d.setDate(day);
1893       d.setMonth(this.getMonth() + value);
1894       break;
1895     case Date.YEAR:
1896       d.setFullYear(this.getFullYear() + value);
1897       break;
1898   }
1899   return d;
1900 };
1901 /**
1902  * @class Roo.lib.Dom
1903  * @licence LGPL
1904  * @static
1905  * 
1906  * Dom utils (from YIU afaik)
1907  *
1908  * 
1909  **/
1910 Roo.lib.Dom = {
1911     /**
1912      * Get the view width
1913      * @param {Boolean} full True will get the full document, otherwise it's the view width
1914      * @return {Number} The width
1915      */
1916      
1917     getViewWidth : function(full) {
1918         return full ? this.getDocumentWidth() : this.getViewportWidth();
1919     },
1920     /**
1921      * Get the view height
1922      * @param {Boolean} full True will get the full document, otherwise it's the view height
1923      * @return {Number} The height
1924      */
1925     getViewHeight : function(full) {
1926         return full ? this.getDocumentHeight() : this.getViewportHeight();
1927     },
1928     /**
1929      * Get the Full Document height 
1930      * @return {Number} The height
1931      */
1932     getDocumentHeight: function() {
1933         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1934         return Math.max(scrollHeight, this.getViewportHeight());
1935     },
1936     /**
1937      * Get the Full Document width
1938      * @return {Number} The width
1939      */
1940     getDocumentWidth: function() {
1941         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1942         return Math.max(scrollWidth, this.getViewportWidth());
1943     },
1944     /**
1945      * Get the Window Viewport height
1946      * @return {Number} The height
1947      */
1948     getViewportHeight: function() {
1949         var height = self.innerHeight;
1950         var mode = document.compatMode;
1951
1952         if ((mode || Roo.isIE) && !Roo.isOpera) {
1953             height = (mode == "CSS1Compat") ?
1954                      document.documentElement.clientHeight :
1955                      document.body.clientHeight;
1956         }
1957
1958         return height;
1959     },
1960     /**
1961      * Get the Window Viewport width
1962      * @return {Number} The width
1963      */
1964     getViewportWidth: function() {
1965         var width = self.innerWidth;
1966         var mode = document.compatMode;
1967
1968         if (mode || Roo.isIE) {
1969             width = (mode == "CSS1Compat") ?
1970                     document.documentElement.clientWidth :
1971                     document.body.clientWidth;
1972         }
1973         return width;
1974     },
1975
1976     isAncestor : function(p, c) {
1977         p = Roo.getDom(p);
1978         c = Roo.getDom(c);
1979         if (!p || !c) {
1980             return false;
1981         }
1982
1983         if (p.contains && !Roo.isSafari) {
1984             return p.contains(c);
1985         } else if (p.compareDocumentPosition) {
1986             return !!(p.compareDocumentPosition(c) & 16);
1987         } else {
1988             var parent = c.parentNode;
1989             while (parent) {
1990                 if (parent == p) {
1991                     return true;
1992                 }
1993                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1994                     return false;
1995                 }
1996                 parent = parent.parentNode;
1997             }
1998             return false;
1999         }
2000     },
2001
2002     getRegion : function(el) {
2003         return Roo.lib.Region.getRegion(el);
2004     },
2005
2006     getY : function(el) {
2007         return this.getXY(el)[1];
2008     },
2009
2010     getX : function(el) {
2011         return this.getXY(el)[0];
2012     },
2013
2014     getXY : function(el) {
2015         var p, pe, b, scroll, bd = document.body;
2016         el = Roo.getDom(el);
2017         var fly = Roo.lib.AnimBase.fly;
2018         if (el.getBoundingClientRect) {
2019             b = el.getBoundingClientRect();
2020             scroll = fly(document).getScroll();
2021             return [b.left + scroll.left, b.top + scroll.top];
2022         }
2023         var x = 0, y = 0;
2024
2025         p = el;
2026
2027         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2028
2029         while (p) {
2030
2031             x += p.offsetLeft;
2032             y += p.offsetTop;
2033
2034             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2035                 hasAbsolute = true;
2036             }
2037
2038             if (Roo.isGecko) {
2039                 pe = fly(p);
2040
2041                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2042                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2043
2044
2045                 x += bl;
2046                 y += bt;
2047
2048
2049                 if (p != el && pe.getStyle('overflow') != 'visible') {
2050                     x += bl;
2051                     y += bt;
2052                 }
2053             }
2054             p = p.offsetParent;
2055         }
2056
2057         if (Roo.isSafari && hasAbsolute) {
2058             x -= bd.offsetLeft;
2059             y -= bd.offsetTop;
2060         }
2061
2062         if (Roo.isGecko && !hasAbsolute) {
2063             var dbd = fly(bd);
2064             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2065             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2066         }
2067
2068         p = el.parentNode;
2069         while (p && p != bd) {
2070             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2071                 x -= p.scrollLeft;
2072                 y -= p.scrollTop;
2073             }
2074             p = p.parentNode;
2075         }
2076         return [x, y];
2077     },
2078  
2079   
2080
2081
2082     setXY : function(el, xy) {
2083         el = Roo.fly(el, '_setXY');
2084         el.position();
2085         var pts = el.translatePoints(xy);
2086         if (xy[0] !== false) {
2087             el.dom.style.left = pts.left + "px";
2088         }
2089         if (xy[1] !== false) {
2090             el.dom.style.top = pts.top + "px";
2091         }
2092     },
2093
2094     setX : function(el, x) {
2095         this.setXY(el, [x, false]);
2096     },
2097
2098     setY : function(el, y) {
2099         this.setXY(el, [false, y]);
2100     }
2101 };
2102 /*
2103  * Portions of this file are based on pieces of Yahoo User Interface Library
2104  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2105  * YUI licensed under the BSD License:
2106  * http://developer.yahoo.net/yui/license.txt
2107  * <script type="text/javascript">
2108  *
2109  */
2110
2111 Roo.lib.Event = function() {
2112     var loadComplete = false;
2113     var listeners = [];
2114     var unloadListeners = [];
2115     var retryCount = 0;
2116     var onAvailStack = [];
2117     var counter = 0;
2118     var lastError = null;
2119
2120     return {
2121         POLL_RETRYS: 200,
2122         POLL_INTERVAL: 20,
2123         EL: 0,
2124         TYPE: 1,
2125         FN: 2,
2126         WFN: 3,
2127         OBJ: 3,
2128         ADJ_SCOPE: 4,
2129         _interval: null,
2130
2131         startInterval: function() {
2132             if (!this._interval) {
2133                 var self = this;
2134                 var callback = function() {
2135                     self._tryPreloadAttach();
2136                 };
2137                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2138
2139             }
2140         },
2141
2142         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2143             onAvailStack.push({ id:         p_id,
2144                 fn:         p_fn,
2145                 obj:        p_obj,
2146                 override:   p_override,
2147                 checkReady: false    });
2148
2149             retryCount = this.POLL_RETRYS;
2150             this.startInterval();
2151         },
2152
2153
2154         addListener: function(el, eventName, fn) {
2155             el = Roo.getDom(el);
2156             if (!el || !fn) {
2157                 return false;
2158             }
2159
2160             if ("unload" == eventName) {
2161                 unloadListeners[unloadListeners.length] =
2162                 [el, eventName, fn];
2163                 return true;
2164             }
2165
2166             var wrappedFn = function(e) {
2167                 return fn(Roo.lib.Event.getEvent(e));
2168             };
2169
2170             var li = [el, eventName, fn, wrappedFn];
2171
2172             var index = listeners.length;
2173             listeners[index] = li;
2174
2175             this.doAdd(el, eventName, wrappedFn, false);
2176             return true;
2177
2178         },
2179
2180
2181         removeListener: function(el, eventName, fn) {
2182             var i, len;
2183
2184             el = Roo.getDom(el);
2185
2186             if(!fn) {
2187                 return this.purgeElement(el, false, eventName);
2188             }
2189
2190
2191             if ("unload" == eventName) {
2192
2193                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2194                     var li = unloadListeners[i];
2195                     if (li &&
2196                         li[0] == el &&
2197                         li[1] == eventName &&
2198                         li[2] == fn) {
2199                         unloadListeners.splice(i, 1);
2200                         return true;
2201                     }
2202                 }
2203
2204                 return false;
2205             }
2206
2207             var cacheItem = null;
2208
2209
2210             var index = arguments[3];
2211
2212             if ("undefined" == typeof index) {
2213                 index = this._getCacheIndex(el, eventName, fn);
2214             }
2215
2216             if (index >= 0) {
2217                 cacheItem = listeners[index];
2218             }
2219
2220             if (!el || !cacheItem) {
2221                 return false;
2222             }
2223
2224             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2225
2226             delete listeners[index][this.WFN];
2227             delete listeners[index][this.FN];
2228             listeners.splice(index, 1);
2229
2230             return true;
2231
2232         },
2233
2234
2235         getTarget: function(ev, resolveTextNode) {
2236             ev = ev.browserEvent || ev;
2237             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2238             var t = ev.target || ev.srcElement;
2239             return this.resolveTextNode(t);
2240         },
2241
2242
2243         resolveTextNode: function(node) {
2244             if (Roo.isSafari && node && 3 == node.nodeType) {
2245                 return node.parentNode;
2246             } else {
2247                 return node;
2248             }
2249         },
2250
2251
2252         getPageX: function(ev) {
2253             ev = ev.browserEvent || ev;
2254             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2255             var x = ev.pageX;
2256             if (!x && 0 !== x) {
2257                 x = ev.clientX || 0;
2258
2259                 if (Roo.isIE) {
2260                     x += this.getScroll()[1];
2261                 }
2262             }
2263
2264             return x;
2265         },
2266
2267
2268         getPageY: function(ev) {
2269             ev = ev.browserEvent || ev;
2270             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2271             var y = ev.pageY;
2272             if (!y && 0 !== y) {
2273                 y = ev.clientY || 0;
2274
2275                 if (Roo.isIE) {
2276                     y += this.getScroll()[0];
2277                 }
2278             }
2279
2280
2281             return y;
2282         },
2283
2284
2285         getXY: function(ev) {
2286             ev = ev.browserEvent || ev;
2287             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2288             return [this.getPageX(ev), this.getPageY(ev)];
2289         },
2290
2291
2292         getRelatedTarget: function(ev) {
2293             ev = ev.browserEvent || ev;
2294             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2295             var t = ev.relatedTarget;
2296             if (!t) {
2297                 if (ev.type == "mouseout") {
2298                     t = ev.toElement;
2299                 } else if (ev.type == "mouseover") {
2300                     t = ev.fromElement;
2301                 }
2302             }
2303
2304             return this.resolveTextNode(t);
2305         },
2306
2307
2308         getTime: function(ev) {
2309             ev = ev.browserEvent || ev;
2310             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2311             if (!ev.time) {
2312                 var t = new Date().getTime();
2313                 try {
2314                     ev.time = t;
2315                 } catch(ex) {
2316                     this.lastError = ex;
2317                     return t;
2318                 }
2319             }
2320
2321             return ev.time;
2322         },
2323
2324
2325         stopEvent: function(ev) {
2326             this.stopPropagation(ev);
2327             this.preventDefault(ev);
2328         },
2329
2330
2331         stopPropagation: function(ev) {
2332             ev = ev.browserEvent || ev;
2333             if (ev.stopPropagation) {
2334                 ev.stopPropagation();
2335             } else {
2336                 ev.cancelBubble = true;
2337             }
2338         },
2339
2340
2341         preventDefault: function(ev) {
2342             ev = ev.browserEvent || ev;
2343             if(ev.preventDefault) {
2344                 ev.preventDefault();
2345             } else {
2346                 ev.returnValue = false;
2347             }
2348         },
2349
2350
2351         getEvent: function(e) {
2352             var ev = e || window.event;
2353             if (!ev) {
2354                 var c = this.getEvent.caller;
2355                 while (c) {
2356                     ev = c.arguments[0];
2357                     if (ev && Event == ev.constructor) {
2358                         break;
2359                     }
2360                     c = c.caller;
2361                 }
2362             }
2363             return ev;
2364         },
2365
2366
2367         getCharCode: function(ev) {
2368             ev = ev.browserEvent || ev;
2369             return ev.charCode || ev.keyCode || 0;
2370         },
2371
2372
2373         _getCacheIndex: function(el, eventName, fn) {
2374             for (var i = 0,len = listeners.length; i < len; ++i) {
2375                 var li = listeners[i];
2376                 if (li &&
2377                     li[this.FN] == fn &&
2378                     li[this.EL] == el &&
2379                     li[this.TYPE] == eventName) {
2380                     return i;
2381                 }
2382             }
2383
2384             return -1;
2385         },
2386
2387
2388         elCache: {},
2389
2390
2391         getEl: function(id) {
2392             return document.getElementById(id);
2393         },
2394
2395
2396         clearCache: function() {
2397         },
2398
2399
2400         _load: function(e) {
2401             loadComplete = true;
2402             var EU = Roo.lib.Event;
2403
2404
2405             if (Roo.isIE) {
2406                 EU.doRemove(window, "load", EU._load);
2407             }
2408         },
2409
2410
2411         _tryPreloadAttach: function() {
2412
2413             if (this.locked) {
2414                 return false;
2415             }
2416
2417             this.locked = true;
2418
2419
2420             var tryAgain = !loadComplete;
2421             if (!tryAgain) {
2422                 tryAgain = (retryCount > 0);
2423             }
2424
2425
2426             var notAvail = [];
2427             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2428                 var item = onAvailStack[i];
2429                 if (item) {
2430                     var el = this.getEl(item.id);
2431
2432                     if (el) {
2433                         if (!item.checkReady ||
2434                             loadComplete ||
2435                             el.nextSibling ||
2436                             (document && document.body)) {
2437
2438                             var scope = el;
2439                             if (item.override) {
2440                                 if (item.override === true) {
2441                                     scope = item.obj;
2442                                 } else {
2443                                     scope = item.override;
2444                                 }
2445                             }
2446                             item.fn.call(scope, item.obj);
2447                             onAvailStack[i] = null;
2448                         }
2449                     } else {
2450                         notAvail.push(item);
2451                     }
2452                 }
2453             }
2454
2455             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2456
2457             if (tryAgain) {
2458
2459                 this.startInterval();
2460             } else {
2461                 clearInterval(this._interval);
2462                 this._interval = null;
2463             }
2464
2465             this.locked = false;
2466
2467             return true;
2468
2469         },
2470
2471
2472         purgeElement: function(el, recurse, eventName) {
2473             var elListeners = this.getListeners(el, eventName);
2474             if (elListeners) {
2475                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2476                     var l = elListeners[i];
2477                     this.removeListener(el, l.type, l.fn);
2478                 }
2479             }
2480
2481             if (recurse && el && el.childNodes) {
2482                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2483                     this.purgeElement(el.childNodes[i], recurse, eventName);
2484                 }
2485             }
2486         },
2487
2488
2489         getListeners: function(el, eventName) {
2490             var results = [], searchLists;
2491             if (!eventName) {
2492                 searchLists = [listeners, unloadListeners];
2493             } else if (eventName == "unload") {
2494                 searchLists = [unloadListeners];
2495             } else {
2496                 searchLists = [listeners];
2497             }
2498
2499             for (var j = 0; j < searchLists.length; ++j) {
2500                 var searchList = searchLists[j];
2501                 if (searchList && searchList.length > 0) {
2502                     for (var i = 0,len = searchList.length; i < len; ++i) {
2503                         var l = searchList[i];
2504                         if (l && l[this.EL] === el &&
2505                             (!eventName || eventName === l[this.TYPE])) {
2506                             results.push({
2507                                 type:   l[this.TYPE],
2508                                 fn:     l[this.FN],
2509                                 obj:    l[this.OBJ],
2510                                 adjust: l[this.ADJ_SCOPE],
2511                                 index:  i
2512                             });
2513                         }
2514                     }
2515                 }
2516             }
2517
2518             return (results.length) ? results : null;
2519         },
2520
2521
2522         _unload: function(e) {
2523
2524             var EU = Roo.lib.Event, i, j, l, len, index;
2525
2526             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2527                 l = unloadListeners[i];
2528                 if (l) {
2529                     var scope = window;
2530                     if (l[EU.ADJ_SCOPE]) {
2531                         if (l[EU.ADJ_SCOPE] === true) {
2532                             scope = l[EU.OBJ];
2533                         } else {
2534                             scope = l[EU.ADJ_SCOPE];
2535                         }
2536                     }
2537                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2538                     unloadListeners[i] = null;
2539                     l = null;
2540                     scope = null;
2541                 }
2542             }
2543
2544             unloadListeners = null;
2545
2546             if (listeners && listeners.length > 0) {
2547                 j = listeners.length;
2548                 while (j) {
2549                     index = j - 1;
2550                     l = listeners[index];
2551                     if (l) {
2552                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2553                                 l[EU.FN], index);
2554                     }
2555                     j = j - 1;
2556                 }
2557                 l = null;
2558
2559                 EU.clearCache();
2560             }
2561
2562             EU.doRemove(window, "unload", EU._unload);
2563
2564         },
2565
2566
2567         getScroll: function() {
2568             var dd = document.documentElement, db = document.body;
2569             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2570                 return [dd.scrollTop, dd.scrollLeft];
2571             } else if (db) {
2572                 return [db.scrollTop, db.scrollLeft];
2573             } else {
2574                 return [0, 0];
2575             }
2576         },
2577
2578
2579         doAdd: function () {
2580             if (window.addEventListener) {
2581                 return function(el, eventName, fn, capture) {
2582                     el.addEventListener(eventName, fn, (capture));
2583                 };
2584             } else if (window.attachEvent) {
2585                 return function(el, eventName, fn, capture) {
2586                     el.attachEvent("on" + eventName, fn);
2587                 };
2588             } else {
2589                 return function() {
2590                 };
2591             }
2592         }(),
2593
2594
2595         doRemove: function() {
2596             if (window.removeEventListener) {
2597                 return function (el, eventName, fn, capture) {
2598                     el.removeEventListener(eventName, fn, (capture));
2599                 };
2600             } else if (window.detachEvent) {
2601                 return function (el, eventName, fn) {
2602                     el.detachEvent("on" + eventName, fn);
2603                 };
2604             } else {
2605                 return function() {
2606                 };
2607             }
2608         }()
2609     };
2610     
2611 }();
2612 (function() {     
2613    
2614     var E = Roo.lib.Event;
2615     E.on = E.addListener;
2616     E.un = E.removeListener;
2617
2618     if (document && document.body) {
2619         E._load();
2620     } else {
2621         E.doAdd(window, "load", E._load);
2622     }
2623     E.doAdd(window, "unload", E._unload);
2624     E._tryPreloadAttach();
2625 })();
2626
2627  
2628
2629 (function() {
2630     /**
2631      * @class Roo.lib.Ajax
2632      *
2633      * provide a simple Ajax request utility functions
2634      * 
2635      * Portions of this file are based on pieces of Yahoo User Interface Library
2636     * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2637     * YUI licensed under the BSD License:
2638     * http://developer.yahoo.net/yui/license.txt
2639     * <script type="text/javascript">
2640     *
2641      *
2642      */
2643     Roo.lib.Ajax = {
2644         /**
2645          * @static 
2646          */
2647         request : function(method, uri, cb, data, options) {
2648             if(options){
2649                 var hs = options.headers;
2650                 if(hs){
2651                     for(var h in hs){
2652                         if(hs.hasOwnProperty(h)){
2653                             this.initHeader(h, hs[h], false);
2654                         }
2655                     }
2656                 }
2657                 if(options.xmlData){
2658                     this.initHeader('Content-Type', 'text/xml', false);
2659                     method = 'POST';
2660                     data = options.xmlData;
2661                 }
2662             }
2663
2664             return this.asyncRequest(method, uri, cb, data);
2665         },
2666         /**
2667          * serialize a form
2668          *
2669          * @static
2670          * @param {DomForm} form element
2671          * @return {String} urlencode form output.
2672          */
2673         serializeForm : function(form) {
2674             if(typeof form == 'string') {
2675                 form = (document.getElementById(form) || document.forms[form]);
2676             }
2677
2678             var el, name, val, disabled, data = '', hasSubmit = false;
2679             for (var i = 0; i < form.elements.length; i++) {
2680                 el = form.elements[i];
2681                 disabled = form.elements[i].disabled;
2682                 name = form.elements[i].name;
2683                 val = form.elements[i].value;
2684
2685                 if (!disabled && name){
2686                     switch (el.type)
2687                             {
2688                         case 'select-one':
2689                         case 'select-multiple':
2690                             for (var j = 0; j < el.options.length; j++) {
2691                                 if (el.options[j].selected) {
2692                                     if (Roo.isIE) {
2693                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2694                                     }
2695                                     else {
2696                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2697                                     }
2698                                 }
2699                             }
2700                             break;
2701                         case 'radio':
2702                         case 'checkbox':
2703                             if (el.checked) {
2704                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2705                             }
2706                             break;
2707                         case 'file':
2708
2709                         case undefined:
2710
2711                         case 'reset':
2712
2713                         case 'button':
2714
2715                             break;
2716                         case 'submit':
2717                             if(hasSubmit == false) {
2718                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2719                                 hasSubmit = true;
2720                             }
2721                             break;
2722                         default:
2723                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2724                             break;
2725                     }
2726                 }
2727             }
2728             data = data.substr(0, data.length - 1);
2729             return data;
2730         },
2731
2732         headers:{},
2733
2734         hasHeaders:false,
2735
2736         useDefaultHeader:true,
2737
2738         defaultPostHeader:'application/x-www-form-urlencoded',
2739
2740         useDefaultXhrHeader:true,
2741
2742         defaultXhrHeader:'XMLHttpRequest',
2743
2744         hasDefaultHeaders:true,
2745
2746         defaultHeaders:{},
2747
2748         poll:{},
2749
2750         timeout:{},
2751
2752         pollInterval:50,
2753
2754         transactionId:0,
2755
2756         setProgId:function(id)
2757         {
2758             this.activeX.unshift(id);
2759         },
2760
2761         setDefaultPostHeader:function(b)
2762         {
2763             this.useDefaultHeader = b;
2764         },
2765
2766         setDefaultXhrHeader:function(b)
2767         {
2768             this.useDefaultXhrHeader = b;
2769         },
2770
2771         setPollingInterval:function(i)
2772         {
2773             if (typeof i == 'number' && isFinite(i)) {
2774                 this.pollInterval = i;
2775             }
2776         },
2777
2778         createXhrObject:function(transactionId)
2779         {
2780             var obj,http;
2781             try
2782             {
2783
2784                 http = new XMLHttpRequest();
2785
2786                 obj = { conn:http, tId:transactionId };
2787             }
2788             catch(e)
2789             {
2790                 for (var i = 0; i < this.activeX.length; ++i) {
2791                     try
2792                     {
2793
2794                         http = new ActiveXObject(this.activeX[i]);
2795
2796                         obj = { conn:http, tId:transactionId };
2797                         break;
2798                     }
2799                     catch(e) {
2800                     }
2801                 }
2802             }
2803             finally
2804             {
2805                 return obj;
2806             }
2807         },
2808
2809         getConnectionObject:function()
2810         {
2811             var o;
2812             var tId = this.transactionId;
2813
2814             try
2815             {
2816                 o = this.createXhrObject(tId);
2817                 if (o) {
2818                     this.transactionId++;
2819                 }
2820             }
2821             catch(e) {
2822             }
2823             finally
2824             {
2825                 return o;
2826             }
2827         },
2828
2829         asyncRequest:function(method, uri, callback, postData)
2830         {
2831             var o = this.getConnectionObject();
2832
2833             if (!o) {
2834                 return null;
2835             }
2836             else {
2837                 o.conn.open(method, uri, true);
2838
2839                 if (this.useDefaultXhrHeader) {
2840                     if (!this.defaultHeaders['X-Requested-With']) {
2841                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2842                     }
2843                 }
2844
2845                 if(postData && this.useDefaultHeader){
2846                     this.initHeader('Content-Type', this.defaultPostHeader);
2847                 }
2848
2849                  if (this.hasDefaultHeaders || this.hasHeaders) {
2850                     this.setHeader(o);
2851                 }
2852
2853                 this.handleReadyState(o, callback);
2854                 o.conn.send(postData || null);
2855
2856                 return o;
2857             }
2858         },
2859
2860         handleReadyState:function(o, callback)
2861         {
2862             var oConn = this;
2863
2864             if (callback && callback.timeout) {
2865                 
2866                 this.timeout[o.tId] = window.setTimeout(function() {
2867                     oConn.abort(o, callback, true);
2868                 }, callback.timeout);
2869             }
2870
2871             this.poll[o.tId] = window.setInterval(
2872                     function() {
2873                         if (o.conn && o.conn.readyState == 4) {
2874                             window.clearInterval(oConn.poll[o.tId]);
2875                             delete oConn.poll[o.tId];
2876
2877                             if(callback && callback.timeout) {
2878                                 window.clearTimeout(oConn.timeout[o.tId]);
2879                                 delete oConn.timeout[o.tId];
2880                             }
2881
2882                             oConn.handleTransactionResponse(o, callback);
2883                         }
2884                     }
2885                     , this.pollInterval);
2886         },
2887
2888         handleTransactionResponse:function(o, callback, isAbort)
2889         {
2890
2891             if (!callback) {
2892                 this.releaseObject(o);
2893                 return;
2894             }
2895
2896             var httpStatus, responseObject;
2897
2898             try
2899             {
2900                 if (o.conn.status !== undefined && o.conn.status != 0) {
2901                     httpStatus = o.conn.status;
2902                 }
2903                 else {
2904                     httpStatus = 13030;
2905                 }
2906             }
2907             catch(e) {
2908
2909
2910                 httpStatus = 13030;
2911             }
2912
2913             if (httpStatus >= 200 && httpStatus < 300) {
2914                 responseObject = this.createResponseObject(o, callback.argument);
2915                 if (callback.success) {
2916                     if (!callback.scope) {
2917                         callback.success(responseObject);
2918                     }
2919                     else {
2920
2921
2922                         callback.success.apply(callback.scope, [responseObject]);
2923                     }
2924                 }
2925             }
2926             else {
2927                 switch (httpStatus) {
2928
2929                     case 12002:
2930                     case 12029:
2931                     case 12030:
2932                     case 12031:
2933                     case 12152:
2934                     case 13030:
2935                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2936                         if (callback.failure) {
2937                             if (!callback.scope) {
2938                                 callback.failure(responseObject);
2939                             }
2940                             else {
2941                                 callback.failure.apply(callback.scope, [responseObject]);
2942                             }
2943                         }
2944                         break;
2945                     default:
2946                         responseObject = this.createResponseObject(o, callback.argument);
2947                         if (callback.failure) {
2948                             if (!callback.scope) {
2949                                 callback.failure(responseObject);
2950                             }
2951                             else {
2952                                 callback.failure.apply(callback.scope, [responseObject]);
2953                             }
2954                         }
2955                 }
2956             }
2957
2958             this.releaseObject(o);
2959             responseObject = null;
2960         },
2961
2962         createResponseObject:function(o, callbackArg)
2963         {
2964             var obj = {};
2965             var headerObj = {};
2966
2967             try
2968             {
2969                 var headerStr = o.conn.getAllResponseHeaders();
2970                 var header = headerStr.split('\n');
2971                 for (var i = 0; i < header.length; i++) {
2972                     var delimitPos = header[i].indexOf(':');
2973                     if (delimitPos != -1) {
2974                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2975                     }
2976                 }
2977             }
2978             catch(e) {
2979             }
2980
2981             obj.tId = o.tId;
2982             obj.status = o.conn.status;
2983             obj.statusText = o.conn.statusText;
2984             obj.getResponseHeader = headerObj;
2985             obj.getAllResponseHeaders = headerStr;
2986             obj.responseText = o.conn.responseText;
2987             obj.responseXML = o.conn.responseXML;
2988
2989             if (typeof callbackArg !== undefined) {
2990                 obj.argument = callbackArg;
2991             }
2992
2993             return obj;
2994         },
2995
2996         createExceptionObject:function(tId, callbackArg, isAbort)
2997         {
2998             var COMM_CODE = 0;
2999             var COMM_ERROR = 'communication failure';
3000             var ABORT_CODE = -1;
3001             var ABORT_ERROR = 'transaction aborted';
3002
3003             var obj = {};
3004
3005             obj.tId = tId;
3006             if (isAbort) {
3007                 obj.status = ABORT_CODE;
3008                 obj.statusText = ABORT_ERROR;
3009             }
3010             else {
3011                 obj.status = COMM_CODE;
3012                 obj.statusText = COMM_ERROR;
3013             }
3014
3015             if (callbackArg) {
3016                 obj.argument = callbackArg;
3017             }
3018
3019             return obj;
3020         },
3021
3022         initHeader:function(label, value, isDefault)
3023         {
3024             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3025
3026             if (headerObj[label] === undefined) {
3027                 headerObj[label] = value;
3028             }
3029             else {
3030
3031
3032                 headerObj[label] = value + "," + headerObj[label];
3033             }
3034
3035             if (isDefault) {
3036                 this.hasDefaultHeaders = true;
3037             }
3038             else {
3039                 this.hasHeaders = true;
3040             }
3041         },
3042
3043
3044         setHeader:function(o)
3045         {
3046             if (this.hasDefaultHeaders) {
3047                 for (var prop in this.defaultHeaders) {
3048                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3049                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3050                     }
3051                 }
3052             }
3053
3054             if (this.hasHeaders) {
3055                 for (var prop in this.headers) {
3056                     if (this.headers.hasOwnProperty(prop)) {
3057                         o.conn.setRequestHeader(prop, this.headers[prop]);
3058                     }
3059                 }
3060                 this.headers = {};
3061                 this.hasHeaders = false;
3062             }
3063         },
3064
3065         resetDefaultHeaders:function() {
3066             delete this.defaultHeaders;
3067             this.defaultHeaders = {};
3068             this.hasDefaultHeaders = false;
3069         },
3070
3071         abort:function(o, callback, isTimeout)
3072         {
3073             if(this.isCallInProgress(o)) {
3074                 o.conn.abort();
3075                 window.clearInterval(this.poll[o.tId]);
3076                 delete this.poll[o.tId];
3077                 if (isTimeout) {
3078                     delete this.timeout[o.tId];
3079                 }
3080
3081                 this.handleTransactionResponse(o, callback, true);
3082
3083                 return true;
3084             }
3085             else {
3086                 return false;
3087             }
3088         },
3089
3090
3091         isCallInProgress:function(o)
3092         {
3093             if (o && o.conn) {
3094                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3095             }
3096             else {
3097
3098                 return false;
3099             }
3100         },
3101
3102
3103         releaseObject:function(o)
3104         {
3105
3106             o.conn = null;
3107
3108             o = null;
3109         },
3110
3111         activeX:[
3112         'MSXML2.XMLHTTP.3.0',
3113         'MSXML2.XMLHTTP',
3114         'Microsoft.XMLHTTP'
3115         ]
3116
3117
3118     };
3119 })();/*
3120  * Portions of this file are based on pieces of Yahoo User Interface Library
3121  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3122  * YUI licensed under the BSD License:
3123  * http://developer.yahoo.net/yui/license.txt
3124  * <script type="text/javascript">
3125  *
3126  */
3127
3128 Roo.lib.Region = function(t, r, b, l) {
3129     this.top = t;
3130     this[1] = t;
3131     this.right = r;
3132     this.bottom = b;
3133     this.left = l;
3134     this[0] = l;
3135 };
3136
3137
3138 Roo.lib.Region.prototype = {
3139     contains : function(region) {
3140         return ( region.left >= this.left &&
3141                  region.right <= this.right &&
3142                  region.top >= this.top &&
3143                  region.bottom <= this.bottom    );
3144
3145     },
3146
3147     getArea : function() {
3148         return ( (this.bottom - this.top) * (this.right - this.left) );
3149     },
3150
3151     intersect : function(region) {
3152         var t = Math.max(this.top, region.top);
3153         var r = Math.min(this.right, region.right);
3154         var b = Math.min(this.bottom, region.bottom);
3155         var l = Math.max(this.left, region.left);
3156
3157         if (b >= t && r >= l) {
3158             return new Roo.lib.Region(t, r, b, l);
3159         } else {
3160             return null;
3161         }
3162     },
3163     union : function(region) {
3164         var t = Math.min(this.top, region.top);
3165         var r = Math.max(this.right, region.right);
3166         var b = Math.max(this.bottom, region.bottom);
3167         var l = Math.min(this.left, region.left);
3168
3169         return new Roo.lib.Region(t, r, b, l);
3170     },
3171
3172     adjust : function(t, l, b, r) {
3173         this.top += t;
3174         this.left += l;
3175         this.right += r;
3176         this.bottom += b;
3177         return this;
3178     }
3179 };
3180
3181 Roo.lib.Region.getRegion = function(el) {
3182     var p = Roo.lib.Dom.getXY(el);
3183
3184     var t = p[1];
3185     var r = p[0] + el.offsetWidth;
3186     var b = p[1] + el.offsetHeight;
3187     var l = p[0];
3188
3189     return new Roo.lib.Region(t, r, b, l);
3190 };
3191 /*
3192  * Portions of this file are based on pieces of Yahoo User Interface Library
3193  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3194  * YUI licensed under the BSD License:
3195  * http://developer.yahoo.net/yui/license.txt
3196  * <script type="text/javascript">
3197  *
3198  */
3199 //@@dep Roo.lib.Region
3200
3201
3202 Roo.lib.Point = function(x, y) {
3203     if (x instanceof Array) {
3204         y = x[1];
3205         x = x[0];
3206     }
3207     this.x = this.right = this.left = this[0] = x;
3208     this.y = this.top = this.bottom = this[1] = y;
3209 };
3210
3211 Roo.lib.Point.prototype = new Roo.lib.Region();
3212 /*
3213  * Portions of this file are based on pieces of Yahoo User Interface Library
3214  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3215  * YUI licensed under the BSD License:
3216  * http://developer.yahoo.net/yui/license.txt
3217  * <script type="text/javascript">
3218  *
3219  */
3220  
3221 (function() {   
3222
3223     Roo.lib.Anim = {
3224         scroll : function(el, args, duration, easing, cb, scope) {
3225             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3226         },
3227
3228         motion : function(el, args, duration, easing, cb, scope) {
3229             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3230         },
3231
3232         color : function(el, args, duration, easing, cb, scope) {
3233             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3234         },
3235
3236         run : function(el, args, duration, easing, cb, scope, type) {
3237             type = type || Roo.lib.AnimBase;
3238             if (typeof easing == "string") {
3239                 easing = Roo.lib.Easing[easing];
3240             }
3241             var anim = new type(el, args, duration, easing);
3242             anim.animateX(function() {
3243                 Roo.callback(cb, scope);
3244             });
3245             return anim;
3246         }
3247     };
3248 })();/*
3249  * Portions of this file are based on pieces of Yahoo User Interface Library
3250  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3251  * YUI licensed under the BSD License:
3252  * http://developer.yahoo.net/yui/license.txt
3253  * <script type="text/javascript">
3254  *
3255  */
3256
3257 (function() {    
3258     var libFlyweight;
3259     
3260     function fly(el) {
3261         if (!libFlyweight) {
3262             libFlyweight = new Roo.Element.Flyweight();
3263         }
3264         libFlyweight.dom = el;
3265         return libFlyweight;
3266     }
3267
3268     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3269     
3270    
3271     
3272     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3273         if (el) {
3274             this.init(el, attributes, duration, method);
3275         }
3276     };
3277
3278     Roo.lib.AnimBase.fly = fly;
3279     
3280     
3281     
3282     Roo.lib.AnimBase.prototype = {
3283
3284         toString: function() {
3285             var el = this.getEl();
3286             var id = el.id || el.tagName;
3287             return ("Anim " + id);
3288         },
3289
3290         patterns: {
3291             noNegatives:        /width|height|opacity|padding/i,
3292             offsetAttribute:  /^((width|height)|(top|left))$/,
3293             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3294             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3295         },
3296
3297
3298         doMethod: function(attr, start, end) {
3299             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3300         },
3301
3302
3303         setAttribute: function(attr, val, unit) {
3304             if (this.patterns.noNegatives.test(attr)) {
3305                 val = (val > 0) ? val : 0;
3306             }
3307
3308             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3309         },
3310
3311
3312         getAttribute: function(attr) {
3313             var el = this.getEl();
3314             var val = fly(el).getStyle(attr);
3315
3316             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3317                 return parseFloat(val);
3318             }
3319
3320             var a = this.patterns.offsetAttribute.exec(attr) || [];
3321             var pos = !!( a[3] );
3322             var box = !!( a[2] );
3323
3324
3325             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3326                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3327             } else {
3328                 val = 0;
3329             }
3330
3331             return val;
3332         },
3333
3334
3335         getDefaultUnit: function(attr) {
3336             if (this.patterns.defaultUnit.test(attr)) {
3337                 return 'px';
3338             }
3339
3340             return '';
3341         },
3342
3343         animateX : function(callback, scope) {
3344             var f = function() {
3345                 this.onComplete.removeListener(f);
3346                 if (typeof callback == "function") {
3347                     callback.call(scope || this, this);
3348                 }
3349             };
3350             this.onComplete.addListener(f, this);
3351             this.animate();
3352         },
3353
3354
3355         setRuntimeAttribute: function(attr) {
3356             var start;
3357             var end;
3358             var attributes = this.attributes;
3359
3360             this.runtimeAttributes[attr] = {};
3361
3362             var isset = function(prop) {
3363                 return (typeof prop !== 'undefined');
3364             };
3365
3366             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3367                 return false;
3368             }
3369
3370             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3371
3372
3373             if (isset(attributes[attr]['to'])) {
3374                 end = attributes[attr]['to'];
3375             } else if (isset(attributes[attr]['by'])) {
3376                 if (start.constructor == Array) {
3377                     end = [];
3378                     for (var i = 0, len = start.length; i < len; ++i) {
3379                         end[i] = start[i] + attributes[attr]['by'][i];
3380                     }
3381                 } else {
3382                     end = start + attributes[attr]['by'];
3383                 }
3384             }
3385
3386             this.runtimeAttributes[attr].start = start;
3387             this.runtimeAttributes[attr].end = end;
3388
3389
3390             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3391         },
3392
3393
3394         init: function(el, attributes, duration, method) {
3395
3396             var isAnimated = false;
3397
3398
3399             var startTime = null;
3400
3401
3402             var actualFrames = 0;
3403
3404
3405             el = Roo.getDom(el);
3406
3407
3408             this.attributes = attributes || {};
3409
3410
3411             this.duration = duration || 1;
3412
3413
3414             this.method = method || Roo.lib.Easing.easeNone;
3415
3416
3417             this.useSeconds = true;
3418
3419
3420             this.currentFrame = 0;
3421
3422
3423             this.totalFrames = Roo.lib.AnimMgr.fps;
3424
3425
3426             this.getEl = function() {
3427                 return el;
3428             };
3429
3430
3431             this.isAnimated = function() {
3432                 return isAnimated;
3433             };
3434
3435
3436             this.getStartTime = function() {
3437                 return startTime;
3438             };
3439
3440             this.runtimeAttributes = {};
3441
3442
3443             this.animate = function() {
3444                 if (this.isAnimated()) {
3445                     return false;
3446                 }
3447
3448                 this.currentFrame = 0;
3449
3450                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3451
3452                 Roo.lib.AnimMgr.registerElement(this);
3453             };
3454
3455
3456             this.stop = function(finish) {
3457                 if (finish) {
3458                     this.currentFrame = this.totalFrames;
3459                     this._onTween.fire();
3460                 }
3461                 Roo.lib.AnimMgr.stop(this);
3462             };
3463
3464             var onStart = function() {
3465                 this.onStart.fire();
3466
3467                 this.runtimeAttributes = {};
3468                 for (var attr in this.attributes) {
3469                     this.setRuntimeAttribute(attr);
3470                 }
3471
3472                 isAnimated = true;
3473                 actualFrames = 0;
3474                 startTime = new Date();
3475             };
3476
3477
3478             var onTween = function() {
3479                 var data = {
3480                     duration: new Date() - this.getStartTime(),
3481                     currentFrame: this.currentFrame
3482                 };
3483
3484                 data.toString = function() {
3485                     return (
3486                             'duration: ' + data.duration +
3487                             ', currentFrame: ' + data.currentFrame
3488                             );
3489                 };
3490
3491                 this.onTween.fire(data);
3492
3493                 var runtimeAttributes = this.runtimeAttributes;
3494
3495                 for (var attr in runtimeAttributes) {
3496                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3497                 }
3498
3499                 actualFrames += 1;
3500             };
3501
3502             var onComplete = function() {
3503                 var actual_duration = (new Date() - startTime) / 1000 ;
3504
3505                 var data = {
3506                     duration: actual_duration,
3507                     frames: actualFrames,
3508                     fps: actualFrames / actual_duration
3509                 };
3510
3511                 data.toString = function() {
3512                     return (
3513                             'duration: ' + data.duration +
3514                             ', frames: ' + data.frames +
3515                             ', fps: ' + data.fps
3516                             );
3517                 };
3518
3519                 isAnimated = false;
3520                 actualFrames = 0;
3521                 this.onComplete.fire(data);
3522             };
3523
3524
3525             this._onStart = new Roo.util.Event(this);
3526             this.onStart = new Roo.util.Event(this);
3527             this.onTween = new Roo.util.Event(this);
3528             this._onTween = new Roo.util.Event(this);
3529             this.onComplete = new Roo.util.Event(this);
3530             this._onComplete = new Roo.util.Event(this);
3531             this._onStart.addListener(onStart);
3532             this._onTween.addListener(onTween);
3533             this._onComplete.addListener(onComplete);
3534         }
3535     };
3536 })();
3537 /*
3538  * Portions of this file are based on pieces of Yahoo User Interface Library
3539  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3540  * YUI licensed under the BSD License:
3541  * http://developer.yahoo.net/yui/license.txt
3542  * <script type="text/javascript">
3543  *
3544  */
3545
3546 Roo.lib.AnimMgr = new function() {
3547
3548     var thread = null;
3549
3550
3551     var queue = [];
3552
3553
3554     var tweenCount = 0;
3555
3556
3557     this.fps = 1000;
3558
3559
3560     this.delay = 1;
3561
3562
3563     this.registerElement = function(tween) {
3564         queue[queue.length] = tween;
3565         tweenCount += 1;
3566         tween._onStart.fire();
3567         this.start();
3568     };
3569
3570
3571     this.unRegister = function(tween, index) {
3572         tween._onComplete.fire();
3573         index = index || getIndex(tween);
3574         if (index != -1) {
3575             queue.splice(index, 1);
3576         }
3577
3578         tweenCount -= 1;
3579         if (tweenCount <= 0) {
3580             this.stop();
3581         }
3582     };
3583
3584
3585     this.start = function() {
3586         if (thread === null) {
3587             thread = setInterval(this.run, this.delay);
3588         }
3589     };
3590
3591
3592     this.stop = function(tween) {
3593         if (!tween) {
3594             clearInterval(thread);
3595
3596             for (var i = 0, len = queue.length; i < len; ++i) {
3597                 if (queue[0].isAnimated()) {
3598                     this.unRegister(queue[0], 0);
3599                 }
3600             }
3601
3602             queue = [];
3603             thread = null;
3604             tweenCount = 0;
3605         }
3606         else {
3607             this.unRegister(tween);
3608         }
3609     };
3610
3611
3612     this.run = function() {
3613         for (var i = 0, len = queue.length; i < len; ++i) {
3614             var tween = queue[i];
3615             if (!tween || !tween.isAnimated()) {
3616                 continue;
3617             }
3618
3619             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3620             {
3621                 tween.currentFrame += 1;
3622
3623                 if (tween.useSeconds) {
3624                     correctFrame(tween);
3625                 }
3626                 tween._onTween.fire();
3627             }
3628             else {
3629                 Roo.lib.AnimMgr.stop(tween, i);
3630             }
3631         }
3632     };
3633
3634     var getIndex = function(anim) {
3635         for (var i = 0, len = queue.length; i < len; ++i) {
3636             if (queue[i] == anim) {
3637                 return i;
3638             }
3639         }
3640         return -1;
3641     };
3642
3643
3644     var correctFrame = function(tween) {
3645         var frames = tween.totalFrames;
3646         var frame = tween.currentFrame;
3647         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3648         var elapsed = (new Date() - tween.getStartTime());
3649         var tweak = 0;
3650
3651         if (elapsed < tween.duration * 1000) {
3652             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3653         } else {
3654             tweak = frames - (frame + 1);
3655         }
3656         if (tweak > 0 && isFinite(tweak)) {
3657             if (tween.currentFrame + tweak >= frames) {
3658                 tweak = frames - (frame + 1);
3659             }
3660
3661             tween.currentFrame += tweak;
3662         }
3663     };
3664 };
3665
3666     /*
3667  * Portions of this file are based on pieces of Yahoo User Interface Library
3668  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3669  * YUI licensed under the BSD License:
3670  * http://developer.yahoo.net/yui/license.txt
3671  * <script type="text/javascript">
3672  *
3673  */
3674 Roo.lib.Bezier = new function() {
3675
3676         this.getPosition = function(points, t) {
3677             var n = points.length;
3678             var tmp = [];
3679
3680             for (var i = 0; i < n; ++i) {
3681                 tmp[i] = [points[i][0], points[i][1]];
3682             }
3683
3684             for (var j = 1; j < n; ++j) {
3685                 for (i = 0; i < n - j; ++i) {
3686                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3687                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3688                 }
3689             }
3690
3691             return [ tmp[0][0], tmp[0][1] ];
3692
3693         };
3694     }; 
3695
3696 /**
3697  * @class Roo.lib.Color
3698  * @constructor
3699  * An abstract Color implementation. Concrete Color implementations should use
3700  * an instance of this function as their prototype, and implement the getRGB and
3701  * getHSL functions. getRGB should return an object representing the RGB
3702  * components of this Color, with the red, green, and blue components in the
3703  * range [0,255] and the alpha component in the range [0,100]. getHSL should
3704  * return an object representing the HSL components of this Color, with the hue
3705  * component in the range [0,360), the saturation and lightness components in
3706  * the range [0,100], and the alpha component in the range [0,1].
3707  *
3708  *
3709  * Color.js
3710  *
3711  * Functions for Color handling and processing.
3712  *
3713  * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3714  *
3715  * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3716  * rights to this program, with the intention of it becoming part of the public
3717  * domain. Because this program is released into the public domain, it comes with
3718  * no warranty either expressed or implied, to the extent permitted by law.
3719  * 
3720  * For more free and public domain JavaScript code by the same author, visit:
3721  * http://www.safalra.com/web-design/javascript/
3722  * 
3723  */
3724 Roo.lib.Color = function() { }
3725
3726
3727 Roo.apply(Roo.lib.Color.prototype, {
3728   
3729   rgb : null,
3730   hsv : null,
3731   hsl : null,
3732   
3733   /**
3734    * getIntegerRGB
3735    * @return {Object} an object representing the RGBA components of this Color. The red,
3736    * green, and blue components are converted to integers in the range [0,255].
3737    * The alpha is a value in the range [0,1].
3738    */
3739   getIntegerRGB : function(){
3740
3741     // get the RGB components of this Color
3742     var rgb = this.getRGB();
3743
3744     // return the integer components
3745     return {
3746       'r' : Math.round(rgb.r),
3747       'g' : Math.round(rgb.g),
3748       'b' : Math.round(rgb.b),
3749       'a' : rgb.a
3750     };
3751
3752   },
3753
3754   /**
3755    * getPercentageRGB
3756    * @return {Object} an object representing the RGBA components of this Color. The red,
3757    * green, and blue components are converted to numbers in the range [0,100].
3758    * The alpha is a value in the range [0,1].
3759    */
3760   getPercentageRGB : function(){
3761
3762     // get the RGB components of this Color
3763     var rgb = this.getRGB();
3764
3765     // return the percentage components
3766     return {
3767       'r' : 100 * rgb.r / 255,
3768       'g' : 100 * rgb.g / 255,
3769       'b' : 100 * rgb.b / 255,
3770       'a' : rgb.a
3771     };
3772
3773   },
3774
3775   /**
3776    * getCSSHexadecimalRGB
3777    * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3778    * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3779    * are two-digit hexadecimal numbers.
3780    */
3781   getCSSHexadecimalRGB : function()
3782   {
3783
3784     // get the integer RGB components
3785     var rgb = this.getIntegerRGB();
3786
3787     // determine the hexadecimal equivalents
3788     var r16 = rgb.r.toString(16);
3789     var g16 = rgb.g.toString(16);
3790     var b16 = rgb.b.toString(16);
3791
3792     // return the CSS RGB Color value
3793     return '#'
3794         + (r16.length == 2 ? r16 : '0' + r16)
3795         + (g16.length == 2 ? g16 : '0' + g16)
3796         + (b16.length == 2 ? b16 : '0' + b16);
3797
3798   },
3799
3800   /**
3801    * getCSSIntegerRGB
3802    * @return {String} a string representing this Color as a CSS integer RGB Color
3803    * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3804    * are integers in the range [0,255].
3805    */
3806   getCSSIntegerRGB : function(){
3807
3808     // get the integer RGB components
3809     var rgb = this.getIntegerRGB();
3810
3811     // return the CSS RGB Color value
3812     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3813
3814   },
3815
3816   /**
3817    * getCSSIntegerRGBA
3818    * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3819    * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3820    * b are integers in the range [0,255] and a is in the range [0,1].
3821    */
3822   getCSSIntegerRGBA : function(){
3823
3824     // get the integer RGB components
3825     var rgb = this.getIntegerRGB();
3826
3827     // return the CSS integer RGBA Color value
3828     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3829
3830   },
3831
3832   /**
3833    * getCSSPercentageRGB
3834    * @return {String} a string representing this Color as a CSS percentage RGB Color
3835    * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3836    * b are in the range [0,100].
3837    */
3838   getCSSPercentageRGB : function(){
3839
3840     // get the percentage RGB components
3841     var rgb = this.getPercentageRGB();
3842
3843     // return the CSS RGB Color value
3844     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3845
3846   },
3847
3848   /**
3849    * getCSSPercentageRGBA
3850    * @return {String} a string representing this Color as a CSS percentage RGBA Color
3851    * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3852    * and b are in the range [0,100] and a is in the range [0,1].
3853    */
3854   getCSSPercentageRGBA : function(){
3855
3856     // get the percentage RGB components
3857     var rgb = this.getPercentageRGB();
3858
3859     // return the CSS percentage RGBA Color value
3860     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3861
3862   },
3863
3864   /**
3865    * getCSSHSL
3866    * @return {String} a string representing this Color as a CSS HSL Color value - that
3867    * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3868    * s and l are in the range [0,100].
3869    */
3870   getCSSHSL : function(){
3871
3872     // get the HSL components
3873     var hsl = this.getHSL();
3874
3875     // return the CSS HSL Color value
3876     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3877
3878   },
3879
3880   /**
3881    * getCSSHSLA
3882    * @return {String} a string representing this Color as a CSS HSLA Color value - that
3883    * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3884    * s and l are in the range [0,100], and a is in the range [0,1].
3885    */
3886   getCSSHSLA : function(){
3887
3888     // get the HSL components
3889     var hsl = this.getHSL();
3890
3891     // return the CSS HSL Color value
3892     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3893
3894   },
3895
3896   /**
3897    * Sets the Color of the specified node to this Color. This functions sets
3898    * the CSS 'color' property for the node. The parameter is:
3899    * 
3900    * @param {DomElement} node - the node whose Color should be set
3901    */
3902   setNodeColor : function(node){
3903
3904     // set the Color of the node
3905     node.style.color = this.getCSSHexadecimalRGB();
3906
3907   },
3908
3909   /**
3910    * Sets the background Color of the specified node to this Color. This
3911    * functions sets the CSS 'background-color' property for the node. The
3912    * parameter is:
3913    *
3914    * @param {DomElement} node - the node whose background Color should be set
3915    */
3916   setNodeBackgroundColor : function(node){
3917
3918     // set the background Color of the node
3919     node.style.backgroundColor = this.getCSSHexadecimalRGB();
3920
3921   },
3922   // convert between formats..
3923   toRGB: function()
3924   {
3925     var r = this.getIntegerRGB();
3926     return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3927     
3928   },
3929   toHSL : function()
3930   {
3931      var hsl = this.getHSL();
3932   // return the CSS HSL Color value
3933     return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
3934     
3935   },
3936   
3937   toHSV : function()
3938   {
3939     var rgb = this.toRGB();
3940     var hsv = rgb.getHSV();
3941    // return the CSS HSL Color value
3942     return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
3943     
3944   },
3945   
3946   // modify  v = 0 ... 1 (eg. 0.5)
3947   saturate : function(v)
3948   {
3949       var rgb = this.toRGB();
3950       var hsv = rgb.getHSV();
3951       return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
3952       
3953   
3954   },
3955   
3956    
3957   /**
3958    * getRGB
3959    * @return {Object} the RGB and alpha components of this Color as an object with r,
3960    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3961    * the range [0,1].
3962    */
3963   getRGB: function(){
3964    
3965     // return the RGB components
3966     return {
3967       'r' : this.rgb.r,
3968       'g' : this.rgb.g,
3969       'b' : this.rgb.b,
3970       'a' : this.alpha
3971     };
3972
3973   },
3974
3975   /**
3976    * getHSV
3977    * @return {Object} the HSV and alpha components of this Color as an object with h,
3978    * s, v, and a properties. h is in the range [0,360), s and v are in the range
3979    * [0,100], and a is in the range [0,1].
3980    */
3981   getHSV : function()
3982   {
3983     
3984     // calculate the HSV components if necessary
3985     if (this.hsv == null) {
3986       this.calculateHSV();
3987     }
3988
3989     // return the HSV components
3990     return {
3991       'h' : this.hsv.h,
3992       's' : this.hsv.s,
3993       'v' : this.hsv.v,
3994       'a' : this.alpha
3995     };
3996
3997   },
3998
3999   /**
4000    * getHSL
4001    * @return {Object} the HSL and alpha components of this Color as an object with h,
4002    * s, l, and a properties. h is in the range [0,360), s and l are in the range
4003    * [0,100], and a is in the range [0,1].
4004    */
4005   getHSL : function(){
4006     
4007      
4008     // calculate the HSV components if necessary
4009     if (this.hsl == null) { this.calculateHSL(); }
4010
4011     // return the HSL components
4012     return {
4013       'h' : this.hsl.h,
4014       's' : this.hsl.s,
4015       'l' : this.hsl.l,
4016       'a' : this.alpha
4017     };
4018
4019   }
4020   
4021
4022 });
4023
4024
4025 /**
4026  * @class Roo.lib.RGBColor
4027  * @extends Roo.lib.Color
4028  * Creates a Color specified in the RGB Color space, with an optional alpha
4029  * component. The parameters are:
4030  * @constructor
4031  * 
4032
4033  * @param {Number} r - the red component, clipped to the range [0,255]
4034  * @param {Number} g - the green component, clipped to the range [0,255]
4035  * @param {Number} b - the blue component, clipped to the range [0,255]
4036  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4037  *     optional and defaults to 1
4038  */
4039 Roo.lib.RGBColor = function (r, g, b, a){
4040
4041   // store the alpha component after clipping it if necessary
4042   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4043
4044   // store the RGB components after clipping them if necessary
4045   this.rgb =
4046       {
4047         'r' : Math.max(0, Math.min(255, r)),
4048         'g' : Math.max(0, Math.min(255, g)),
4049         'b' : Math.max(0, Math.min(255, b))
4050       };
4051
4052   // initialise the HSV and HSL components to null
4053   
4054
4055   /* 
4056    * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4057    * range [0,360). The parameters are:
4058    *
4059    * maximum - the maximum of the RGB component values
4060    * range   - the range of the RGB component values
4061    */
4062    
4063
4064 }
4065 // this does an 'exteds'
4066 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4067
4068   
4069     getHue  : function(maximum, range)
4070     {
4071       var rgb = this.rgb;
4072        
4073       // check whether the range is zero
4074       if (range == 0){
4075   
4076         // set the hue to zero (any hue is acceptable as the Color is grey)
4077         var hue = 0;
4078   
4079       }else{
4080   
4081         // determine which of the components has the highest value and set the hue
4082         switch (maximum){
4083   
4084           // red has the highest value
4085           case rgb.r:
4086             var hue = (rgb.g - rgb.b) / range * 60;
4087             if (hue < 0) { hue += 360; }
4088             break;
4089   
4090           // green has the highest value
4091           case rgb.g:
4092             var hue = (rgb.b - rgb.r) / range * 60 + 120;
4093             break;
4094   
4095           // blue has the highest value
4096           case rgb.b:
4097             var hue = (rgb.r - rgb.g) / range * 60 + 240;
4098             break;
4099   
4100         }
4101   
4102       }
4103   
4104       // return the hue
4105       return hue;
4106   
4107     },
4108
4109   /* //private Calculates and stores the HSV components of this RGBColor so that they can
4110    * be returned be the getHSV function.
4111    */
4112    calculateHSV : function(){
4113     var rgb = this.rgb;
4114     // get the maximum and range of the RGB component values
4115     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4116     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4117
4118     // store the HSV components
4119     this.hsv =
4120         {
4121           'h' : this.getHue(maximum, range),
4122           's' : (maximum == 0 ? 0 : 100 * range / maximum),
4123           'v' : maximum / 2.55
4124         };
4125
4126   },
4127
4128   /* //private Calculates and stores the HSL components of this RGBColor so that they can
4129    * be returned be the getHSL function.
4130    */
4131    calculateHSL : function(){
4132     var rgb = this.rgb;
4133     // get the maximum and range of the RGB component values
4134     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4135     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4136
4137     // determine the lightness in the range [0,1]
4138     var l = maximum / 255 - range / 510;
4139
4140     // store the HSL components
4141     this.hsl =
4142         {
4143           'h' : this.getHue(maximum, range),
4144           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4145           'l' : 100 * l
4146         };
4147
4148   }
4149
4150 });
4151
4152 /**
4153  * @class Roo.lib.HSVColor
4154  * @extends Roo.lib.Color
4155  * Creates a Color specified in the HSV Color space, with an optional alpha
4156  * component. The parameters are:
4157  * @constructor
4158  *
4159  * @param {Number} h - the hue component, wrapped to the range [0,360)
4160  * @param {Number} s - the saturation component, clipped to the range [0,100]
4161  * @param {Number} v - the value component, clipped to the range [0,100]
4162  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4163  *     optional and defaults to 1
4164  */
4165 Roo.lib.HSVColor = function (h, s, v, a){
4166
4167   // store the alpha component after clipping it if necessary
4168   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4169
4170   // store the HSV components after clipping or wrapping them if necessary
4171   this.hsv =
4172       {
4173         'h' : (h % 360 + 360) % 360,
4174         's' : Math.max(0, Math.min(100, s)),
4175         'v' : Math.max(0, Math.min(100, v))
4176       };
4177
4178   // initialise the RGB and HSL components to null
4179   this.rgb = null;
4180   this.hsl = null;
4181 }
4182
4183 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4184   /* Calculates and stores the RGB components of this HSVColor so that they can
4185    * be returned be the getRGB function.
4186    */
4187   calculateRGB: function ()
4188   {
4189     var hsv = this.hsv;
4190     // check whether the saturation is zero
4191     if (hsv.s == 0){
4192
4193       // set the Color to the appropriate shade of grey
4194       var r = hsv.v;
4195       var g = hsv.v;
4196       var b = hsv.v;
4197
4198     }else{
4199
4200       // set some temporary values
4201       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
4202       var p  = hsv.v * (1 - hsv.s / 100);
4203       var q  = hsv.v * (1 - hsv.s / 100 * f);
4204       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
4205
4206       // set the RGB Color components to their temporary values
4207       switch (Math.floor(hsv.h / 60)){
4208         case 0: var r = hsv.v; var g = t; var b = p; break;
4209         case 1: var r = q; var g = hsv.v; var b = p; break;
4210         case 2: var r = p; var g = hsv.v; var b = t; break;
4211         case 3: var r = p; var g = q; var b = hsv.v; break;
4212         case 4: var r = t; var g = p; var b = hsv.v; break;
4213         case 5: var r = hsv.v; var g = p; var b = q; break;
4214       }
4215
4216     }
4217
4218     // store the RGB components
4219     this.rgb =
4220         {
4221           'r' : r * 2.55,
4222           'g' : g * 2.55,
4223           'b' : b * 2.55
4224         };
4225
4226   },
4227
4228   /* Calculates and stores the HSL components of this HSVColor so that they can
4229    * be returned be the getHSL function.
4230    */
4231   calculateHSL : function (){
4232
4233     var hsv = this.hsv;
4234     // determine the lightness in the range [0,100]
4235     var l = (2 - hsv.s / 100) * hsv.v / 2;
4236
4237     // store the HSL components
4238     this.hsl =
4239         {
4240           'h' : hsv.h,
4241           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4242           'l' : l
4243         };
4244
4245     // correct a division-by-zero error
4246     if (isNaN(hsl.s)) { hsl.s = 0; }
4247
4248   } 
4249  
4250
4251 });
4252  
4253
4254 /**
4255  * @class Roo.lib.HSLColor
4256  * @extends Roo.lib.Color
4257  *
4258  * @constructor
4259  * Creates a Color specified in the HSL Color space, with an optional alpha
4260  * component. The parameters are:
4261  *
4262  * @param {Number} h - the hue component, wrapped to the range [0,360)
4263  * @param {Number} s - the saturation component, clipped to the range [0,100]
4264  * @param {Number} l - the lightness component, clipped to the range [0,100]
4265  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4266  *     optional and defaults to 1
4267  */
4268
4269 Roo.lib.HSLColor = function(h, s, l, a){
4270
4271   // store the alpha component after clipping it if necessary
4272   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4273
4274   // store the HSL components after clipping or wrapping them if necessary
4275   this.hsl =
4276       {
4277         'h' : (h % 360 + 360) % 360,
4278         's' : Math.max(0, Math.min(100, s)),
4279         'l' : Math.max(0, Math.min(100, l))
4280       };
4281
4282   // initialise the RGB and HSV components to null
4283 }
4284
4285 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4286
4287   /* Calculates and stores the RGB components of this HSLColor so that they can
4288    * be returned be the getRGB function.
4289    */
4290   calculateRGB: function (){
4291
4292     // check whether the saturation is zero
4293     if (this.hsl.s == 0){
4294
4295       // store the RGB components representing the appropriate shade of grey
4296       this.rgb =
4297           {
4298             'r' : this.hsl.l * 2.55,
4299             'g' : this.hsl.l * 2.55,
4300             'b' : this.hsl.l * 2.55
4301           };
4302
4303     }else{
4304
4305       // set some temporary values
4306       var p = this.hsl.l < 50
4307             ? this.hsl.l * (1 + hsl.s / 100)
4308             : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4309       var q = 2 * hsl.l - p;
4310
4311       // initialise the RGB components
4312       this.rgb =
4313           {
4314             'r' : (h + 120) / 60 % 6,
4315             'g' : h / 60,
4316             'b' : (h + 240) / 60 % 6
4317           };
4318
4319       // loop over the RGB components
4320       for (var key in this.rgb){
4321
4322         // ensure that the property is not inherited from the root object
4323         if (this.rgb.hasOwnProperty(key)){
4324
4325           // set the component to its value in the range [0,100]
4326           if (this.rgb[key] < 1){
4327             this.rgb[key] = q + (p - q) * this.rgb[key];
4328           }else if (this.rgb[key] < 3){
4329             this.rgb[key] = p;
4330           }else if (this.rgb[key] < 4){
4331             this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4332           }else{
4333             this.rgb[key] = q;
4334           }
4335
4336           // set the component to its value in the range [0,255]
4337           this.rgb[key] *= 2.55;
4338
4339         }
4340
4341       }
4342
4343     }
4344
4345   },
4346
4347   /* Calculates and stores the HSV components of this HSLColor so that they can
4348    * be returned be the getHSL function.
4349    */
4350    calculateHSV : function(){
4351
4352     // set a temporary value
4353     var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4354
4355     // store the HSV components
4356     this.hsv =
4357         {
4358           'h' : this.hsl.h,
4359           's' : 200 * t / (this.hsl.l + t),
4360           'v' : t + this.hsl.l
4361         };
4362
4363     // correct a division-by-zero error
4364     if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4365
4366   }
4367  
4368
4369 });
4370 /*
4371  * Portions of this file are based on pieces of Yahoo User Interface Library
4372  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4373  * YUI licensed under the BSD License:
4374  * http://developer.yahoo.net/yui/license.txt
4375  * <script type="text/javascript">
4376  *
4377  */
4378 (function() {
4379
4380     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4381         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4382     };
4383
4384     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4385
4386     var fly = Roo.lib.AnimBase.fly;
4387     var Y = Roo.lib;
4388     var superclass = Y.ColorAnim.superclass;
4389     var proto = Y.ColorAnim.prototype;
4390
4391     proto.toString = function() {
4392         var el = this.getEl();
4393         var id = el.id || el.tagName;
4394         return ("ColorAnim " + id);
4395     };
4396
4397     proto.patterns.color = /color$/i;
4398     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4399     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4400     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4401     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4402
4403
4404     proto.parseColor = function(s) {
4405         if (s.length == 3) {
4406             return s;
4407         }
4408
4409         var c = this.patterns.hex.exec(s);
4410         if (c && c.length == 4) {
4411             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4412         }
4413
4414         c = this.patterns.rgb.exec(s);
4415         if (c && c.length == 4) {
4416             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4417         }
4418
4419         c = this.patterns.hex3.exec(s);
4420         if (c && c.length == 4) {
4421             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4422         }
4423
4424         return null;
4425     };
4426     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4427     proto.getAttribute = function(attr) {
4428         var el = this.getEl();
4429         if (this.patterns.color.test(attr)) {
4430             var val = fly(el).getStyle(attr);
4431
4432             if (this.patterns.transparent.test(val)) {
4433                 var parent = el.parentNode;
4434                 val = fly(parent).getStyle(attr);
4435
4436                 while (parent && this.patterns.transparent.test(val)) {
4437                     parent = parent.parentNode;
4438                     val = fly(parent).getStyle(attr);
4439                     if (parent.tagName.toUpperCase() == 'HTML') {
4440                         val = '#fff';
4441                     }
4442                 }
4443             }
4444         } else {
4445             val = superclass.getAttribute.call(this, attr);
4446         }
4447
4448         return val;
4449     };
4450     proto.getAttribute = function(attr) {
4451         var el = this.getEl();
4452         if (this.patterns.color.test(attr)) {
4453             var val = fly(el).getStyle(attr);
4454
4455             if (this.patterns.transparent.test(val)) {
4456                 var parent = el.parentNode;
4457                 val = fly(parent).getStyle(attr);
4458
4459                 while (parent && this.patterns.transparent.test(val)) {
4460                     parent = parent.parentNode;
4461                     val = fly(parent).getStyle(attr);
4462                     if (parent.tagName.toUpperCase() == 'HTML') {
4463                         val = '#fff';
4464                     }
4465                 }
4466             }
4467         } else {
4468             val = superclass.getAttribute.call(this, attr);
4469         }
4470
4471         return val;
4472     };
4473
4474     proto.doMethod = function(attr, start, end) {
4475         var val;
4476
4477         if (this.patterns.color.test(attr)) {
4478             val = [];
4479             for (var i = 0, len = start.length; i < len; ++i) {
4480                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4481             }
4482
4483             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4484         }
4485         else {
4486             val = superclass.doMethod.call(this, attr, start, end);
4487         }
4488
4489         return val;
4490     };
4491
4492     proto.setRuntimeAttribute = function(attr) {
4493         superclass.setRuntimeAttribute.call(this, attr);
4494
4495         if (this.patterns.color.test(attr)) {
4496             var attributes = this.attributes;
4497             var start = this.parseColor(this.runtimeAttributes[attr].start);
4498             var end = this.parseColor(this.runtimeAttributes[attr].end);
4499
4500             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4501                 end = this.parseColor(attributes[attr].by);
4502
4503                 for (var i = 0, len = start.length; i < len; ++i) {
4504                     end[i] = start[i] + end[i];
4505                 }
4506             }
4507
4508             this.runtimeAttributes[attr].start = start;
4509             this.runtimeAttributes[attr].end = end;
4510         }
4511     };
4512 })();
4513
4514 /*
4515  * Portions of this file are based on pieces of Yahoo User Interface Library
4516  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4517  * YUI licensed under the BSD License:
4518  * http://developer.yahoo.net/yui/license.txt
4519  * <script type="text/javascript">
4520  *
4521  */
4522 Roo.lib.Easing = {
4523
4524
4525     easeNone: function (t, b, c, d) {
4526         return c * t / d + b;
4527     },
4528
4529
4530     easeIn: function (t, b, c, d) {
4531         return c * (t /= d) * t + b;
4532     },
4533
4534
4535     easeOut: function (t, b, c, d) {
4536         return -c * (t /= d) * (t - 2) + b;
4537     },
4538
4539
4540     easeBoth: function (t, b, c, d) {
4541         if ((t /= d / 2) < 1) {
4542             return c / 2 * t * t + b;
4543         }
4544
4545         return -c / 2 * ((--t) * (t - 2) - 1) + b;
4546     },
4547
4548
4549     easeInStrong: function (t, b, c, d) {
4550         return c * (t /= d) * t * t * t + b;
4551     },
4552
4553
4554     easeOutStrong: function (t, b, c, d) {
4555         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4556     },
4557
4558
4559     easeBothStrong: function (t, b, c, d) {
4560         if ((t /= d / 2) < 1) {
4561             return c / 2 * t * t * t * t + b;
4562         }
4563
4564         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4565     },
4566
4567
4568
4569     elasticIn: function (t, b, c, d, a, p) {
4570         if (t == 0) {
4571             return b;
4572         }
4573         if ((t /= d) == 1) {
4574             return b + c;
4575         }
4576         if (!p) {
4577             p = d * .3;
4578         }
4579
4580         if (!a || a < Math.abs(c)) {
4581             a = c;
4582             var s = p / 4;
4583         }
4584         else {
4585             var s = p / (2 * Math.PI) * Math.asin(c / a);
4586         }
4587
4588         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4589     },
4590
4591
4592     elasticOut: function (t, b, c, d, a, p) {
4593         if (t == 0) {
4594             return b;
4595         }
4596         if ((t /= d) == 1) {
4597             return b + c;
4598         }
4599         if (!p) {
4600             p = d * .3;
4601         }
4602
4603         if (!a || a < Math.abs(c)) {
4604             a = c;
4605             var s = p / 4;
4606         }
4607         else {
4608             var s = p / (2 * Math.PI) * Math.asin(c / a);
4609         }
4610
4611         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4612     },
4613
4614
4615     elasticBoth: function (t, b, c, d, a, p) {
4616         if (t == 0) {
4617             return b;
4618         }
4619
4620         if ((t /= d / 2) == 2) {
4621             return b + c;
4622         }
4623
4624         if (!p) {
4625             p = d * (.3 * 1.5);
4626         }
4627
4628         if (!a || a < Math.abs(c)) {
4629             a = c;
4630             var s = p / 4;
4631         }
4632         else {
4633             var s = p / (2 * Math.PI) * Math.asin(c / a);
4634         }
4635
4636         if (t < 1) {
4637             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4638                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4639         }
4640         return a * Math.pow(2, -10 * (t -= 1)) *
4641                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4642     },
4643
4644
4645
4646     backIn: function (t, b, c, d, s) {
4647         if (typeof s == 'undefined') {
4648             s = 1.70158;
4649         }
4650         return c * (t /= d) * t * ((s + 1) * t - s) + b;
4651     },
4652
4653
4654     backOut: function (t, b, c, d, s) {
4655         if (typeof s == 'undefined') {
4656             s = 1.70158;
4657         }
4658         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4659     },
4660
4661
4662     backBoth: function (t, b, c, d, s) {
4663         if (typeof s == 'undefined') {
4664             s = 1.70158;
4665         }
4666
4667         if ((t /= d / 2 ) < 1) {
4668             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4669         }
4670         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4671     },
4672
4673
4674     bounceIn: function (t, b, c, d) {
4675         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4676     },
4677
4678
4679     bounceOut: function (t, b, c, d) {
4680         if ((t /= d) < (1 / 2.75)) {
4681             return c * (7.5625 * t * t) + b;
4682         } else if (t < (2 / 2.75)) {
4683             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4684         } else if (t < (2.5 / 2.75)) {
4685             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4686         }
4687         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4688     },
4689
4690
4691     bounceBoth: function (t, b, c, d) {
4692         if (t < d / 2) {
4693             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4694         }
4695         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4696     }
4697 };/*
4698  * Portions of this file are based on pieces of Yahoo User Interface Library
4699  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4700  * YUI licensed under the BSD License:
4701  * http://developer.yahoo.net/yui/license.txt
4702  * <script type="text/javascript">
4703  *
4704  */
4705     (function() {
4706         Roo.lib.Motion = function(el, attributes, duration, method) {
4707             if (el) {
4708                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4709             }
4710         };
4711
4712         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4713
4714
4715         var Y = Roo.lib;
4716         var superclass = Y.Motion.superclass;
4717         var proto = Y.Motion.prototype;
4718
4719         proto.toString = function() {
4720             var el = this.getEl();
4721             var id = el.id || el.tagName;
4722             return ("Motion " + id);
4723         };
4724
4725         proto.patterns.points = /^points$/i;
4726
4727         proto.setAttribute = function(attr, val, unit) {
4728             if (this.patterns.points.test(attr)) {
4729                 unit = unit || 'px';
4730                 superclass.setAttribute.call(this, 'left', val[0], unit);
4731                 superclass.setAttribute.call(this, 'top', val[1], unit);
4732             } else {
4733                 superclass.setAttribute.call(this, attr, val, unit);
4734             }
4735         };
4736
4737         proto.getAttribute = function(attr) {
4738             if (this.patterns.points.test(attr)) {
4739                 var val = [
4740                         superclass.getAttribute.call(this, 'left'),
4741                         superclass.getAttribute.call(this, 'top')
4742                         ];
4743             } else {
4744                 val = superclass.getAttribute.call(this, attr);
4745             }
4746
4747             return val;
4748         };
4749
4750         proto.doMethod = function(attr, start, end) {
4751             var val = null;
4752
4753             if (this.patterns.points.test(attr)) {
4754                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4755                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4756             } else {
4757                 val = superclass.doMethod.call(this, attr, start, end);
4758             }
4759             return val;
4760         };
4761
4762         proto.setRuntimeAttribute = function(attr) {
4763             if (this.patterns.points.test(attr)) {
4764                 var el = this.getEl();
4765                 var attributes = this.attributes;
4766                 var start;
4767                 var control = attributes['points']['control'] || [];
4768                 var end;
4769                 var i, len;
4770
4771                 if (control.length > 0 && !(control[0] instanceof Array)) {
4772                     control = [control];
4773                 } else {
4774                     var tmp = [];
4775                     for (i = 0,len = control.length; i < len; ++i) {
4776                         tmp[i] = control[i];
4777                     }
4778                     control = tmp;
4779                 }
4780
4781                 Roo.fly(el).position();
4782
4783                 if (isset(attributes['points']['from'])) {
4784                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4785                 }
4786                 else {
4787                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4788                 }
4789
4790                 start = this.getAttribute('points');
4791
4792
4793                 if (isset(attributes['points']['to'])) {
4794                     end = translateValues.call(this, attributes['points']['to'], start);
4795
4796                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4797                     for (i = 0,len = control.length; i < len; ++i) {
4798                         control[i] = translateValues.call(this, control[i], start);
4799                     }
4800
4801
4802                 } else if (isset(attributes['points']['by'])) {
4803                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4804
4805                     for (i = 0,len = control.length; i < len; ++i) {
4806                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4807                     }
4808                 }
4809
4810                 this.runtimeAttributes[attr] = [start];
4811
4812                 if (control.length > 0) {
4813                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4814                 }
4815
4816                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4817             }
4818             else {
4819                 superclass.setRuntimeAttribute.call(this, attr);
4820             }
4821         };
4822
4823         var translateValues = function(val, start) {
4824             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4825             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4826
4827             return val;
4828         };
4829
4830         var isset = function(prop) {
4831             return (typeof prop !== 'undefined');
4832         };
4833     })();
4834 /*
4835  * Portions of this file are based on pieces of Yahoo User Interface Library
4836  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4837  * YUI licensed under the BSD License:
4838  * http://developer.yahoo.net/yui/license.txt
4839  * <script type="text/javascript">
4840  *
4841  */
4842     (function() {
4843         Roo.lib.Scroll = function(el, attributes, duration, method) {
4844             if (el) {
4845                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4846             }
4847         };
4848
4849         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4850
4851
4852         var Y = Roo.lib;
4853         var superclass = Y.Scroll.superclass;
4854         var proto = Y.Scroll.prototype;
4855
4856         proto.toString = function() {
4857             var el = this.getEl();
4858             var id = el.id || el.tagName;
4859             return ("Scroll " + id);
4860         };
4861
4862         proto.doMethod = function(attr, start, end) {
4863             var val = null;
4864
4865             if (attr == 'scroll') {
4866                 val = [
4867                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4868                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4869                         ];
4870
4871             } else {
4872                 val = superclass.doMethod.call(this, attr, start, end);
4873             }
4874             return val;
4875         };
4876
4877         proto.getAttribute = function(attr) {
4878             var val = null;
4879             var el = this.getEl();
4880
4881             if (attr == 'scroll') {
4882                 val = [ el.scrollLeft, el.scrollTop ];
4883             } else {
4884                 val = superclass.getAttribute.call(this, attr);
4885             }
4886
4887             return val;
4888         };
4889
4890         proto.setAttribute = function(attr, val, unit) {
4891             var el = this.getEl();
4892
4893             if (attr == 'scroll') {
4894                 el.scrollLeft = val[0];
4895                 el.scrollTop = val[1];
4896             } else {
4897                 superclass.setAttribute.call(this, attr, val, unit);
4898             }
4899         };
4900     })();
4901 /*
4902  * Based on:
4903  * Ext JS Library 1.1.1
4904  * Copyright(c) 2006-2007, Ext JS, LLC.
4905  *
4906  * Originally Released Under LGPL - original licence link has changed is not relivant.
4907  *
4908  * Fork - LGPL
4909  * <script type="text/javascript">
4910  */
4911
4912
4913 // nasty IE9 hack - what a pile of crap that is..
4914
4915  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4916     Range.prototype.createContextualFragment = function (html) {
4917         var doc = window.document;
4918         var container = doc.createElement("div");
4919         container.innerHTML = html;
4920         var frag = doc.createDocumentFragment(), n;
4921         while ((n = container.firstChild)) {
4922             frag.appendChild(n);
4923         }
4924         return frag;
4925     };
4926 }
4927
4928 /**
4929  * @class Roo.DomHelper
4930  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4931  * 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>.
4932  * @static
4933  */
4934 Roo.DomHelper = function(){
4935     var tempTableEl = null;
4936     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4937     var tableRe = /^table|tbody|tr|td$/i;
4938     var xmlns = {};
4939     // build as innerHTML where available
4940     /** @ignore */
4941     var createHtml = function(o){
4942         if(typeof o == 'string'){
4943             return o;
4944         }
4945         var b = "";
4946         if(!o.tag){
4947             o.tag = "div";
4948         }
4949         b += "<" + o.tag;
4950         for(var attr in o){
4951             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4952             if(attr == "style"){
4953                 var s = o["style"];
4954                 if(typeof s == "function"){
4955                     s = s.call();
4956                 }
4957                 if(typeof s == "string"){
4958                     b += ' style="' + s + '"';
4959                 }else if(typeof s == "object"){
4960                     b += ' style="';
4961                     for(var key in s){
4962                         if(typeof s[key] != "function"){
4963                             b += key + ":" + s[key] + ";";
4964                         }
4965                     }
4966                     b += '"';
4967                 }
4968             }else{
4969                 if(attr == "cls"){
4970                     b += ' class="' + o["cls"] + '"';
4971                 }else if(attr == "htmlFor"){
4972                     b += ' for="' + o["htmlFor"] + '"';
4973                 }else{
4974                     b += " " + attr + '="' + o[attr] + '"';
4975                 }
4976             }
4977         }
4978         if(emptyTags.test(o.tag)){
4979             b += "/>";
4980         }else{
4981             b += ">";
4982             var cn = o.children || o.cn;
4983             if(cn){
4984                 //http://bugs.kde.org/show_bug.cgi?id=71506
4985                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4986                     for(var i = 0, len = cn.length; i < len; i++) {
4987                         b += createHtml(cn[i], b);
4988                     }
4989                 }else{
4990                     b += createHtml(cn, b);
4991                 }
4992             }
4993             if(o.html){
4994                 b += o.html;
4995             }
4996             b += "</" + o.tag + ">";
4997         }
4998         return b;
4999     };
5000
5001     // build as dom
5002     /** @ignore */
5003     var createDom = function(o, parentNode){
5004          
5005         // defininition craeted..
5006         var ns = false;
5007         if (o.ns && o.ns != 'html') {
5008                
5009             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5010                 xmlns[o.ns] = o.xmlns;
5011                 ns = o.xmlns;
5012             }
5013             if (typeof(xmlns[o.ns]) == 'undefined') {
5014                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5015             }
5016             ns = xmlns[o.ns];
5017         }
5018         
5019         
5020         if (typeof(o) == 'string') {
5021             return parentNode.appendChild(document.createTextNode(o));
5022         }
5023         o.tag = o.tag || div;
5024         if (o.ns && Roo.isIE) {
5025             ns = false;
5026             o.tag = o.ns + ':' + o.tag;
5027             
5028         }
5029         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
5030         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5031         for(var attr in o){
5032             
5033             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
5034                     attr == "style" || typeof o[attr] == "function") { continue; }
5035                     
5036             if(attr=="cls" && Roo.isIE){
5037                 el.className = o["cls"];
5038             }else{
5039                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5040                 else { 
5041                     el[attr] = o[attr];
5042                 }
5043             }
5044         }
5045         Roo.DomHelper.applyStyles(el, o.style);
5046         var cn = o.children || o.cn;
5047         if(cn){
5048             //http://bugs.kde.org/show_bug.cgi?id=71506
5049              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5050                 for(var i = 0, len = cn.length; i < len; i++) {
5051                     createDom(cn[i], el);
5052                 }
5053             }else{
5054                 createDom(cn, el);
5055             }
5056         }
5057         if(o.html){
5058             el.innerHTML = o.html;
5059         }
5060         if(parentNode){
5061            parentNode.appendChild(el);
5062         }
5063         return el;
5064     };
5065
5066     var ieTable = function(depth, s, h, e){
5067         tempTableEl.innerHTML = [s, h, e].join('');
5068         var i = -1, el = tempTableEl;
5069         while(++i < depth && el.firstChild){
5070             el = el.firstChild;
5071         }
5072         return el;
5073     };
5074
5075     // kill repeat to save bytes
5076     var ts = '<table>',
5077         te = '</table>',
5078         tbs = ts+'<tbody>',
5079         tbe = '</tbody>'+te,
5080         trs = tbs + '<tr>',
5081         tre = '</tr>'+tbe;
5082
5083     /**
5084      * @ignore
5085      * Nasty code for IE's broken table implementation
5086      */
5087     var insertIntoTable = function(tag, where, el, html){
5088         if(!tempTableEl){
5089             tempTableEl = document.createElement('div');
5090         }
5091         var node;
5092         var before = null;
5093         if(tag == 'td'){
5094             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5095                 return;
5096             }
5097             if(where == 'beforebegin'){
5098                 before = el;
5099                 el = el.parentNode;
5100             } else{
5101                 before = el.nextSibling;
5102                 el = el.parentNode;
5103             }
5104             node = ieTable(4, trs, html, tre);
5105         }
5106         else if(tag == 'tr'){
5107             if(where == 'beforebegin'){
5108                 before = el;
5109                 el = el.parentNode;
5110                 node = ieTable(3, tbs, html, tbe);
5111             } else if(where == 'afterend'){
5112                 before = el.nextSibling;
5113                 el = el.parentNode;
5114                 node = ieTable(3, tbs, html, tbe);
5115             } else{ // INTO a TR
5116                 if(where == 'afterbegin'){
5117                     before = el.firstChild;
5118                 }
5119                 node = ieTable(4, trs, html, tre);
5120             }
5121         } else if(tag == 'tbody'){
5122             if(where == 'beforebegin'){
5123                 before = el;
5124                 el = el.parentNode;
5125                 node = ieTable(2, ts, html, te);
5126             } else if(where == 'afterend'){
5127                 before = el.nextSibling;
5128                 el = el.parentNode;
5129                 node = ieTable(2, ts, html, te);
5130             } else{
5131                 if(where == 'afterbegin'){
5132                     before = el.firstChild;
5133                 }
5134                 node = ieTable(3, tbs, html, tbe);
5135             }
5136         } else{ // TABLE
5137             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5138                 return;
5139             }
5140             if(where == 'afterbegin'){
5141                 before = el.firstChild;
5142             }
5143             node = ieTable(2, ts, html, te);
5144         }
5145         el.insertBefore(node, before);
5146         return node;
5147     };
5148
5149     return {
5150     /** True to force the use of DOM instead of html fragments @type Boolean */
5151     useDom : false,
5152
5153     /**
5154      * Returns the markup for the passed Element(s) config
5155      * @param {Object} o The Dom object spec (and children)
5156      * @return {String}
5157      */
5158     markup : function(o){
5159         return createHtml(o);
5160     },
5161
5162     /**
5163      * Applies a style specification to an element
5164      * @param {String/HTMLElement} el The element to apply styles to
5165      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5166      * a function which returns such a specification.
5167      */
5168     applyStyles : function(el, styles){
5169         if(styles){
5170            el = Roo.fly(el);
5171            if(typeof styles == "string"){
5172                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5173                var matches;
5174                while ((matches = re.exec(styles)) != null){
5175                    el.setStyle(matches[1], matches[2]);
5176                }
5177            }else if (typeof styles == "object"){
5178                for (var style in styles){
5179                   el.setStyle(style, styles[style]);
5180                }
5181            }else if (typeof styles == "function"){
5182                 Roo.DomHelper.applyStyles(el, styles.call());
5183            }
5184         }
5185     },
5186
5187     /**
5188      * Inserts an HTML fragment into the Dom
5189      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5190      * @param {HTMLElement} el The context element
5191      * @param {String} html The HTML fragmenet
5192      * @return {HTMLElement} The new node
5193      */
5194     insertHtml : function(where, el, html){
5195         where = where.toLowerCase();
5196         if(el.insertAdjacentHTML){
5197             if(tableRe.test(el.tagName)){
5198                 var rs;
5199                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5200                     return rs;
5201                 }
5202             }
5203             switch(where){
5204                 case "beforebegin":
5205                     el.insertAdjacentHTML('BeforeBegin', html);
5206                     return el.previousSibling;
5207                 case "afterbegin":
5208                     el.insertAdjacentHTML('AfterBegin', html);
5209                     return el.firstChild;
5210                 case "beforeend":
5211                     el.insertAdjacentHTML('BeforeEnd', html);
5212                     return el.lastChild;
5213                 case "afterend":
5214                     el.insertAdjacentHTML('AfterEnd', html);
5215                     return el.nextSibling;
5216             }
5217             throw 'Illegal insertion point -> "' + where + '"';
5218         }
5219         var range = el.ownerDocument.createRange();
5220         var frag;
5221         switch(where){
5222              case "beforebegin":
5223                 range.setStartBefore(el);
5224                 frag = range.createContextualFragment(html);
5225                 el.parentNode.insertBefore(frag, el);
5226                 return el.previousSibling;
5227              case "afterbegin":
5228                 if(el.firstChild){
5229                     range.setStartBefore(el.firstChild);
5230                     frag = range.createContextualFragment(html);
5231                     el.insertBefore(frag, el.firstChild);
5232                     return el.firstChild;
5233                 }else{
5234                     el.innerHTML = html;
5235                     return el.firstChild;
5236                 }
5237             case "beforeend":
5238                 if(el.lastChild){
5239                     range.setStartAfter(el.lastChild);
5240                     frag = range.createContextualFragment(html);
5241                     el.appendChild(frag);
5242                     return el.lastChild;
5243                 }else{
5244                     el.innerHTML = html;
5245                     return el.lastChild;
5246                 }
5247             case "afterend":
5248                 range.setStartAfter(el);
5249                 frag = range.createContextualFragment(html);
5250                 el.parentNode.insertBefore(frag, el.nextSibling);
5251                 return el.nextSibling;
5252             }
5253             throw 'Illegal insertion point -> "' + where + '"';
5254     },
5255
5256     /**
5257      * Creates new Dom element(s) and inserts them before el
5258      * @param {String/HTMLElement/Element} el The context element
5259      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5260      * @param {Boolean} returnElement (optional) true to return a Roo.Element
5261      * @return {HTMLElement/Roo.Element} The new node
5262      */
5263     insertBefore : function(el, o, returnElement){
5264         return this.doInsert(el, o, returnElement, "beforeBegin");
5265     },
5266
5267     /**
5268      * Creates new Dom element(s) and inserts them after el
5269      * @param {String/HTMLElement/Element} el The context element
5270      * @param {Object} o The Dom object spec (and children)
5271      * @param {Boolean} returnElement (optional) true to return a Roo.Element
5272      * @return {HTMLElement/Roo.Element} The new node
5273      */
5274     insertAfter : function(el, o, returnElement){
5275         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5276     },
5277
5278     /**
5279      * Creates new Dom element(s) and inserts them as the first child of el
5280      * @param {String/HTMLElement/Element} el The context element
5281      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5282      * @param {Boolean} returnElement (optional) true to return a Roo.Element
5283      * @return {HTMLElement/Roo.Element} The new node
5284      */
5285     insertFirst : function(el, o, returnElement){
5286         return this.doInsert(el, o, returnElement, "afterBegin");
5287     },
5288
5289     // private
5290     doInsert : function(el, o, returnElement, pos, sibling){
5291         el = Roo.getDom(el);
5292         var newNode;
5293         if(this.useDom || o.ns){
5294             newNode = createDom(o, null);
5295             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5296         }else{
5297             var html = createHtml(o);
5298             newNode = this.insertHtml(pos, el, html);
5299         }
5300         return returnElement ? Roo.get(newNode, true) : newNode;
5301     },
5302
5303     /**
5304      * Creates new Dom element(s) and appends them to el
5305      * @param {String/HTMLElement/Element} el The context element
5306      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5307      * @param {Boolean} returnElement (optional) true to return a Roo.Element
5308      * @return {HTMLElement/Roo.Element} The new node
5309      */
5310     append : function(el, o, returnElement){
5311         el = Roo.getDom(el);
5312         var newNode;
5313         if(this.useDom || o.ns){
5314             newNode = createDom(o, null);
5315             el.appendChild(newNode);
5316         }else{
5317             var html = createHtml(o);
5318             newNode = this.insertHtml("beforeEnd", el, html);
5319         }
5320         return returnElement ? Roo.get(newNode, true) : newNode;
5321     },
5322
5323     /**
5324      * Creates new Dom element(s) and overwrites the contents of el with them
5325      * @param {String/HTMLElement/Element} el The context element
5326      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5327      * @param {Boolean} returnElement (optional) true to return a Roo.Element
5328      * @return {HTMLElement/Roo.Element} The new node
5329      */
5330     overwrite : function(el, o, returnElement){
5331         el = Roo.getDom(el);
5332         if (o.ns) {
5333           
5334             while (el.childNodes.length) {
5335                 el.removeChild(el.firstChild);
5336             }
5337             createDom(o, el);
5338         } else {
5339             el.innerHTML = createHtml(o);   
5340         }
5341         
5342         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5343     },
5344
5345     /**
5346      * Creates a new Roo.DomHelper.Template from the Dom object spec
5347      * @param {Object} o The Dom object spec (and children)
5348      * @return {Roo.DomHelper.Template} The new template
5349      */
5350     createTemplate : function(o){
5351         var html = createHtml(o);
5352         return new Roo.Template(html);
5353     }
5354     };
5355 }();
5356 /*
5357  * Based on:
5358  * Ext JS Library 1.1.1
5359  * Copyright(c) 2006-2007, Ext JS, LLC.
5360  *
5361  * Originally Released Under LGPL - original licence link has changed is not relivant.
5362  *
5363  * Fork - LGPL
5364  * <script type="text/javascript">
5365  */
5366  
5367 /**
5368 * @class Roo.Template
5369 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5370 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5371 * Usage:
5372 <pre><code>
5373 var t = new Roo.Template({
5374     html :  '&lt;div name="{id}"&gt;' + 
5375         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5376         '&lt;/div&gt;',
5377     myformat: function (value, allValues) {
5378         return 'XX' + value;
5379     }
5380 });
5381 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5382 </code></pre>
5383 * For more information see this blog post with examples:
5384 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5385      - Create Elements using DOM, HTML fragments and Templates</a>. 
5386 * @constructor
5387 * @param {Object} cfg - Configuration object.
5388 */
5389 Roo.Template = function(cfg){
5390     // BC!
5391     if(cfg instanceof Array){
5392         cfg = cfg.join("");
5393     }else if(arguments.length > 1){
5394         cfg = Array.prototype.join.call(arguments, "");
5395     }
5396     
5397     
5398     if (typeof(cfg) == 'object') {
5399         Roo.apply(this,cfg)
5400     } else {
5401         // bc
5402         this.html = cfg;
5403     }
5404     if (this.url) {
5405         this.load();
5406     }
5407     
5408 };
5409 Roo.Template.prototype = {
5410     
5411     /**
5412      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5413      */
5414     onLoad : false,
5415     
5416     
5417     /**
5418      * @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..
5419      *                    it should be fixed so that template is observable...
5420      */
5421     url : false,
5422     /**
5423      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5424      */
5425     html : '',
5426     
5427     
5428     compiled : false,
5429     loaded : false,
5430     /**
5431      * Returns an HTML fragment of this template with the specified values applied.
5432      * @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'})
5433      * @return {String} The HTML fragment
5434      */
5435     
5436    
5437     
5438     applyTemplate : function(values){
5439         //Roo.log(["applyTemplate", values]);
5440         try {
5441            
5442             if(this.compiled){
5443                 return this.compiled(values);
5444             }
5445             var useF = this.disableFormats !== true;
5446             var fm = Roo.util.Format, tpl = this;
5447             var fn = function(m, name, format, args){
5448                 if(format && useF){
5449                     if(format.substr(0, 5) == "this."){
5450                         return tpl.call(format.substr(5), values[name], values);
5451                     }else{
5452                         if(args){
5453                             // quoted values are required for strings in compiled templates, 
5454                             // but for non compiled we need to strip them
5455                             // quoted reversed for jsmin
5456                             var re = /^\s*['"](.*)["']\s*$/;
5457                             args = args.split(',');
5458                             for(var i = 0, len = args.length; i < len; i++){
5459                                 args[i] = args[i].replace(re, "$1");
5460                             }
5461                             args = [values[name]].concat(args);
5462                         }else{
5463                             args = [values[name]];
5464                         }
5465                         return fm[format].apply(fm, args);
5466                     }
5467                 }else{
5468                     return values[name] !== undefined ? values[name] : "";
5469                 }
5470             };
5471             return this.html.replace(this.re, fn);
5472         } catch (e) {
5473             Roo.log(e);
5474             throw e;
5475         }
5476          
5477     },
5478     
5479     loading : false,
5480       
5481     load : function ()
5482     {
5483          
5484         if (this.loading) {
5485             return;
5486         }
5487         var _t = this;
5488         
5489         this.loading = true;
5490         this.compiled = false;
5491         
5492         var cx = new Roo.data.Connection();
5493         cx.request({
5494             url : this.url,
5495             method : 'GET',
5496             success : function (response) {
5497                 _t.loading = false;
5498                 _t.url = false;
5499                 
5500                 _t.set(response.responseText,true);
5501                 _t.loaded = true;
5502                 if (_t.onLoad) {
5503                     _t.onLoad();
5504                 }
5505              },
5506             failure : function(response) {
5507                 Roo.log("Template failed to load from " + _t.url);
5508                 _t.loading = false;
5509             }
5510         });
5511     },
5512
5513     /**
5514      * Sets the HTML used as the template and optionally compiles it.
5515      * @param {String} html
5516      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5517      * @return {Roo.Template} this
5518      */
5519     set : function(html, compile){
5520         this.html = html;
5521         this.compiled = false;
5522         if(compile){
5523             this.compile();
5524         }
5525         return this;
5526     },
5527     
5528     /**
5529      * True to disable format functions (defaults to false)
5530      * @type Boolean
5531      */
5532     disableFormats : false,
5533     
5534     /**
5535     * The regular expression used to match template variables 
5536     * @type RegExp
5537     * @property 
5538     */
5539     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5540     
5541     /**
5542      * Compiles the template into an internal function, eliminating the RegEx overhead.
5543      * @return {Roo.Template} this
5544      */
5545     compile : function(){
5546         var fm = Roo.util.Format;
5547         var useF = this.disableFormats !== true;
5548         var sep = Roo.isGecko ? "+" : ",";
5549         var fn = function(m, name, format, args){
5550             if(format && useF){
5551                 args = args ? ',' + args : "";
5552                 if(format.substr(0, 5) != "this."){
5553                     format = "fm." + format + '(';
5554                 }else{
5555                     format = 'this.call("'+ format.substr(5) + '", ';
5556                     args = ", values";
5557                 }
5558             }else{
5559                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5560             }
5561             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5562         };
5563         var body;
5564         // branched to use + in gecko and [].join() in others
5565         if(Roo.isGecko){
5566             body = "this.compiled = function(values){ return '" +
5567                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5568                     "';};";
5569         }else{
5570             body = ["this.compiled = function(values){ return ['"];
5571             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5572             body.push("'].join('');};");
5573             body = body.join('');
5574         }
5575         /**
5576          * eval:var:values
5577          * eval:var:fm
5578          */
5579         eval(body);
5580         return this;
5581     },
5582     
5583     // private function used to call members
5584     call : function(fnName, value, allValues){
5585         return this[fnName](value, allValues);
5586     },
5587     
5588     /**
5589      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5590      * @param {String/HTMLElement/Roo.Element} el The context element
5591      * @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'})
5592      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5593      * @return {HTMLElement/Roo.Element} The new node or Element
5594      */
5595     insertFirst: function(el, values, returnElement){
5596         return this.doInsert('afterBegin', el, values, returnElement);
5597     },
5598
5599     /**
5600      * Applies the supplied values to the template and inserts the new node(s) before el.
5601      * @param {String/HTMLElement/Roo.Element} el The context element
5602      * @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'})
5603      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5604      * @return {HTMLElement/Roo.Element} The new node or Element
5605      */
5606     insertBefore: function(el, values, returnElement){
5607         return this.doInsert('beforeBegin', el, values, returnElement);
5608     },
5609
5610     /**
5611      * Applies the supplied values to the template and inserts the new node(s) after el.
5612      * @param {String/HTMLElement/Roo.Element} el The context element
5613      * @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'})
5614      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5615      * @return {HTMLElement/Roo.Element} The new node or Element
5616      */
5617     insertAfter : function(el, values, returnElement){
5618         return this.doInsert('afterEnd', el, values, returnElement);
5619     },
5620     
5621     /**
5622      * Applies the supplied values to the template and appends the new node(s) to el.
5623      * @param {String/HTMLElement/Roo.Element} el The context element
5624      * @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'})
5625      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5626      * @return {HTMLElement/Roo.Element} The new node or Element
5627      */
5628     append : function(el, values, returnElement){
5629         return this.doInsert('beforeEnd', el, values, returnElement);
5630     },
5631
5632     doInsert : function(where, el, values, returnEl){
5633         el = Roo.getDom(el);
5634         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
5635         return returnEl ? Roo.get(newNode, true) : newNode;
5636     },
5637
5638     /**
5639      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
5640      * @param {String/HTMLElement/Roo.Element} el The context element
5641      * @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'})
5642      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5643      * @return {HTMLElement/Roo.Element} The new node or Element
5644      */
5645     overwrite : function(el, values, returnElement){
5646         el = Roo.getDom(el);
5647         el.innerHTML = this.applyTemplate(values);
5648         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5649     }
5650 };
5651 /**
5652  * Alias for {@link #applyTemplate}
5653  * @method
5654  */
5655 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
5656
5657 // backwards compat
5658 Roo.DomHelper.Template = Roo.Template;
5659
5660 /**
5661  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
5662  * @param {String/HTMLElement} el A DOM element or its id
5663  * @returns {Roo.Template} The created template
5664  * @static
5665  */
5666 Roo.Template.from = function(el){
5667     el = Roo.getDom(el);
5668     return new Roo.Template(el.value || el.innerHTML);
5669 };/*
5670  * Based on:
5671  * Ext JS Library 1.1.1
5672  * Copyright(c) 2006-2007, Ext JS, LLC.
5673  *
5674  * Originally Released Under LGPL - original licence link has changed is not relivant.
5675  *
5676  * Fork - LGPL
5677  * <script type="text/javascript">
5678  */
5679  
5680
5681 /*
5682  * This is code is also distributed under MIT license for use
5683  * with jQuery and prototype JavaScript libraries.
5684  */
5685 /**
5686  * @class Roo.DomQuery
5687 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).
5688 <p>
5689 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>
5690
5691 <p>
5692 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.
5693 </p>
5694 <h4>Element Selectors:</h4>
5695 <ul class="list">
5696     <li> <b>*</b> any element</li>
5697     <li> <b>E</b> an element with the tag E</li>
5698     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
5699     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
5700     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
5701     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
5702 </ul>
5703 <h4>Attribute Selectors:</h4>
5704 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
5705 <ul class="list">
5706     <li> <b>E[foo]</b> has an attribute "foo"</li>
5707     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5708     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5709     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5710     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5711     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5712     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5713 </ul>
5714 <h4>Pseudo Classes:</h4>
5715 <ul class="list">
5716     <li> <b>E:first-child</b> E is the first child of its parent</li>
5717     <li> <b>E:last-child</b> E is the last child of its parent</li>
5718     <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>
5719     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5720     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5721     <li> <b>E:only-child</b> E is the only child of its parent</li>
5722     <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>
5723     <li> <b>E:first</b> the first E in the resultset</li>
5724     <li> <b>E:last</b> the last E in the resultset</li>
5725     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5726     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5727     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5728     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5729     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5730     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5731     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5732     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5733     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5734 </ul>
5735 <h4>CSS Value Selectors:</h4>
5736 <ul class="list">
5737     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5738     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5739     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5740     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5741     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5742     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5743 </ul>
5744  * @static
5745  */
5746 Roo.DomQuery = function(){
5747     var cache = {}, simpleCache = {}, valueCache = {};
5748     var nonSpace = /\S/;
5749     var trimRe = /^\s+|\s+$/g;
5750     var tplRe = /\{(\d+)\}/g;
5751     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5752     var tagTokenRe = /^(#)?([\w-\*]+)/;
5753     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5754
5755     function child(p, index){
5756         var i = 0;
5757         var n = p.firstChild;
5758         while(n){
5759             if(n.nodeType == 1){
5760                if(++i == index){
5761                    return n;
5762                }
5763             }
5764             n = n.nextSibling;
5765         }
5766         return null;
5767     };
5768
5769     function next(n){
5770         while((n = n.nextSibling) && n.nodeType != 1);
5771         return n;
5772     };
5773
5774     function prev(n){
5775         while((n = n.previousSibling) && n.nodeType != 1);
5776         return n;
5777     };
5778
5779     function children(d){
5780         var n = d.firstChild, ni = -1;
5781             while(n){
5782                 var nx = n.nextSibling;
5783                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5784                     d.removeChild(n);
5785                 }else{
5786                     n.nodeIndex = ++ni;
5787                 }
5788                 n = nx;
5789             }
5790             return this;
5791         };
5792
5793     function byClassName(c, a, v){
5794         if(!v){
5795             return c;
5796         }
5797         var r = [], ri = -1, cn;
5798         for(var i = 0, ci; ci = c[i]; i++){
5799             
5800             
5801             if((' '+
5802                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5803                  +' ').indexOf(v) != -1){
5804                 r[++ri] = ci;
5805             }
5806         }
5807         return r;
5808     };
5809
5810     function attrValue(n, attr){
5811         if(!n.tagName && typeof n.length != "undefined"){
5812             n = n[0];
5813         }
5814         if(!n){
5815             return null;
5816         }
5817         if(attr == "for"){
5818             return n.htmlFor;
5819         }
5820         if(attr == "class" || attr == "className"){
5821             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5822         }
5823         return n.getAttribute(attr) || n[attr];
5824
5825     };
5826
5827     function getNodes(ns, mode, tagName){
5828         var result = [], ri = -1, cs;
5829         if(!ns){
5830             return result;
5831         }
5832         tagName = tagName || "*";
5833         if(typeof ns.getElementsByTagName != "undefined"){
5834             ns = [ns];
5835         }
5836         if(!mode){
5837             for(var i = 0, ni; ni = ns[i]; i++){
5838                 cs = ni.getElementsByTagName(tagName);
5839                 for(var j = 0, ci; ci = cs[j]; j++){
5840                     result[++ri] = ci;
5841                 }
5842             }
5843         }else if(mode == "/" || mode == ">"){
5844             var utag = tagName.toUpperCase();
5845             for(var i = 0, ni, cn; ni = ns[i]; i++){
5846                 cn = ni.children || ni.childNodes;
5847                 for(var j = 0, cj; cj = cn[j]; j++){
5848                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5849                         result[++ri] = cj;
5850                     }
5851                 }
5852             }
5853         }else if(mode == "+"){
5854             var utag = tagName.toUpperCase();
5855             for(var i = 0, n; n = ns[i]; i++){
5856                 while((n = n.nextSibling) && n.nodeType != 1);
5857                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5858                     result[++ri] = n;
5859                 }
5860             }
5861         }else if(mode == "~"){
5862             for(var i = 0, n; n = ns[i]; i++){
5863                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5864                 if(n){
5865                     result[++ri] = n;
5866                 }
5867             }
5868         }
5869         return result;
5870     };
5871
5872     function concat(a, b){
5873         if(b.slice){
5874             return a.concat(b);
5875         }
5876         for(var i = 0, l = b.length; i < l; i++){
5877             a[a.length] = b[i];
5878         }
5879         return a;
5880     }
5881
5882     function byTag(cs, tagName){
5883         if(cs.tagName || cs == document){
5884             cs = [cs];
5885         }
5886         if(!tagName){
5887             return cs;
5888         }
5889         var r = [], ri = -1;
5890         tagName = tagName.toLowerCase();
5891         for(var i = 0, ci; ci = cs[i]; i++){
5892             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5893                 r[++ri] = ci;
5894             }
5895         }
5896         return r;
5897     };
5898
5899     function byId(cs, attr, id){
5900         if(cs.tagName || cs == document){
5901             cs = [cs];
5902         }
5903         if(!id){
5904             return cs;
5905         }
5906         var r = [], ri = -1;
5907         for(var i = 0,ci; ci = cs[i]; i++){
5908             if(ci && ci.id == id){
5909                 r[++ri] = ci;
5910                 return r;
5911             }
5912         }
5913         return r;
5914     };
5915
5916     function byAttribute(cs, attr, value, op, custom){
5917         var r = [], ri = -1, st = custom=="{";
5918         var f = Roo.DomQuery.operators[op];
5919         for(var i = 0, ci; ci = cs[i]; i++){
5920             var a;
5921             if(st){
5922                 a = Roo.DomQuery.getStyle(ci, attr);
5923             }
5924             else if(attr == "class" || attr == "className"){
5925                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
5926             }else if(attr == "for"){
5927                 a = ci.htmlFor;
5928             }else if(attr == "href"){
5929                 a = ci.getAttribute("href", 2);
5930             }else{
5931                 a = ci.getAttribute(attr);
5932             }
5933             if((f && f(a, value)) || (!f && a)){
5934                 r[++ri] = ci;
5935             }
5936         }
5937         return r;
5938     };
5939
5940     function byPseudo(cs, name, value){
5941         return Roo.DomQuery.pseudos[name](cs, value);
5942     };
5943
5944     // This is for IE MSXML which does not support expandos.
5945     // IE runs the same speed using setAttribute, however FF slows way down
5946     // and Safari completely fails so they need to continue to use expandos.
5947     var isIE = window.ActiveXObject ? true : false;
5948
5949     // this eval is stop the compressor from
5950     // renaming the variable to something shorter
5951     
5952     /** eval:var:batch */
5953     var batch = 30803; 
5954
5955     var key = 30803;
5956
5957     function nodupIEXml(cs){
5958         var d = ++key;
5959         cs[0].setAttribute("_nodup", d);
5960         var r = [cs[0]];
5961         for(var i = 1, len = cs.length; i < len; i++){
5962             var c = cs[i];
5963             if(!c.getAttribute("_nodup") != d){
5964                 c.setAttribute("_nodup", d);
5965                 r[r.length] = c;
5966             }
5967         }
5968         for(var i = 0, len = cs.length; i < len; i++){
5969             cs[i].removeAttribute("_nodup");
5970         }
5971         return r;
5972     }
5973
5974     function nodup(cs){
5975         if(!cs){
5976             return [];
5977         }
5978         var len = cs.length, c, i, r = cs, cj, ri = -1;
5979         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5980             return cs;
5981         }
5982         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5983             return nodupIEXml(cs);
5984         }
5985         var d = ++key;
5986         cs[0]._nodup = d;
5987         for(i = 1; c = cs[i]; i++){
5988             if(c._nodup != d){
5989                 c._nodup = d;
5990             }else{
5991                 r = [];
5992                 for(var j = 0; j < i; j++){
5993                     r[++ri] = cs[j];
5994                 }
5995                 for(j = i+1; cj = cs[j]; j++){
5996                     if(cj._nodup != d){
5997                         cj._nodup = d;
5998                         r[++ri] = cj;
5999                     }
6000                 }
6001                 return r;
6002             }
6003         }
6004         return r;
6005     }
6006
6007     function quickDiffIEXml(c1, c2){
6008         var d = ++key;
6009         for(var i = 0, len = c1.length; i < len; i++){
6010             c1[i].setAttribute("_qdiff", d);
6011         }
6012         var r = [];
6013         for(var i = 0, len = c2.length; i < len; i++){
6014             if(c2[i].getAttribute("_qdiff") != d){
6015                 r[r.length] = c2[i];
6016             }
6017         }
6018         for(var i = 0, len = c1.length; i < len; i++){
6019            c1[i].removeAttribute("_qdiff");
6020         }
6021         return r;
6022     }
6023
6024     function quickDiff(c1, c2){
6025         var len1 = c1.length;
6026         if(!len1){
6027             return c2;
6028         }
6029         if(isIE && c1[0].selectSingleNode){
6030             return quickDiffIEXml(c1, c2);
6031         }
6032         var d = ++key;
6033         for(var i = 0; i < len1; i++){
6034             c1[i]._qdiff = d;
6035         }
6036         var r = [];
6037         for(var i = 0, len = c2.length; i < len; i++){
6038             if(c2[i]._qdiff != d){
6039                 r[r.length] = c2[i];
6040             }
6041         }
6042         return r;
6043     }
6044
6045     function quickId(ns, mode, root, id){
6046         if(ns == root){
6047            var d = root.ownerDocument || root;
6048            return d.getElementById(id);
6049         }
6050         ns = getNodes(ns, mode, "*");
6051         return byId(ns, null, id);
6052     }
6053
6054     return {
6055         getStyle : function(el, name){
6056             return Roo.fly(el).getStyle(name);
6057         },
6058         /**
6059          * Compiles a selector/xpath query into a reusable function. The returned function
6060          * takes one parameter "root" (optional), which is the context node from where the query should start.
6061          * @param {String} selector The selector/xpath query
6062          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6063          * @return {Function}
6064          */
6065         compile : function(path, type){
6066             type = type || "select";
6067             
6068             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6069             var q = path, mode, lq;
6070             var tk = Roo.DomQuery.matchers;
6071             var tklen = tk.length;
6072             var mm;
6073
6074             // accept leading mode switch
6075             var lmode = q.match(modeRe);
6076             if(lmode && lmode[1]){
6077                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6078                 q = q.replace(lmode[1], "");
6079             }
6080             // strip leading slashes
6081             while(path.substr(0, 1)=="/"){
6082                 path = path.substr(1);
6083             }
6084
6085             while(q && lq != q){
6086                 lq = q;
6087                 var tm = q.match(tagTokenRe);
6088                 if(type == "select"){
6089                     if(tm){
6090                         if(tm[1] == "#"){
6091                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6092                         }else{
6093                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6094                         }
6095                         q = q.replace(tm[0], "");
6096                     }else if(q.substr(0, 1) != '@'){
6097                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6098                     }
6099                 }else{
6100                     if(tm){
6101                         if(tm[1] == "#"){
6102                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6103                         }else{
6104                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6105                         }
6106                         q = q.replace(tm[0], "");
6107                     }
6108                 }
6109                 while(!(mm = q.match(modeRe))){
6110                     var matched = false;
6111                     for(var j = 0; j < tklen; j++){
6112                         var t = tk[j];
6113                         var m = q.match(t.re);
6114                         if(m){
6115                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6116                                                     return m[i];
6117                                                 });
6118                             q = q.replace(m[0], "");
6119                             matched = true;
6120                             break;
6121                         }
6122                     }
6123                     // prevent infinite loop on bad selector
6124                     if(!matched){
6125                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6126                     }
6127                 }
6128                 if(mm[1]){
6129                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6130                     q = q.replace(mm[1], "");
6131                 }
6132             }
6133             fn[fn.length] = "return nodup(n);\n}";
6134             
6135              /** 
6136               * list of variables that need from compression as they are used by eval.
6137              *  eval:var:batch 
6138              *  eval:var:nodup
6139              *  eval:var:byTag
6140              *  eval:var:ById
6141              *  eval:var:getNodes
6142              *  eval:var:quickId
6143              *  eval:var:mode
6144              *  eval:var:root
6145              *  eval:var:n
6146              *  eval:var:byClassName
6147              *  eval:var:byPseudo
6148              *  eval:var:byAttribute
6149              *  eval:var:attrValue
6150              * 
6151              **/ 
6152             eval(fn.join(""));
6153             return f;
6154         },
6155
6156         /**
6157          * Selects a group of elements.
6158          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6159          * @param {Node} root (optional) The start of the query (defaults to document).
6160          * @return {Array}
6161          */
6162         select : function(path, root, type){
6163             if(!root || root == document){
6164                 root = document;
6165             }
6166             if(typeof root == "string"){
6167                 root = document.getElementById(root);
6168             }
6169             var paths = path.split(",");
6170             var results = [];
6171             for(var i = 0, len = paths.length; i < len; i++){
6172                 var p = paths[i].replace(trimRe, "");
6173                 if(!cache[p]){
6174                     cache[p] = Roo.DomQuery.compile(p);
6175                     if(!cache[p]){
6176                         throw p + " is not a valid selector";
6177                     }
6178                 }
6179                 var result = cache[p](root);
6180                 if(result && result != document){
6181                     results = results.concat(result);
6182                 }
6183             }
6184             if(paths.length > 1){
6185                 return nodup(results);
6186             }
6187             return results;
6188         },
6189
6190         /**
6191          * Selects a single element.
6192          * @param {String} selector The selector/xpath query
6193          * @param {Node} root (optional) The start of the query (defaults to document).
6194          * @return {Element}
6195          */
6196         selectNode : function(path, root){
6197             return Roo.DomQuery.select(path, root)[0];
6198         },
6199
6200         /**
6201          * Selects the value of a node, optionally replacing null with the defaultValue.
6202          * @param {String} selector The selector/xpath query
6203          * @param {Node} root (optional) The start of the query (defaults to document).
6204          * @param {String} defaultValue
6205          */
6206         selectValue : function(path, root, defaultValue){
6207             path = path.replace(trimRe, "");
6208             if(!valueCache[path]){
6209                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6210             }
6211             var n = valueCache[path](root);
6212             n = n[0] ? n[0] : n;
6213             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6214             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6215         },
6216
6217         /**
6218          * Selects the value of a node, parsing integers and floats.
6219          * @param {String} selector The selector/xpath query
6220          * @param {Node} root (optional) The start of the query (defaults to document).
6221          * @param {Number} defaultValue
6222          * @return {Number}
6223          */
6224         selectNumber : function(path, root, defaultValue){
6225             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6226             return parseFloat(v);
6227         },
6228
6229         /**
6230          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6231          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6232          * @param {String} selector The simple selector to test
6233          * @return {Boolean}
6234          */
6235         is : function(el, ss){
6236             if(typeof el == "string"){
6237                 el = document.getElementById(el);
6238             }
6239             var isArray = (el instanceof Array);
6240             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6241             return isArray ? (result.length == el.length) : (result.length > 0);
6242         },
6243
6244         /**
6245          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6246          * @param {Array} el An array of elements to filter
6247          * @param {String} selector The simple selector to test
6248          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6249          * the selector instead of the ones that match
6250          * @return {Array}
6251          */
6252         filter : function(els, ss, nonMatches){
6253             ss = ss.replace(trimRe, "");
6254             if(!simpleCache[ss]){
6255                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6256             }
6257             var result = simpleCache[ss](els);
6258             return nonMatches ? quickDiff(result, els) : result;
6259         },
6260
6261         /**
6262          * Collection of matching regular expressions and code snippets.
6263          */
6264         matchers : [{
6265                 re: /^\.([\w-]+)/,
6266                 select: 'n = byClassName(n, null, " {1} ");'
6267             }, {
6268                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6269                 select: 'n = byPseudo(n, "{1}", "{2}");'
6270             },{
6271                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6272                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6273             }, {
6274                 re: /^#([\w-]+)/,
6275                 select: 'n = byId(n, null, "{1}");'
6276             },{
6277                 re: /^@([\w-]+)/,
6278                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6279             }
6280         ],
6281
6282         /**
6283          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6284          * 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;.
6285          */
6286         operators : {
6287             "=" : function(a, v){
6288                 return a == v;
6289             },
6290             "!=" : function(a, v){
6291                 return a != v;
6292             },
6293             "^=" : function(a, v){
6294                 return a && a.substr(0, v.length) == v;
6295             },
6296             "$=" : function(a, v){
6297                 return a && a.substr(a.length-v.length) == v;
6298             },
6299             "*=" : function(a, v){
6300                 return a && a.indexOf(v) !== -1;
6301             },
6302             "%=" : function(a, v){
6303                 return (a % v) == 0;
6304             },
6305             "|=" : function(a, v){
6306                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6307             },
6308             "~=" : function(a, v){
6309                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6310             }
6311         },
6312
6313         /**
6314          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6315          * and the argument (if any) supplied in the selector.
6316          */
6317         pseudos : {
6318             "first-child" : function(c){
6319                 var r = [], ri = -1, n;
6320                 for(var i = 0, ci; ci = n = c[i]; i++){
6321                     while((n = n.previousSibling) && n.nodeType != 1);
6322                     if(!n){
6323                         r[++ri] = ci;
6324                     }
6325                 }
6326                 return r;
6327             },
6328
6329             "last-child" : function(c){
6330                 var r = [], ri = -1, n;
6331                 for(var i = 0, ci; ci = n = c[i]; i++){
6332                     while((n = n.nextSibling) && n.nodeType != 1);
6333                     if(!n){
6334                         r[++ri] = ci;
6335                     }
6336                 }
6337                 return r;
6338             },
6339
6340             "nth-child" : function(c, a) {
6341                 var r = [], ri = -1;
6342                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6343                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6344                 for(var i = 0, n; n = c[i]; i++){
6345                     var pn = n.parentNode;
6346                     if (batch != pn._batch) {
6347                         var j = 0;
6348                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6349                             if(cn.nodeType == 1){
6350                                cn.nodeIndex = ++j;
6351                             }
6352                         }
6353                         pn._batch = batch;
6354                     }
6355                     if (f == 1) {
6356                         if (l == 0 || n.nodeIndex == l){
6357                             r[++ri] = n;
6358                         }
6359                     } else if ((n.nodeIndex + l) % f == 0){
6360                         r[++ri] = n;
6361                     }
6362                 }
6363
6364                 return r;
6365             },
6366
6367             "only-child" : function(c){
6368                 var r = [], ri = -1;;
6369                 for(var i = 0, ci; ci = c[i]; i++){
6370                     if(!prev(ci) && !next(ci)){
6371                         r[++ri] = ci;
6372                     }
6373                 }
6374                 return r;
6375             },
6376
6377             "empty" : function(c){
6378                 var r = [], ri = -1;
6379                 for(var i = 0, ci; ci = c[i]; i++){
6380                     var cns = ci.childNodes, j = 0, cn, empty = true;
6381                     while(cn = cns[j]){
6382                         ++j;
6383                         if(cn.nodeType == 1 || cn.nodeType == 3){
6384                             empty = false;
6385                             break;
6386                         }
6387                     }
6388                     if(empty){
6389                         r[++ri] = ci;
6390                     }
6391                 }
6392                 return r;
6393             },
6394
6395             "contains" : function(c, v){
6396                 var r = [], ri = -1;
6397                 for(var i = 0, ci; ci = c[i]; i++){
6398                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6399                         r[++ri] = ci;
6400                     }
6401                 }
6402                 return r;
6403             },
6404
6405             "nodeValue" : function(c, v){
6406                 var r = [], ri = -1;
6407                 for(var i = 0, ci; ci = c[i]; i++){
6408                     if(ci.firstChild && ci.firstChild.nodeValue == v){
6409                         r[++ri] = ci;
6410                     }
6411                 }
6412                 return r;
6413             },
6414
6415             "checked" : function(c){
6416                 var r = [], ri = -1;
6417                 for(var i = 0, ci; ci = c[i]; i++){
6418                     if(ci.checked == true){
6419                         r[++ri] = ci;
6420                     }
6421                 }
6422                 return r;
6423             },
6424
6425             "not" : function(c, ss){
6426                 return Roo.DomQuery.filter(c, ss, true);
6427             },
6428
6429             "odd" : function(c){
6430                 return this["nth-child"](c, "odd");
6431             },
6432
6433             "even" : function(c){
6434                 return this["nth-child"](c, "even");
6435             },
6436
6437             "nth" : function(c, a){
6438                 return c[a-1] || [];
6439             },
6440
6441             "first" : function(c){
6442                 return c[0] || [];
6443             },
6444
6445             "last" : function(c){
6446                 return c[c.length-1] || [];
6447             },
6448
6449             "has" : function(c, ss){
6450                 var s = Roo.DomQuery.select;
6451                 var r = [], ri = -1;
6452                 for(var i = 0, ci; ci = c[i]; i++){
6453                     if(s(ss, ci).length > 0){
6454                         r[++ri] = ci;
6455                     }
6456                 }
6457                 return r;
6458             },
6459
6460             "next" : function(c, ss){
6461                 var is = Roo.DomQuery.is;
6462                 var r = [], ri = -1;
6463                 for(var i = 0, ci; ci = c[i]; i++){
6464                     var n = next(ci);
6465                     if(n && is(n, ss)){
6466                         r[++ri] = ci;
6467                     }
6468                 }
6469                 return r;
6470             },
6471
6472             "prev" : function(c, ss){
6473                 var is = Roo.DomQuery.is;
6474                 var r = [], ri = -1;
6475                 for(var i = 0, ci; ci = c[i]; i++){
6476                     var n = prev(ci);
6477                     if(n && is(n, ss)){
6478                         r[++ri] = ci;
6479                     }
6480                 }
6481                 return r;
6482             }
6483         }
6484     };
6485 }();
6486
6487 /**
6488  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6489  * @param {String} path The selector/xpath query
6490  * @param {Node} root (optional) The start of the query (defaults to document).
6491  * @return {Array}
6492  * @member Roo
6493  * @method query
6494  */
6495 Roo.query = Roo.DomQuery.select;
6496 /*
6497  * Based on:
6498  * Ext JS Library 1.1.1
6499  * Copyright(c) 2006-2007, Ext JS, LLC.
6500  *
6501  * Originally Released Under LGPL - original licence link has changed is not relivant.
6502  *
6503  * Fork - LGPL
6504  * <script type="text/javascript">
6505  */
6506
6507 /**
6508  * @class Roo.util.Observable
6509  * Base class that provides a common interface for publishing events. Subclasses are expected to
6510  * to have a property "events" with all the events defined.<br>
6511  * For example:
6512  * <pre><code>
6513  Employee = function(name){
6514     this.name = name;
6515     this.addEvents({
6516         "fired" : true,
6517         "quit" : true
6518     });
6519  }
6520  Roo.extend(Employee, Roo.util.Observable);
6521 </code></pre>
6522  * @param {Object} config properties to use (incuding events / listeners)
6523  */
6524
6525 Roo.util.Observable = function(cfg){
6526     
6527     cfg = cfg|| {};
6528     this.addEvents(cfg.events || {});
6529     if (cfg.events) {
6530         delete cfg.events; // make sure
6531     }
6532      
6533     Roo.apply(this, cfg);
6534     
6535     if(this.listeners){
6536         this.on(this.listeners);
6537         delete this.listeners;
6538     }
6539 };
6540 Roo.util.Observable.prototype = {
6541     /** 
6542  * @cfg {Object} listeners  list of events and functions to call for this object, 
6543  * For example :
6544  * <pre><code>
6545     listeners :  { 
6546        'click' : function(e) {
6547            ..... 
6548         } ,
6549         .... 
6550     } 
6551   </code></pre>
6552  */
6553     
6554     
6555     /**
6556      * Fires the specified event with the passed parameters (minus the event name).
6557      * @param {String} eventName
6558      * @param {Object...} args Variable number of parameters are passed to handlers
6559      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6560      */
6561     fireEvent : function(){
6562         var ce = this.events[arguments[0].toLowerCase()];
6563         if(typeof ce == "object"){
6564             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6565         }else{
6566             return true;
6567         }
6568     },
6569
6570     // private
6571     filterOptRe : /^(?:scope|delay|buffer|single)$/,
6572
6573     /**
6574      * Appends an event handler to this component
6575      * @param {String}   eventName The type of event to listen for
6576      * @param {Function} handler The method the event invokes
6577      * @param {Object}   scope (optional) The scope in which to execute the handler
6578      * function. The handler function's "this" context.
6579      * @param {Object}   options (optional) An object containing handler configuration
6580      * properties. This may contain any of the following properties:<ul>
6581      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6582      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6583      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6584      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6585      * by the specified number of milliseconds. If the event fires again within that time, the original
6586      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6587      * </ul><br>
6588      * <p>
6589      * <b>Combining Options</b><br>
6590      * Using the options argument, it is possible to combine different types of listeners:<br>
6591      * <br>
6592      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6593                 <pre><code>
6594                 el.on('click', this.onClick, this, {
6595                         single: true,
6596                 delay: 100,
6597                 forumId: 4
6598                 });
6599                 </code></pre>
6600      * <p>
6601      * <b>Attaching multiple handlers in 1 call</b><br>
6602      * The method also allows for a single argument to be passed which is a config object containing properties
6603      * which specify multiple handlers.
6604      * <pre><code>
6605                 el.on({
6606                         'click': {
6607                         fn: this.onClick,
6608                         scope: this,
6609                         delay: 100
6610                 }, 
6611                 'mouseover': {
6612                         fn: this.onMouseOver,
6613                         scope: this
6614                 },
6615                 'mouseout': {
6616                         fn: this.onMouseOut,
6617                         scope: this
6618                 }
6619                 });
6620                 </code></pre>
6621      * <p>
6622      * Or a shorthand syntax which passes the same scope object to all handlers:
6623         <pre><code>
6624                 el.on({
6625                         'click': this.onClick,
6626                 'mouseover': this.onMouseOver,
6627                 'mouseout': this.onMouseOut,
6628                 scope: this
6629                 });
6630                 </code></pre>
6631      */
6632     addListener : function(eventName, fn, scope, o){
6633         if(typeof eventName == "object"){
6634             o = eventName;
6635             for(var e in o){
6636                 if(this.filterOptRe.test(e)){
6637                     continue;
6638                 }
6639                 if(typeof o[e] == "function"){
6640                     // shared options
6641                     this.addListener(e, o[e], o.scope,  o);
6642                 }else{
6643                     // individual options
6644                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
6645                 }
6646             }
6647             return;
6648         }
6649         o = (!o || typeof o == "boolean") ? {} : o;
6650         eventName = eventName.toLowerCase();
6651         var ce = this.events[eventName] || true;
6652         if(typeof ce == "boolean"){
6653             ce = new Roo.util.Event(this, eventName);
6654             this.events[eventName] = ce;
6655         }
6656         ce.addListener(fn, scope, o);
6657     },
6658
6659     /**
6660      * Removes a listener
6661      * @param {String}   eventName     The type of event to listen for
6662      * @param {Function} handler        The handler to remove
6663      * @param {Object}   scope  (optional) The scope (this object) for the handler
6664      */
6665     removeListener : function(eventName, fn, scope){
6666         var ce = this.events[eventName.toLowerCase()];
6667         if(typeof ce == "object"){
6668             ce.removeListener(fn, scope);
6669         }
6670     },
6671
6672     /**
6673      * Removes all listeners for this object
6674      */
6675     purgeListeners : function(){
6676         for(var evt in this.events){
6677             if(typeof this.events[evt] == "object"){
6678                  this.events[evt].clearListeners();
6679             }
6680         }
6681     },
6682
6683     relayEvents : function(o, events){
6684         var createHandler = function(ename){
6685             return function(){
6686                  
6687                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
6688             };
6689         };
6690         for(var i = 0, len = events.length; i < len; i++){
6691             var ename = events[i];
6692             if(!this.events[ename]){
6693                 this.events[ename] = true;
6694             };
6695             o.on(ename, createHandler(ename), this);
6696         }
6697     },
6698
6699     /**
6700      * Used to define events on this Observable
6701      * @param {Object} object The object with the events defined
6702      */
6703     addEvents : function(o){
6704         if(!this.events){
6705             this.events = {};
6706         }
6707         Roo.applyIf(this.events, o);
6708     },
6709
6710     /**
6711      * Checks to see if this object has any listeners for a specified event
6712      * @param {String} eventName The name of the event to check for
6713      * @return {Boolean} True if the event is being listened for, else false
6714      */
6715     hasListener : function(eventName){
6716         var e = this.events[eventName];
6717         return typeof e == "object" && e.listeners.length > 0;
6718     }
6719 };
6720 /**
6721  * Appends an event handler to this element (shorthand for addListener)
6722  * @param {String}   eventName     The type of event to listen for
6723  * @param {Function} handler        The method the event invokes
6724  * @param {Object}   scope (optional) The scope in which to execute the handler
6725  * function. The handler function's "this" context.
6726  * @param {Object}   options  (optional)
6727  * @method
6728  */
6729 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6730 /**
6731  * Removes a listener (shorthand for removeListener)
6732  * @param {String}   eventName     The type of event to listen for
6733  * @param {Function} handler        The handler to remove
6734  * @param {Object}   scope  (optional) The scope (this object) for the handler
6735  * @method
6736  */
6737 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6738
6739 /**
6740  * Starts capture on the specified Observable. All events will be passed
6741  * to the supplied function with the event name + standard signature of the event
6742  * <b>before</b> the event is fired. If the supplied function returns false,
6743  * the event will not fire.
6744  * @param {Observable} o The Observable to capture
6745  * @param {Function} fn The function to call
6746  * @param {Object} scope (optional) The scope (this object) for the fn
6747  * @static
6748  */
6749 Roo.util.Observable.capture = function(o, fn, scope){
6750     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6751 };
6752
6753 /**
6754  * Removes <b>all</b> added captures from the Observable.
6755  * @param {Observable} o The Observable to release
6756  * @static
6757  */
6758 Roo.util.Observable.releaseCapture = function(o){
6759     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6760 };
6761
6762 (function(){
6763
6764     var createBuffered = function(h, o, scope){
6765         var task = new Roo.util.DelayedTask();
6766         return function(){
6767             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6768         };
6769     };
6770
6771     var createSingle = function(h, e, fn, scope){
6772         return function(){
6773             e.removeListener(fn, scope);
6774             return h.apply(scope, arguments);
6775         };
6776     };
6777
6778     var createDelayed = function(h, o, scope){
6779         return function(){
6780             var args = Array.prototype.slice.call(arguments, 0);
6781             setTimeout(function(){
6782                 h.apply(scope, args);
6783             }, o.delay || 10);
6784         };
6785     };
6786
6787     Roo.util.Event = function(obj, name){
6788         this.name = name;
6789         this.obj = obj;
6790         this.listeners = [];
6791     };
6792
6793     Roo.util.Event.prototype = {
6794         addListener : function(fn, scope, options){
6795             var o = options || {};
6796             scope = scope || this.obj;
6797             if(!this.isListening(fn, scope)){
6798                 var l = {fn: fn, scope: scope, options: o};
6799                 var h = fn;
6800                 if(o.delay){
6801                     h = createDelayed(h, o, scope);
6802                 }
6803                 if(o.single){
6804                     h = createSingle(h, this, fn, scope);
6805                 }
6806                 if(o.buffer){
6807                     h = createBuffered(h, o, scope);
6808                 }
6809                 l.fireFn = h;
6810                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6811                     this.listeners.push(l);
6812                 }else{
6813                     this.listeners = this.listeners.slice(0);
6814                     this.listeners.push(l);
6815                 }
6816             }
6817         },
6818
6819         findListener : function(fn, scope){
6820             scope = scope || this.obj;
6821             var ls = this.listeners;
6822             for(var i = 0, len = ls.length; i < len; i++){
6823                 var l = ls[i];
6824                 if(l.fn == fn && l.scope == scope){
6825                     return i;
6826                 }
6827             }
6828             return -1;
6829         },
6830
6831         isListening : function(fn, scope){
6832             return this.findListener(fn, scope) != -1;
6833         },
6834
6835         removeListener : function(fn, scope){
6836             var index;
6837             if((index = this.findListener(fn, scope)) != -1){
6838                 if(!this.firing){
6839                     this.listeners.splice(index, 1);
6840                 }else{
6841                     this.listeners = this.listeners.slice(0);
6842                     this.listeners.splice(index, 1);
6843                 }
6844                 return true;
6845             }
6846             return false;
6847         },
6848
6849         clearListeners : function(){
6850             this.listeners = [];
6851         },
6852
6853         fire : function(){
6854             var ls = this.listeners, scope, len = ls.length;
6855             if(len > 0){
6856                 this.firing = true;
6857                 var args = Array.prototype.slice.call(arguments, 0);                
6858                 for(var i = 0; i < len; i++){
6859                     var l = ls[i];
6860                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6861                         this.firing = false;
6862                         return false;
6863                     }
6864                 }
6865                 this.firing = false;
6866             }
6867             return true;
6868         }
6869     };
6870 })();/*
6871  * RooJS Library 
6872  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6873  *
6874  * Licence LGPL 
6875  *
6876  */
6877  
6878 /**
6879  * @class Roo.Document
6880  * @extends Roo.util.Observable
6881  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6882  * 
6883  * @param {Object} config the methods and properties of the 'base' class for the application.
6884  * 
6885  *  Generic Page handler - implement this to start your app..
6886  * 
6887  * eg.
6888  *  MyProject = new Roo.Document({
6889         events : {
6890             'load' : true // your events..
6891         },
6892         listeners : {
6893             'ready' : function() {
6894                 // fired on Roo.onReady()
6895             }
6896         }
6897  * 
6898  */
6899 Roo.Document = function(cfg) {
6900      
6901     this.addEvents({ 
6902         'ready' : true
6903     });
6904     Roo.util.Observable.call(this,cfg);
6905     
6906     var _this = this;
6907     
6908     Roo.onReady(function() {
6909         _this.fireEvent('ready');
6910     },null,false);
6911     
6912     
6913 }
6914
6915 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6916  * Based on:
6917  * Ext JS Library 1.1.1
6918  * Copyright(c) 2006-2007, Ext JS, LLC.
6919  *
6920  * Originally Released Under LGPL - original licence link has changed is not relivant.
6921  *
6922  * Fork - LGPL
6923  * <script type="text/javascript">
6924  */
6925
6926 /**
6927  * @class Roo.EventManager
6928  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6929  * several useful events directly.
6930  * See {@link Roo.EventObject} for more details on normalized event objects.
6931  * @static
6932  */
6933 Roo.EventManager = function(){
6934     var docReadyEvent, docReadyProcId, docReadyState = false;
6935     var resizeEvent, resizeTask, textEvent, textSize;
6936     var E = Roo.lib.Event;
6937     var D = Roo.lib.Dom;
6938
6939     
6940     
6941
6942     var fireDocReady = function(){
6943         if(!docReadyState){
6944             docReadyState = true;
6945             Roo.isReady = true;
6946             if(docReadyProcId){
6947                 clearInterval(docReadyProcId);
6948             }
6949             if(Roo.isGecko || Roo.isOpera) {
6950                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6951             }
6952             if(Roo.isIE){
6953                 var defer = document.getElementById("ie-deferred-loader");
6954                 if(defer){
6955                     defer.onreadystatechange = null;
6956                     defer.parentNode.removeChild(defer);
6957                 }
6958             }
6959             if(docReadyEvent){
6960                 docReadyEvent.fire();
6961                 docReadyEvent.clearListeners();
6962             }
6963         }
6964     };
6965     
6966     var initDocReady = function(){
6967         docReadyEvent = new Roo.util.Event();
6968         if(Roo.isGecko || Roo.isOpera) {
6969             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6970         }else if(Roo.isIE){
6971             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6972             var defer = document.getElementById("ie-deferred-loader");
6973             defer.onreadystatechange = function(){
6974                 if(this.readyState == "complete"){
6975                     fireDocReady();
6976                 }
6977             };
6978         }else if(Roo.isSafari){ 
6979             docReadyProcId = setInterval(function(){
6980                 var rs = document.readyState;
6981                 if(rs == "complete") {
6982                     fireDocReady();     
6983                  }
6984             }, 10);
6985         }
6986         // no matter what, make sure it fires on load
6987         E.on(window, "load", fireDocReady);
6988     };
6989
6990     var createBuffered = function(h, o){
6991         var task = new Roo.util.DelayedTask(h);
6992         return function(e){
6993             // create new event object impl so new events don't wipe out properties
6994             e = new Roo.EventObjectImpl(e);
6995             task.delay(o.buffer, h, null, [e]);
6996         };
6997     };
6998
6999     var createSingle = function(h, el, ename, fn){
7000         return function(e){
7001             Roo.EventManager.removeListener(el, ename, fn);
7002             h(e);
7003         };
7004     };
7005
7006     var createDelayed = function(h, o){
7007         return function(e){
7008             // create new event object impl so new events don't wipe out properties
7009             e = new Roo.EventObjectImpl(e);
7010             setTimeout(function(){
7011                 h(e);
7012             }, o.delay || 10);
7013         };
7014     };
7015     var transitionEndVal = false;
7016     
7017     var transitionEnd = function()
7018     {
7019         if (transitionEndVal) {
7020             return transitionEndVal;
7021         }
7022         var el = document.createElement('div');
7023
7024         var transEndEventNames = {
7025             WebkitTransition : 'webkitTransitionEnd',
7026             MozTransition    : 'transitionend',
7027             OTransition      : 'oTransitionEnd otransitionend',
7028             transition       : 'transitionend'
7029         };
7030     
7031         for (var name in transEndEventNames) {
7032             if (el.style[name] !== undefined) {
7033                 transitionEndVal = transEndEventNames[name];
7034                 return  transitionEndVal ;
7035             }
7036         }
7037     }
7038     
7039   
7040
7041     var listen = function(element, ename, opt, fn, scope)
7042     {
7043         var o = (!opt || typeof opt == "boolean") ? {} : opt;
7044         fn = fn || o.fn; scope = scope || o.scope;
7045         var el = Roo.getDom(element);
7046         
7047         
7048         if(!el){
7049             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7050         }
7051         
7052         if (ename == 'transitionend') {
7053             ename = transitionEnd();
7054         }
7055         var h = function(e){
7056             e = Roo.EventObject.setEvent(e);
7057             var t;
7058             if(o.delegate){
7059                 t = e.getTarget(o.delegate, el);
7060                 if(!t){
7061                     return;
7062                 }
7063             }else{
7064                 t = e.target;
7065             }
7066             if(o.stopEvent === true){
7067                 e.stopEvent();
7068             }
7069             if(o.preventDefault === true){
7070                e.preventDefault();
7071             }
7072             if(o.stopPropagation === true){
7073                 e.stopPropagation();
7074             }
7075
7076             if(o.normalized === false){
7077                 e = e.browserEvent;
7078             }
7079
7080             fn.call(scope || el, e, t, o);
7081         };
7082         if(o.delay){
7083             h = createDelayed(h, o);
7084         }
7085         if(o.single){
7086             h = createSingle(h, el, ename, fn);
7087         }
7088         if(o.buffer){
7089             h = createBuffered(h, o);
7090         }
7091         
7092         fn._handlers = fn._handlers || [];
7093         
7094         
7095         fn._handlers.push([Roo.id(el), ename, h]);
7096         
7097         
7098          
7099         E.on(el, ename, h); // this adds the actuall listener to the object..
7100         
7101         
7102         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7103             el.addEventListener("DOMMouseScroll", h, false);
7104             E.on(window, 'unload', function(){
7105                 el.removeEventListener("DOMMouseScroll", h, false);
7106             });
7107         }
7108         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7109             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7110         }
7111         return h;
7112     };
7113
7114     var stopListening = function(el, ename, fn){
7115         var id = Roo.id(el), hds = fn._handlers, hd = fn;
7116         if(hds){
7117             for(var i = 0, len = hds.length; i < len; i++){
7118                 var h = hds[i];
7119                 if(h[0] == id && h[1] == ename){
7120                     hd = h[2];
7121                     hds.splice(i, 1);
7122                     break;
7123                 }
7124             }
7125         }
7126         E.un(el, ename, hd);
7127         el = Roo.getDom(el);
7128         if(ename == "mousewheel" && el.addEventListener){
7129             el.removeEventListener("DOMMouseScroll", hd, false);
7130         }
7131         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7132             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7133         }
7134     };
7135
7136     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7137     
7138     var pub = {
7139         
7140         
7141         /** 
7142          * Fix for doc tools
7143          * @scope Roo.EventManager
7144          */
7145         
7146         
7147         /** 
7148          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7149          * object with a Roo.EventObject
7150          * @param {Function} fn        The method the event invokes
7151          * @param {Object}   scope    An object that becomes the scope of the handler
7152          * @param {boolean}  override If true, the obj passed in becomes
7153          *                             the execution scope of the listener
7154          * @return {Function} The wrapped function
7155          * @deprecated
7156          */
7157         wrap : function(fn, scope, override){
7158             return function(e){
7159                 Roo.EventObject.setEvent(e);
7160                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7161             };
7162         },
7163         
7164         /**
7165      * Appends an event handler to an element (shorthand for addListener)
7166      * @param {String/HTMLElement}   element        The html element or id to assign the
7167      * @param {String}   eventName The type of event to listen for
7168      * @param {Function} handler The method the event invokes
7169      * @param {Object}   scope (optional) The scope in which to execute the handler
7170      * function. The handler function's "this" context.
7171      * @param {Object}   options (optional) An object containing handler configuration
7172      * properties. This may contain any of the following properties:<ul>
7173      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7174      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7175      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7176      * <li>preventDefault {Boolean} True to prevent the default action</li>
7177      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7178      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7179      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7180      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7181      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7182      * by the specified number of milliseconds. If the event fires again within that time, the original
7183      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7184      * </ul><br>
7185      * <p>
7186      * <b>Combining Options</b><br>
7187      * Using the options argument, it is possible to combine different types of listeners:<br>
7188      * <br>
7189      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7190      * Code:<pre><code>
7191 el.on('click', this.onClick, this, {
7192     single: true,
7193     delay: 100,
7194     stopEvent : true,
7195     forumId: 4
7196 });</code></pre>
7197      * <p>
7198      * <b>Attaching multiple handlers in 1 call</b><br>
7199       * The method also allows for a single argument to be passed which is a config object containing properties
7200      * which specify multiple handlers.
7201      * <p>
7202      * Code:<pre><code>
7203 el.on({
7204     'click' : {
7205         fn: this.onClick
7206         scope: this,
7207         delay: 100
7208     },
7209     'mouseover' : {
7210         fn: this.onMouseOver
7211         scope: this
7212     },
7213     'mouseout' : {
7214         fn: this.onMouseOut
7215         scope: this
7216     }
7217 });</code></pre>
7218      * <p>
7219      * Or a shorthand syntax:<br>
7220      * Code:<pre><code>
7221 el.on({
7222     'click' : this.onClick,
7223     'mouseover' : this.onMouseOver,
7224     'mouseout' : this.onMouseOut
7225     scope: this
7226 });</code></pre>
7227      */
7228         addListener : function(element, eventName, fn, scope, options){
7229             if(typeof eventName == "object"){
7230                 var o = eventName;
7231                 for(var e in o){
7232                     if(propRe.test(e)){
7233                         continue;
7234                     }
7235                     if(typeof o[e] == "function"){
7236                         // shared options
7237                         listen(element, e, o, o[e], o.scope);
7238                     }else{
7239                         // individual options
7240                         listen(element, e, o[e]);
7241                     }
7242                 }
7243                 return;
7244             }
7245             return listen(element, eventName, options, fn, scope);
7246         },
7247         
7248         /**
7249          * Removes an event handler
7250          *
7251          * @param {String/HTMLElement}   element        The id or html element to remove the 
7252          *                             event from
7253          * @param {String}   eventName     The type of event
7254          * @param {Function} fn
7255          * @return {Boolean} True if a listener was actually removed
7256          */
7257         removeListener : function(element, eventName, fn){
7258             return stopListening(element, eventName, fn);
7259         },
7260         
7261         /**
7262          * Fires when the document is ready (before onload and before images are loaded). Can be 
7263          * accessed shorthanded Roo.onReady().
7264          * @param {Function} fn        The method the event invokes
7265          * @param {Object}   scope    An  object that becomes the scope of the handler
7266          * @param {boolean}  options
7267          */
7268         onDocumentReady : function(fn, scope, options){
7269             if(docReadyState){ // if it already fired
7270                 docReadyEvent.addListener(fn, scope, options);
7271                 docReadyEvent.fire();
7272                 docReadyEvent.clearListeners();
7273                 return;
7274             }
7275             if(!docReadyEvent){
7276                 initDocReady();
7277             }
7278             docReadyEvent.addListener(fn, scope, options);
7279         },
7280         
7281         /**
7282          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7283          * @param {Function} fn        The method the event invokes
7284          * @param {Object}   scope    An object that becomes the scope of the handler
7285          * @param {boolean}  options
7286          */
7287         onWindowResize : function(fn, scope, options)
7288         {
7289             if(!resizeEvent){
7290                 resizeEvent = new Roo.util.Event();
7291                 resizeTask = new Roo.util.DelayedTask(function(){
7292                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7293                 });
7294                 E.on(window, "resize", function()
7295                 {
7296                     if (Roo.isIE) {
7297                         resizeTask.delay(50);
7298                     } else {
7299                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7300                     }
7301                 });
7302             }
7303             resizeEvent.addListener(fn, scope, options);
7304         },
7305
7306         /**
7307          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7308          * @param {Function} fn        The method the event invokes
7309          * @param {Object}   scope    An object that becomes the scope of the handler
7310          * @param {boolean}  options
7311          */
7312         onTextResize : function(fn, scope, options){
7313             if(!textEvent){
7314                 textEvent = new Roo.util.Event();
7315                 var textEl = new Roo.Element(document.createElement('div'));
7316                 textEl.dom.className = 'x-text-resize';
7317                 textEl.dom.innerHTML = 'X';
7318                 textEl.appendTo(document.body);
7319                 textSize = textEl.dom.offsetHeight;
7320                 setInterval(function(){
7321                     if(textEl.dom.offsetHeight != textSize){
7322                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7323                     }
7324                 }, this.textResizeInterval);
7325             }
7326             textEvent.addListener(fn, scope, options);
7327         },
7328
7329         /**
7330          * Removes the passed window resize listener.
7331          * @param {Function} fn        The method the event invokes
7332          * @param {Object}   scope    The scope of handler
7333          */
7334         removeResizeListener : function(fn, scope){
7335             if(resizeEvent){
7336                 resizeEvent.removeListener(fn, scope);
7337             }
7338         },
7339
7340         // private
7341         fireResize : function(){
7342             if(resizeEvent){
7343                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7344             }   
7345         },
7346         /**
7347          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7348          */
7349         ieDeferSrc : false,
7350         /**
7351          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7352          */
7353         textResizeInterval : 50
7354     };
7355     
7356     /**
7357      * Fix for doc tools
7358      * @scopeAlias pub=Roo.EventManager
7359      */
7360     
7361      /**
7362      * Appends an event handler to an element (shorthand for addListener)
7363      * @param {String/HTMLElement}   element        The html element or id to assign the
7364      * @param {String}   eventName The type of event to listen for
7365      * @param {Function} handler The method the event invokes
7366      * @param {Object}   scope (optional) The scope in which to execute the handler
7367      * function. The handler function's "this" context.
7368      * @param {Object}   options (optional) An object containing handler configuration
7369      * properties. This may contain any of the following properties:<ul>
7370      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7371      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7372      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7373      * <li>preventDefault {Boolean} True to prevent the default action</li>
7374      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7375      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7376      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7377      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7378      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7379      * by the specified number of milliseconds. If the event fires again within that time, the original
7380      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7381      * </ul><br>
7382      * <p>
7383      * <b>Combining Options</b><br>
7384      * Using the options argument, it is possible to combine different types of listeners:<br>
7385      * <br>
7386      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7387      * Code:<pre><code>
7388 el.on('click', this.onClick, this, {
7389     single: true,
7390     delay: 100,
7391     stopEvent : true,
7392     forumId: 4
7393 });</code></pre>
7394      * <p>
7395      * <b>Attaching multiple handlers in 1 call</b><br>
7396       * The method also allows for a single argument to be passed which is a config object containing properties
7397      * which specify multiple handlers.
7398      * <p>
7399      * Code:<pre><code>
7400 el.on({
7401     'click' : {
7402         fn: this.onClick
7403         scope: this,
7404         delay: 100
7405     },
7406     'mouseover' : {
7407         fn: this.onMouseOver
7408         scope: this
7409     },
7410     'mouseout' : {
7411         fn: this.onMouseOut
7412         scope: this
7413     }
7414 });</code></pre>
7415      * <p>
7416      * Or a shorthand syntax:<br>
7417      * Code:<pre><code>
7418 el.on({
7419     'click' : this.onClick,
7420     'mouseover' : this.onMouseOver,
7421     'mouseout' : this.onMouseOut
7422     scope: this
7423 });</code></pre>
7424      */
7425     pub.on = pub.addListener;
7426     pub.un = pub.removeListener;
7427
7428     pub.stoppedMouseDownEvent = new Roo.util.Event();
7429     return pub;
7430 }();
7431 /**
7432   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
7433   * @param {Function} fn        The method the event invokes
7434   * @param {Object}   scope    An  object that becomes the scope of the handler
7435   * @param {boolean}  override If true, the obj passed in becomes
7436   *                             the execution scope of the listener
7437   * @member Roo
7438   * @method onReady
7439  */
7440 Roo.onReady = Roo.EventManager.onDocumentReady;
7441
7442 Roo.onReady(function(){
7443     var bd = Roo.get(document.body);
7444     if(!bd){ return; }
7445
7446     var cls = [
7447             Roo.isIE ? "roo-ie"
7448             : Roo.isIE11 ? "roo-ie11"
7449             : Roo.isEdge ? "roo-edge"
7450             : Roo.isGecko ? "roo-gecko"
7451             : Roo.isOpera ? "roo-opera"
7452             : Roo.isSafari ? "roo-safari" : ""];
7453
7454     if(Roo.isMac){
7455         cls.push("roo-mac");
7456     }
7457     if(Roo.isLinux){
7458         cls.push("roo-linux");
7459     }
7460     if(Roo.isIOS){
7461         cls.push("roo-ios");
7462     }
7463     if(Roo.isTouch){
7464         cls.push("roo-touch");
7465     }
7466     if(Roo.isBorderBox){
7467         cls.push('roo-border-box');
7468     }
7469     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7470         var p = bd.dom.parentNode;
7471         if(p){
7472             p.className += ' roo-strict';
7473         }
7474     }
7475     bd.addClass(cls.join(' '));
7476 });
7477
7478 /**
7479  * @class Roo.EventObject
7480  * EventObject exposes the Yahoo! UI Event functionality directly on the object
7481  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
7482  * Example:
7483  * <pre><code>
7484  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7485     e.preventDefault();
7486     var target = e.getTarget();
7487     ...
7488  }
7489  var myDiv = Roo.get("myDiv");
7490  myDiv.on("click", handleClick);
7491  //or
7492  Roo.EventManager.on("myDiv", 'click', handleClick);
7493  Roo.EventManager.addListener("myDiv", 'click', handleClick);
7494  </code></pre>
7495  * @static
7496  */
7497 Roo.EventObject = function(){
7498     
7499     var E = Roo.lib.Event;
7500     
7501     // safari keypress events for special keys return bad keycodes
7502     var safariKeys = {
7503         63234 : 37, // left
7504         63235 : 39, // right
7505         63232 : 38, // up
7506         63233 : 40, // down
7507         63276 : 33, // page up
7508         63277 : 34, // page down
7509         63272 : 46, // delete
7510         63273 : 36, // home
7511         63275 : 35  // end
7512     };
7513
7514     // normalize button clicks
7515     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7516                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7517
7518     Roo.EventObjectImpl = function(e){
7519         if(e){
7520             this.setEvent(e.browserEvent || e);
7521         }
7522     };
7523     Roo.EventObjectImpl.prototype = {
7524         /**
7525          * Used to fix doc tools.
7526          * @scope Roo.EventObject.prototype
7527          */
7528             
7529
7530         
7531         
7532         /** The normal browser event */
7533         browserEvent : null,
7534         /** The button pressed in a mouse event */
7535         button : -1,
7536         /** True if the shift key was down during the event */
7537         shiftKey : false,
7538         /** True if the control key was down during the event */
7539         ctrlKey : false,
7540         /** True if the alt key was down during the event */
7541         altKey : false,
7542
7543         /** Key constant 
7544         * @type Number */
7545         BACKSPACE : 8,
7546         /** Key constant 
7547         * @type Number */
7548         TAB : 9,
7549         /** Key constant 
7550         * @type Number */
7551         RETURN : 13,
7552         /** Key constant 
7553         * @type Number */
7554         ENTER : 13,
7555         /** Key constant 
7556         * @type Number */
7557         SHIFT : 16,
7558         /** Key constant 
7559         * @type Number */
7560         CONTROL : 17,
7561         /** Key constant 
7562         * @type Number */
7563         ESC : 27,
7564         /** Key constant 
7565         * @type Number */
7566         SPACE : 32,
7567         /** Key constant 
7568         * @type Number */
7569         PAGEUP : 33,
7570         /** Key constant 
7571         * @type Number */
7572         PAGEDOWN : 34,
7573         /** Key constant 
7574         * @type Number */
7575         END : 35,
7576         /** Key constant 
7577         * @type Number */
7578         HOME : 36,
7579         /** Key constant 
7580         * @type Number */
7581         LEFT : 37,
7582         /** Key constant 
7583         * @type Number */
7584         UP : 38,
7585         /** Key constant 
7586         * @type Number */
7587         RIGHT : 39,
7588         /** Key constant 
7589         * @type Number */
7590         DOWN : 40,
7591         /** Key constant 
7592         * @type Number */
7593         DELETE : 46,
7594         /** Key constant 
7595         * @type Number */
7596         F5 : 116,
7597
7598            /** @private */
7599         setEvent : function(e){
7600             if(e == this || (e && e.browserEvent)){ // already wrapped
7601                 return e;
7602             }
7603             this.browserEvent = e;
7604             if(e){
7605                 // normalize buttons
7606                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
7607                 if(e.type == 'click' && this.button == -1){
7608                     this.button = 0;
7609                 }
7610                 this.type = e.type;
7611                 this.shiftKey = e.shiftKey;
7612                 // mac metaKey behaves like ctrlKey
7613                 this.ctrlKey = e.ctrlKey || e.metaKey;
7614                 this.altKey = e.altKey;
7615                 // in getKey these will be normalized for the mac
7616                 this.keyCode = e.keyCode;
7617                 // keyup warnings on firefox.
7618                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
7619                 // cache the target for the delayed and or buffered events
7620                 this.target = E.getTarget(e);
7621                 // same for XY
7622                 this.xy = E.getXY(e);
7623             }else{
7624                 this.button = -1;
7625                 this.shiftKey = false;
7626                 this.ctrlKey = false;
7627                 this.altKey = false;
7628                 this.keyCode = 0;
7629                 this.charCode =0;
7630                 this.target = null;
7631                 this.xy = [0, 0];
7632             }
7633             return this;
7634         },
7635
7636         /**
7637          * Stop the event (preventDefault and stopPropagation)
7638          */
7639         stopEvent : function(){
7640             if(this.browserEvent){
7641                 if(this.browserEvent.type == 'mousedown'){
7642                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
7643                 }
7644                 E.stopEvent(this.browserEvent);
7645             }
7646         },
7647
7648         /**
7649          * Prevents the browsers default handling of the event.
7650          */
7651         preventDefault : function(){
7652             if(this.browserEvent){
7653                 E.preventDefault(this.browserEvent);
7654             }
7655         },
7656
7657         /** @private */
7658         isNavKeyPress : function(){
7659             var k = this.keyCode;
7660             k = Roo.isSafari ? (safariKeys[k] || k) : k;
7661             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
7662         },
7663
7664         isSpecialKey : function(){
7665             var k = this.keyCode;
7666             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
7667             (k == 16) || (k == 17) ||
7668             (k >= 18 && k <= 20) ||
7669             (k >= 33 && k <= 35) ||
7670             (k >= 36 && k <= 39) ||
7671             (k >= 44 && k <= 45);
7672         },
7673         /**
7674          * Cancels bubbling of the event.
7675          */
7676         stopPropagation : function(){
7677             if(this.browserEvent){
7678                 if(this.type == 'mousedown'){
7679                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
7680                 }
7681                 E.stopPropagation(this.browserEvent);
7682             }
7683         },
7684
7685         /**
7686          * Gets the key code for the event.
7687          * @return {Number}
7688          */
7689         getCharCode : function(){
7690             return this.charCode || this.keyCode;
7691         },
7692
7693         /**
7694          * Returns a normalized keyCode for the event.
7695          * @return {Number} The key code
7696          */
7697         getKey : function(){
7698             var k = this.keyCode || this.charCode;
7699             return Roo.isSafari ? (safariKeys[k] || k) : k;
7700         },
7701
7702         /**
7703          * Gets the x coordinate of the event.
7704          * @return {Number}
7705          */
7706         getPageX : function(){
7707             return this.xy[0];
7708         },
7709
7710         /**
7711          * Gets the y coordinate of the event.
7712          * @return {Number}
7713          */
7714         getPageY : function(){
7715             return this.xy[1];
7716         },
7717
7718         /**
7719          * Gets the time of the event.
7720          * @return {Number}
7721          */
7722         getTime : function(){
7723             if(this.browserEvent){
7724                 return E.getTime(this.browserEvent);
7725             }
7726             return null;
7727         },
7728
7729         /**
7730          * Gets the page coordinates of the event.
7731          * @return {Array} The xy values like [x, y]
7732          */
7733         getXY : function(){
7734             return this.xy;
7735         },
7736
7737         /**
7738          * Gets the target for the event.
7739          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7740          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7741                 search as a number or element (defaults to 10 || document.body)
7742          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7743          * @return {HTMLelement}
7744          */
7745         getTarget : function(selector, maxDepth, returnEl){
7746             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7747         },
7748         /**
7749          * Gets the related target.
7750          * @return {HTMLElement}
7751          */
7752         getRelatedTarget : function(){
7753             if(this.browserEvent){
7754                 return E.getRelatedTarget(this.browserEvent);
7755             }
7756             return null;
7757         },
7758
7759         /**
7760          * Normalizes mouse wheel delta across browsers
7761          * @return {Number} The delta
7762          */
7763         getWheelDelta : function(){
7764             var e = this.browserEvent;
7765             var delta = 0;
7766             if(e.wheelDelta){ /* IE/Opera. */
7767                 delta = e.wheelDelta/120;
7768             }else if(e.detail){ /* Mozilla case. */
7769                 delta = -e.detail/3;
7770             }
7771             return delta;
7772         },
7773
7774         /**
7775          * Returns true if the control, meta, shift or alt key was pressed during this event.
7776          * @return {Boolean}
7777          */
7778         hasModifier : function(){
7779             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7780         },
7781
7782         /**
7783          * Returns true if the target of this event equals el or is a child of el
7784          * @param {String/HTMLElement/Element} el
7785          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7786          * @return {Boolean}
7787          */
7788         within : function(el, related){
7789             var t = this[related ? "getRelatedTarget" : "getTarget"]();
7790             return t && Roo.fly(el).contains(t);
7791         },
7792
7793         getPoint : function(){
7794             return new Roo.lib.Point(this.xy[0], this.xy[1]);
7795         }
7796     };
7797
7798     return new Roo.EventObjectImpl();
7799 }();
7800             
7801     /*
7802  * Based on:
7803  * Ext JS Library 1.1.1
7804  * Copyright(c) 2006-2007, Ext JS, LLC.
7805  *
7806  * Originally Released Under LGPL - original licence link has changed is not relivant.
7807  *
7808  * Fork - LGPL
7809  * <script type="text/javascript">
7810  */
7811
7812  
7813 // was in Composite Element!??!?!
7814  
7815 (function(){
7816     var D = Roo.lib.Dom;
7817     var E = Roo.lib.Event;
7818     var A = Roo.lib.Anim;
7819
7820     // local style camelizing for speed
7821     var propCache = {};
7822     var camelRe = /(-[a-z])/gi;
7823     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7824     var view = document.defaultView;
7825
7826 /**
7827  * @class Roo.Element
7828  * Represents an Element in the DOM.<br><br>
7829  * Usage:<br>
7830 <pre><code>
7831 var el = Roo.get("my-div");
7832
7833 // or with getEl
7834 var el = getEl("my-div");
7835
7836 // or with a DOM element
7837 var el = Roo.get(myDivElement);
7838 </code></pre>
7839  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7840  * each call instead of constructing a new one.<br><br>
7841  * <b>Animations</b><br />
7842  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7843  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7844 <pre>
7845 Option    Default   Description
7846 --------- --------  ---------------------------------------------
7847 duration  .35       The duration of the animation in seconds
7848 easing    easeOut   The YUI easing method
7849 callback  none      A function to execute when the anim completes
7850 scope     this      The scope (this) of the callback function
7851 </pre>
7852 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7853 * manipulate the animation. Here's an example:
7854 <pre><code>
7855 var el = Roo.get("my-div");
7856
7857 // no animation
7858 el.setWidth(100);
7859
7860 // default animation
7861 el.setWidth(100, true);
7862
7863 // animation with some options set
7864 el.setWidth(100, {
7865     duration: 1,
7866     callback: this.foo,
7867     scope: this
7868 });
7869
7870 // using the "anim" property to get the Anim object
7871 var opt = {
7872     duration: 1,
7873     callback: this.foo,
7874     scope: this
7875 };
7876 el.setWidth(100, opt);
7877 ...
7878 if(opt.anim.isAnimated()){
7879     opt.anim.stop();
7880 }
7881 </code></pre>
7882 * <b> Composite (Collections of) Elements</b><br />
7883  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7884  * @constructor Create a new Element directly.
7885  * @param {String/HTMLElement} element
7886  * @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).
7887  */
7888     Roo.Element = function(element, forceNew)
7889     {
7890         var dom = typeof element == "string" ?
7891                 document.getElementById(element) : element;
7892         
7893         this.listeners = {};
7894         
7895         if(!dom){ // invalid id/element
7896             return null;
7897         }
7898         var id = dom.id;
7899         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7900             return Roo.Element.cache[id];
7901         }
7902
7903         /**
7904          * The DOM element
7905          * @type HTMLElement
7906          */
7907         this.dom = dom;
7908
7909         /**
7910          * The DOM element ID
7911          * @type String
7912          */
7913         this.id = id || Roo.id(dom);
7914         
7915         return this; // assumed for cctor?
7916     };
7917
7918     var El = Roo.Element;
7919
7920     El.prototype = {
7921         /**
7922          * The element's default display mode  (defaults to "") 
7923          * @type String
7924          */
7925         originalDisplay : "",
7926
7927         
7928         // note this is overridden in BS version..
7929         visibilityMode : 1, 
7930         /**
7931          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7932          * @type String
7933          */
7934         defaultUnit : "px",
7935         
7936         /**
7937          * Sets the element's visibility mode. When setVisible() is called it
7938          * will use this to determine whether to set the visibility or the display property.
7939          * @param visMode Element.VISIBILITY or Element.DISPLAY
7940          * @return {Roo.Element} this
7941          */
7942         setVisibilityMode : function(visMode){
7943             this.visibilityMode = visMode;
7944             return this;
7945         },
7946         /**
7947          * Convenience method for setVisibilityMode(Element.DISPLAY)
7948          * @param {String} display (optional) What to set display to when visible
7949          * @return {Roo.Element} this
7950          */
7951         enableDisplayMode : function(display){
7952             this.setVisibilityMode(El.DISPLAY);
7953             if(typeof display != "undefined") { this.originalDisplay = display; }
7954             return this;
7955         },
7956
7957         /**
7958          * 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)
7959          * @param {String} selector The simple selector to test
7960          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7961                 search as a number or element (defaults to 10 || document.body)
7962          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7963          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7964          */
7965         findParent : function(simpleSelector, maxDepth, returnEl){
7966             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7967             maxDepth = maxDepth || 50;
7968             if(typeof maxDepth != "number"){
7969                 stopEl = Roo.getDom(maxDepth);
7970                 maxDepth = 10;
7971             }
7972             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7973                 if(dq.is(p, simpleSelector)){
7974                     return returnEl ? Roo.get(p) : p;
7975                 }
7976                 depth++;
7977                 p = p.parentNode;
7978             }
7979             return null;
7980         },
7981
7982
7983         /**
7984          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7985          * @param {String} selector The simple selector to test
7986          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7987                 search as a number or element (defaults to 10 || document.body)
7988          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7989          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7990          */
7991         findParentNode : function(simpleSelector, maxDepth, returnEl){
7992             var p = Roo.fly(this.dom.parentNode, '_internal');
7993             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7994         },
7995         
7996         /**
7997          * Looks at  the scrollable parent element
7998          */
7999         findScrollableParent : function()
8000         {
8001             var overflowRegex = /(auto|scroll)/;
8002             
8003             if(this.getStyle('position') === 'fixed'){
8004                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8005             }
8006             
8007             var excludeStaticParent = this.getStyle('position') === "absolute";
8008             
8009             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8010                 
8011                 if (excludeStaticParent && parent.getStyle('position') === "static") {
8012                     continue;
8013                 }
8014                 
8015                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8016                     return parent;
8017                 }
8018                 
8019                 if(parent.dom.nodeName.toLowerCase() == 'body'){
8020                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8021                 }
8022             }
8023             
8024             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8025         },
8026
8027         /**
8028          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8029          * This is a shortcut for findParentNode() that always returns an Roo.Element.
8030          * @param {String} selector The simple selector to test
8031          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8032                 search as a number or element (defaults to 10 || document.body)
8033          * @return {Roo.Element} The matching DOM node (or null if no match was found)
8034          */
8035         up : function(simpleSelector, maxDepth){
8036             return this.findParentNode(simpleSelector, maxDepth, true);
8037         },
8038
8039
8040
8041         /**
8042          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8043          * @param {String} selector The simple selector to test
8044          * @return {Boolean} True if this element matches the selector, else false
8045          */
8046         is : function(simpleSelector){
8047             return Roo.DomQuery.is(this.dom, simpleSelector);
8048         },
8049
8050         /**
8051          * Perform animation on this element.
8052          * @param {Object} args The YUI animation control args
8053          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8054          * @param {Function} onComplete (optional) Function to call when animation completes
8055          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8056          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8057          * @return {Roo.Element} this
8058          */
8059         animate : function(args, duration, onComplete, easing, animType){
8060             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8061             return this;
8062         },
8063
8064         /*
8065          * @private Internal animation call
8066          */
8067         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8068             animType = animType || 'run';
8069             opt = opt || {};
8070             var anim = Roo.lib.Anim[animType](
8071                 this.dom, args,
8072                 (opt.duration || defaultDur) || .35,
8073                 (opt.easing || defaultEase) || 'easeOut',
8074                 function(){
8075                     Roo.callback(cb, this);
8076                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8077                 },
8078                 this
8079             );
8080             opt.anim = anim;
8081             return anim;
8082         },
8083
8084         // private legacy anim prep
8085         preanim : function(a, i){
8086             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8087         },
8088
8089         /**
8090          * Removes worthless text nodes
8091          * @param {Boolean} forceReclean (optional) By default the element
8092          * keeps track if it has been cleaned already so
8093          * you can call this over and over. However, if you update the element and
8094          * need to force a reclean, you can pass true.
8095          */
8096         clean : function(forceReclean){
8097             if(this.isCleaned && forceReclean !== true){
8098                 return this;
8099             }
8100             var ns = /\S/;
8101             var d = this.dom, n = d.firstChild, ni = -1;
8102             while(n){
8103                 var nx = n.nextSibling;
8104                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8105                     d.removeChild(n);
8106                 }else{
8107                     n.nodeIndex = ++ni;
8108                 }
8109                 n = nx;
8110             }
8111             this.isCleaned = true;
8112             return this;
8113         },
8114
8115         // private
8116         calcOffsetsTo : function(el){
8117             el = Roo.get(el);
8118             var d = el.dom;
8119             var restorePos = false;
8120             if(el.getStyle('position') == 'static'){
8121                 el.position('relative');
8122                 restorePos = true;
8123             }
8124             var x = 0, y =0;
8125             var op = this.dom;
8126             while(op && op != d && op.tagName != 'HTML'){
8127                 x+= op.offsetLeft;
8128                 y+= op.offsetTop;
8129                 op = op.offsetParent;
8130             }
8131             if(restorePos){
8132                 el.position('static');
8133             }
8134             return [x, y];
8135         },
8136
8137         /**
8138          * Scrolls this element into view within the passed container.
8139          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8140          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8141          * @return {Roo.Element} this
8142          */
8143         scrollIntoView : function(container, hscroll){
8144             var c = Roo.getDom(container) || document.body;
8145             var el = this.dom;
8146
8147             var o = this.calcOffsetsTo(c),
8148                 l = o[0],
8149                 t = o[1],
8150                 b = t+el.offsetHeight,
8151                 r = l+el.offsetWidth;
8152
8153             var ch = c.clientHeight;
8154             var ct = parseInt(c.scrollTop, 10);
8155             var cl = parseInt(c.scrollLeft, 10);
8156             var cb = ct + ch;
8157             var cr = cl + c.clientWidth;
8158
8159             if(t < ct){
8160                 c.scrollTop = t;
8161             }else if(b > cb){
8162                 c.scrollTop = b-ch;
8163             }
8164
8165             if(hscroll !== false){
8166                 if(l < cl){
8167                     c.scrollLeft = l;
8168                 }else if(r > cr){
8169                     c.scrollLeft = r-c.clientWidth;
8170                 }
8171             }
8172             return this;
8173         },
8174
8175         // private
8176         scrollChildIntoView : function(child, hscroll){
8177             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8178         },
8179
8180         /**
8181          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8182          * the new height may not be available immediately.
8183          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8184          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8185          * @param {Function} onComplete (optional) Function to call when animation completes
8186          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8187          * @return {Roo.Element} this
8188          */
8189         autoHeight : function(animate, duration, onComplete, easing){
8190             var oldHeight = this.getHeight();
8191             this.clip();
8192             this.setHeight(1); // force clipping
8193             setTimeout(function(){
8194                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8195                 if(!animate){
8196                     this.setHeight(height);
8197                     this.unclip();
8198                     if(typeof onComplete == "function"){
8199                         onComplete();
8200                     }
8201                 }else{
8202                     this.setHeight(oldHeight); // restore original height
8203                     this.setHeight(height, animate, duration, function(){
8204                         this.unclip();
8205                         if(typeof onComplete == "function") { onComplete(); }
8206                     }.createDelegate(this), easing);
8207                 }
8208             }.createDelegate(this), 0);
8209             return this;
8210         },
8211
8212         /**
8213          * Returns true if this element is an ancestor of the passed element
8214          * @param {HTMLElement/String} el The element to check
8215          * @return {Boolean} True if this element is an ancestor of el, else false
8216          */
8217         contains : function(el){
8218             if(!el){return false;}
8219             return D.isAncestor(this.dom, el.dom ? el.dom : el);
8220         },
8221
8222         /**
8223          * Checks whether the element is currently visible using both visibility and display properties.
8224          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8225          * @return {Boolean} True if the element is currently visible, else false
8226          */
8227         isVisible : function(deep) {
8228             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8229             if(deep !== true || !vis){
8230                 return vis;
8231             }
8232             var p = this.dom.parentNode;
8233             while(p && p.tagName.toLowerCase() != "body"){
8234                 if(!Roo.fly(p, '_isVisible').isVisible()){
8235                     return false;
8236                 }
8237                 p = p.parentNode;
8238             }
8239             return true;
8240         },
8241
8242         /**
8243          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8244          * @param {String} selector The CSS selector
8245          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8246          * @return {CompositeElement/CompositeElementLite} The composite element
8247          */
8248         select : function(selector, unique){
8249             return El.select(selector, unique, this.dom);
8250         },
8251
8252         /**
8253          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8254          * @param {String} selector The CSS selector
8255          * @return {Array} An array of the matched nodes
8256          */
8257         query : function(selector, unique){
8258             return Roo.DomQuery.select(selector, this.dom);
8259         },
8260
8261         /**
8262          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8263          * @param {String} selector The CSS selector
8264          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8265          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8266          */
8267         child : function(selector, returnDom){
8268             var n = Roo.DomQuery.selectNode(selector, this.dom);
8269             return returnDom ? n : Roo.get(n);
8270         },
8271
8272         /**
8273          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8274          * @param {String} selector The CSS selector
8275          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8276          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8277          */
8278         down : function(selector, returnDom){
8279             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8280             return returnDom ? n : Roo.get(n);
8281         },
8282
8283         /**
8284          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8285          * @param {String} group The group the DD object is member of
8286          * @param {Object} config The DD config object
8287          * @param {Object} overrides An object containing methods to override/implement on the DD object
8288          * @return {Roo.dd.DD} The DD object
8289          */
8290         initDD : function(group, config, overrides){
8291             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8292             return Roo.apply(dd, overrides);
8293         },
8294
8295         /**
8296          * Initializes a {@link Roo.dd.DDProxy} object for this element.
8297          * @param {String} group The group the DDProxy object is member of
8298          * @param {Object} config The DDProxy config object
8299          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8300          * @return {Roo.dd.DDProxy} The DDProxy object
8301          */
8302         initDDProxy : function(group, config, overrides){
8303             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8304             return Roo.apply(dd, overrides);
8305         },
8306
8307         /**
8308          * Initializes a {@link Roo.dd.DDTarget} object for this element.
8309          * @param {String} group The group the DDTarget object is member of
8310          * @param {Object} config The DDTarget config object
8311          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8312          * @return {Roo.dd.DDTarget} The DDTarget object
8313          */
8314         initDDTarget : function(group, config, overrides){
8315             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8316             return Roo.apply(dd, overrides);
8317         },
8318
8319         /**
8320          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8321          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8322          * @param {Boolean} visible Whether the element is visible
8323          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8324          * @return {Roo.Element} this
8325          */
8326          setVisible : function(visible, animate){
8327             if(!animate || !A){
8328                 if(this.visibilityMode == El.DISPLAY){
8329                     this.setDisplayed(visible);
8330                 }else{
8331                     this.fixDisplay();
8332                     this.dom.style.visibility = visible ? "visible" : "hidden";
8333                 }
8334             }else{
8335                 // closure for composites
8336                 var dom = this.dom;
8337                 var visMode = this.visibilityMode;
8338                 if(visible){
8339                     this.setOpacity(.01);
8340                     this.setVisible(true);
8341                 }
8342                 this.anim({opacity: { to: (visible?1:0) }},
8343                       this.preanim(arguments, 1),
8344                       null, .35, 'easeIn', function(){
8345                          if(!visible){
8346                              if(visMode == El.DISPLAY){
8347                                  dom.style.display = "none";
8348                              }else{
8349                                  dom.style.visibility = "hidden";
8350                              }
8351                              Roo.get(dom).setOpacity(1);
8352                          }
8353                      });
8354             }
8355             return this;
8356         },
8357
8358         /**
8359          * Returns true if display is not "none"
8360          * @return {Boolean}
8361          */
8362         isDisplayed : function() {
8363             return this.getStyle("display") != "none";
8364         },
8365
8366         /**
8367          * Toggles the element's visibility or display, depending on visibility mode.
8368          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8369          * @return {Roo.Element} this
8370          */
8371         toggle : function(animate){
8372             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8373             return this;
8374         },
8375
8376         /**
8377          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8378          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8379          * @return {Roo.Element} this
8380          */
8381         setDisplayed : function(value) {
8382             if(typeof value == "boolean"){
8383                value = value ? this.originalDisplay : "none";
8384             }
8385             this.setStyle("display", value);
8386             return this;
8387         },
8388
8389         /**
8390          * Tries to focus the element. Any exceptions are caught and ignored.
8391          * @return {Roo.Element} this
8392          */
8393         focus : function() {
8394             try{
8395                 this.dom.focus();
8396             }catch(e){}
8397             return this;
8398         },
8399
8400         /**
8401          * Tries to blur the element. Any exceptions are caught and ignored.
8402          * @return {Roo.Element} this
8403          */
8404         blur : function() {
8405             try{
8406                 this.dom.blur();
8407             }catch(e){}
8408             return this;
8409         },
8410
8411         /**
8412          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8413          * @param {String/Array} className The CSS class to add, or an array of classes
8414          * @return {Roo.Element} this
8415          */
8416         addClass : function(className){
8417             if(className instanceof Array){
8418                 for(var i = 0, len = className.length; i < len; i++) {
8419                     this.addClass(className[i]);
8420                 }
8421             }else{
8422                 if(className && !this.hasClass(className)){
8423                     if (this.dom instanceof SVGElement) {
8424                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
8425                     } else {
8426                         this.dom.className = this.dom.className + " " + className;
8427                     }
8428                 }
8429             }
8430             return this;
8431         },
8432
8433         /**
8434          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8435          * @param {String/Array} className The CSS class to add, or an array of classes
8436          * @return {Roo.Element} this
8437          */
8438         radioClass : function(className){
8439             var siblings = this.dom.parentNode.childNodes;
8440             for(var i = 0; i < siblings.length; i++) {
8441                 var s = siblings[i];
8442                 if(s.nodeType == 1){
8443                     Roo.get(s).removeClass(className);
8444                 }
8445             }
8446             this.addClass(className);
8447             return this;
8448         },
8449
8450         /**
8451          * Removes one or more CSS classes from the element.
8452          * @param {String/Array} className The CSS class to remove, or an array of classes
8453          * @return {Roo.Element} this
8454          */
8455         removeClass : function(className){
8456             
8457             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8458             if(!className || !cn){
8459                 return this;
8460             }
8461             if(className instanceof Array){
8462                 for(var i = 0, len = className.length; i < len; i++) {
8463                     this.removeClass(className[i]);
8464                 }
8465             }else{
8466                 if(this.hasClass(className)){
8467                     var re = this.classReCache[className];
8468                     if (!re) {
8469                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8470                        this.classReCache[className] = re;
8471                     }
8472                     if (this.dom instanceof SVGElement) {
8473                         this.dom.className.baseVal = cn.replace(re, " ");
8474                     } else {
8475                         this.dom.className = cn.replace(re, " ");
8476                     }
8477                 }
8478             }
8479             return this;
8480         },
8481
8482         // private
8483         classReCache: {},
8484
8485         /**
8486          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8487          * @param {String} className The CSS class to toggle
8488          * @return {Roo.Element} this
8489          */
8490         toggleClass : function(className){
8491             if(this.hasClass(className)){
8492                 this.removeClass(className);
8493             }else{
8494                 this.addClass(className);
8495             }
8496             return this;
8497         },
8498
8499         /**
8500          * Checks if the specified CSS class exists on this element's DOM node.
8501          * @param {String} className The CSS class to check for
8502          * @return {Boolean} True if the class exists, else false
8503          */
8504         hasClass : function(className){
8505             if (this.dom instanceof SVGElement) {
8506                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
8507             } 
8508             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8509         },
8510
8511         /**
8512          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
8513          * @param {String} oldClassName The CSS class to replace
8514          * @param {String} newClassName The replacement CSS class
8515          * @return {Roo.Element} this
8516          */
8517         replaceClass : function(oldClassName, newClassName){
8518             this.removeClass(oldClassName);
8519             this.addClass(newClassName);
8520             return this;
8521         },
8522
8523         /**
8524          * Returns an object with properties matching the styles requested.
8525          * For example, el.getStyles('color', 'font-size', 'width') might return
8526          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8527          * @param {String} style1 A style name
8528          * @param {String} style2 A style name
8529          * @param {String} etc.
8530          * @return {Object} The style object
8531          */
8532         getStyles : function(){
8533             var a = arguments, len = a.length, r = {};
8534             for(var i = 0; i < len; i++){
8535                 r[a[i]] = this.getStyle(a[i]);
8536             }
8537             return r;
8538         },
8539
8540         /**
8541          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8542          * @param {String} property The style property whose value is returned.
8543          * @return {String} The current value of the style property for this element.
8544          */
8545         getStyle : function(){
8546             return view && view.getComputedStyle ?
8547                 function(prop){
8548                     var el = this.dom, v, cs, camel;
8549                     if(prop == 'float'){
8550                         prop = "cssFloat";
8551                     }
8552                     if(el.style && (v = el.style[prop])){
8553                         return v;
8554                     }
8555                     if(cs = view.getComputedStyle(el, "")){
8556                         if(!(camel = propCache[prop])){
8557                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
8558                         }
8559                         return cs[camel];
8560                     }
8561                     return null;
8562                 } :
8563                 function(prop){
8564                     var el = this.dom, v, cs, camel;
8565                     if(prop == 'opacity'){
8566                         if(typeof el.style.filter == 'string'){
8567                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8568                             if(m){
8569                                 var fv = parseFloat(m[1]);
8570                                 if(!isNaN(fv)){
8571                                     return fv ? fv / 100 : 0;
8572                                 }
8573                             }
8574                         }
8575                         return 1;
8576                     }else if(prop == 'float'){
8577                         prop = "styleFloat";
8578                     }
8579                     if(!(camel = propCache[prop])){
8580                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
8581                     }
8582                     if(v = el.style[camel]){
8583                         return v;
8584                     }
8585                     if(cs = el.currentStyle){
8586                         return cs[camel];
8587                     }
8588                     return null;
8589                 };
8590         }(),
8591
8592         /**
8593          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8594          * @param {String/Object} property The style property to be set, or an object of multiple styles.
8595          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8596          * @return {Roo.Element} this
8597          */
8598         setStyle : function(prop, value){
8599             if(typeof prop == "string"){
8600                 
8601                 if (prop == 'float') {
8602                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
8603                     return this;
8604                 }
8605                 
8606                 var camel;
8607                 if(!(camel = propCache[prop])){
8608                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
8609                 }
8610                 
8611                 if(camel == 'opacity') {
8612                     this.setOpacity(value);
8613                 }else{
8614                     this.dom.style[camel] = value;
8615                 }
8616             }else{
8617                 for(var style in prop){
8618                     if(typeof prop[style] != "function"){
8619                        this.setStyle(style, prop[style]);
8620                     }
8621                 }
8622             }
8623             return this;
8624         },
8625
8626         /**
8627          * More flexible version of {@link #setStyle} for setting style properties.
8628          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
8629          * a function which returns such a specification.
8630          * @return {Roo.Element} this
8631          */
8632         applyStyles : function(style){
8633             Roo.DomHelper.applyStyles(this.dom, style);
8634             return this;
8635         },
8636
8637         /**
8638           * 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).
8639           * @return {Number} The X position of the element
8640           */
8641         getX : function(){
8642             return D.getX(this.dom);
8643         },
8644
8645         /**
8646           * 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).
8647           * @return {Number} The Y position of the element
8648           */
8649         getY : function(){
8650             return D.getY(this.dom);
8651         },
8652
8653         /**
8654           * 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).
8655           * @return {Array} The XY position of the element
8656           */
8657         getXY : function(){
8658             return D.getXY(this.dom);
8659         },
8660
8661         /**
8662          * 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).
8663          * @param {Number} The X position of the element
8664          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8665          * @return {Roo.Element} this
8666          */
8667         setX : function(x, animate){
8668             if(!animate || !A){
8669                 D.setX(this.dom, x);
8670             }else{
8671                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
8672             }
8673             return this;
8674         },
8675
8676         /**
8677          * 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).
8678          * @param {Number} The Y position of the element
8679          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8680          * @return {Roo.Element} this
8681          */
8682         setY : function(y, animate){
8683             if(!animate || !A){
8684                 D.setY(this.dom, y);
8685             }else{
8686                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
8687             }
8688             return this;
8689         },
8690
8691         /**
8692          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
8693          * @param {String} left The left CSS property value
8694          * @return {Roo.Element} this
8695          */
8696         setLeft : function(left){
8697             this.setStyle("left", this.addUnits(left));
8698             return this;
8699         },
8700
8701         /**
8702          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
8703          * @param {String} top The top CSS property value
8704          * @return {Roo.Element} this
8705          */
8706         setTop : function(top){
8707             this.setStyle("top", this.addUnits(top));
8708             return this;
8709         },
8710
8711         /**
8712          * Sets the element's CSS right style.
8713          * @param {String} right The right CSS property value
8714          * @return {Roo.Element} this
8715          */
8716         setRight : function(right){
8717             this.setStyle("right", this.addUnits(right));
8718             return this;
8719         },
8720
8721         /**
8722          * Sets the element's CSS bottom style.
8723          * @param {String} bottom The bottom CSS property value
8724          * @return {Roo.Element} this
8725          */
8726         setBottom : function(bottom){
8727             this.setStyle("bottom", this.addUnits(bottom));
8728             return this;
8729         },
8730
8731         /**
8732          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8733          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8734          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8735          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8736          * @return {Roo.Element} this
8737          */
8738         setXY : function(pos, animate){
8739             if(!animate || !A){
8740                 D.setXY(this.dom, pos);
8741             }else{
8742                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8743             }
8744             return this;
8745         },
8746
8747         /**
8748          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8749          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8750          * @param {Number} x X value for new position (coordinates are page-based)
8751          * @param {Number} y Y value for new position (coordinates are page-based)
8752          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8753          * @return {Roo.Element} this
8754          */
8755         setLocation : function(x, y, animate){
8756             this.setXY([x, y], this.preanim(arguments, 2));
8757             return this;
8758         },
8759
8760         /**
8761          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8762          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8763          * @param {Number} x X value for new position (coordinates are page-based)
8764          * @param {Number} y Y value for new position (coordinates are page-based)
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         moveTo : function(x, y, animate){
8769             this.setXY([x, y], this.preanim(arguments, 2));
8770             return this;
8771         },
8772
8773         /**
8774          * Returns the region of the given element.
8775          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8776          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8777          */
8778         getRegion : function(){
8779             return D.getRegion(this.dom);
8780         },
8781
8782         /**
8783          * Returns the offset height of the element
8784          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8785          * @return {Number} The element's height
8786          */
8787         getHeight : function(contentHeight){
8788             var h = this.dom.offsetHeight || 0;
8789             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8790         },
8791
8792         /**
8793          * Returns the offset width of the element
8794          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8795          * @return {Number} The element's width
8796          */
8797         getWidth : function(contentWidth){
8798             var w = this.dom.offsetWidth || 0;
8799             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8800         },
8801
8802         /**
8803          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8804          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8805          * if a height has not been set using CSS.
8806          * @return {Number}
8807          */
8808         getComputedHeight : function(){
8809             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8810             if(!h){
8811                 h = parseInt(this.getStyle('height'), 10) || 0;
8812                 if(!this.isBorderBox()){
8813                     h += this.getFrameWidth('tb');
8814                 }
8815             }
8816             return h;
8817         },
8818
8819         /**
8820          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8821          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8822          * if a width has not been set using CSS.
8823          * @return {Number}
8824          */
8825         getComputedWidth : function(){
8826             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8827             if(!w){
8828                 w = parseInt(this.getStyle('width'), 10) || 0;
8829                 if(!this.isBorderBox()){
8830                     w += this.getFrameWidth('lr');
8831                 }
8832             }
8833             return w;
8834         },
8835
8836         /**
8837          * Returns the size of the element.
8838          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8839          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8840          */
8841         getSize : function(contentSize){
8842             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8843         },
8844
8845         /**
8846          * Returns the width and height of the viewport.
8847          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8848          */
8849         getViewSize : function(){
8850             var d = this.dom, doc = document, aw = 0, ah = 0;
8851             if(d == doc || d == doc.body){
8852                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8853             }else{
8854                 return {
8855                     width : d.clientWidth,
8856                     height: d.clientHeight
8857                 };
8858             }
8859         },
8860
8861         /**
8862          * Returns the value of the "value" attribute
8863          * @param {Boolean} asNumber true to parse the value as a number
8864          * @return {String/Number}
8865          */
8866         getValue : function(asNumber){
8867             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8868         },
8869
8870         // private
8871         adjustWidth : function(width){
8872             if(typeof width == "number"){
8873                 if(this.autoBoxAdjust && !this.isBorderBox()){
8874                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8875                 }
8876                 if(width < 0){
8877                     width = 0;
8878                 }
8879             }
8880             return width;
8881         },
8882
8883         // private
8884         adjustHeight : function(height){
8885             if(typeof height == "number"){
8886                if(this.autoBoxAdjust && !this.isBorderBox()){
8887                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8888                }
8889                if(height < 0){
8890                    height = 0;
8891                }
8892             }
8893             return height;
8894         },
8895
8896         /**
8897          * Set the width of the element
8898          * @param {Number} width The new width
8899          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8900          * @return {Roo.Element} this
8901          */
8902         setWidth : function(width, animate){
8903             width = this.adjustWidth(width);
8904             if(!animate || !A){
8905                 this.dom.style.width = this.addUnits(width);
8906             }else{
8907                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8908             }
8909             return this;
8910         },
8911
8912         /**
8913          * Set the height of the element
8914          * @param {Number} height The new height
8915          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8916          * @return {Roo.Element} this
8917          */
8918          setHeight : function(height, animate){
8919             height = this.adjustHeight(height);
8920             if(!animate || !A){
8921                 this.dom.style.height = this.addUnits(height);
8922             }else{
8923                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8924             }
8925             return this;
8926         },
8927
8928         /**
8929          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8930          * @param {Number} width The new width
8931          * @param {Number} height The new height
8932          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8933          * @return {Roo.Element} this
8934          */
8935          setSize : function(width, height, animate){
8936             if(typeof width == "object"){ // in case of object from getSize()
8937                 height = width.height; width = width.width;
8938             }
8939             width = this.adjustWidth(width); height = this.adjustHeight(height);
8940             if(!animate || !A){
8941                 this.dom.style.width = this.addUnits(width);
8942                 this.dom.style.height = this.addUnits(height);
8943             }else{
8944                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8945             }
8946             return this;
8947         },
8948
8949         /**
8950          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8951          * @param {Number} x X value for new position (coordinates are page-based)
8952          * @param {Number} y Y value for new position (coordinates are page-based)
8953          * @param {Number} width The new width
8954          * @param {Number} height The new height
8955          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8956          * @return {Roo.Element} this
8957          */
8958         setBounds : function(x, y, width, height, animate){
8959             if(!animate || !A){
8960                 this.setSize(width, height);
8961                 this.setLocation(x, y);
8962             }else{
8963                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8964                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8965                               this.preanim(arguments, 4), 'motion');
8966             }
8967             return this;
8968         },
8969
8970         /**
8971          * 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.
8972          * @param {Roo.lib.Region} region The region to fill
8973          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8974          * @return {Roo.Element} this
8975          */
8976         setRegion : function(region, animate){
8977             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8978             return this;
8979         },
8980
8981         /**
8982          * Appends an event handler
8983          *
8984          * @param {String}   eventName     The type of event to append
8985          * @param {Function} fn        The method the event invokes
8986          * @param {Object} scope       (optional) The scope (this object) of the fn
8987          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8988          */
8989         addListener : function(eventName, fn, scope, options)
8990         {
8991             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
8992                 this.addListener('touchstart', this.onTapHandler, this);
8993             }
8994             
8995             // we need to handle a special case where dom element is a svg element.
8996             // in this case we do not actua
8997             if (!this.dom) {
8998                 return;
8999             }
9000             
9001             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9002                 if (typeof(this.listeners[eventName]) == 'undefined') {
9003                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
9004                 }
9005                 this.listeners[eventName].addListener(fn, scope, options);
9006                 return;
9007             }
9008             
9009                 
9010             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
9011             
9012             
9013         },
9014         tapedTwice : false,
9015         onTapHandler : function(event)
9016         {
9017             if(!this.tapedTwice) {
9018                 this.tapedTwice = true;
9019                 var s = this;
9020                 setTimeout( function() {
9021                     s.tapedTwice = false;
9022                 }, 300 );
9023                 return;
9024             }
9025             event.preventDefault();
9026             var revent = new MouseEvent('dblclick',  {
9027                 view: window,
9028                 bubbles: true,
9029                 cancelable: true
9030             });
9031              
9032             this.dom.dispatchEvent(revent);
9033             //action on double tap goes below
9034              
9035         }, 
9036  
9037         /**
9038          * Removes an event handler from this element
9039          * @param {String} eventName the type of event to remove
9040          * @param {Function} fn the method the event invokes
9041          * @param {Function} scope (needed for svg fake listeners)
9042          * @return {Roo.Element} this
9043          */
9044         removeListener : function(eventName, fn, scope){
9045             Roo.EventManager.removeListener(this.dom,  eventName, fn);
9046             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
9047                 return this;
9048             }
9049             this.listeners[eventName].removeListener(fn, scope);
9050             return this;
9051         },
9052
9053         /**
9054          * Removes all previous added listeners from this element
9055          * @return {Roo.Element} this
9056          */
9057         removeAllListeners : function(){
9058             E.purgeElement(this.dom);
9059             this.listeners = {};
9060             return this;
9061         },
9062
9063         relayEvent : function(eventName, observable){
9064             this.on(eventName, function(e){
9065                 observable.fireEvent(eventName, e);
9066             });
9067         },
9068
9069         
9070         /**
9071          * Set the opacity of the element
9072          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9073          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9074          * @return {Roo.Element} this
9075          */
9076          setOpacity : function(opacity, animate){
9077             if(!animate || !A){
9078                 var s = this.dom.style;
9079                 if(Roo.isIE){
9080                     s.zoom = 1;
9081                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9082                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9083                 }else{
9084                     s.opacity = opacity;
9085                 }
9086             }else{
9087                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9088             }
9089             return this;
9090         },
9091
9092         /**
9093          * Gets the left X coordinate
9094          * @param {Boolean} local True to get the local css position instead of page coordinate
9095          * @return {Number}
9096          */
9097         getLeft : function(local){
9098             if(!local){
9099                 return this.getX();
9100             }else{
9101                 return parseInt(this.getStyle("left"), 10) || 0;
9102             }
9103         },
9104
9105         /**
9106          * Gets the right X coordinate of the element (element X position + element width)
9107          * @param {Boolean} local True to get the local css position instead of page coordinate
9108          * @return {Number}
9109          */
9110         getRight : function(local){
9111             if(!local){
9112                 return this.getX() + this.getWidth();
9113             }else{
9114                 return (this.getLeft(true) + this.getWidth()) || 0;
9115             }
9116         },
9117
9118         /**
9119          * Gets the top Y coordinate
9120          * @param {Boolean} local True to get the local css position instead of page coordinate
9121          * @return {Number}
9122          */
9123         getTop : function(local) {
9124             if(!local){
9125                 return this.getY();
9126             }else{
9127                 return parseInt(this.getStyle("top"), 10) || 0;
9128             }
9129         },
9130
9131         /**
9132          * Gets the bottom Y coordinate of the element (element Y position + element height)
9133          * @param {Boolean} local True to get the local css position instead of page coordinate
9134          * @return {Number}
9135          */
9136         getBottom : function(local){
9137             if(!local){
9138                 return this.getY() + this.getHeight();
9139             }else{
9140                 return (this.getTop(true) + this.getHeight()) || 0;
9141             }
9142         },
9143
9144         /**
9145         * Initializes positioning on this element. If a desired position is not passed, it will make the
9146         * the element positioned relative IF it is not already positioned.
9147         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9148         * @param {Number} zIndex (optional) The zIndex to apply
9149         * @param {Number} x (optional) Set the page X position
9150         * @param {Number} y (optional) Set the page Y position
9151         */
9152         position : function(pos, zIndex, x, y){
9153             if(!pos){
9154                if(this.getStyle('position') == 'static'){
9155                    this.setStyle('position', 'relative');
9156                }
9157             }else{
9158                 this.setStyle("position", pos);
9159             }
9160             if(zIndex){
9161                 this.setStyle("z-index", zIndex);
9162             }
9163             if(x !== undefined && y !== undefined){
9164                 this.setXY([x, y]);
9165             }else if(x !== undefined){
9166                 this.setX(x);
9167             }else if(y !== undefined){
9168                 this.setY(y);
9169             }
9170         },
9171
9172         /**
9173         * Clear positioning back to the default when the document was loaded
9174         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9175         * @return {Roo.Element} this
9176          */
9177         clearPositioning : function(value){
9178             value = value ||'';
9179             this.setStyle({
9180                 "left": value,
9181                 "right": value,
9182                 "top": value,
9183                 "bottom": value,
9184                 "z-index": "",
9185                 "position" : "static"
9186             });
9187             return this;
9188         },
9189
9190         /**
9191         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9192         * snapshot before performing an update and then restoring the element.
9193         * @return {Object}
9194         */
9195         getPositioning : function(){
9196             var l = this.getStyle("left");
9197             var t = this.getStyle("top");
9198             return {
9199                 "position" : this.getStyle("position"),
9200                 "left" : l,
9201                 "right" : l ? "" : this.getStyle("right"),
9202                 "top" : t,
9203                 "bottom" : t ? "" : this.getStyle("bottom"),
9204                 "z-index" : this.getStyle("z-index")
9205             };
9206         },
9207
9208         /**
9209          * Gets the width of the border(s) for the specified side(s)
9210          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9211          * passing lr would get the border (l)eft width + the border (r)ight width.
9212          * @return {Number} The width of the sides passed added together
9213          */
9214         getBorderWidth : function(side){
9215             return this.addStyles(side, El.borders);
9216         },
9217
9218         /**
9219          * Gets the width of the padding(s) for the specified side(s)
9220          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9221          * passing lr would get the padding (l)eft + the padding (r)ight.
9222          * @return {Number} The padding of the sides passed added together
9223          */
9224         getPadding : function(side){
9225             return this.addStyles(side, El.paddings);
9226         },
9227
9228         /**
9229         * Set positioning with an object returned by getPositioning().
9230         * @param {Object} posCfg
9231         * @return {Roo.Element} this
9232          */
9233         setPositioning : function(pc){
9234             this.applyStyles(pc);
9235             if(pc.right == "auto"){
9236                 this.dom.style.right = "";
9237             }
9238             if(pc.bottom == "auto"){
9239                 this.dom.style.bottom = "";
9240             }
9241             return this;
9242         },
9243
9244         // private
9245         fixDisplay : function(){
9246             if(this.getStyle("display") == "none"){
9247                 this.setStyle("visibility", "hidden");
9248                 this.setStyle("display", this.originalDisplay); // first try reverting to default
9249                 if(this.getStyle("display") == "none"){ // if that fails, default to block
9250                     this.setStyle("display", "block");
9251                 }
9252             }
9253         },
9254
9255         /**
9256          * Quick set left and top adding default units
9257          * @param {String} left The left CSS property value
9258          * @param {String} top The top CSS property value
9259          * @return {Roo.Element} this
9260          */
9261          setLeftTop : function(left, top){
9262             this.dom.style.left = this.addUnits(left);
9263             this.dom.style.top = this.addUnits(top);
9264             return this;
9265         },
9266
9267         /**
9268          * Move this element relative to its current position.
9269          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9270          * @param {Number} distance How far to move the element in pixels
9271          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9272          * @return {Roo.Element} this
9273          */
9274          move : function(direction, distance, animate){
9275             var xy = this.getXY();
9276             direction = direction.toLowerCase();
9277             switch(direction){
9278                 case "l":
9279                 case "left":
9280                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9281                     break;
9282                case "r":
9283                case "right":
9284                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9285                     break;
9286                case "t":
9287                case "top":
9288                case "up":
9289                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9290                     break;
9291                case "b":
9292                case "bottom":
9293                case "down":
9294                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9295                     break;
9296             }
9297             return this;
9298         },
9299
9300         /**
9301          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9302          * @return {Roo.Element} this
9303          */
9304         clip : function(){
9305             if(!this.isClipped){
9306                this.isClipped = true;
9307                this.originalClip = {
9308                    "o": this.getStyle("overflow"),
9309                    "x": this.getStyle("overflow-x"),
9310                    "y": this.getStyle("overflow-y")
9311                };
9312                this.setStyle("overflow", "hidden");
9313                this.setStyle("overflow-x", "hidden");
9314                this.setStyle("overflow-y", "hidden");
9315             }
9316             return this;
9317         },
9318
9319         /**
9320          *  Return clipping (overflow) to original clipping before clip() was called
9321          * @return {Roo.Element} this
9322          */
9323         unclip : function(){
9324             if(this.isClipped){
9325                 this.isClipped = false;
9326                 var o = this.originalClip;
9327                 if(o.o){this.setStyle("overflow", o.o);}
9328                 if(o.x){this.setStyle("overflow-x", o.x);}
9329                 if(o.y){this.setStyle("overflow-y", o.y);}
9330             }
9331             return this;
9332         },
9333
9334
9335         /**
9336          * Gets the x,y coordinates specified by the anchor position on the element.
9337          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
9338          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9339          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
9340          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9341          * @return {Array} [x, y] An array containing the element's x and y coordinates
9342          */
9343         getAnchorXY : function(anchor, local, s){
9344             //Passing a different size is useful for pre-calculating anchors,
9345             //especially for anchored animations that change the el size.
9346
9347             var w, h, vp = false;
9348             if(!s){
9349                 var d = this.dom;
9350                 if(d == document.body || d == document){
9351                     vp = true;
9352                     w = D.getViewWidth(); h = D.getViewHeight();
9353                 }else{
9354                     w = this.getWidth(); h = this.getHeight();
9355                 }
9356             }else{
9357                 w = s.width;  h = s.height;
9358             }
9359             var x = 0, y = 0, r = Math.round;
9360             switch((anchor || "tl").toLowerCase()){
9361                 case "c":
9362                     x = r(w*.5);
9363                     y = r(h*.5);
9364                 break;
9365                 case "t":
9366                     x = r(w*.5);
9367                     y = 0;
9368                 break;
9369                 case "l":
9370                     x = 0;
9371                     y = r(h*.5);
9372                 break;
9373                 case "r":
9374                     x = w;
9375                     y = r(h*.5);
9376                 break;
9377                 case "b":
9378                     x = r(w*.5);
9379                     y = h;
9380                 break;
9381                 case "tl":
9382                     x = 0;
9383                     y = 0;
9384                 break;
9385                 case "bl":
9386                     x = 0;
9387                     y = h;
9388                 break;
9389                 case "br":
9390                     x = w;
9391                     y = h;
9392                 break;
9393                 case "tr":
9394                     x = w;
9395                     y = 0;
9396                 break;
9397             }
9398             if(local === true){
9399                 return [x, y];
9400             }
9401             if(vp){
9402                 var sc = this.getScroll();
9403                 return [x + sc.left, y + sc.top];
9404             }
9405             //Add the element's offset xy
9406             var o = this.getXY();
9407             return [x+o[0], y+o[1]];
9408         },
9409
9410         /**
9411          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9412          * supported position values.
9413          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9414          * @param {String} position The position to align to.
9415          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9416          * @return {Array} [x, y]
9417          */
9418         getAlignToXY : function(el, p, o)
9419         {
9420             el = Roo.get(el);
9421             var d = this.dom;
9422             if(!el.dom){
9423                 throw "Element.alignTo with an element that doesn't exist";
9424             }
9425             var c = false; //constrain to viewport
9426             var p1 = "", p2 = "";
9427             o = o || [0,0];
9428
9429             if(!p){
9430                 p = "tl-bl";
9431             }else if(p == "?"){
9432                 p = "tl-bl?";
9433             }else if(p.indexOf("-") == -1){
9434                 p = "tl-" + p;
9435             }
9436             p = p.toLowerCase();
9437             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9438             if(!m){
9439                throw "Element.alignTo with an invalid alignment " + p;
9440             }
9441             p1 = m[1]; p2 = m[2]; c = !!m[3];
9442
9443             //Subtract the aligned el's internal xy from the target's offset xy
9444             //plus custom offset to get the aligned el's new offset xy
9445             var a1 = this.getAnchorXY(p1, true);
9446             var a2 = el.getAnchorXY(p2, false);
9447             var x = a2[0] - a1[0] + o[0];
9448             var y = a2[1] - a1[1] + o[1];
9449             if(c){
9450                 //constrain the aligned el to viewport if necessary
9451                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9452                 // 5px of margin for ie
9453                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9454
9455                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9456                 //perpendicular to the vp border, allow the aligned el to slide on that border,
9457                 //otherwise swap the aligned el to the opposite border of the target.
9458                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9459                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9460                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
9461                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9462
9463                var doc = document;
9464                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9465                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9466
9467                if((x+w) > dw + scrollX){
9468                     x = swapX ? r.left-w : dw+scrollX-w;
9469                 }
9470                if(x < scrollX){
9471                    x = swapX ? r.right : scrollX;
9472                }
9473                if((y+h) > dh + scrollY){
9474                     y = swapY ? r.top-h : dh+scrollY-h;
9475                 }
9476                if (y < scrollY){
9477                    y = swapY ? r.bottom : scrollY;
9478                }
9479             }
9480             return [x,y];
9481         },
9482
9483         // private
9484         getConstrainToXY : function(){
9485             var os = {top:0, left:0, bottom:0, right: 0};
9486
9487             return function(el, local, offsets, proposedXY){
9488                 el = Roo.get(el);
9489                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9490
9491                 var vw, vh, vx = 0, vy = 0;
9492                 if(el.dom == document.body || el.dom == document){
9493                     vw = Roo.lib.Dom.getViewWidth();
9494                     vh = Roo.lib.Dom.getViewHeight();
9495                 }else{
9496                     vw = el.dom.clientWidth;
9497                     vh = el.dom.clientHeight;
9498                     if(!local){
9499                         var vxy = el.getXY();
9500                         vx = vxy[0];
9501                         vy = vxy[1];
9502                     }
9503                 }
9504
9505                 var s = el.getScroll();
9506
9507                 vx += offsets.left + s.left;
9508                 vy += offsets.top + s.top;
9509
9510                 vw -= offsets.right;
9511                 vh -= offsets.bottom;
9512
9513                 var vr = vx+vw;
9514                 var vb = vy+vh;
9515
9516                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9517                 var x = xy[0], y = xy[1];
9518                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9519
9520                 // only move it if it needs it
9521                 var moved = false;
9522
9523                 // first validate right/bottom
9524                 if((x + w) > vr){
9525                     x = vr - w;
9526                     moved = true;
9527                 }
9528                 if((y + h) > vb){
9529                     y = vb - h;
9530                     moved = true;
9531                 }
9532                 // then make sure top/left isn't negative
9533                 if(x < vx){
9534                     x = vx;
9535                     moved = true;
9536                 }
9537                 if(y < vy){
9538                     y = vy;
9539                     moved = true;
9540                 }
9541                 return moved ? [x, y] : false;
9542             };
9543         }(),
9544
9545         // private
9546         adjustForConstraints : function(xy, parent, offsets){
9547             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
9548         },
9549
9550         /**
9551          * Aligns this element with another element relative to the specified anchor points. If the other element is the
9552          * document it aligns it to the viewport.
9553          * The position parameter is optional, and can be specified in any one of the following formats:
9554          * <ul>
9555          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9556          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9557          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
9558          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
9559          *   <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
9560          *       element's anchor point, and the second value is used as the target's anchor point.</li>
9561          * </ul>
9562          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
9563          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9564          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
9565          * that specified in order to enforce the viewport constraints.
9566          * Following are all of the supported anchor positions:
9567     <pre>
9568     Value  Description
9569     -----  -----------------------------
9570     tl     The top left corner (default)
9571     t      The center of the top edge
9572     tr     The top right corner
9573     l      The center of the left edge
9574     c      In the center of the element
9575     r      The center of the right edge
9576     bl     The bottom left corner
9577     b      The center of the bottom edge
9578     br     The bottom right corner
9579     </pre>
9580     Example Usage:
9581     <pre><code>
9582     // align el to other-el using the default positioning ("tl-bl", non-constrained)
9583     el.alignTo("other-el");
9584
9585     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9586     el.alignTo("other-el", "tr?");
9587
9588     // align the bottom right corner of el with the center left edge of other-el
9589     el.alignTo("other-el", "br-l?");
9590
9591     // align the center of el with the bottom left corner of other-el and
9592     // adjust the x position by -6 pixels (and the y position by 0)
9593     el.alignTo("other-el", "c-bl", [-6, 0]);
9594     </code></pre>
9595          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9596          * @param {String} position The position to align to.
9597          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9598          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9599          * @return {Roo.Element} this
9600          */
9601         alignTo : function(element, position, offsets, animate){
9602             var xy = this.getAlignToXY(element, position, offsets);
9603             this.setXY(xy, this.preanim(arguments, 3));
9604             return this;
9605         },
9606
9607         /**
9608          * Anchors an element to another element and realigns it when the window is resized.
9609          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9610          * @param {String} position The position to align to.
9611          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9612          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
9613          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
9614          * is a number, it is used as the buffer delay (defaults to 50ms).
9615          * @param {Function} callback The function to call after the animation finishes
9616          * @return {Roo.Element} this
9617          */
9618         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
9619             var action = function(){
9620                 this.alignTo(el, alignment, offsets, animate);
9621                 Roo.callback(callback, this);
9622             };
9623             Roo.EventManager.onWindowResize(action, this);
9624             var tm = typeof monitorScroll;
9625             if(tm != 'undefined'){
9626                 Roo.EventManager.on(window, 'scroll', action, this,
9627                     {buffer: tm == 'number' ? monitorScroll : 50});
9628             }
9629             action.call(this); // align immediately
9630             return this;
9631         },
9632         /**
9633          * Clears any opacity settings from this element. Required in some cases for IE.
9634          * @return {Roo.Element} this
9635          */
9636         clearOpacity : function(){
9637             if (window.ActiveXObject) {
9638                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
9639                     this.dom.style.filter = "";
9640                 }
9641             } else {
9642                 this.dom.style.opacity = "";
9643                 this.dom.style["-moz-opacity"] = "";
9644                 this.dom.style["-khtml-opacity"] = "";
9645             }
9646             return this;
9647         },
9648
9649         /**
9650          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9651          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9652          * @return {Roo.Element} this
9653          */
9654         hide : function(animate){
9655             this.setVisible(false, this.preanim(arguments, 0));
9656             return this;
9657         },
9658
9659         /**
9660         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9661         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9662          * @return {Roo.Element} this
9663          */
9664         show : function(animate){
9665             this.setVisible(true, this.preanim(arguments, 0));
9666             return this;
9667         },
9668
9669         /**
9670          * @private Test if size has a unit, otherwise appends the default
9671          */
9672         addUnits : function(size){
9673             return Roo.Element.addUnits(size, this.defaultUnit);
9674         },
9675
9676         /**
9677          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
9678          * @return {Roo.Element} this
9679          */
9680         beginMeasure : function(){
9681             var el = this.dom;
9682             if(el.offsetWidth || el.offsetHeight){
9683                 return this; // offsets work already
9684             }
9685             var changed = [];
9686             var p = this.dom, b = document.body; // start with this element
9687             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
9688                 var pe = Roo.get(p);
9689                 if(pe.getStyle('display') == 'none'){
9690                     changed.push({el: p, visibility: pe.getStyle("visibility")});
9691                     p.style.visibility = "hidden";
9692                     p.style.display = "block";
9693                 }
9694                 p = p.parentNode;
9695             }
9696             this._measureChanged = changed;
9697             return this;
9698
9699         },
9700
9701         /**
9702          * Restores displays to before beginMeasure was called
9703          * @return {Roo.Element} this
9704          */
9705         endMeasure : function(){
9706             var changed = this._measureChanged;
9707             if(changed){
9708                 for(var i = 0, len = changed.length; i < len; i++) {
9709                     var r = changed[i];
9710                     r.el.style.visibility = r.visibility;
9711                     r.el.style.display = "none";
9712                 }
9713                 this._measureChanged = null;
9714             }
9715             return this;
9716         },
9717
9718         /**
9719         * Update the innerHTML of this element, optionally searching for and processing scripts
9720         * @param {String} html The new HTML
9721         * @param {Boolean} loadScripts (optional) true to look for and process scripts
9722         * @param {Function} callback For async script loading you can be noticed when the update completes
9723         * @return {Roo.Element} this
9724          */
9725         update : function(html, loadScripts, callback){
9726             if(typeof html == "undefined"){
9727                 html = "";
9728             }
9729             if(loadScripts !== true){
9730                 this.dom.innerHTML = html;
9731                 if(typeof callback == "function"){
9732                     callback();
9733                 }
9734                 return this;
9735             }
9736             var id = Roo.id();
9737             var dom = this.dom;
9738
9739             html += '<span id="' + id + '"></span>';
9740
9741             E.onAvailable(id, function(){
9742                 var hd = document.getElementsByTagName("head")[0];
9743                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9744                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9745                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9746
9747                 var match;
9748                 while(match = re.exec(html)){
9749                     var attrs = match[1];
9750                     var srcMatch = attrs ? attrs.match(srcRe) : false;
9751                     if(srcMatch && srcMatch[2]){
9752                        var s = document.createElement("script");
9753                        s.src = srcMatch[2];
9754                        var typeMatch = attrs.match(typeRe);
9755                        if(typeMatch && typeMatch[2]){
9756                            s.type = typeMatch[2];
9757                        }
9758                        hd.appendChild(s);
9759                     }else if(match[2] && match[2].length > 0){
9760                         if(window.execScript) {
9761                            window.execScript(match[2]);
9762                         } else {
9763                             /**
9764                              * eval:var:id
9765                              * eval:var:dom
9766                              * eval:var:html
9767                              * 
9768                              */
9769                            window.eval(match[2]);
9770                         }
9771                     }
9772                 }
9773                 var el = document.getElementById(id);
9774                 if(el){el.parentNode.removeChild(el);}
9775                 if(typeof callback == "function"){
9776                     callback();
9777                 }
9778             });
9779             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9780             return this;
9781         },
9782
9783         /**
9784          * Direct access to the UpdateManager update() method (takes the same parameters).
9785          * @param {String/Function} url The url for this request or a function to call to get the url
9786          * @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}
9787          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9788          * @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.
9789          * @return {Roo.Element} this
9790          */
9791         load : function(){
9792             var um = this.getUpdateManager();
9793             um.update.apply(um, arguments);
9794             return this;
9795         },
9796
9797         /**
9798         * Gets this element's UpdateManager
9799         * @return {Roo.UpdateManager} The UpdateManager
9800         */
9801         getUpdateManager : function(){
9802             if(!this.updateManager){
9803                 this.updateManager = new Roo.UpdateManager(this);
9804             }
9805             return this.updateManager;
9806         },
9807
9808         /**
9809          * Disables text selection for this element (normalized across browsers)
9810          * @return {Roo.Element} this
9811          */
9812         unselectable : function(){
9813             this.dom.unselectable = "on";
9814             this.swallowEvent("selectstart", true);
9815             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9816             this.addClass("x-unselectable");
9817             return this;
9818         },
9819
9820         /**
9821         * Calculates the x, y to center this element on the screen
9822         * @return {Array} The x, y values [x, y]
9823         */
9824         getCenterXY : function(){
9825             return this.getAlignToXY(document, 'c-c');
9826         },
9827
9828         /**
9829         * Centers the Element in either the viewport, or another Element.
9830         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9831         */
9832         center : function(centerIn){
9833             this.alignTo(centerIn || document, 'c-c');
9834             return this;
9835         },
9836
9837         /**
9838          * Tests various css rules/browsers to determine if this element uses a border box
9839          * @return {Boolean}
9840          */
9841         isBorderBox : function(){
9842             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9843         },
9844
9845         /**
9846          * Return a box {x, y, width, height} that can be used to set another elements
9847          * size/location to match this element.
9848          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9849          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9850          * @return {Object} box An object in the format {x, y, width, height}
9851          */
9852         getBox : function(contentBox, local){
9853             var xy;
9854             if(!local){
9855                 xy = this.getXY();
9856             }else{
9857                 var left = parseInt(this.getStyle("left"), 10) || 0;
9858                 var top = parseInt(this.getStyle("top"), 10) || 0;
9859                 xy = [left, top];
9860             }
9861             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9862             if(!contentBox){
9863                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9864             }else{
9865                 var l = this.getBorderWidth("l")+this.getPadding("l");
9866                 var r = this.getBorderWidth("r")+this.getPadding("r");
9867                 var t = this.getBorderWidth("t")+this.getPadding("t");
9868                 var b = this.getBorderWidth("b")+this.getPadding("b");
9869                 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)};
9870             }
9871             bx.right = bx.x + bx.width;
9872             bx.bottom = bx.y + bx.height;
9873             return bx;
9874         },
9875
9876         /**
9877          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9878          for more information about the sides.
9879          * @param {String} sides
9880          * @return {Number}
9881          */
9882         getFrameWidth : function(sides, onlyContentBox){
9883             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9884         },
9885
9886         /**
9887          * 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.
9888          * @param {Object} box The box to fill {x, y, width, height}
9889          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9890          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9891          * @return {Roo.Element} this
9892          */
9893         setBox : function(box, adjust, animate){
9894             var w = box.width, h = box.height;
9895             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9896                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9897                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9898             }
9899             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9900             return this;
9901         },
9902
9903         /**
9904          * Forces the browser to repaint this element
9905          * @return {Roo.Element} this
9906          */
9907          repaint : function(){
9908             var dom = this.dom;
9909             this.addClass("x-repaint");
9910             setTimeout(function(){
9911                 Roo.get(dom).removeClass("x-repaint");
9912             }, 1);
9913             return this;
9914         },
9915
9916         /**
9917          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9918          * then it returns the calculated width of the sides (see getPadding)
9919          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9920          * @return {Object/Number}
9921          */
9922         getMargins : function(side){
9923             if(!side){
9924                 return {
9925                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9926                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9927                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9928                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9929                 };
9930             }else{
9931                 return this.addStyles(side, El.margins);
9932              }
9933         },
9934
9935         // private
9936         addStyles : function(sides, styles){
9937             var val = 0, v, w;
9938             for(var i = 0, len = sides.length; i < len; i++){
9939                 v = this.getStyle(styles[sides.charAt(i)]);
9940                 if(v){
9941                      w = parseInt(v, 10);
9942                      if(w){ val += w; }
9943                 }
9944             }
9945             return val;
9946         },
9947
9948         /**
9949          * Creates a proxy element of this element
9950          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9951          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9952          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9953          * @return {Roo.Element} The new proxy element
9954          */
9955         createProxy : function(config, renderTo, matchBox){
9956             if(renderTo){
9957                 renderTo = Roo.getDom(renderTo);
9958             }else{
9959                 renderTo = document.body;
9960             }
9961             config = typeof config == "object" ?
9962                 config : {tag : "div", cls: config};
9963             var proxy = Roo.DomHelper.append(renderTo, config, true);
9964             if(matchBox){
9965                proxy.setBox(this.getBox());
9966             }
9967             return proxy;
9968         },
9969
9970         /**
9971          * Puts a mask over this element to disable user interaction. Requires core.css.
9972          * This method can only be applied to elements which accept child nodes.
9973          * @param {String} msg (optional) A message to display in the mask
9974          * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
9975          * @return {Element} The mask  element
9976          */
9977         mask : function(msg, msgCls)
9978         {
9979             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9980                 this.setStyle("position", "relative");
9981             }
9982             if(!this._mask){
9983                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9984             }
9985             
9986             this.addClass("x-masked");
9987             this._mask.setDisplayed(true);
9988             
9989             // we wander
9990             var z = 0;
9991             var dom = this.dom;
9992             while (dom && dom.style) {
9993                 if (!isNaN(parseInt(dom.style.zIndex))) {
9994                     z = Math.max(z, parseInt(dom.style.zIndex));
9995                 }
9996                 dom = dom.parentNode;
9997             }
9998             // if we are masking the body - then it hides everything..
9999             if (this.dom == document.body) {
10000                 z = 1000000;
10001                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10002                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10003             }
10004            
10005             if(typeof msg == 'string'){
10006                 if(!this._maskMsg){
10007                     this._maskMsg = Roo.DomHelper.append(this.dom, {
10008                         cls: "roo-el-mask-msg", 
10009                         cn: [
10010                             {
10011                                 tag: 'i',
10012                                 cls: 'fa fa-spinner fa-spin'
10013                             },
10014                             {
10015                                 tag: 'div'
10016                             }   
10017                         ]
10018                     }, true);
10019                 }
10020                 var mm = this._maskMsg;
10021                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10022                 if (mm.dom.lastChild) { // weird IE issue?
10023                     mm.dom.lastChild.innerHTML = msg;
10024                 }
10025                 mm.setDisplayed(true);
10026                 mm.center(this);
10027                 mm.setStyle('z-index', z + 102);
10028             }
10029             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10030                 this._mask.setHeight(this.getHeight());
10031             }
10032             this._mask.setStyle('z-index', z + 100);
10033             
10034             return this._mask;
10035         },
10036
10037         /**
10038          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10039          * it is cached for reuse.
10040          */
10041         unmask : function(removeEl){
10042             if(this._mask){
10043                 if(removeEl === true){
10044                     this._mask.remove();
10045                     delete this._mask;
10046                     if(this._maskMsg){
10047                         this._maskMsg.remove();
10048                         delete this._maskMsg;
10049                     }
10050                 }else{
10051                     this._mask.setDisplayed(false);
10052                     if(this._maskMsg){
10053                         this._maskMsg.setDisplayed(false);
10054                     }
10055                 }
10056             }
10057             this.removeClass("x-masked");
10058         },
10059
10060         /**
10061          * Returns true if this element is masked
10062          * @return {Boolean}
10063          */
10064         isMasked : function(){
10065             return this._mask && this._mask.isVisible();
10066         },
10067
10068         /**
10069          * Creates an iframe shim for this element to keep selects and other windowed objects from
10070          * showing through.
10071          * @return {Roo.Element} The new shim element
10072          */
10073         createShim : function(){
10074             var el = document.createElement('iframe');
10075             el.frameBorder = 'no';
10076             el.className = 'roo-shim';
10077             if(Roo.isIE && Roo.isSecure){
10078                 el.src = Roo.SSL_SECURE_URL;
10079             }
10080             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10081             shim.autoBoxAdjust = false;
10082             return shim;
10083         },
10084
10085         /**
10086          * Removes this element from the DOM and deletes it from the cache
10087          */
10088         remove : function(){
10089             if(this.dom.parentNode){
10090                 this.dom.parentNode.removeChild(this.dom);
10091             }
10092             delete El.cache[this.dom.id];
10093         },
10094
10095         /**
10096          * Sets up event handlers to add and remove a css class when the mouse is over this element
10097          * @param {String} className
10098          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10099          * mouseout events for children elements
10100          * @return {Roo.Element} this
10101          */
10102         addClassOnOver : function(className, preventFlicker){
10103             this.on("mouseover", function(){
10104                 Roo.fly(this, '_internal').addClass(className);
10105             }, this.dom);
10106             var removeFn = function(e){
10107                 if(preventFlicker !== true || !e.within(this, true)){
10108                     Roo.fly(this, '_internal').removeClass(className);
10109                 }
10110             };
10111             this.on("mouseout", removeFn, this.dom);
10112             return this;
10113         },
10114
10115         /**
10116          * Sets up event handlers to add and remove a css class when this element has the focus
10117          * @param {String} className
10118          * @return {Roo.Element} this
10119          */
10120         addClassOnFocus : function(className){
10121             this.on("focus", function(){
10122                 Roo.fly(this, '_internal').addClass(className);
10123             }, this.dom);
10124             this.on("blur", function(){
10125                 Roo.fly(this, '_internal').removeClass(className);
10126             }, this.dom);
10127             return this;
10128         },
10129         /**
10130          * 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)
10131          * @param {String} className
10132          * @return {Roo.Element} this
10133          */
10134         addClassOnClick : function(className){
10135             var dom = this.dom;
10136             this.on("mousedown", function(){
10137                 Roo.fly(dom, '_internal').addClass(className);
10138                 var d = Roo.get(document);
10139                 var fn = function(){
10140                     Roo.fly(dom, '_internal').removeClass(className);
10141                     d.removeListener("mouseup", fn);
10142                 };
10143                 d.on("mouseup", fn);
10144             });
10145             return this;
10146         },
10147
10148         /**
10149          * Stops the specified event from bubbling and optionally prevents the default action
10150          * @param {String} eventName
10151          * @param {Boolean} preventDefault (optional) true to prevent the default action too
10152          * @return {Roo.Element} this
10153          */
10154         swallowEvent : function(eventName, preventDefault){
10155             var fn = function(e){
10156                 e.stopPropagation();
10157                 if(preventDefault){
10158                     e.preventDefault();
10159                 }
10160             };
10161             if(eventName instanceof Array){
10162                 for(var i = 0, len = eventName.length; i < len; i++){
10163                      this.on(eventName[i], fn);
10164                 }
10165                 return this;
10166             }
10167             this.on(eventName, fn);
10168             return this;
10169         },
10170
10171         /**
10172          * @private
10173          */
10174         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10175
10176         /**
10177          * Sizes this element to its parent element's dimensions performing
10178          * neccessary box adjustments.
10179          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10180          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10181          * @return {Roo.Element} this
10182          */
10183         fitToParent : function(monitorResize, targetParent) {
10184           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10185           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10186           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10187             return this;
10188           }
10189           var p = Roo.get(targetParent || this.dom.parentNode);
10190           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10191           if (monitorResize === true) {
10192             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10193             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10194           }
10195           return this;
10196         },
10197
10198         /**
10199          * Gets the next sibling, skipping text nodes
10200          * @return {HTMLElement} The next sibling or null
10201          */
10202         getNextSibling : function(){
10203             var n = this.dom.nextSibling;
10204             while(n && n.nodeType != 1){
10205                 n = n.nextSibling;
10206             }
10207             return n;
10208         },
10209
10210         /**
10211          * Gets the previous sibling, skipping text nodes
10212          * @return {HTMLElement} The previous sibling or null
10213          */
10214         getPrevSibling : function(){
10215             var n = this.dom.previousSibling;
10216             while(n && n.nodeType != 1){
10217                 n = n.previousSibling;
10218             }
10219             return n;
10220         },
10221
10222
10223         /**
10224          * Appends the passed element(s) to this element
10225          * @param {String/HTMLElement/Array/Element/CompositeElement} el
10226          * @return {Roo.Element} this
10227          */
10228         appendChild: function(el){
10229             el = Roo.get(el);
10230             el.appendTo(this);
10231             return this;
10232         },
10233
10234         /**
10235          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10236          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
10237          * automatically generated with the specified attributes.
10238          * @param {HTMLElement} insertBefore (optional) a child element of this element
10239          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10240          * @return {Roo.Element} The new child element
10241          */
10242         createChild: function(config, insertBefore, returnDom){
10243             config = config || {tag:'div'};
10244             if(insertBefore){
10245                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10246             }
10247             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
10248         },
10249
10250         /**
10251          * Appends this element to the passed element
10252          * @param {String/HTMLElement/Element} el The new parent element
10253          * @return {Roo.Element} this
10254          */
10255         appendTo: function(el){
10256             el = Roo.getDom(el);
10257             el.appendChild(this.dom);
10258             return this;
10259         },
10260
10261         /**
10262          * Inserts this element before the passed element in the DOM
10263          * @param {String/HTMLElement/Element} el The element to insert before
10264          * @return {Roo.Element} this
10265          */
10266         insertBefore: function(el){
10267             el = Roo.getDom(el);
10268             el.parentNode.insertBefore(this.dom, el);
10269             return this;
10270         },
10271
10272         /**
10273          * Inserts this element after the passed element in the DOM
10274          * @param {String/HTMLElement/Element} el The element to insert after
10275          * @return {Roo.Element} this
10276          */
10277         insertAfter: function(el){
10278             el = Roo.getDom(el);
10279             el.parentNode.insertBefore(this.dom, el.nextSibling);
10280             return this;
10281         },
10282
10283         /**
10284          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10285          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10286          * @return {Roo.Element} The new child
10287          */
10288         insertFirst: function(el, returnDom){
10289             el = el || {};
10290             if(typeof el == 'object' && !el.nodeType){ // dh config
10291                 return this.createChild(el, this.dom.firstChild, returnDom);
10292             }else{
10293                 el = Roo.getDom(el);
10294                 this.dom.insertBefore(el, this.dom.firstChild);
10295                 return !returnDom ? Roo.get(el) : el;
10296             }
10297         },
10298
10299         /**
10300          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10301          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10302          * @param {String} where (optional) 'before' or 'after' defaults to before
10303          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10304          * @return {Roo.Element} the inserted Element
10305          */
10306         insertSibling: function(el, where, returnDom){
10307             where = where ? where.toLowerCase() : 'before';
10308             el = el || {};
10309             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10310
10311             if(typeof el == 'object' && !el.nodeType){ // dh config
10312                 if(where == 'after' && !this.dom.nextSibling){
10313                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10314                 }else{
10315                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10316                 }
10317
10318             }else{
10319                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10320                             where == 'before' ? this.dom : this.dom.nextSibling);
10321                 if(!returnDom){
10322                     rt = Roo.get(rt);
10323                 }
10324             }
10325             return rt;
10326         },
10327
10328         /**
10329          * Creates and wraps this element with another element
10330          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10331          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10332          * @return {HTMLElement/Element} The newly created wrapper element
10333          */
10334         wrap: function(config, returnDom){
10335             if(!config){
10336                 config = {tag: "div"};
10337             }
10338             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10339             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10340             return newEl;
10341         },
10342
10343         /**
10344          * Replaces the passed element with this element
10345          * @param {String/HTMLElement/Element} el The element to replace
10346          * @return {Roo.Element} this
10347          */
10348         replace: function(el){
10349             el = Roo.get(el);
10350             this.insertBefore(el);
10351             el.remove();
10352             return this;
10353         },
10354
10355         /**
10356          * Inserts an html fragment into this element
10357          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10358          * @param {String} html The HTML fragment
10359          * @param {Boolean} returnEl True to return an Roo.Element
10360          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10361          */
10362         insertHtml : function(where, html, returnEl){
10363             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10364             return returnEl ? Roo.get(el) : el;
10365         },
10366
10367         /**
10368          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10369          * @param {Object} o The object with the attributes
10370          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10371          * @return {Roo.Element} this
10372          */
10373         set : function(o, useSet){
10374             var el = this.dom;
10375             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10376             for(var attr in o){
10377                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
10378                 if(attr=="cls"){
10379                     el.className = o["cls"];
10380                 }else{
10381                     if(useSet) {
10382                         el.setAttribute(attr, o[attr]);
10383                     } else {
10384                         el[attr] = o[attr];
10385                     }
10386                 }
10387             }
10388             if(o.style){
10389                 Roo.DomHelper.applyStyles(el, o.style);
10390             }
10391             return this;
10392         },
10393
10394         /**
10395          * Convenience method for constructing a KeyMap
10396          * @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:
10397          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10398          * @param {Function} fn The function to call
10399          * @param {Object} scope (optional) The scope of the function
10400          * @return {Roo.KeyMap} The KeyMap created
10401          */
10402         addKeyListener : function(key, fn, scope){
10403             var config;
10404             if(typeof key != "object" || key instanceof Array){
10405                 config = {
10406                     key: key,
10407                     fn: fn,
10408                     scope: scope
10409                 };
10410             }else{
10411                 config = {
10412                     key : key.key,
10413                     shift : key.shift,
10414                     ctrl : key.ctrl,
10415                     alt : key.alt,
10416                     fn: fn,
10417                     scope: scope
10418                 };
10419             }
10420             return new Roo.KeyMap(this, config);
10421         },
10422
10423         /**
10424          * Creates a KeyMap for this element
10425          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10426          * @return {Roo.KeyMap} The KeyMap created
10427          */
10428         addKeyMap : function(config){
10429             return new Roo.KeyMap(this, config);
10430         },
10431
10432         /**
10433          * Returns true if this element is scrollable.
10434          * @return {Boolean}
10435          */
10436          isScrollable : function(){
10437             var dom = this.dom;
10438             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10439         },
10440
10441         /**
10442          * 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().
10443          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10444          * @param {Number} value The new scroll value
10445          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10446          * @return {Element} this
10447          */
10448
10449         scrollTo : function(side, value, animate){
10450             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10451             if(!animate || !A){
10452                 this.dom[prop] = value;
10453             }else{
10454                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10455                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10456             }
10457             return this;
10458         },
10459
10460         /**
10461          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10462          * within this element's scrollable range.
10463          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10464          * @param {Number} distance How far to scroll the element in pixels
10465          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10466          * @return {Boolean} Returns true if a scroll was triggered or false if the element
10467          * was scrolled as far as it could go.
10468          */
10469          scroll : function(direction, distance, animate){
10470              if(!this.isScrollable()){
10471                  return;
10472              }
10473              var el = this.dom;
10474              var l = el.scrollLeft, t = el.scrollTop;
10475              var w = el.scrollWidth, h = el.scrollHeight;
10476              var cw = el.clientWidth, ch = el.clientHeight;
10477              direction = direction.toLowerCase();
10478              var scrolled = false;
10479              var a = this.preanim(arguments, 2);
10480              switch(direction){
10481                  case "l":
10482                  case "left":
10483                      if(w - l > cw){
10484                          var v = Math.min(l + distance, w-cw);
10485                          this.scrollTo("left", v, a);
10486                          scrolled = true;
10487                      }
10488                      break;
10489                 case "r":
10490                 case "right":
10491                      if(l > 0){
10492                          var v = Math.max(l - distance, 0);
10493                          this.scrollTo("left", v, a);
10494                          scrolled = true;
10495                      }
10496                      break;
10497                 case "t":
10498                 case "top":
10499                 case "up":
10500                      if(t > 0){
10501                          var v = Math.max(t - distance, 0);
10502                          this.scrollTo("top", v, a);
10503                          scrolled = true;
10504                      }
10505                      break;
10506                 case "b":
10507                 case "bottom":
10508                 case "down":
10509                      if(h - t > ch){
10510                          var v = Math.min(t + distance, h-ch);
10511                          this.scrollTo("top", v, a);
10512                          scrolled = true;
10513                      }
10514                      break;
10515              }
10516              return scrolled;
10517         },
10518
10519         /**
10520          * Translates the passed page coordinates into left/top css values for this element
10521          * @param {Number/Array} x The page x or an array containing [x, y]
10522          * @param {Number} y The page y
10523          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10524          */
10525         translatePoints : function(x, y){
10526             if(typeof x == 'object' || x instanceof Array){
10527                 y = x[1]; x = x[0];
10528             }
10529             var p = this.getStyle('position');
10530             var o = this.getXY();
10531
10532             var l = parseInt(this.getStyle('left'), 10);
10533             var t = parseInt(this.getStyle('top'), 10);
10534
10535             if(isNaN(l)){
10536                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10537             }
10538             if(isNaN(t)){
10539                 t = (p == "relative") ? 0 : this.dom.offsetTop;
10540             }
10541
10542             return {left: (x - o[0] + l), top: (y - o[1] + t)};
10543         },
10544
10545         /**
10546          * Returns the current scroll position of the element.
10547          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10548          */
10549         getScroll : function(){
10550             var d = this.dom, doc = document;
10551             if(d == doc || d == doc.body){
10552                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10553                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10554                 return {left: l, top: t};
10555             }else{
10556                 return {left: d.scrollLeft, top: d.scrollTop};
10557             }
10558         },
10559
10560         /**
10561          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10562          * are convert to standard 6 digit hex color.
10563          * @param {String} attr The css attribute
10564          * @param {String} defaultValue The default value to use when a valid color isn't found
10565          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10566          * YUI color anims.
10567          */
10568         getColor : function(attr, defaultValue, prefix){
10569             var v = this.getStyle(attr);
10570             if(!v || v == "transparent" || v == "inherit") {
10571                 return defaultValue;
10572             }
10573             var color = typeof prefix == "undefined" ? "#" : prefix;
10574             if(v.substr(0, 4) == "rgb("){
10575                 var rvs = v.slice(4, v.length -1).split(",");
10576                 for(var i = 0; i < 3; i++){
10577                     var h = parseInt(rvs[i]).toString(16);
10578                     if(h < 16){
10579                         h = "0" + h;
10580                     }
10581                     color += h;
10582                 }
10583             } else {
10584                 if(v.substr(0, 1) == "#"){
10585                     if(v.length == 4) {
10586                         for(var i = 1; i < 4; i++){
10587                             var c = v.charAt(i);
10588                             color +=  c + c;
10589                         }
10590                     }else if(v.length == 7){
10591                         color += v.substr(1);
10592                     }
10593                 }
10594             }
10595             return(color.length > 5 ? color.toLowerCase() : defaultValue);
10596         },
10597
10598         /**
10599          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
10600          * gradient background, rounded corners and a 4-way shadow.
10601          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
10602          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
10603          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
10604          * @return {Roo.Element} this
10605          */
10606         boxWrap : function(cls){
10607             cls = cls || 'x-box';
10608             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
10609             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
10610             return el;
10611         },
10612
10613         /**
10614          * Returns the value of a namespaced attribute from the element's underlying DOM node.
10615          * @param {String} namespace The namespace in which to look for the attribute
10616          * @param {String} name The attribute name
10617          * @return {String} The attribute value
10618          */
10619         getAttributeNS : Roo.isIE ? function(ns, name){
10620             var d = this.dom;
10621             var type = typeof d[ns+":"+name];
10622             if(type != 'undefined' && type != 'unknown'){
10623                 return d[ns+":"+name];
10624             }
10625             return d[name];
10626         } : function(ns, name){
10627             var d = this.dom;
10628             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
10629         },
10630         
10631         
10632         /**
10633          * Sets or Returns the value the dom attribute value
10634          * @param {String|Object} name The attribute name (or object to set multiple attributes)
10635          * @param {String} value (optional) The value to set the attribute to
10636          * @return {String} The attribute value
10637          */
10638         attr : function(name){
10639             if (arguments.length > 1) {
10640                 this.dom.setAttribute(name, arguments[1]);
10641                 return arguments[1];
10642             }
10643             if (typeof(name) == 'object') {
10644                 for(var i in name) {
10645                     this.attr(i, name[i]);
10646                 }
10647                 return name;
10648             }
10649             
10650             
10651             if (!this.dom.hasAttribute(name)) {
10652                 return undefined;
10653             }
10654             return this.dom.getAttribute(name);
10655         }
10656         
10657         
10658         
10659     };
10660
10661     var ep = El.prototype;
10662
10663     /**
10664      * Appends an event handler (Shorthand for addListener)
10665      * @param {String}   eventName     The type of event to append
10666      * @param {Function} fn        The method the event invokes
10667      * @param {Object} scope       (optional) The scope (this object) of the fn
10668      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
10669      * @method
10670      */
10671     ep.on = ep.addListener;
10672         // backwards compat
10673     ep.mon = ep.addListener;
10674
10675     /**
10676      * Removes an event handler from this element (shorthand for removeListener)
10677      * @param {String} eventName the type of event to remove
10678      * @param {Function} fn the method the event invokes
10679      * @return {Roo.Element} this
10680      * @method
10681      */
10682     ep.un = ep.removeListener;
10683
10684     /**
10685      * true to automatically adjust width and height settings for box-model issues (default to true)
10686      */
10687     ep.autoBoxAdjust = true;
10688
10689     // private
10690     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
10691
10692     // private
10693     El.addUnits = function(v, defaultUnit){
10694         if(v === "" || v == "auto"){
10695             return v;
10696         }
10697         if(v === undefined){
10698             return '';
10699         }
10700         if(typeof v == "number" || !El.unitPattern.test(v)){
10701             return v + (defaultUnit || 'px');
10702         }
10703         return v;
10704     };
10705
10706     // special markup used throughout Roo when box wrapping elements
10707     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>';
10708     /**
10709      * Visibility mode constant - Use visibility to hide element
10710      * @static
10711      * @type Number
10712      */
10713     El.VISIBILITY = 1;
10714     /**
10715      * Visibility mode constant - Use display to hide element
10716      * @static
10717      * @type Number
10718      */
10719     El.DISPLAY = 2;
10720
10721     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10722     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10723     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10724
10725
10726
10727     /**
10728      * @private
10729      */
10730     El.cache = {};
10731
10732     var docEl;
10733
10734     /**
10735      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10736      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10737      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10738      * @return {Element} The Element object
10739      * @static
10740      */
10741     El.get = function(el){
10742         var ex, elm, id;
10743         if(!el){ return null; }
10744         if(typeof el == "string"){ // element id
10745             if(!(elm = document.getElementById(el))){
10746                 return null;
10747             }
10748             if(ex = El.cache[el]){
10749                 ex.dom = elm;
10750             }else{
10751                 ex = El.cache[el] = new El(elm);
10752             }
10753             return ex;
10754         }else if(el.tagName){ // dom element
10755             if(!(id = el.id)){
10756                 id = Roo.id(el);
10757             }
10758             if(ex = El.cache[id]){
10759                 ex.dom = el;
10760             }else{
10761                 ex = El.cache[id] = new El(el);
10762             }
10763             return ex;
10764         }else if(el instanceof El){
10765             if(el != docEl){
10766                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10767                                                               // catch case where it hasn't been appended
10768                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10769             }
10770             return el;
10771         }else if(el.isComposite){
10772             return el;
10773         }else if(el instanceof Array){
10774             return El.select(el);
10775         }else if(el == document){
10776             // create a bogus element object representing the document object
10777             if(!docEl){
10778                 var f = function(){};
10779                 f.prototype = El.prototype;
10780                 docEl = new f();
10781                 docEl.dom = document;
10782             }
10783             return docEl;
10784         }
10785         return null;
10786     };
10787
10788     // private
10789     El.uncache = function(el){
10790         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10791             if(a[i]){
10792                 delete El.cache[a[i].id || a[i]];
10793             }
10794         }
10795     };
10796
10797     // private
10798     // Garbage collection - uncache elements/purge listeners on orphaned elements
10799     // so we don't hold a reference and cause the browser to retain them
10800     El.garbageCollect = function(){
10801         if(!Roo.enableGarbageCollector){
10802             clearInterval(El.collectorThread);
10803             return;
10804         }
10805         for(var eid in El.cache){
10806             var el = El.cache[eid], d = el.dom;
10807             // -------------------------------------------------------
10808             // Determining what is garbage:
10809             // -------------------------------------------------------
10810             // !d
10811             // dom node is null, definitely garbage
10812             // -------------------------------------------------------
10813             // !d.parentNode
10814             // no parentNode == direct orphan, definitely garbage
10815             // -------------------------------------------------------
10816             // !d.offsetParent && !document.getElementById(eid)
10817             // display none elements have no offsetParent so we will
10818             // also try to look it up by it's id. However, check
10819             // offsetParent first so we don't do unneeded lookups.
10820             // This enables collection of elements that are not orphans
10821             // directly, but somewhere up the line they have an orphan
10822             // parent.
10823             // -------------------------------------------------------
10824             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10825                 delete El.cache[eid];
10826                 if(d && Roo.enableListenerCollection){
10827                     E.purgeElement(d);
10828                 }
10829             }
10830         }
10831     }
10832     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10833
10834
10835     // dom is optional
10836     El.Flyweight = function(dom){
10837         this.dom = dom;
10838     };
10839     El.Flyweight.prototype = El.prototype;
10840
10841     El._flyweights = {};
10842     /**
10843      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10844      * the dom node can be overwritten by other code.
10845      * @param {String/HTMLElement} el The dom node or id
10846      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10847      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10848      * @static
10849      * @return {Element} The shared Element object
10850      */
10851     El.fly = function(el, named){
10852         named = named || '_global';
10853         el = Roo.getDom(el);
10854         if(!el){
10855             return null;
10856         }
10857         if(!El._flyweights[named]){
10858             El._flyweights[named] = new El.Flyweight();
10859         }
10860         El._flyweights[named].dom = el;
10861         return El._flyweights[named];
10862     };
10863
10864     /**
10865      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10866      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10867      * Shorthand of {@link Roo.Element#get}
10868      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10869      * @return {Element} The Element object
10870      * @member Roo
10871      * @method get
10872      */
10873     Roo.get = El.get;
10874     /**
10875      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10876      * the dom node can be overwritten by other code.
10877      * Shorthand of {@link Roo.Element#fly}
10878      * @param {String/HTMLElement} el The dom node or id
10879      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10880      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10881      * @static
10882      * @return {Element} The shared Element object
10883      * @member Roo
10884      * @method fly
10885      */
10886     Roo.fly = El.fly;
10887
10888     // speedy lookup for elements never to box adjust
10889     var noBoxAdjust = Roo.isStrict ? {
10890         select:1
10891     } : {
10892         input:1, select:1, textarea:1
10893     };
10894     if(Roo.isIE || Roo.isGecko){
10895         noBoxAdjust['button'] = 1;
10896     }
10897
10898
10899     Roo.EventManager.on(window, 'unload', function(){
10900         delete El.cache;
10901         delete El._flyweights;
10902     });
10903 })();
10904
10905
10906
10907
10908 if(Roo.DomQuery){
10909     Roo.Element.selectorFunction = Roo.DomQuery.select;
10910 }
10911
10912 Roo.Element.select = function(selector, unique, root){
10913     var els;
10914     if(typeof selector == "string"){
10915         els = Roo.Element.selectorFunction(selector, root);
10916     }else if(selector.length !== undefined){
10917         els = selector;
10918     }else{
10919         throw "Invalid selector";
10920     }
10921     if(unique === true){
10922         return new Roo.CompositeElement(els);
10923     }else{
10924         return new Roo.CompositeElementLite(els);
10925     }
10926 };
10927 /**
10928  * Selects elements based on the passed CSS selector to enable working on them as 1.
10929  * @param {String/Array} selector The CSS selector or an array of elements
10930  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10931  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10932  * @return {CompositeElementLite/CompositeElement}
10933  * @member Roo
10934  * @method select
10935  */
10936 Roo.select = Roo.Element.select;
10937
10938
10939
10940
10941
10942
10943
10944
10945
10946
10947
10948
10949
10950
10951 /*
10952  * Based on:
10953  * Ext JS Library 1.1.1
10954  * Copyright(c) 2006-2007, Ext JS, LLC.
10955  *
10956  * Originally Released Under LGPL - original licence link has changed is not relivant.
10957  *
10958  * Fork - LGPL
10959  * <script type="text/javascript">
10960  */
10961
10962
10963
10964 //Notifies Element that fx methods are available
10965 Roo.enableFx = true;
10966
10967 /**
10968  * @class Roo.Fx
10969  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10970  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10971  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10972  * Element effects to work.</p><br/>
10973  *
10974  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10975  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10976  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10977  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10978  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10979  * expected results and should be done with care.</p><br/>
10980  *
10981  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10982  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10983 <pre>
10984 Value  Description
10985 -----  -----------------------------
10986 tl     The top left corner
10987 t      The center of the top edge
10988 tr     The top right corner
10989 l      The center of the left edge
10990 r      The center of the right edge
10991 bl     The bottom left corner
10992 b      The center of the bottom edge
10993 br     The bottom right corner
10994 </pre>
10995  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10996  * below are common options that can be passed to any Fx method.</b>
10997  * @cfg {Function} callback A function called when the effect is finished
10998  * @cfg {Object} scope The scope of the effect function
10999  * @cfg {String} easing A valid Easing value for the effect
11000  * @cfg {String} afterCls A css class to apply after the effect
11001  * @cfg {Number} duration The length of time (in seconds) that the effect should last
11002  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11003  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
11004  * effects that end with the element being visually hidden, ignored otherwise)
11005  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11006  * a function which returns such a specification that will be applied to the Element after the effect finishes
11007  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11008  * @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
11009  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11010  */
11011 Roo.Fx = {
11012         /**
11013          * Slides the element into view.  An anchor point can be optionally passed to set the point of
11014          * origin for the slide effect.  This function automatically handles wrapping the element with
11015          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11016          * Usage:
11017          *<pre><code>
11018 // default: slide the element in from the top
11019 el.slideIn();
11020
11021 // custom: slide the element in from the right with a 2-second duration
11022 el.slideIn('r', { duration: 2 });
11023
11024 // common config options shown with default values
11025 el.slideIn('t', {
11026     easing: 'easeOut',
11027     duration: .5
11028 });
11029 </code></pre>
11030          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11031          * @param {Object} options (optional) Object literal with any of the Fx config options
11032          * @return {Roo.Element} The Element
11033          */
11034     slideIn : function(anchor, o){
11035         var el = this.getFxEl();
11036         o = o || {};
11037
11038         el.queueFx(o, function(){
11039
11040             anchor = anchor || "t";
11041
11042             // fix display to visibility
11043             this.fixDisplay();
11044
11045             // restore values after effect
11046             var r = this.getFxRestore();
11047             var b = this.getBox();
11048             // fixed size for slide
11049             this.setSize(b);
11050
11051             // wrap if needed
11052             var wrap = this.fxWrap(r.pos, o, "hidden");
11053
11054             var st = this.dom.style;
11055             st.visibility = "visible";
11056             st.position = "absolute";
11057
11058             // clear out temp styles after slide and unwrap
11059             var after = function(){
11060                 el.fxUnwrap(wrap, r.pos, o);
11061                 st.width = r.width;
11062                 st.height = r.height;
11063                 el.afterFx(o);
11064             };
11065             // time to calc the positions
11066             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11067
11068             switch(anchor.toLowerCase()){
11069                 case "t":
11070                     wrap.setSize(b.width, 0);
11071                     st.left = st.bottom = "0";
11072                     a = {height: bh};
11073                 break;
11074                 case "l":
11075                     wrap.setSize(0, b.height);
11076                     st.right = st.top = "0";
11077                     a = {width: bw};
11078                 break;
11079                 case "r":
11080                     wrap.setSize(0, b.height);
11081                     wrap.setX(b.right);
11082                     st.left = st.top = "0";
11083                     a = {width: bw, points: pt};
11084                 break;
11085                 case "b":
11086                     wrap.setSize(b.width, 0);
11087                     wrap.setY(b.bottom);
11088                     st.left = st.top = "0";
11089                     a = {height: bh, points: pt};
11090                 break;
11091                 case "tl":
11092                     wrap.setSize(0, 0);
11093                     st.right = st.bottom = "0";
11094                     a = {width: bw, height: bh};
11095                 break;
11096                 case "bl":
11097                     wrap.setSize(0, 0);
11098                     wrap.setY(b.y+b.height);
11099                     st.right = st.top = "0";
11100                     a = {width: bw, height: bh, points: pt};
11101                 break;
11102                 case "br":
11103                     wrap.setSize(0, 0);
11104                     wrap.setXY([b.right, b.bottom]);
11105                     st.left = st.top = "0";
11106                     a = {width: bw, height: bh, points: pt};
11107                 break;
11108                 case "tr":
11109                     wrap.setSize(0, 0);
11110                     wrap.setX(b.x+b.width);
11111                     st.left = st.bottom = "0";
11112                     a = {width: bw, height: bh, points: pt};
11113                 break;
11114             }
11115             this.dom.style.visibility = "visible";
11116             wrap.show();
11117
11118             arguments.callee.anim = wrap.fxanim(a,
11119                 o,
11120                 'motion',
11121                 .5,
11122                 'easeOut', after);
11123         });
11124         return this;
11125     },
11126     
11127         /**
11128          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
11129          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
11130          * 'hidden') but block elements will still take up space in the document.  The element must be removed
11131          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
11132          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11133          * Usage:
11134          *<pre><code>
11135 // default: slide the element out to the top
11136 el.slideOut();
11137
11138 // custom: slide the element out to the right with a 2-second duration
11139 el.slideOut('r', { duration: 2 });
11140
11141 // common config options shown with default values
11142 el.slideOut('t', {
11143     easing: 'easeOut',
11144     duration: .5,
11145     remove: false,
11146     useDisplay: false
11147 });
11148 </code></pre>
11149          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11150          * @param {Object} options (optional) Object literal with any of the Fx config options
11151          * @return {Roo.Element} The Element
11152          */
11153     slideOut : function(anchor, o){
11154         var el = this.getFxEl();
11155         o = o || {};
11156
11157         el.queueFx(o, function(){
11158
11159             anchor = anchor || "t";
11160
11161             // restore values after effect
11162             var r = this.getFxRestore();
11163             
11164             var b = this.getBox();
11165             // fixed size for slide
11166             this.setSize(b);
11167
11168             // wrap if needed
11169             var wrap = this.fxWrap(r.pos, o, "visible");
11170
11171             var st = this.dom.style;
11172             st.visibility = "visible";
11173             st.position = "absolute";
11174
11175             wrap.setSize(b);
11176
11177             var after = function(){
11178                 if(o.useDisplay){
11179                     el.setDisplayed(false);
11180                 }else{
11181                     el.hide();
11182                 }
11183
11184                 el.fxUnwrap(wrap, r.pos, o);
11185
11186                 st.width = r.width;
11187                 st.height = r.height;
11188
11189                 el.afterFx(o);
11190             };
11191
11192             var a, zero = {to: 0};
11193             switch(anchor.toLowerCase()){
11194                 case "t":
11195                     st.left = st.bottom = "0";
11196                     a = {height: zero};
11197                 break;
11198                 case "l":
11199                     st.right = st.top = "0";
11200                     a = {width: zero};
11201                 break;
11202                 case "r":
11203                     st.left = st.top = "0";
11204                     a = {width: zero, points: {to:[b.right, b.y]}};
11205                 break;
11206                 case "b":
11207                     st.left = st.top = "0";
11208                     a = {height: zero, points: {to:[b.x, b.bottom]}};
11209                 break;
11210                 case "tl":
11211                     st.right = st.bottom = "0";
11212                     a = {width: zero, height: zero};
11213                 break;
11214                 case "bl":
11215                     st.right = st.top = "0";
11216                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11217                 break;
11218                 case "br":
11219                     st.left = st.top = "0";
11220                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11221                 break;
11222                 case "tr":
11223                     st.left = st.bottom = "0";
11224                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11225                 break;
11226             }
11227
11228             arguments.callee.anim = wrap.fxanim(a,
11229                 o,
11230                 'motion',
11231                 .5,
11232                 "easeOut", after);
11233         });
11234         return this;
11235     },
11236
11237         /**
11238          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
11239          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
11240          * The element must be removed from the DOM using the 'remove' config option if desired.
11241          * Usage:
11242          *<pre><code>
11243 // default
11244 el.puff();
11245
11246 // common config options shown with default values
11247 el.puff({
11248     easing: 'easeOut',
11249     duration: .5,
11250     remove: false,
11251     useDisplay: false
11252 });
11253 </code></pre>
11254          * @param {Object} options (optional) Object literal with any of the Fx config options
11255          * @return {Roo.Element} The Element
11256          */
11257     puff : function(o){
11258         var el = this.getFxEl();
11259         o = o || {};
11260
11261         el.queueFx(o, function(){
11262             this.clearOpacity();
11263             this.show();
11264
11265             // restore values after effect
11266             var r = this.getFxRestore();
11267             var st = this.dom.style;
11268
11269             var after = function(){
11270                 if(o.useDisplay){
11271                     el.setDisplayed(false);
11272                 }else{
11273                     el.hide();
11274                 }
11275
11276                 el.clearOpacity();
11277
11278                 el.setPositioning(r.pos);
11279                 st.width = r.width;
11280                 st.height = r.height;
11281                 st.fontSize = '';
11282                 el.afterFx(o);
11283             };
11284
11285             var width = this.getWidth();
11286             var height = this.getHeight();
11287
11288             arguments.callee.anim = this.fxanim({
11289                     width : {to: this.adjustWidth(width * 2)},
11290                     height : {to: this.adjustHeight(height * 2)},
11291                     points : {by: [-(width * .5), -(height * .5)]},
11292                     opacity : {to: 0},
11293                     fontSize: {to:200, unit: "%"}
11294                 },
11295                 o,
11296                 'motion',
11297                 .5,
11298                 "easeOut", after);
11299         });
11300         return this;
11301     },
11302
11303         /**
11304          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11305          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
11306          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11307          * Usage:
11308          *<pre><code>
11309 // default
11310 el.switchOff();
11311
11312 // all config options shown with default values
11313 el.switchOff({
11314     easing: 'easeIn',
11315     duration: .3,
11316     remove: false,
11317     useDisplay: false
11318 });
11319 </code></pre>
11320          * @param {Object} options (optional) Object literal with any of the Fx config options
11321          * @return {Roo.Element} The Element
11322          */
11323     switchOff : function(o){
11324         var el = this.getFxEl();
11325         o = o || {};
11326
11327         el.queueFx(o, function(){
11328             this.clearOpacity();
11329             this.clip();
11330
11331             // restore values after effect
11332             var r = this.getFxRestore();
11333             var st = this.dom.style;
11334
11335             var after = function(){
11336                 if(o.useDisplay){
11337                     el.setDisplayed(false);
11338                 }else{
11339                     el.hide();
11340                 }
11341
11342                 el.clearOpacity();
11343                 el.setPositioning(r.pos);
11344                 st.width = r.width;
11345                 st.height = r.height;
11346
11347                 el.afterFx(o);
11348             };
11349
11350             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11351                 this.clearOpacity();
11352                 (function(){
11353                     this.fxanim({
11354                         height:{to:1},
11355                         points:{by:[0, this.getHeight() * .5]}
11356                     }, o, 'motion', 0.3, 'easeIn', after);
11357                 }).defer(100, this);
11358             });
11359         });
11360         return this;
11361     },
11362
11363     /**
11364      * Highlights the Element by setting a color (applies to the background-color by default, but can be
11365      * changed using the "attr" config option) and then fading back to the original color. If no original
11366      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11367      * Usage:
11368 <pre><code>
11369 // default: highlight background to yellow
11370 el.highlight();
11371
11372 // custom: highlight foreground text to blue for 2 seconds
11373 el.highlight("0000ff", { attr: 'color', duration: 2 });
11374
11375 // common config options shown with default values
11376 el.highlight("ffff9c", {
11377     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11378     endColor: (current color) or "ffffff",
11379     easing: 'easeIn',
11380     duration: 1
11381 });
11382 </code></pre>
11383      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11384      * @param {Object} options (optional) Object literal with any of the Fx config options
11385      * @return {Roo.Element} The Element
11386      */ 
11387     highlight : function(color, o){
11388         var el = this.getFxEl();
11389         o = o || {};
11390
11391         el.queueFx(o, function(){
11392             color = color || "ffff9c";
11393             attr = o.attr || "backgroundColor";
11394
11395             this.clearOpacity();
11396             this.show();
11397
11398             var origColor = this.getColor(attr);
11399             var restoreColor = this.dom.style[attr];
11400             endColor = (o.endColor || origColor) || "ffffff";
11401
11402             var after = function(){
11403                 el.dom.style[attr] = restoreColor;
11404                 el.afterFx(o);
11405             };
11406
11407             var a = {};
11408             a[attr] = {from: color, to: endColor};
11409             arguments.callee.anim = this.fxanim(a,
11410                 o,
11411                 'color',
11412                 1,
11413                 'easeIn', after);
11414         });
11415         return this;
11416     },
11417
11418    /**
11419     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11420     * Usage:
11421 <pre><code>
11422 // default: a single light blue ripple
11423 el.frame();
11424
11425 // custom: 3 red ripples lasting 3 seconds total
11426 el.frame("ff0000", 3, { duration: 3 });
11427
11428 // common config options shown with default values
11429 el.frame("C3DAF9", 1, {
11430     duration: 1 //duration of entire animation (not each individual ripple)
11431     // Note: Easing is not configurable and will be ignored if included
11432 });
11433 </code></pre>
11434     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11435     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11436     * @param {Object} options (optional) Object literal with any of the Fx config options
11437     * @return {Roo.Element} The Element
11438     */
11439     frame : function(color, count, o){
11440         var el = this.getFxEl();
11441         o = o || {};
11442
11443         el.queueFx(o, function(){
11444             color = color || "#C3DAF9";
11445             if(color.length == 6){
11446                 color = "#" + color;
11447             }
11448             count = count || 1;
11449             duration = o.duration || 1;
11450             this.show();
11451
11452             var b = this.getBox();
11453             var animFn = function(){
11454                 var proxy = this.createProxy({
11455
11456                      style:{
11457                         visbility:"hidden",
11458                         position:"absolute",
11459                         "z-index":"35000", // yee haw
11460                         border:"0px solid " + color
11461                      }
11462                   });
11463                 var scale = Roo.isBorderBox ? 2 : 1;
11464                 proxy.animate({
11465                     top:{from:b.y, to:b.y - 20},
11466                     left:{from:b.x, to:b.x - 20},
11467                     borderWidth:{from:0, to:10},
11468                     opacity:{from:1, to:0},
11469                     height:{from:b.height, to:(b.height + (20*scale))},
11470                     width:{from:b.width, to:(b.width + (20*scale))}
11471                 }, duration, function(){
11472                     proxy.remove();
11473                 });
11474                 if(--count > 0){
11475                      animFn.defer((duration/2)*1000, this);
11476                 }else{
11477                     el.afterFx(o);
11478                 }
11479             };
11480             animFn.call(this);
11481         });
11482         return this;
11483     },
11484
11485    /**
11486     * Creates a pause before any subsequent queued effects begin.  If there are
11487     * no effects queued after the pause it will have no effect.
11488     * Usage:
11489 <pre><code>
11490 el.pause(1);
11491 </code></pre>
11492     * @param {Number} seconds The length of time to pause (in seconds)
11493     * @return {Roo.Element} The Element
11494     */
11495     pause : function(seconds){
11496         var el = this.getFxEl();
11497         var o = {};
11498
11499         el.queueFx(o, function(){
11500             setTimeout(function(){
11501                 el.afterFx(o);
11502             }, seconds * 1000);
11503         });
11504         return this;
11505     },
11506
11507    /**
11508     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
11509     * using the "endOpacity" config option.
11510     * Usage:
11511 <pre><code>
11512 // default: fade in from opacity 0 to 100%
11513 el.fadeIn();
11514
11515 // custom: fade in from opacity 0 to 75% over 2 seconds
11516 el.fadeIn({ endOpacity: .75, duration: 2});
11517
11518 // common config options shown with default values
11519 el.fadeIn({
11520     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11521     easing: 'easeOut',
11522     duration: .5
11523 });
11524 </code></pre>
11525     * @param {Object} options (optional) Object literal with any of the Fx config options
11526     * @return {Roo.Element} The Element
11527     */
11528     fadeIn : function(o){
11529         var el = this.getFxEl();
11530         o = o || {};
11531         el.queueFx(o, function(){
11532             this.setOpacity(0);
11533             this.fixDisplay();
11534             this.dom.style.visibility = 'visible';
11535             var to = o.endOpacity || 1;
11536             arguments.callee.anim = this.fxanim({opacity:{to:to}},
11537                 o, null, .5, "easeOut", function(){
11538                 if(to == 1){
11539                     this.clearOpacity();
11540                 }
11541                 el.afterFx(o);
11542             });
11543         });
11544         return this;
11545     },
11546
11547    /**
11548     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
11549     * using the "endOpacity" config option.
11550     * Usage:
11551 <pre><code>
11552 // default: fade out from the element's current opacity to 0
11553 el.fadeOut();
11554
11555 // custom: fade out from the element's current opacity to 25% over 2 seconds
11556 el.fadeOut({ endOpacity: .25, duration: 2});
11557
11558 // common config options shown with default values
11559 el.fadeOut({
11560     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11561     easing: 'easeOut',
11562     duration: .5
11563     remove: false,
11564     useDisplay: false
11565 });
11566 </code></pre>
11567     * @param {Object} options (optional) Object literal with any of the Fx config options
11568     * @return {Roo.Element} The Element
11569     */
11570     fadeOut : function(o){
11571         var el = this.getFxEl();
11572         o = o || {};
11573         el.queueFx(o, function(){
11574             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11575                 o, null, .5, "easeOut", function(){
11576                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11577                      this.dom.style.display = "none";
11578                 }else{
11579                      this.dom.style.visibility = "hidden";
11580                 }
11581                 this.clearOpacity();
11582                 el.afterFx(o);
11583             });
11584         });
11585         return this;
11586     },
11587
11588    /**
11589     * Animates the transition of an element's dimensions from a starting height/width
11590     * to an ending height/width.
11591     * Usage:
11592 <pre><code>
11593 // change height and width to 100x100 pixels
11594 el.scale(100, 100);
11595
11596 // common config options shown with default values.  The height and width will default to
11597 // the element's existing values if passed as null.
11598 el.scale(
11599     [element's width],
11600     [element's height], {
11601     easing: 'easeOut',
11602     duration: .35
11603 });
11604 </code></pre>
11605     * @param {Number} width  The new width (pass undefined to keep the original width)
11606     * @param {Number} height  The new height (pass undefined to keep the original height)
11607     * @param {Object} options (optional) Object literal with any of the Fx config options
11608     * @return {Roo.Element} The Element
11609     */
11610     scale : function(w, h, o){
11611         this.shift(Roo.apply({}, o, {
11612             width: w,
11613             height: h
11614         }));
11615         return this;
11616     },
11617
11618    /**
11619     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
11620     * Any of these properties not specified in the config object will not be changed.  This effect 
11621     * requires that at least one new dimension, position or opacity setting must be passed in on
11622     * the config object in order for the function to have any effect.
11623     * Usage:
11624 <pre><code>
11625 // slide the element horizontally to x position 200 while changing the height and opacity
11626 el.shift({ x: 200, height: 50, opacity: .8 });
11627
11628 // common config options shown with default values.
11629 el.shift({
11630     width: [element's width],
11631     height: [element's height],
11632     x: [element's x position],
11633     y: [element's y position],
11634     opacity: [element's opacity],
11635     easing: 'easeOut',
11636     duration: .35
11637 });
11638 </code></pre>
11639     * @param {Object} options  Object literal with any of the Fx config options
11640     * @return {Roo.Element} The Element
11641     */
11642     shift : function(o){
11643         var el = this.getFxEl();
11644         o = o || {};
11645         el.queueFx(o, function(){
11646             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
11647             if(w !== undefined){
11648                 a.width = {to: this.adjustWidth(w)};
11649             }
11650             if(h !== undefined){
11651                 a.height = {to: this.adjustHeight(h)};
11652             }
11653             if(x !== undefined || y !== undefined){
11654                 a.points = {to: [
11655                     x !== undefined ? x : this.getX(),
11656                     y !== undefined ? y : this.getY()
11657                 ]};
11658             }
11659             if(op !== undefined){
11660                 a.opacity = {to: op};
11661             }
11662             if(o.xy !== undefined){
11663                 a.points = {to: o.xy};
11664             }
11665             arguments.callee.anim = this.fxanim(a,
11666                 o, 'motion', .35, "easeOut", function(){
11667                 el.afterFx(o);
11668             });
11669         });
11670         return this;
11671     },
11672
11673         /**
11674          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
11675          * ending point of the effect.
11676          * Usage:
11677          *<pre><code>
11678 // default: slide the element downward while fading out
11679 el.ghost();
11680
11681 // custom: slide the element out to the right with a 2-second duration
11682 el.ghost('r', { duration: 2 });
11683
11684 // common config options shown with default values
11685 el.ghost('b', {
11686     easing: 'easeOut',
11687     duration: .5
11688     remove: false,
11689     useDisplay: false
11690 });
11691 </code></pre>
11692          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
11693          * @param {Object} options (optional) Object literal with any of the Fx config options
11694          * @return {Roo.Element} The Element
11695          */
11696     ghost : function(anchor, o){
11697         var el = this.getFxEl();
11698         o = o || {};
11699
11700         el.queueFx(o, function(){
11701             anchor = anchor || "b";
11702
11703             // restore values after effect
11704             var r = this.getFxRestore();
11705             var w = this.getWidth(),
11706                 h = this.getHeight();
11707
11708             var st = this.dom.style;
11709
11710             var after = function(){
11711                 if(o.useDisplay){
11712                     el.setDisplayed(false);
11713                 }else{
11714                     el.hide();
11715                 }
11716
11717                 el.clearOpacity();
11718                 el.setPositioning(r.pos);
11719                 st.width = r.width;
11720                 st.height = r.height;
11721
11722                 el.afterFx(o);
11723             };
11724
11725             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11726             switch(anchor.toLowerCase()){
11727                 case "t":
11728                     pt.by = [0, -h];
11729                 break;
11730                 case "l":
11731                     pt.by = [-w, 0];
11732                 break;
11733                 case "r":
11734                     pt.by = [w, 0];
11735                 break;
11736                 case "b":
11737                     pt.by = [0, h];
11738                 break;
11739                 case "tl":
11740                     pt.by = [-w, -h];
11741                 break;
11742                 case "bl":
11743                     pt.by = [-w, h];
11744                 break;
11745                 case "br":
11746                     pt.by = [w, h];
11747                 break;
11748                 case "tr":
11749                     pt.by = [w, -h];
11750                 break;
11751             }
11752
11753             arguments.callee.anim = this.fxanim(a,
11754                 o,
11755                 'motion',
11756                 .5,
11757                 "easeOut", after);
11758         });
11759         return this;
11760     },
11761
11762         /**
11763          * Ensures that all effects queued after syncFx is called on the element are
11764          * run concurrently.  This is the opposite of {@link #sequenceFx}.
11765          * @return {Roo.Element} The Element
11766          */
11767     syncFx : function(){
11768         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11769             block : false,
11770             concurrent : true,
11771             stopFx : false
11772         });
11773         return this;
11774     },
11775
11776         /**
11777          * Ensures that all effects queued after sequenceFx is called on the element are
11778          * run in sequence.  This is the opposite of {@link #syncFx}.
11779          * @return {Roo.Element} The Element
11780          */
11781     sequenceFx : function(){
11782         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11783             block : false,
11784             concurrent : false,
11785             stopFx : false
11786         });
11787         return this;
11788     },
11789
11790         /* @private */
11791     nextFx : function(){
11792         var ef = this.fxQueue[0];
11793         if(ef){
11794             ef.call(this);
11795         }
11796     },
11797
11798         /**
11799          * Returns true if the element has any effects actively running or queued, else returns false.
11800          * @return {Boolean} True if element has active effects, else false
11801          */
11802     hasActiveFx : function(){
11803         return this.fxQueue && this.fxQueue[0];
11804     },
11805
11806         /**
11807          * Stops any running effects and clears the element's internal effects queue if it contains
11808          * any additional effects that haven't started yet.
11809          * @return {Roo.Element} The Element
11810          */
11811     stopFx : function(){
11812         if(this.hasActiveFx()){
11813             var cur = this.fxQueue[0];
11814             if(cur && cur.anim && cur.anim.isAnimated()){
11815                 this.fxQueue = [cur]; // clear out others
11816                 cur.anim.stop(true);
11817             }
11818         }
11819         return this;
11820     },
11821
11822         /* @private */
11823     beforeFx : function(o){
11824         if(this.hasActiveFx() && !o.concurrent){
11825            if(o.stopFx){
11826                this.stopFx();
11827                return true;
11828            }
11829            return false;
11830         }
11831         return true;
11832     },
11833
11834         /**
11835          * Returns true if the element is currently blocking so that no other effect can be queued
11836          * until this effect is finished, else returns false if blocking is not set.  This is commonly
11837          * used to ensure that an effect initiated by a user action runs to completion prior to the
11838          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11839          * @return {Boolean} True if blocking, else false
11840          */
11841     hasFxBlock : function(){
11842         var q = this.fxQueue;
11843         return q && q[0] && q[0].block;
11844     },
11845
11846         /* @private */
11847     queueFx : function(o, fn){
11848         if(!this.fxQueue){
11849             this.fxQueue = [];
11850         }
11851         if(!this.hasFxBlock()){
11852             Roo.applyIf(o, this.fxDefaults);
11853             if(!o.concurrent){
11854                 var run = this.beforeFx(o);
11855                 fn.block = o.block;
11856                 this.fxQueue.push(fn);
11857                 if(run){
11858                     this.nextFx();
11859                 }
11860             }else{
11861                 fn.call(this);
11862             }
11863         }
11864         return this;
11865     },
11866
11867         /* @private */
11868     fxWrap : function(pos, o, vis){
11869         var wrap;
11870         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11871             var wrapXY;
11872             if(o.fixPosition){
11873                 wrapXY = this.getXY();
11874             }
11875             var div = document.createElement("div");
11876             div.style.visibility = vis;
11877             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11878             wrap.setPositioning(pos);
11879             if(wrap.getStyle("position") == "static"){
11880                 wrap.position("relative");
11881             }
11882             this.clearPositioning('auto');
11883             wrap.clip();
11884             wrap.dom.appendChild(this.dom);
11885             if(wrapXY){
11886                 wrap.setXY(wrapXY);
11887             }
11888         }
11889         return wrap;
11890     },
11891
11892         /* @private */
11893     fxUnwrap : function(wrap, pos, o){
11894         this.clearPositioning();
11895         this.setPositioning(pos);
11896         if(!o.wrap){
11897             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11898             wrap.remove();
11899         }
11900     },
11901
11902         /* @private */
11903     getFxRestore : function(){
11904         var st = this.dom.style;
11905         return {pos: this.getPositioning(), width: st.width, height : st.height};
11906     },
11907
11908         /* @private */
11909     afterFx : function(o){
11910         if(o.afterStyle){
11911             this.applyStyles(o.afterStyle);
11912         }
11913         if(o.afterCls){
11914             this.addClass(o.afterCls);
11915         }
11916         if(o.remove === true){
11917             this.remove();
11918         }
11919         Roo.callback(o.callback, o.scope, [this]);
11920         if(!o.concurrent){
11921             this.fxQueue.shift();
11922             this.nextFx();
11923         }
11924     },
11925
11926         /* @private */
11927     getFxEl : function(){ // support for composite element fx
11928         return Roo.get(this.dom);
11929     },
11930
11931         /* @private */
11932     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11933         animType = animType || 'run';
11934         opt = opt || {};
11935         var anim = Roo.lib.Anim[animType](
11936             this.dom, args,
11937             (opt.duration || defaultDur) || .35,
11938             (opt.easing || defaultEase) || 'easeOut',
11939             function(){
11940                 Roo.callback(cb, this);
11941             },
11942             this
11943         );
11944         opt.anim = anim;
11945         return anim;
11946     }
11947 };
11948
11949 // backwords compat
11950 Roo.Fx.resize = Roo.Fx.scale;
11951
11952 //When included, Roo.Fx is automatically applied to Element so that all basic
11953 //effects are available directly via the Element API
11954 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11955  * Based on:
11956  * Ext JS Library 1.1.1
11957  * Copyright(c) 2006-2007, Ext JS, LLC.
11958  *
11959  * Originally Released Under LGPL - original licence link has changed is not relivant.
11960  *
11961  * Fork - LGPL
11962  * <script type="text/javascript">
11963  */
11964
11965
11966 /**
11967  * @class Roo.CompositeElement
11968  * Standard composite class. Creates a Roo.Element for every element in the collection.
11969  * <br><br>
11970  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11971  * actions will be performed on all the elements in this collection.</b>
11972  * <br><br>
11973  * All methods return <i>this</i> and can be chained.
11974  <pre><code>
11975  var els = Roo.select("#some-el div.some-class", true);
11976  // or select directly from an existing element
11977  var el = Roo.get('some-el');
11978  el.select('div.some-class', true);
11979
11980  els.setWidth(100); // all elements become 100 width
11981  els.hide(true); // all elements fade out and hide
11982  // or
11983  els.setWidth(100).hide(true);
11984  </code></pre>
11985  */
11986 Roo.CompositeElement = function(els){
11987     this.elements = [];
11988     this.addElements(els);
11989 };
11990 Roo.CompositeElement.prototype = {
11991     isComposite: true,
11992     addElements : function(els){
11993         if(!els) {
11994             return this;
11995         }
11996         if(typeof els == "string"){
11997             els = Roo.Element.selectorFunction(els);
11998         }
11999         var yels = this.elements;
12000         var index = yels.length-1;
12001         for(var i = 0, len = els.length; i < len; i++) {
12002                 yels[++index] = Roo.get(els[i]);
12003         }
12004         return this;
12005     },
12006
12007     /**
12008     * Clears this composite and adds the elements returned by the passed selector.
12009     * @param {String/Array} els A string CSS selector, an array of elements or an element
12010     * @return {CompositeElement} this
12011     */
12012     fill : function(els){
12013         this.elements = [];
12014         this.add(els);
12015         return this;
12016     },
12017
12018     /**
12019     * Filters this composite to only elements that match the passed selector.
12020     * @param {String} selector A string CSS selector
12021     * @param {Boolean} inverse return inverse filter (not matches)
12022     * @return {CompositeElement} this
12023     */
12024     filter : function(selector, inverse){
12025         var els = [];
12026         inverse = inverse || false;
12027         this.each(function(el){
12028             var match = inverse ? !el.is(selector) : el.is(selector);
12029             if(match){
12030                 els[els.length] = el.dom;
12031             }
12032         });
12033         this.fill(els);
12034         return this;
12035     },
12036
12037     invoke : function(fn, args){
12038         var els = this.elements;
12039         for(var i = 0, len = els.length; i < len; i++) {
12040                 Roo.Element.prototype[fn].apply(els[i], args);
12041         }
12042         return this;
12043     },
12044     /**
12045     * Adds elements to this composite.
12046     * @param {String/Array} els A string CSS selector, an array of elements or an element
12047     * @return {CompositeElement} this
12048     */
12049     add : function(els){
12050         if(typeof els == "string"){
12051             this.addElements(Roo.Element.selectorFunction(els));
12052         }else if(els.length !== undefined){
12053             this.addElements(els);
12054         }else{
12055             this.addElements([els]);
12056         }
12057         return this;
12058     },
12059     /**
12060     * Calls the passed function passing (el, this, index) for each element in this composite.
12061     * @param {Function} fn The function to call
12062     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12063     * @return {CompositeElement} this
12064     */
12065     each : function(fn, scope){
12066         var els = this.elements;
12067         for(var i = 0, len = els.length; i < len; i++){
12068             if(fn.call(scope || els[i], els[i], this, i) === false) {
12069                 break;
12070             }
12071         }
12072         return this;
12073     },
12074
12075     /**
12076      * Returns the Element object at the specified index
12077      * @param {Number} index
12078      * @return {Roo.Element}
12079      */
12080     item : function(index){
12081         return this.elements[index] || null;
12082     },
12083
12084     /**
12085      * Returns the first Element
12086      * @return {Roo.Element}
12087      */
12088     first : function(){
12089         return this.item(0);
12090     },
12091
12092     /**
12093      * Returns the last Element
12094      * @return {Roo.Element}
12095      */
12096     last : function(){
12097         return this.item(this.elements.length-1);
12098     },
12099
12100     /**
12101      * Returns the number of elements in this composite
12102      * @return Number
12103      */
12104     getCount : function(){
12105         return this.elements.length;
12106     },
12107
12108     /**
12109      * Returns true if this composite contains the passed element
12110      * @return Boolean
12111      */
12112     contains : function(el){
12113         return this.indexOf(el) !== -1;
12114     },
12115
12116     /**
12117      * Returns true if this composite contains the passed element
12118      * @return Boolean
12119      */
12120     indexOf : function(el){
12121         return this.elements.indexOf(Roo.get(el));
12122     },
12123
12124
12125     /**
12126     * Removes the specified element(s).
12127     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12128     * or an array of any of those.
12129     * @param {Boolean} removeDom (optional) True to also remove the element from the document
12130     * @return {CompositeElement} this
12131     */
12132     removeElement : function(el, removeDom){
12133         if(el instanceof Array){
12134             for(var i = 0, len = el.length; i < len; i++){
12135                 this.removeElement(el[i]);
12136             }
12137             return this;
12138         }
12139         var index = typeof el == 'number' ? el : this.indexOf(el);
12140         if(index !== -1){
12141             if(removeDom){
12142                 var d = this.elements[index];
12143                 if(d.dom){
12144                     d.remove();
12145                 }else{
12146                     d.parentNode.removeChild(d);
12147                 }
12148             }
12149             this.elements.splice(index, 1);
12150         }
12151         return this;
12152     },
12153
12154     /**
12155     * Replaces the specified element with the passed element.
12156     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12157     * to replace.
12158     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12159     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12160     * @return {CompositeElement} this
12161     */
12162     replaceElement : function(el, replacement, domReplace){
12163         var index = typeof el == 'number' ? el : this.indexOf(el);
12164         if(index !== -1){
12165             if(domReplace){
12166                 this.elements[index].replaceWith(replacement);
12167             }else{
12168                 this.elements.splice(index, 1, Roo.get(replacement))
12169             }
12170         }
12171         return this;
12172     },
12173
12174     /**
12175      * Removes all elements.
12176      */
12177     clear : function(){
12178         this.elements = [];
12179     }
12180 };
12181 (function(){
12182     Roo.CompositeElement.createCall = function(proto, fnName){
12183         if(!proto[fnName]){
12184             proto[fnName] = function(){
12185                 return this.invoke(fnName, arguments);
12186             };
12187         }
12188     };
12189     for(var fnName in Roo.Element.prototype){
12190         if(typeof Roo.Element.prototype[fnName] == "function"){
12191             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12192         }
12193     };
12194 })();
12195 /*
12196  * Based on:
12197  * Ext JS Library 1.1.1
12198  * Copyright(c) 2006-2007, Ext JS, LLC.
12199  *
12200  * Originally Released Under LGPL - original licence link has changed is not relivant.
12201  *
12202  * Fork - LGPL
12203  * <script type="text/javascript">
12204  */
12205
12206 /**
12207  * @class Roo.CompositeElementLite
12208  * @extends Roo.CompositeElement
12209  * Flyweight composite class. Reuses the same Roo.Element for element operations.
12210  <pre><code>
12211  var els = Roo.select("#some-el div.some-class");
12212  // or select directly from an existing element
12213  var el = Roo.get('some-el');
12214  el.select('div.some-class');
12215
12216  els.setWidth(100); // all elements become 100 width
12217  els.hide(true); // all elements fade out and hide
12218  // or
12219  els.setWidth(100).hide(true);
12220  </code></pre><br><br>
12221  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12222  * actions will be performed on all the elements in this collection.</b>
12223  */
12224 Roo.CompositeElementLite = function(els){
12225     Roo.CompositeElementLite.superclass.constructor.call(this, els);
12226     this.el = new Roo.Element.Flyweight();
12227 };
12228 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12229     addElements : function(els){
12230         if(els){
12231             if(els instanceof Array){
12232                 this.elements = this.elements.concat(els);
12233             }else{
12234                 var yels = this.elements;
12235                 var index = yels.length-1;
12236                 for(var i = 0, len = els.length; i < len; i++) {
12237                     yels[++index] = els[i];
12238                 }
12239             }
12240         }
12241         return this;
12242     },
12243     invoke : function(fn, args){
12244         var els = this.elements;
12245         var el = this.el;
12246         for(var i = 0, len = els.length; i < len; i++) {
12247             el.dom = els[i];
12248                 Roo.Element.prototype[fn].apply(el, args);
12249         }
12250         return this;
12251     },
12252     /**
12253      * Returns a flyweight Element of the dom element object at the specified index
12254      * @param {Number} index
12255      * @return {Roo.Element}
12256      */
12257     item : function(index){
12258         if(!this.elements[index]){
12259             return null;
12260         }
12261         this.el.dom = this.elements[index];
12262         return this.el;
12263     },
12264
12265     // fixes scope with flyweight
12266     addListener : function(eventName, handler, scope, opt){
12267         var els = this.elements;
12268         for(var i = 0, len = els.length; i < len; i++) {
12269             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12270         }
12271         return this;
12272     },
12273
12274     /**
12275     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12276     * passed is the flyweight (shared) Roo.Element instance, so if you require a
12277     * a reference to the dom node, use el.dom.</b>
12278     * @param {Function} fn The function to call
12279     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12280     * @return {CompositeElement} this
12281     */
12282     each : function(fn, scope){
12283         var els = this.elements;
12284         var el = this.el;
12285         for(var i = 0, len = els.length; i < len; i++){
12286             el.dom = els[i];
12287                 if(fn.call(scope || el, el, this, i) === false){
12288                 break;
12289             }
12290         }
12291         return this;
12292     },
12293
12294     indexOf : function(el){
12295         return this.elements.indexOf(Roo.getDom(el));
12296     },
12297
12298     replaceElement : function(el, replacement, domReplace){
12299         var index = typeof el == 'number' ? el : this.indexOf(el);
12300         if(index !== -1){
12301             replacement = Roo.getDom(replacement);
12302             if(domReplace){
12303                 var d = this.elements[index];
12304                 d.parentNode.insertBefore(replacement, d);
12305                 d.parentNode.removeChild(d);
12306             }
12307             this.elements.splice(index, 1, replacement);
12308         }
12309         return this;
12310     }
12311 });
12312 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12313
12314 /*
12315  * Based on:
12316  * Ext JS Library 1.1.1
12317  * Copyright(c) 2006-2007, Ext JS, LLC.
12318  *
12319  * Originally Released Under LGPL - original licence link has changed is not relivant.
12320  *
12321  * Fork - LGPL
12322  * <script type="text/javascript">
12323  */
12324
12325  
12326
12327 /**
12328  * @class Roo.data.Connection
12329  * @extends Roo.util.Observable
12330  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12331  * either to a configured URL, or to a URL specified at request time. 
12332  * 
12333  * Requests made by this class are asynchronous, and will return immediately. No data from
12334  * the server will be available to the statement immediately following the {@link #request} call.
12335  * To process returned data, use a callback in the request options object, or an event listener.
12336  * 
12337  * Note: If you are doing a file upload, you will not get a normal response object sent back to
12338  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12339  * The response object is created using the innerHTML of the IFRAME's document as the responseText
12340  * property and, if present, the IFRAME's XML document as the responseXML property.
12341  * 
12342  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12343  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
12344  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12345  * standard DOM methods.
12346  * @constructor
12347  * @param {Object} config a configuration object.
12348  */
12349 Roo.data.Connection = function(config){
12350     Roo.apply(this, config);
12351     this.addEvents({
12352         /**
12353          * @event beforerequest
12354          * Fires before a network request is made to retrieve a data object.
12355          * @param {Connection} conn This Connection object.
12356          * @param {Object} options The options config object passed to the {@link #request} method.
12357          */
12358         "beforerequest" : true,
12359         /**
12360          * @event requestcomplete
12361          * Fires if the request was successfully completed.
12362          * @param {Connection} conn This Connection object.
12363          * @param {Object} response The XHR object containing the response data.
12364          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12365          * @param {Object} options The options config object passed to the {@link #request} method.
12366          */
12367         "requestcomplete" : true,
12368         /**
12369          * @event requestexception
12370          * Fires if an error HTTP status was returned from the server.
12371          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12372          * @param {Connection} conn This Connection object.
12373          * @param {Object} response The XHR object containing the response data.
12374          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12375          * @param {Object} options The options config object passed to the {@link #request} method.
12376          */
12377         "requestexception" : true
12378     });
12379     Roo.data.Connection.superclass.constructor.call(this);
12380 };
12381
12382 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12383     /**
12384      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12385      */
12386     /**
12387      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12388      * extra parameters to each request made by this object. (defaults to undefined)
12389      */
12390     /**
12391      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12392      *  to each request made by this object. (defaults to undefined)
12393      */
12394     /**
12395      * @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)
12396      */
12397     /**
12398      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12399      */
12400     timeout : 30000,
12401     /**
12402      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12403      * @type Boolean
12404      */
12405     autoAbort:false,
12406
12407     /**
12408      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12409      * @type Boolean
12410      */
12411     disableCaching: true,
12412
12413     /**
12414      * Sends an HTTP request to a remote server.
12415      * @param {Object} options An object which may contain the following properties:<ul>
12416      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12417      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12418      * request, a url encoded string or a function to call to get either.</li>
12419      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12420      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12421      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12422      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12423      * <li>options {Object} The parameter to the request call.</li>
12424      * <li>success {Boolean} True if the request succeeded.</li>
12425      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12426      * </ul></li>
12427      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12428      * The callback is passed the following parameters:<ul>
12429      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12430      * <li>options {Object} The parameter to the request call.</li>
12431      * </ul></li>
12432      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12433      * The callback is passed the following parameters:<ul>
12434      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12435      * <li>options {Object} The parameter to the request call.</li>
12436      * </ul></li>
12437      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12438      * for the callback function. Defaults to the browser window.</li>
12439      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12440      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12441      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12442      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12443      * params for the post data. Any params will be appended to the URL.</li>
12444      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12445      * </ul>
12446      * @return {Number} transactionId
12447      */
12448     request : function(o){
12449         if(this.fireEvent("beforerequest", this, o) !== false){
12450             var p = o.params;
12451
12452             if(typeof p == "function"){
12453                 p = p.call(o.scope||window, o);
12454             }
12455             if(typeof p == "object"){
12456                 p = Roo.urlEncode(o.params);
12457             }
12458             if(this.extraParams){
12459                 var extras = Roo.urlEncode(this.extraParams);
12460                 p = p ? (p + '&' + extras) : extras;
12461             }
12462
12463             var url = o.url || this.url;
12464             if(typeof url == 'function'){
12465                 url = url.call(o.scope||window, o);
12466             }
12467
12468             if(o.form){
12469                 var form = Roo.getDom(o.form);
12470                 url = url || form.action;
12471
12472                 var enctype = form.getAttribute("enctype");
12473                 
12474                 if (o.formData) {
12475                     return this.doFormDataUpload(o, url);
12476                 }
12477                 
12478                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12479                     return this.doFormUpload(o, p, url);
12480                 }
12481                 var f = Roo.lib.Ajax.serializeForm(form);
12482                 p = p ? (p + '&' + f) : f;
12483             }
12484             
12485             if (!o.form && o.formData) {
12486                 o.formData = o.formData === true ? new FormData() : o.formData;
12487                 for (var k in o.params) {
12488                     o.formData.append(k,o.params[k]);
12489                 }
12490                     
12491                 return this.doFormDataUpload(o, url);
12492             }
12493             
12494
12495             var hs = o.headers;
12496             if(this.defaultHeaders){
12497                 hs = Roo.apply(hs || {}, this.defaultHeaders);
12498                 if(!o.headers){
12499                     o.headers = hs;
12500                 }
12501             }
12502
12503             var cb = {
12504                 success: this.handleResponse,
12505                 failure: this.handleFailure,
12506                 scope: this,
12507                 argument: {options: o},
12508                 timeout : o.timeout || this.timeout
12509             };
12510
12511             var method = o.method||this.method||(p ? "POST" : "GET");
12512
12513             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12514                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12515             }
12516
12517             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12518                 if(o.autoAbort){
12519                     this.abort();
12520                 }
12521             }else if(this.autoAbort !== false){
12522                 this.abort();
12523             }
12524
12525             if((method == 'GET' && p) || o.xmlData){
12526                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12527                 p = '';
12528             }
12529             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12530             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12531             Roo.lib.Ajax.useDefaultHeader == true;
12532             return this.transId;
12533         }else{
12534             Roo.callback(o.callback, o.scope, [o, null, null]);
12535             return null;
12536         }
12537     },
12538
12539     /**
12540      * Determine whether this object has a request outstanding.
12541      * @param {Number} transactionId (Optional) defaults to the last transaction
12542      * @return {Boolean} True if there is an outstanding request.
12543      */
12544     isLoading : function(transId){
12545         if(transId){
12546             return Roo.lib.Ajax.isCallInProgress(transId);
12547         }else{
12548             return this.transId ? true : false;
12549         }
12550     },
12551
12552     /**
12553      * Aborts any outstanding request.
12554      * @param {Number} transactionId (Optional) defaults to the last transaction
12555      */
12556     abort : function(transId){
12557         if(transId || this.isLoading()){
12558             Roo.lib.Ajax.abort(transId || this.transId);
12559         }
12560     },
12561
12562     // private
12563     handleResponse : function(response){
12564         this.transId = false;
12565         var options = response.argument.options;
12566         response.argument = options ? options.argument : null;
12567         this.fireEvent("requestcomplete", this, response, options);
12568         Roo.callback(options.success, options.scope, [response, options]);
12569         Roo.callback(options.callback, options.scope, [options, true, response]);
12570     },
12571
12572     // private
12573     handleFailure : function(response, e){
12574         this.transId = false;
12575         var options = response.argument.options;
12576         response.argument = options ? options.argument : null;
12577         this.fireEvent("requestexception", this, response, options, e);
12578         Roo.callback(options.failure, options.scope, [response, options]);
12579         Roo.callback(options.callback, options.scope, [options, false, response]);
12580     },
12581
12582     // private
12583     doFormUpload : function(o, ps, url){
12584         var id = Roo.id();
12585         var frame = document.createElement('iframe');
12586         frame.id = id;
12587         frame.name = id;
12588         frame.className = 'x-hidden';
12589         if(Roo.isIE){
12590             frame.src = Roo.SSL_SECURE_URL;
12591         }
12592         document.body.appendChild(frame);
12593
12594         if(Roo.isIE){
12595            document.frames[id].name = id;
12596         }
12597
12598         var form = Roo.getDom(o.form);
12599         form.target = id;
12600         form.method = 'POST';
12601         form.enctype = form.encoding = 'multipart/form-data';
12602         if(url){
12603             form.action = url;
12604         }
12605
12606         var hiddens, hd;
12607         if(ps){ // add dynamic params
12608             hiddens = [];
12609             ps = Roo.urlDecode(ps, false);
12610             for(var k in ps){
12611                 if(ps.hasOwnProperty(k)){
12612                     hd = document.createElement('input');
12613                     hd.type = 'hidden';
12614                     hd.name = k;
12615                     hd.value = ps[k];
12616                     form.appendChild(hd);
12617                     hiddens.push(hd);
12618                 }
12619             }
12620         }
12621
12622         function cb(){
12623             var r = {  // bogus response object
12624                 responseText : '',
12625                 responseXML : null
12626             };
12627
12628             r.argument = o ? o.argument : null;
12629
12630             try { //
12631                 var doc;
12632                 if(Roo.isIE){
12633                     doc = frame.contentWindow.document;
12634                 }else {
12635                     doc = (frame.contentDocument || window.frames[id].document);
12636                 }
12637                 if(doc && doc.body){
12638                     r.responseText = doc.body.innerHTML;
12639                 }
12640                 if(doc && doc.XMLDocument){
12641                     r.responseXML = doc.XMLDocument;
12642                 }else {
12643                     r.responseXML = doc;
12644                 }
12645             }
12646             catch(e) {
12647                 // ignore
12648             }
12649
12650             Roo.EventManager.removeListener(frame, 'load', cb, this);
12651
12652             this.fireEvent("requestcomplete", this, r, o);
12653             Roo.callback(o.success, o.scope, [r, o]);
12654             Roo.callback(o.callback, o.scope, [o, true, r]);
12655
12656             setTimeout(function(){document.body.removeChild(frame);}, 100);
12657         }
12658
12659         Roo.EventManager.on(frame, 'load', cb, this);
12660         form.submit();
12661
12662         if(hiddens){ // remove dynamic params
12663             for(var i = 0, len = hiddens.length; i < len; i++){
12664                 form.removeChild(hiddens[i]);
12665             }
12666         }
12667     },
12668     // this is a 'formdata version???'
12669     
12670     
12671     doFormDataUpload : function(o,  url)
12672     {
12673         var formData;
12674         if (o.form) {
12675             var form =  Roo.getDom(o.form);
12676             form.enctype = form.encoding = 'multipart/form-data';
12677             formData = o.formData === true ? new FormData(form) : o.formData;
12678         } else {
12679             formData = o.formData === true ? new FormData() : o.formData;
12680         }
12681         
12682       
12683         var cb = {
12684             success: this.handleResponse,
12685             failure: this.handleFailure,
12686             scope: this,
12687             argument: {options: o},
12688             timeout : o.timeout || this.timeout
12689         };
12690  
12691         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12692             if(o.autoAbort){
12693                 this.abort();
12694             }
12695         }else if(this.autoAbort !== false){
12696             this.abort();
12697         }
12698
12699         //Roo.lib.Ajax.defaultPostHeader = null;
12700         Roo.lib.Ajax.useDefaultHeader = false;
12701         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
12702         Roo.lib.Ajax.useDefaultHeader = true;
12703  
12704          
12705     }
12706     
12707 });
12708 /*
12709  * Based on:
12710  * Ext JS Library 1.1.1
12711  * Copyright(c) 2006-2007, Ext JS, LLC.
12712  *
12713  * Originally Released Under LGPL - original licence link has changed is not relivant.
12714  *
12715  * Fork - LGPL
12716  * <script type="text/javascript">
12717  */
12718  
12719 /**
12720  * Global Ajax request class.
12721  * 
12722  * @class Roo.Ajax
12723  * @extends Roo.data.Connection
12724  * @static
12725  * 
12726  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
12727  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12728  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
12729  * @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)
12730  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12731  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12732  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
12733  */
12734 Roo.Ajax = new Roo.data.Connection({
12735     // fix up the docs
12736     /**
12737      * @scope Roo.Ajax
12738      * @type {Boolear} 
12739      */
12740     autoAbort : false,
12741
12742     /**
12743      * Serialize the passed form into a url encoded string
12744      * @scope Roo.Ajax
12745      * @param {String/HTMLElement} form
12746      * @return {String}
12747      */
12748     serializeForm : function(form){
12749         return Roo.lib.Ajax.serializeForm(form);
12750     }
12751 });/*
12752  * Based on:
12753  * Ext JS Library 1.1.1
12754  * Copyright(c) 2006-2007, Ext JS, LLC.
12755  *
12756  * Originally Released Under LGPL - original licence link has changed is not relivant.
12757  *
12758  * Fork - LGPL
12759  * <script type="text/javascript">
12760  */
12761
12762  
12763 /**
12764  * @class Roo.UpdateManager
12765  * @extends Roo.util.Observable
12766  * Provides AJAX-style update for Element object.<br><br>
12767  * Usage:<br>
12768  * <pre><code>
12769  * // Get it from a Roo.Element object
12770  * var el = Roo.get("foo");
12771  * var mgr = el.getUpdateManager();
12772  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
12773  * ...
12774  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12775  * <br>
12776  * // or directly (returns the same UpdateManager instance)
12777  * var mgr = new Roo.UpdateManager("myElementId");
12778  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12779  * mgr.on("update", myFcnNeedsToKnow);
12780  * <br>
12781    // short handed call directly from the element object
12782    Roo.get("foo").load({
12783         url: "bar.php",
12784         scripts:true,
12785         params: "for=bar",
12786         text: "Loading Foo..."
12787    });
12788  * </code></pre>
12789  * @constructor
12790  * Create new UpdateManager directly.
12791  * @param {String/HTMLElement/Roo.Element} el The element to update
12792  * @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).
12793  */
12794 Roo.UpdateManager = function(el, forceNew){
12795     el = Roo.get(el);
12796     if(!forceNew && el.updateManager){
12797         return el.updateManager;
12798     }
12799     /**
12800      * The Element object
12801      * @type Roo.Element
12802      */
12803     this.el = el;
12804     /**
12805      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12806      * @type String
12807      */
12808     this.defaultUrl = null;
12809
12810     this.addEvents({
12811         /**
12812          * @event beforeupdate
12813          * Fired before an update is made, return false from your handler and the update is cancelled.
12814          * @param {Roo.Element} el
12815          * @param {String/Object/Function} url
12816          * @param {String/Object} params
12817          */
12818         "beforeupdate": true,
12819         /**
12820          * @event update
12821          * Fired after successful update is made.
12822          * @param {Roo.Element} el
12823          * @param {Object} oResponseObject The response Object
12824          */
12825         "update": true,
12826         /**
12827          * @event failure
12828          * Fired on update failure.
12829          * @param {Roo.Element} el
12830          * @param {Object} oResponseObject The response Object
12831          */
12832         "failure": true
12833     });
12834     var d = Roo.UpdateManager.defaults;
12835     /**
12836      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12837      * @type String
12838      */
12839     this.sslBlankUrl = d.sslBlankUrl;
12840     /**
12841      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12842      * @type Boolean
12843      */
12844     this.disableCaching = d.disableCaching;
12845     /**
12846      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12847      * @type String
12848      */
12849     this.indicatorText = d.indicatorText;
12850     /**
12851      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12852      * @type String
12853      */
12854     this.showLoadIndicator = d.showLoadIndicator;
12855     /**
12856      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12857      * @type Number
12858      */
12859     this.timeout = d.timeout;
12860
12861     /**
12862      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12863      * @type Boolean
12864      */
12865     this.loadScripts = d.loadScripts;
12866
12867     /**
12868      * Transaction object of current executing transaction
12869      */
12870     this.transaction = null;
12871
12872     /**
12873      * @private
12874      */
12875     this.autoRefreshProcId = null;
12876     /**
12877      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12878      * @type Function
12879      */
12880     this.refreshDelegate = this.refresh.createDelegate(this);
12881     /**
12882      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12883      * @type Function
12884      */
12885     this.updateDelegate = this.update.createDelegate(this);
12886     /**
12887      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12888      * @type Function
12889      */
12890     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12891     /**
12892      * @private
12893      */
12894     this.successDelegate = this.processSuccess.createDelegate(this);
12895     /**
12896      * @private
12897      */
12898     this.failureDelegate = this.processFailure.createDelegate(this);
12899
12900     if(!this.renderer){
12901      /**
12902       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12903       */
12904     this.renderer = new Roo.UpdateManager.BasicRenderer();
12905     }
12906     
12907     Roo.UpdateManager.superclass.constructor.call(this);
12908 };
12909
12910 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12911     /**
12912      * Get the Element this UpdateManager is bound to
12913      * @return {Roo.Element} The element
12914      */
12915     getEl : function(){
12916         return this.el;
12917     },
12918     /**
12919      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12920      * @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:
12921 <pre><code>
12922 um.update({<br/>
12923     url: "your-url.php",<br/>
12924     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12925     callback: yourFunction,<br/>
12926     scope: yourObject, //(optional scope)  <br/>
12927     discardUrl: false, <br/>
12928     nocache: false,<br/>
12929     text: "Loading...",<br/>
12930     timeout: 30,<br/>
12931     scripts: false<br/>
12932 });
12933 </code></pre>
12934      * The only required property is url. The optional properties nocache, text and scripts
12935      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12936      * @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}
12937      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12938      * @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.
12939      */
12940     update : function(url, params, callback, discardUrl){
12941         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12942             var method = this.method,
12943                 cfg;
12944             if(typeof url == "object"){ // must be config object
12945                 cfg = url;
12946                 url = cfg.url;
12947                 params = params || cfg.params;
12948                 callback = callback || cfg.callback;
12949                 discardUrl = discardUrl || cfg.discardUrl;
12950                 if(callback && cfg.scope){
12951                     callback = callback.createDelegate(cfg.scope);
12952                 }
12953                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12954                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12955                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12956                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12957                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12958             }
12959             this.showLoading();
12960             if(!discardUrl){
12961                 this.defaultUrl = url;
12962             }
12963             if(typeof url == "function"){
12964                 url = url.call(this);
12965             }
12966
12967             method = method || (params ? "POST" : "GET");
12968             if(method == "GET"){
12969                 url = this.prepareUrl(url);
12970             }
12971
12972             var o = Roo.apply(cfg ||{}, {
12973                 url : url,
12974                 params: params,
12975                 success: this.successDelegate,
12976                 failure: this.failureDelegate,
12977                 callback: undefined,
12978                 timeout: (this.timeout*1000),
12979                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12980             });
12981             Roo.log("updated manager called with timeout of " + o.timeout);
12982             this.transaction = Roo.Ajax.request(o);
12983         }
12984     },
12985
12986     /**
12987      * 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.
12988      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12989      * @param {String/HTMLElement} form The form Id or form element
12990      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12991      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12992      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12993      */
12994     formUpdate : function(form, url, reset, callback){
12995         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12996             if(typeof url == "function"){
12997                 url = url.call(this);
12998             }
12999             form = Roo.getDom(form);
13000             this.transaction = Roo.Ajax.request({
13001                 form: form,
13002                 url:url,
13003                 success: this.successDelegate,
13004                 failure: this.failureDelegate,
13005                 timeout: (this.timeout*1000),
13006                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13007             });
13008             this.showLoading.defer(1, this);
13009         }
13010     },
13011
13012     /**
13013      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13014      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13015      */
13016     refresh : function(callback){
13017         if(this.defaultUrl == null){
13018             return;
13019         }
13020         this.update(this.defaultUrl, null, callback, true);
13021     },
13022
13023     /**
13024      * Set this element to auto refresh.
13025      * @param {Number} interval How often to update (in seconds).
13026      * @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)
13027      * @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}
13028      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13029      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13030      */
13031     startAutoRefresh : function(interval, url, params, callback, refreshNow){
13032         if(refreshNow){
13033             this.update(url || this.defaultUrl, params, callback, true);
13034         }
13035         if(this.autoRefreshProcId){
13036             clearInterval(this.autoRefreshProcId);
13037         }
13038         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13039     },
13040
13041     /**
13042      * Stop auto refresh on this element.
13043      */
13044      stopAutoRefresh : function(){
13045         if(this.autoRefreshProcId){
13046             clearInterval(this.autoRefreshProcId);
13047             delete this.autoRefreshProcId;
13048         }
13049     },
13050
13051     isAutoRefreshing : function(){
13052        return this.autoRefreshProcId ? true : false;
13053     },
13054     /**
13055      * Called to update the element to "Loading" state. Override to perform custom action.
13056      */
13057     showLoading : function(){
13058         if(this.showLoadIndicator){
13059             this.el.update(this.indicatorText);
13060         }
13061     },
13062
13063     /**
13064      * Adds unique parameter to query string if disableCaching = true
13065      * @private
13066      */
13067     prepareUrl : function(url){
13068         if(this.disableCaching){
13069             var append = "_dc=" + (new Date().getTime());
13070             if(url.indexOf("?") !== -1){
13071                 url += "&" + append;
13072             }else{
13073                 url += "?" + append;
13074             }
13075         }
13076         return url;
13077     },
13078
13079     /**
13080      * @private
13081      */
13082     processSuccess : function(response){
13083         this.transaction = null;
13084         if(response.argument.form && response.argument.reset){
13085             try{ // put in try/catch since some older FF releases had problems with this
13086                 response.argument.form.reset();
13087             }catch(e){}
13088         }
13089         if(this.loadScripts){
13090             this.renderer.render(this.el, response, this,
13091                 this.updateComplete.createDelegate(this, [response]));
13092         }else{
13093             this.renderer.render(this.el, response, this);
13094             this.updateComplete(response);
13095         }
13096     },
13097
13098     updateComplete : function(response){
13099         this.fireEvent("update", this.el, response);
13100         if(typeof response.argument.callback == "function"){
13101             response.argument.callback(this.el, true, response);
13102         }
13103     },
13104
13105     /**
13106      * @private
13107      */
13108     processFailure : function(response){
13109         this.transaction = null;
13110         this.fireEvent("failure", this.el, response);
13111         if(typeof response.argument.callback == "function"){
13112             response.argument.callback(this.el, false, response);
13113         }
13114     },
13115
13116     /**
13117      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13118      * @param {Object} renderer The object implementing the render() method
13119      */
13120     setRenderer : function(renderer){
13121         this.renderer = renderer;
13122     },
13123
13124     getRenderer : function(){
13125        return this.renderer;
13126     },
13127
13128     /**
13129      * Set the defaultUrl used for updates
13130      * @param {String/Function} defaultUrl The url or a function to call to get the url
13131      */
13132     setDefaultUrl : function(defaultUrl){
13133         this.defaultUrl = defaultUrl;
13134     },
13135
13136     /**
13137      * Aborts the executing transaction
13138      */
13139     abort : function(){
13140         if(this.transaction){
13141             Roo.Ajax.abort(this.transaction);
13142         }
13143     },
13144
13145     /**
13146      * Returns true if an update is in progress
13147      * @return {Boolean}
13148      */
13149     isUpdating : function(){
13150         if(this.transaction){
13151             return Roo.Ajax.isLoading(this.transaction);
13152         }
13153         return false;
13154     }
13155 });
13156
13157 /**
13158  * @class Roo.UpdateManager.defaults
13159  * @static (not really - but it helps the doc tool)
13160  * The defaults collection enables customizing the default properties of UpdateManager
13161  */
13162    Roo.UpdateManager.defaults = {
13163        /**
13164          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13165          * @type Number
13166          */
13167          timeout : 30,
13168
13169          /**
13170          * True to process scripts by default (Defaults to false).
13171          * @type Boolean
13172          */
13173         loadScripts : false,
13174
13175         /**
13176         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13177         * @type String
13178         */
13179         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13180         /**
13181          * Whether to append unique parameter on get request to disable caching (Defaults to false).
13182          * @type Boolean
13183          */
13184         disableCaching : false,
13185         /**
13186          * Whether to show indicatorText when loading (Defaults to true).
13187          * @type Boolean
13188          */
13189         showLoadIndicator : true,
13190         /**
13191          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13192          * @type String
13193          */
13194         indicatorText : '<div class="loading-indicator">Loading...</div>'
13195    };
13196
13197 /**
13198  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13199  *Usage:
13200  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13201  * @param {String/HTMLElement/Roo.Element} el The element to update
13202  * @param {String} url The url
13203  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13204  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13205  * @static
13206  * @deprecated
13207  * @member Roo.UpdateManager
13208  */
13209 Roo.UpdateManager.updateElement = function(el, url, params, options){
13210     var um = Roo.get(el, true).getUpdateManager();
13211     Roo.apply(um, options);
13212     um.update(url, params, options ? options.callback : null);
13213 };
13214 // alias for backwards compat
13215 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13216 /**
13217  * @class Roo.UpdateManager.BasicRenderer
13218  * Default Content renderer. Updates the elements innerHTML with the responseText.
13219  */
13220 Roo.UpdateManager.BasicRenderer = function(){};
13221
13222 Roo.UpdateManager.BasicRenderer.prototype = {
13223     /**
13224      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13225      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13226      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13227      * @param {Roo.Element} el The element being rendered
13228      * @param {Object} response The YUI Connect response object
13229      * @param {UpdateManager} updateManager The calling update manager
13230      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13231      */
13232      render : function(el, response, updateManager, callback){
13233         el.update(response.responseText, updateManager.loadScripts, callback);
13234     }
13235 };
13236 /*
13237  * Based on:
13238  * Roo JS
13239  * (c)) Alan Knowles
13240  * Licence : LGPL
13241  */
13242
13243
13244 /**
13245  * @class Roo.DomTemplate
13246  * @extends Roo.Template
13247  * An effort at a dom based template engine..
13248  *
13249  * Similar to XTemplate, except it uses dom parsing to create the template..
13250  *
13251  * Supported features:
13252  *
13253  *  Tags:
13254
13255 <pre><code>
13256       {a_variable} - output encoded.
13257       {a_variable.format:("Y-m-d")} - call a method on the variable
13258       {a_variable:raw} - unencoded output
13259       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13260       {a_variable:this.method_on_template(...)} - call a method on the template object.
13261  
13262 </code></pre>
13263  *  The tpl tag:
13264 <pre><code>
13265         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
13266         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
13267         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
13268         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
13269   
13270 </code></pre>
13271  *      
13272  */
13273 Roo.DomTemplate = function()
13274 {
13275      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13276      if (this.html) {
13277         this.compile();
13278      }
13279 };
13280
13281
13282 Roo.extend(Roo.DomTemplate, Roo.Template, {
13283     /**
13284      * id counter for sub templates.
13285      */
13286     id : 0,
13287     /**
13288      * flag to indicate if dom parser is inside a pre,
13289      * it will strip whitespace if not.
13290      */
13291     inPre : false,
13292     
13293     /**
13294      * The various sub templates
13295      */
13296     tpls : false,
13297     
13298     
13299     
13300     /**
13301      *
13302      * basic tag replacing syntax
13303      * WORD:WORD()
13304      *
13305      * // you can fake an object call by doing this
13306      *  x.t:(test,tesT) 
13307      * 
13308      */
13309     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13310     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13311     
13312     iterChild : function (node, method) {
13313         
13314         var oldPre = this.inPre;
13315         if (node.tagName == 'PRE') {
13316             this.inPre = true;
13317         }
13318         for( var i = 0; i < node.childNodes.length; i++) {
13319             method.call(this, node.childNodes[i]);
13320         }
13321         this.inPre = oldPre;
13322     },
13323     
13324     
13325     
13326     /**
13327      * compile the template
13328      *
13329      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13330      *
13331      */
13332     compile: function()
13333     {
13334         var s = this.html;
13335         
13336         // covert the html into DOM...
13337         var doc = false;
13338         var div =false;
13339         try {
13340             doc = document.implementation.createHTMLDocument("");
13341             doc.documentElement.innerHTML =   this.html  ;
13342             div = doc.documentElement;
13343         } catch (e) {
13344             // old IE... - nasty -- it causes all sorts of issues.. with
13345             // images getting pulled from server..
13346             div = document.createElement('div');
13347             div.innerHTML = this.html;
13348         }
13349         //doc.documentElement.innerHTML = htmlBody
13350          
13351         
13352         
13353         this.tpls = [];
13354         var _t = this;
13355         this.iterChild(div, function(n) {_t.compileNode(n, true); });
13356         
13357         var tpls = this.tpls;
13358         
13359         // create a top level template from the snippet..
13360         
13361         //Roo.log(div.innerHTML);
13362         
13363         var tpl = {
13364             uid : 'master',
13365             id : this.id++,
13366             attr : false,
13367             value : false,
13368             body : div.innerHTML,
13369             
13370             forCall : false,
13371             execCall : false,
13372             dom : div,
13373             isTop : true
13374             
13375         };
13376         tpls.unshift(tpl);
13377         
13378         
13379         // compile them...
13380         this.tpls = [];
13381         Roo.each(tpls, function(tp){
13382             this.compileTpl(tp);
13383             this.tpls[tp.id] = tp;
13384         }, this);
13385         
13386         this.master = tpls[0];
13387         return this;
13388         
13389         
13390     },
13391     
13392     compileNode : function(node, istop) {
13393         // test for
13394         //Roo.log(node);
13395         
13396         
13397         // skip anything not a tag..
13398         if (node.nodeType != 1) {
13399             if (node.nodeType == 3 && !this.inPre) {
13400                 // reduce white space..
13401                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
13402                 
13403             }
13404             return;
13405         }
13406         
13407         var tpl = {
13408             uid : false,
13409             id : false,
13410             attr : false,
13411             value : false,
13412             body : '',
13413             
13414             forCall : false,
13415             execCall : false,
13416             dom : false,
13417             isTop : istop
13418             
13419             
13420         };
13421         
13422         
13423         switch(true) {
13424             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13425             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13426             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13427             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13428             // no default..
13429         }
13430         
13431         
13432         if (!tpl.attr) {
13433             // just itterate children..
13434             this.iterChild(node,this.compileNode);
13435             return;
13436         }
13437         tpl.uid = this.id++;
13438         tpl.value = node.getAttribute('roo-' +  tpl.attr);
13439         node.removeAttribute('roo-'+ tpl.attr);
13440         if (tpl.attr != 'name') {
13441             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13442             node.parentNode.replaceChild(placeholder,  node);
13443         } else {
13444             
13445             var placeholder =  document.createElement('span');
13446             placeholder.className = 'roo-tpl-' + tpl.value;
13447             node.parentNode.replaceChild(placeholder,  node);
13448         }
13449         
13450         // parent now sees '{domtplXXXX}
13451         this.iterChild(node,this.compileNode);
13452         
13453         // we should now have node body...
13454         var div = document.createElement('div');
13455         div.appendChild(node);
13456         tpl.dom = node;
13457         // this has the unfortunate side effect of converting tagged attributes
13458         // eg. href="{...}" into %7C...%7D
13459         // this has been fixed by searching for those combo's although it's a bit hacky..
13460         
13461         
13462         tpl.body = div.innerHTML;
13463         
13464         
13465          
13466         tpl.id = tpl.uid;
13467         switch(tpl.attr) {
13468             case 'for' :
13469                 switch (tpl.value) {
13470                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13471                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13472                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13473                 }
13474                 break;
13475             
13476             case 'exec':
13477                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13478                 break;
13479             
13480             case 'if':     
13481                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13482                 break;
13483             
13484             case 'name':
13485                 tpl.id  = tpl.value; // replace non characters???
13486                 break;
13487             
13488         }
13489         
13490         
13491         this.tpls.push(tpl);
13492         
13493         
13494         
13495     },
13496     
13497     
13498     
13499     
13500     /**
13501      * Compile a segment of the template into a 'sub-template'
13502      *
13503      * 
13504      * 
13505      *
13506      */
13507     compileTpl : function(tpl)
13508     {
13509         var fm = Roo.util.Format;
13510         var useF = this.disableFormats !== true;
13511         
13512         var sep = Roo.isGecko ? "+\n" : ",\n";
13513         
13514         var undef = function(str) {
13515             Roo.debug && Roo.log("Property not found :"  + str);
13516             return '';
13517         };
13518           
13519         //Roo.log(tpl.body);
13520         
13521         
13522         
13523         var fn = function(m, lbrace, name, format, args)
13524         {
13525             //Roo.log("ARGS");
13526             //Roo.log(arguments);
13527             args = args ? args.replace(/\\'/g,"'") : args;
13528             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13529             if (typeof(format) == 'undefined') {
13530                 format =  'htmlEncode'; 
13531             }
13532             if (format == 'raw' ) {
13533                 format = false;
13534             }
13535             
13536             if(name.substr(0, 6) == 'domtpl'){
13537                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13538             }
13539             
13540             // build an array of options to determine if value is undefined..
13541             
13542             // basically get 'xxxx.yyyy' then do
13543             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13544             //    (function () { Roo.log("Property not found"); return ''; })() :
13545             //    ......
13546             
13547             var udef_ar = [];
13548             var lookfor = '';
13549             Roo.each(name.split('.'), function(st) {
13550                 lookfor += (lookfor.length ? '.': '') + st;
13551                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
13552             });
13553             
13554             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13555             
13556             
13557             if(format && useF){
13558                 
13559                 args = args ? ',' + args : "";
13560                  
13561                 if(format.substr(0, 5) != "this."){
13562                     format = "fm." + format + '(';
13563                 }else{
13564                     format = 'this.call("'+ format.substr(5) + '", ';
13565                     args = ", values";
13566                 }
13567                 
13568                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
13569             }
13570              
13571             if (args && args.length) {
13572                 // called with xxyx.yuu:(test,test)
13573                 // change to ()
13574                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
13575             }
13576             // raw.. - :raw modifier..
13577             return "'"+ sep + udef_st  + name + ")"+sep+"'";
13578             
13579         };
13580         var body;
13581         // branched to use + in gecko and [].join() in others
13582         if(Roo.isGecko){
13583             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
13584                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13585                     "';};};";
13586         }else{
13587             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
13588             body.push(tpl.body.replace(/(\r\n|\n)/g,
13589                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13590             body.push("'].join('');};};");
13591             body = body.join('');
13592         }
13593         
13594         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13595        
13596         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
13597         eval(body);
13598         
13599         return this;
13600     },
13601      
13602     /**
13603      * same as applyTemplate, except it's done to one of the subTemplates
13604      * when using named templates, you can do:
13605      *
13606      * var str = pl.applySubTemplate('your-name', values);
13607      *
13608      * 
13609      * @param {Number} id of the template
13610      * @param {Object} values to apply to template
13611      * @param {Object} parent (normaly the instance of this object)
13612      */
13613     applySubTemplate : function(id, values, parent)
13614     {
13615         
13616         
13617         var t = this.tpls[id];
13618         
13619         
13620         try { 
13621             if(t.ifCall && !t.ifCall.call(this, values, parent)){
13622                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
13623                 return '';
13624             }
13625         } catch(e) {
13626             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
13627             Roo.log(values);
13628           
13629             return '';
13630         }
13631         try { 
13632             
13633             if(t.execCall && t.execCall.call(this, values, parent)){
13634                 return '';
13635             }
13636         } catch(e) {
13637             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13638             Roo.log(values);
13639             return '';
13640         }
13641         
13642         try {
13643             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
13644             parent = t.target ? values : parent;
13645             if(t.forCall && vs instanceof Array){
13646                 var buf = [];
13647                 for(var i = 0, len = vs.length; i < len; i++){
13648                     try {
13649                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
13650                     } catch (e) {
13651                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13652                         Roo.log(e.body);
13653                         //Roo.log(t.compiled);
13654                         Roo.log(vs[i]);
13655                     }   
13656                 }
13657                 return buf.join('');
13658             }
13659         } catch (e) {
13660             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13661             Roo.log(values);
13662             return '';
13663         }
13664         try {
13665             return t.compiled.call(this, vs, parent);
13666         } catch (e) {
13667             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13668             Roo.log(e.body);
13669             //Roo.log(t.compiled);
13670             Roo.log(values);
13671             return '';
13672         }
13673     },
13674
13675    
13676
13677     applyTemplate : function(values){
13678         return this.master.compiled.call(this, values, {});
13679         //var s = this.subs;
13680     },
13681
13682     apply : function(){
13683         return this.applyTemplate.apply(this, arguments);
13684     }
13685
13686  });
13687
13688 Roo.DomTemplate.from = function(el){
13689     el = Roo.getDom(el);
13690     return new Roo.Domtemplate(el.value || el.innerHTML);
13691 };/*
13692  * Based on:
13693  * Ext JS Library 1.1.1
13694  * Copyright(c) 2006-2007, Ext JS, LLC.
13695  *
13696  * Originally Released Under LGPL - original licence link has changed is not relivant.
13697  *
13698  * Fork - LGPL
13699  * <script type="text/javascript">
13700  */
13701
13702 /**
13703  * @class Roo.util.DelayedTask
13704  * Provides a convenient method of performing setTimeout where a new
13705  * timeout cancels the old timeout. An example would be performing validation on a keypress.
13706  * You can use this class to buffer
13707  * the keypress events for a certain number of milliseconds, and perform only if they stop
13708  * for that amount of time.
13709  * @constructor The parameters to this constructor serve as defaults and are not required.
13710  * @param {Function} fn (optional) The default function to timeout
13711  * @param {Object} scope (optional) The default scope of that timeout
13712  * @param {Array} args (optional) The default Array of arguments
13713  */
13714 Roo.util.DelayedTask = function(fn, scope, args){
13715     var id = null, d, t;
13716
13717     var call = function(){
13718         var now = new Date().getTime();
13719         if(now - t >= d){
13720             clearInterval(id);
13721             id = null;
13722             fn.apply(scope, args || []);
13723         }
13724     };
13725     /**
13726      * Cancels any pending timeout and queues a new one
13727      * @param {Number} delay The milliseconds to delay
13728      * @param {Function} newFn (optional) Overrides function passed to constructor
13729      * @param {Object} newScope (optional) Overrides scope passed to constructor
13730      * @param {Array} newArgs (optional) Overrides args passed to constructor
13731      */
13732     this.delay = function(delay, newFn, newScope, newArgs){
13733         if(id && delay != d){
13734             this.cancel();
13735         }
13736         d = delay;
13737         t = new Date().getTime();
13738         fn = newFn || fn;
13739         scope = newScope || scope;
13740         args = newArgs || args;
13741         if(!id){
13742             id = setInterval(call, d);
13743         }
13744     };
13745
13746     /**
13747      * Cancel the last queued timeout
13748      */
13749     this.cancel = function(){
13750         if(id){
13751             clearInterval(id);
13752             id = null;
13753         }
13754     };
13755 };/*
13756  * Based on:
13757  * Ext JS Library 1.1.1
13758  * Copyright(c) 2006-2007, Ext JS, LLC.
13759  *
13760  * Originally Released Under LGPL - original licence link has changed is not relivant.
13761  *
13762  * Fork - LGPL
13763  * <script type="text/javascript">
13764  */
13765 /**
13766  * @class Roo.util.TaskRunner
13767  * Manage background tasks - not sure why this is better that setInterval?
13768  * @static
13769  *
13770  */
13771  
13772 Roo.util.TaskRunner = function(interval){
13773     interval = interval || 10;
13774     var tasks = [], removeQueue = [];
13775     var id = 0;
13776     var running = false;
13777
13778     var stopThread = function(){
13779         running = false;
13780         clearInterval(id);
13781         id = 0;
13782     };
13783
13784     var startThread = function(){
13785         if(!running){
13786             running = true;
13787             id = setInterval(runTasks, interval);
13788         }
13789     };
13790
13791     var removeTask = function(task){
13792         removeQueue.push(task);
13793         if(task.onStop){
13794             task.onStop();
13795         }
13796     };
13797
13798     var runTasks = function(){
13799         if(removeQueue.length > 0){
13800             for(var i = 0, len = removeQueue.length; i < len; i++){
13801                 tasks.remove(removeQueue[i]);
13802             }
13803             removeQueue = [];
13804             if(tasks.length < 1){
13805                 stopThread();
13806                 return;
13807             }
13808         }
13809         var now = new Date().getTime();
13810         for(var i = 0, len = tasks.length; i < len; ++i){
13811             var t = tasks[i];
13812             var itime = now - t.taskRunTime;
13813             if(t.interval <= itime){
13814                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13815                 t.taskRunTime = now;
13816                 if(rt === false || t.taskRunCount === t.repeat){
13817                     removeTask(t);
13818                     return;
13819                 }
13820             }
13821             if(t.duration && t.duration <= (now - t.taskStartTime)){
13822                 removeTask(t);
13823             }
13824         }
13825     };
13826
13827     /**
13828      * Queues a new task.
13829      * @param {Object} task
13830      *
13831      * Task property : interval = how frequent to run.
13832      * Task object should implement
13833      * function run()
13834      * Task object may implement
13835      * function onStop()
13836      */
13837     this.start = function(task){
13838         tasks.push(task);
13839         task.taskStartTime = new Date().getTime();
13840         task.taskRunTime = 0;
13841         task.taskRunCount = 0;
13842         startThread();
13843         return task;
13844     };
13845     /**
13846      * Stop  new task.
13847      * @param {Object} task
13848      */
13849     this.stop = function(task){
13850         removeTask(task);
13851         return task;
13852     };
13853     /**
13854      * Stop all Tasks
13855      */
13856     this.stopAll = function(){
13857         stopThread();
13858         for(var i = 0, len = tasks.length; i < len; i++){
13859             if(tasks[i].onStop){
13860                 tasks[i].onStop();
13861             }
13862         }
13863         tasks = [];
13864         removeQueue = [];
13865     };
13866 };
13867
13868 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13869  * Based on:
13870  * Ext JS Library 1.1.1
13871  * Copyright(c) 2006-2007, Ext JS, LLC.
13872  *
13873  * Originally Released Under LGPL - original licence link has changed is not relivant.
13874  *
13875  * Fork - LGPL
13876  * <script type="text/javascript">
13877  */
13878
13879  
13880 /**
13881  * @class Roo.util.MixedCollection
13882  * @extends Roo.util.Observable
13883  * A Collection class that maintains both numeric indexes and keys and exposes events.
13884  * @constructor
13885  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13886  * collection (defaults to false)
13887  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13888  * and return the key value for that item.  This is used when available to look up the key on items that
13889  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
13890  * equivalent to providing an implementation for the {@link #getKey} method.
13891  */
13892 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13893     this.items = [];
13894     this.map = {};
13895     this.keys = [];
13896     this.length = 0;
13897     this.addEvents({
13898         /**
13899          * @event clear
13900          * Fires when the collection is cleared.
13901          */
13902         "clear" : true,
13903         /**
13904          * @event add
13905          * Fires when an item is added to the collection.
13906          * @param {Number} index The index at which the item was added.
13907          * @param {Object} o The item added.
13908          * @param {String} key The key associated with the added item.
13909          */
13910         "add" : true,
13911         /**
13912          * @event replace
13913          * Fires when an item is replaced in the collection.
13914          * @param {String} key he key associated with the new added.
13915          * @param {Object} old The item being replaced.
13916          * @param {Object} new The new item.
13917          */
13918         "replace" : true,
13919         /**
13920          * @event remove
13921          * Fires when an item is removed from the collection.
13922          * @param {Object} o The item being removed.
13923          * @param {String} key (optional) The key associated with the removed item.
13924          */
13925         "remove" : true,
13926         "sort" : true
13927     });
13928     this.allowFunctions = allowFunctions === true;
13929     if(keyFn){
13930         this.getKey = keyFn;
13931     }
13932     Roo.util.MixedCollection.superclass.constructor.call(this);
13933 };
13934
13935 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13936     allowFunctions : false,
13937     
13938 /**
13939  * Adds an item to the collection.
13940  * @param {String} key The key to associate with the item
13941  * @param {Object} o The item to add.
13942  * @return {Object} The item added.
13943  */
13944     add : function(key, o){
13945         if(arguments.length == 1){
13946             o = arguments[0];
13947             key = this.getKey(o);
13948         }
13949         if(typeof key == "undefined" || key === null){
13950             this.length++;
13951             this.items.push(o);
13952             this.keys.push(null);
13953         }else{
13954             var old = this.map[key];
13955             if(old){
13956                 return this.replace(key, o);
13957             }
13958             this.length++;
13959             this.items.push(o);
13960             this.map[key] = o;
13961             this.keys.push(key);
13962         }
13963         this.fireEvent("add", this.length-1, o, key);
13964         return o;
13965     },
13966        
13967 /**
13968   * MixedCollection has a generic way to fetch keys if you implement getKey.
13969 <pre><code>
13970 // normal way
13971 var mc = new Roo.util.MixedCollection();
13972 mc.add(someEl.dom.id, someEl);
13973 mc.add(otherEl.dom.id, otherEl);
13974 //and so on
13975
13976 // using getKey
13977 var mc = new Roo.util.MixedCollection();
13978 mc.getKey = function(el){
13979    return el.dom.id;
13980 };
13981 mc.add(someEl);
13982 mc.add(otherEl);
13983
13984 // or via the constructor
13985 var mc = new Roo.util.MixedCollection(false, function(el){
13986    return el.dom.id;
13987 });
13988 mc.add(someEl);
13989 mc.add(otherEl);
13990 </code></pre>
13991  * @param o {Object} The item for which to find the key.
13992  * @return {Object} The key for the passed item.
13993  */
13994     getKey : function(o){
13995          return o.id; 
13996     },
13997    
13998 /**
13999  * Replaces an item in the collection.
14000  * @param {String} key The key associated with the item to replace, or the item to replace.
14001  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14002  * @return {Object}  The new item.
14003  */
14004     replace : function(key, o){
14005         if(arguments.length == 1){
14006             o = arguments[0];
14007             key = this.getKey(o);
14008         }
14009         var old = this.item(key);
14010         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14011              return this.add(key, o);
14012         }
14013         var index = this.indexOfKey(key);
14014         this.items[index] = o;
14015         this.map[key] = o;
14016         this.fireEvent("replace", key, old, o);
14017         return o;
14018     },
14019    
14020 /**
14021  * Adds all elements of an Array or an Object to the collection.
14022  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14023  * an Array of values, each of which are added to the collection.
14024  */
14025     addAll : function(objs){
14026         if(arguments.length > 1 || objs instanceof Array){
14027             var args = arguments.length > 1 ? arguments : objs;
14028             for(var i = 0, len = args.length; i < len; i++){
14029                 this.add(args[i]);
14030             }
14031         }else{
14032             for(var key in objs){
14033                 if(this.allowFunctions || typeof objs[key] != "function"){
14034                     this.add(key, objs[key]);
14035                 }
14036             }
14037         }
14038     },
14039    
14040 /**
14041  * Executes the specified function once for every item in the collection, passing each
14042  * item as the first and only parameter. returning false from the function will stop the iteration.
14043  * @param {Function} fn The function to execute for each item.
14044  * @param {Object} scope (optional) The scope in which to execute the function.
14045  */
14046     each : function(fn, scope){
14047         var items = [].concat(this.items); // each safe for removal
14048         for(var i = 0, len = items.length; i < len; i++){
14049             if(fn.call(scope || items[i], items[i], i, len) === false){
14050                 break;
14051             }
14052         }
14053     },
14054    
14055 /**
14056  * Executes the specified function once for every key in the collection, passing each
14057  * key, and its associated item as the first two parameters.
14058  * @param {Function} fn The function to execute for each item.
14059  * @param {Object} scope (optional) The scope in which to execute the function.
14060  */
14061     eachKey : function(fn, scope){
14062         for(var i = 0, len = this.keys.length; i < len; i++){
14063             fn.call(scope || window, this.keys[i], this.items[i], i, len);
14064         }
14065     },
14066    
14067 /**
14068  * Returns the first item in the collection which elicits a true return value from the
14069  * passed selection function.
14070  * @param {Function} fn The selection function to execute for each item.
14071  * @param {Object} scope (optional) The scope in which to execute the function.
14072  * @return {Object} The first item in the collection which returned true from the selection function.
14073  */
14074     find : function(fn, scope){
14075         for(var i = 0, len = this.items.length; i < len; i++){
14076             if(fn.call(scope || window, this.items[i], this.keys[i])){
14077                 return this.items[i];
14078             }
14079         }
14080         return null;
14081     },
14082    
14083 /**
14084  * Inserts an item at the specified index in the collection.
14085  * @param {Number} index The index to insert the item at.
14086  * @param {String} key The key to associate with the new item, or the item itself.
14087  * @param {Object} o  (optional) If the second parameter was a key, the new item.
14088  * @return {Object} The item inserted.
14089  */
14090     insert : function(index, key, o){
14091         if(arguments.length == 2){
14092             o = arguments[1];
14093             key = this.getKey(o);
14094         }
14095         if(index >= this.length){
14096             return this.add(key, o);
14097         }
14098         this.length++;
14099         this.items.splice(index, 0, o);
14100         if(typeof key != "undefined" && key != null){
14101             this.map[key] = o;
14102         }
14103         this.keys.splice(index, 0, key);
14104         this.fireEvent("add", index, o, key);
14105         return o;
14106     },
14107    
14108 /**
14109  * Removed an item from the collection.
14110  * @param {Object} o The item to remove.
14111  * @return {Object} The item removed.
14112  */
14113     remove : function(o){
14114         return this.removeAt(this.indexOf(o));
14115     },
14116    
14117 /**
14118  * Remove an item from a specified index in the collection.
14119  * @param {Number} index The index within the collection of the item to remove.
14120  */
14121     removeAt : function(index){
14122         if(index < this.length && index >= 0){
14123             this.length--;
14124             var o = this.items[index];
14125             this.items.splice(index, 1);
14126             var key = this.keys[index];
14127             if(typeof key != "undefined"){
14128                 delete this.map[key];
14129             }
14130             this.keys.splice(index, 1);
14131             this.fireEvent("remove", o, key);
14132         }
14133     },
14134    
14135 /**
14136  * Removed an item associated with the passed key fom the collection.
14137  * @param {String} key The key of the item to remove.
14138  */
14139     removeKey : function(key){
14140         return this.removeAt(this.indexOfKey(key));
14141     },
14142    
14143 /**
14144  * Returns the number of items in the collection.
14145  * @return {Number} the number of items in the collection.
14146  */
14147     getCount : function(){
14148         return this.length; 
14149     },
14150    
14151 /**
14152  * Returns index within the collection of the passed Object.
14153  * @param {Object} o The item to find the index of.
14154  * @return {Number} index of the item.
14155  */
14156     indexOf : function(o){
14157         if(!this.items.indexOf){
14158             for(var i = 0, len = this.items.length; i < len; i++){
14159                 if(this.items[i] == o) {
14160                     return i;
14161                 }
14162             }
14163             return -1;
14164         }else{
14165             return this.items.indexOf(o);
14166         }
14167     },
14168    
14169 /**
14170  * Returns index within the collection of the passed key.
14171  * @param {String} key The key to find the index of.
14172  * @return {Number} index of the key.
14173  */
14174     indexOfKey : function(key){
14175         if(!this.keys.indexOf){
14176             for(var i = 0, len = this.keys.length; i < len; i++){
14177                 if(this.keys[i] == key) {
14178                     return i;
14179                 }
14180             }
14181             return -1;
14182         }else{
14183             return this.keys.indexOf(key);
14184         }
14185     },
14186    
14187 /**
14188  * Returns the item associated with the passed key OR index. Key has priority over index.
14189  * @param {String/Number} key The key or index of the item.
14190  * @return {Object} The item associated with the passed key.
14191  */
14192     item : function(key){
14193         if (key === 'length') {
14194             return null;
14195         }
14196         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14197         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14198     },
14199     
14200 /**
14201  * Returns the item at the specified index.
14202  * @param {Number} index The index of the item.
14203  * @return {Object}
14204  */
14205     itemAt : function(index){
14206         return this.items[index];
14207     },
14208     
14209 /**
14210  * Returns the item associated with the passed key.
14211  * @param {String/Number} key The key of the item.
14212  * @return {Object} The item associated with the passed key.
14213  */
14214     key : function(key){
14215         return this.map[key];
14216     },
14217    
14218 /**
14219  * Returns true if the collection contains the passed Object as an item.
14220  * @param {Object} o  The Object to look for in the collection.
14221  * @return {Boolean} True if the collection contains the Object as an item.
14222  */
14223     contains : function(o){
14224         return this.indexOf(o) != -1;
14225     },
14226    
14227 /**
14228  * Returns true if the collection contains the passed Object as a key.
14229  * @param {String} key The key to look for in the collection.
14230  * @return {Boolean} True if the collection contains the Object as a key.
14231  */
14232     containsKey : function(key){
14233         return typeof this.map[key] != "undefined";
14234     },
14235    
14236 /**
14237  * Removes all items from the collection.
14238  */
14239     clear : function(){
14240         this.length = 0;
14241         this.items = [];
14242         this.keys = [];
14243         this.map = {};
14244         this.fireEvent("clear");
14245     },
14246    
14247 /**
14248  * Returns the first item in the collection.
14249  * @return {Object} the first item in the collection..
14250  */
14251     first : function(){
14252         return this.items[0]; 
14253     },
14254    
14255 /**
14256  * Returns the last item in the collection.
14257  * @return {Object} the last item in the collection..
14258  */
14259     last : function(){
14260         return this.items[this.length-1];   
14261     },
14262     
14263     _sort : function(property, dir, fn){
14264         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14265         fn = fn || function(a, b){
14266             return a-b;
14267         };
14268         var c = [], k = this.keys, items = this.items;
14269         for(var i = 0, len = items.length; i < len; i++){
14270             c[c.length] = {key: k[i], value: items[i], index: i};
14271         }
14272         c.sort(function(a, b){
14273             var v = fn(a[property], b[property]) * dsc;
14274             if(v == 0){
14275                 v = (a.index < b.index ? -1 : 1);
14276             }
14277             return v;
14278         });
14279         for(var i = 0, len = c.length; i < len; i++){
14280             items[i] = c[i].value;
14281             k[i] = c[i].key;
14282         }
14283         this.fireEvent("sort", this);
14284     },
14285     
14286     /**
14287      * Sorts this collection with the passed comparison function
14288      * @param {String} direction (optional) "ASC" or "DESC"
14289      * @param {Function} fn (optional) comparison function
14290      */
14291     sort : function(dir, fn){
14292         this._sort("value", dir, fn);
14293     },
14294     
14295     /**
14296      * Sorts this collection by keys
14297      * @param {String} direction (optional) "ASC" or "DESC"
14298      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14299      */
14300     keySort : function(dir, fn){
14301         this._sort("key", dir, fn || function(a, b){
14302             return String(a).toUpperCase()-String(b).toUpperCase();
14303         });
14304     },
14305     
14306     /**
14307      * Returns a range of items in this collection
14308      * @param {Number} startIndex (optional) defaults to 0
14309      * @param {Number} endIndex (optional) default to the last item
14310      * @return {Array} An array of items
14311      */
14312     getRange : function(start, end){
14313         var items = this.items;
14314         if(items.length < 1){
14315             return [];
14316         }
14317         start = start || 0;
14318         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14319         var r = [];
14320         if(start <= end){
14321             for(var i = start; i <= end; i++) {
14322                     r[r.length] = items[i];
14323             }
14324         }else{
14325             for(var i = start; i >= end; i--) {
14326                     r[r.length] = items[i];
14327             }
14328         }
14329         return r;
14330     },
14331         
14332     /**
14333      * Filter the <i>objects</i> in this collection by a specific property. 
14334      * Returns a new collection that has been filtered.
14335      * @param {String} property A property on your objects
14336      * @param {String/RegExp} value Either string that the property values 
14337      * should start with or a RegExp to test against the property
14338      * @return {MixedCollection} The new filtered collection
14339      */
14340     filter : function(property, value){
14341         if(!value.exec){ // not a regex
14342             value = String(value);
14343             if(value.length == 0){
14344                 return this.clone();
14345             }
14346             value = new RegExp("^" + Roo.escapeRe(value), "i");
14347         }
14348         return this.filterBy(function(o){
14349             return o && value.test(o[property]);
14350         });
14351         },
14352     
14353     /**
14354      * Filter by a function. * Returns a new collection that has been filtered.
14355      * The passed function will be called with each 
14356      * object in the collection. If the function returns true, the value is included 
14357      * otherwise it is filtered.
14358      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14359      * @param {Object} scope (optional) The scope of the function (defaults to this) 
14360      * @return {MixedCollection} The new filtered collection
14361      */
14362     filterBy : function(fn, scope){
14363         var r = new Roo.util.MixedCollection();
14364         r.getKey = this.getKey;
14365         var k = this.keys, it = this.items;
14366         for(var i = 0, len = it.length; i < len; i++){
14367             if(fn.call(scope||this, it[i], k[i])){
14368                                 r.add(k[i], it[i]);
14369                         }
14370         }
14371         return r;
14372     },
14373     
14374     /**
14375      * Creates a duplicate of this collection
14376      * @return {MixedCollection}
14377      */
14378     clone : function(){
14379         var r = new Roo.util.MixedCollection();
14380         var k = this.keys, it = this.items;
14381         for(var i = 0, len = it.length; i < len; i++){
14382             r.add(k[i], it[i]);
14383         }
14384         r.getKey = this.getKey;
14385         return r;
14386     }
14387 });
14388 /**
14389  * Returns the item associated with the passed key or index.
14390  * @method
14391  * @param {String/Number} key The key or index of the item.
14392  * @return {Object} The item associated with the passed key.
14393  */
14394 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14395  * Based on:
14396  * Ext JS Library 1.1.1
14397  * Copyright(c) 2006-2007, Ext JS, LLC.
14398  *
14399  * Originally Released Under LGPL - original licence link has changed is not relivant.
14400  *
14401  * Fork - LGPL
14402  * <script type="text/javascript">
14403  */
14404 /**
14405  * @class Roo.util.JSON
14406  * Modified version of Douglas Crockford"s json.js that doesn"t
14407  * mess with the Object prototype 
14408  * http://www.json.org/js.html
14409  * @static
14410  */
14411 Roo.util.JSON = new (function(){
14412     var useHasOwn = {}.hasOwnProperty ? true : false;
14413     
14414     // crashes Safari in some instances
14415     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14416     
14417     var pad = function(n) {
14418         return n < 10 ? "0" + n : n;
14419     };
14420     
14421     var m = {
14422         "\b": '\\b',
14423         "\t": '\\t',
14424         "\n": '\\n',
14425         "\f": '\\f',
14426         "\r": '\\r',
14427         '"' : '\\"',
14428         "\\": '\\\\'
14429     };
14430
14431     var encodeString = function(s){
14432         if (/["\\\x00-\x1f]/.test(s)) {
14433             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14434                 var c = m[b];
14435                 if(c){
14436                     return c;
14437                 }
14438                 c = b.charCodeAt();
14439                 return "\\u00" +
14440                     Math.floor(c / 16).toString(16) +
14441                     (c % 16).toString(16);
14442             }) + '"';
14443         }
14444         return '"' + s + '"';
14445     };
14446     
14447     var encodeArray = function(o){
14448         var a = ["["], b, i, l = o.length, v;
14449             for (i = 0; i < l; i += 1) {
14450                 v = o[i];
14451                 switch (typeof v) {
14452                     case "undefined":
14453                     case "function":
14454                     case "unknown":
14455                         break;
14456                     default:
14457                         if (b) {
14458                             a.push(',');
14459                         }
14460                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14461                         b = true;
14462                 }
14463             }
14464             a.push("]");
14465             return a.join("");
14466     };
14467     
14468     var encodeDate = function(o){
14469         return '"' + o.getFullYear() + "-" +
14470                 pad(o.getMonth() + 1) + "-" +
14471                 pad(o.getDate()) + "T" +
14472                 pad(o.getHours()) + ":" +
14473                 pad(o.getMinutes()) + ":" +
14474                 pad(o.getSeconds()) + '"';
14475     };
14476     
14477     /**
14478      * Encodes an Object, Array or other value
14479      * @param {Mixed} o The variable to encode
14480      * @return {String} The JSON string
14481      */
14482     this.encode = function(o)
14483     {
14484         // should this be extended to fully wrap stringify..
14485         
14486         if(typeof o == "undefined" || o === null){
14487             return "null";
14488         }else if(o instanceof Array){
14489             return encodeArray(o);
14490         }else if(o instanceof Date){
14491             return encodeDate(o);
14492         }else if(typeof o == "string"){
14493             return encodeString(o);
14494         }else if(typeof o == "number"){
14495             return isFinite(o) ? String(o) : "null";
14496         }else if(typeof o == "boolean"){
14497             return String(o);
14498         }else {
14499             var a = ["{"], b, i, v;
14500             for (i in o) {
14501                 if(!useHasOwn || o.hasOwnProperty(i)) {
14502                     v = o[i];
14503                     switch (typeof v) {
14504                     case "undefined":
14505                     case "function":
14506                     case "unknown":
14507                         break;
14508                     default:
14509                         if(b){
14510                             a.push(',');
14511                         }
14512                         a.push(this.encode(i), ":",
14513                                 v === null ? "null" : this.encode(v));
14514                         b = true;
14515                     }
14516                 }
14517             }
14518             a.push("}");
14519             return a.join("");
14520         }
14521     };
14522     
14523     /**
14524      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14525      * @param {String} json The JSON string
14526      * @return {Object} The resulting object
14527      */
14528     this.decode = function(json){
14529         
14530         return  /** eval:var:json */ eval("(" + json + ')');
14531     };
14532 })();
14533 /** 
14534  * Shorthand for {@link Roo.util.JSON#encode}
14535  * @member Roo encode 
14536  * @method */
14537 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14538 /** 
14539  * Shorthand for {@link Roo.util.JSON#decode}
14540  * @member Roo decode 
14541  * @method */
14542 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14543 /*
14544  * Based on:
14545  * Ext JS Library 1.1.1
14546  * Copyright(c) 2006-2007, Ext JS, LLC.
14547  *
14548  * Originally Released Under LGPL - original licence link has changed is not relivant.
14549  *
14550  * Fork - LGPL
14551  * <script type="text/javascript">
14552  */
14553  
14554 /**
14555  * @class Roo.util.Format
14556  * Reusable data formatting functions
14557  * @static
14558  */
14559 Roo.util.Format = function(){
14560     var trimRe = /^\s+|\s+$/g;
14561     return {
14562         /**
14563          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14564          * @param {String} value The string to truncate
14565          * @param {Number} length The maximum length to allow before truncating
14566          * @return {String} The converted text
14567          */
14568         ellipsis : function(value, len){
14569             if(value && value.length > len){
14570                 return value.substr(0, len-3)+"...";
14571             }
14572             return value;
14573         },
14574
14575         /**
14576          * Checks a reference and converts it to empty string if it is undefined
14577          * @param {Mixed} value Reference to check
14578          * @return {Mixed} Empty string if converted, otherwise the original value
14579          */
14580         undef : function(value){
14581             return typeof value != "undefined" ? value : "";
14582         },
14583
14584         /**
14585          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14586          * @param {String} value The string to encode
14587          * @return {String} The encoded text
14588          */
14589         htmlEncode : function(value){
14590             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
14591         },
14592
14593         /**
14594          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14595          * @param {String} value The string to decode
14596          * @return {String} The decoded text
14597          */
14598         htmlDecode : function(value){
14599             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
14600         },
14601
14602         /**
14603          * Trims any whitespace from either side of a string
14604          * @param {String} value The text to trim
14605          * @return {String} The trimmed text
14606          */
14607         trim : function(value){
14608             return String(value).replace(trimRe, "");
14609         },
14610
14611         /**
14612          * Returns a substring from within an original string
14613          * @param {String} value The original text
14614          * @param {Number} start The start index of the substring
14615          * @param {Number} length The length of the substring
14616          * @return {String} The substring
14617          */
14618         substr : function(value, start, length){
14619             return String(value).substr(start, length);
14620         },
14621
14622         /**
14623          * Converts a string to all lower case letters
14624          * @param {String} value The text to convert
14625          * @return {String} The converted text
14626          */
14627         lowercase : function(value){
14628             return String(value).toLowerCase();
14629         },
14630
14631         /**
14632          * Converts a string to all upper case letters
14633          * @param {String} value The text to convert
14634          * @return {String} The converted text
14635          */
14636         uppercase : function(value){
14637             return String(value).toUpperCase();
14638         },
14639
14640         /**
14641          * Converts the first character only of a string to upper case
14642          * @param {String} value The text to convert
14643          * @return {String} The converted text
14644          */
14645         capitalize : function(value){
14646             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
14647         },
14648
14649         // private
14650         call : function(value, fn){
14651             if(arguments.length > 2){
14652                 var args = Array.prototype.slice.call(arguments, 2);
14653                 args.unshift(value);
14654                  
14655                 return /** eval:var:value */  eval(fn).apply(window, args);
14656             }else{
14657                 /** eval:var:value */
14658                 return /** eval:var:value */ eval(fn).call(window, value);
14659             }
14660         },
14661
14662        
14663         /**
14664          * safer version of Math.toFixed..??/
14665          * @param {Number/String} value The numeric value to format
14666          * @param {Number/String} value Decimal places 
14667          * @return {String} The formatted currency string
14668          */
14669         toFixed : function(v, n)
14670         {
14671             // why not use to fixed - precision is buggered???
14672             if (!n) {
14673                 return Math.round(v-0);
14674             }
14675             var fact = Math.pow(10,n+1);
14676             v = (Math.round((v-0)*fact))/fact;
14677             var z = (''+fact).substring(2);
14678             if (v == Math.floor(v)) {
14679                 return Math.floor(v) + '.' + z;
14680             }
14681             
14682             // now just padd decimals..
14683             var ps = String(v).split('.');
14684             var fd = (ps[1] + z);
14685             var r = fd.substring(0,n); 
14686             var rm = fd.substring(n); 
14687             if (rm < 5) {
14688                 return ps[0] + '.' + r;
14689             }
14690             r*=1; // turn it into a number;
14691             r++;
14692             if (String(r).length != n) {
14693                 ps[0]*=1;
14694                 ps[0]++;
14695                 r = String(r).substring(1); // chop the end off.
14696             }
14697             
14698             return ps[0] + '.' + r;
14699              
14700         },
14701         
14702         /**
14703          * Format a number as US currency
14704          * @param {Number/String} value The numeric value to format
14705          * @return {String} The formatted currency string
14706          */
14707         usMoney : function(v){
14708             return '$' + Roo.util.Format.number(v);
14709         },
14710         
14711         /**
14712          * Format a number
14713          * eventually this should probably emulate php's number_format
14714          * @param {Number/String} value The numeric value to format
14715          * @param {Number} decimals number of decimal places
14716          * @param {String} delimiter for thousands (default comma)
14717          * @return {String} The formatted currency string
14718          */
14719         number : function(v, decimals, thousandsDelimiter)
14720         {
14721             // multiply and round.
14722             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
14723             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
14724             
14725             var mul = Math.pow(10, decimals);
14726             var zero = String(mul).substring(1);
14727             v = (Math.round((v-0)*mul))/mul;
14728             
14729             // if it's '0' number.. then
14730             
14731             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
14732             v = String(v);
14733             var ps = v.split('.');
14734             var whole = ps[0];
14735             
14736             var r = /(\d+)(\d{3})/;
14737             // add comma's
14738             
14739             if(thousandsDelimiter.length != 0) {
14740                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14741             } 
14742             
14743             var sub = ps[1] ?
14744                     // has decimals..
14745                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14746                     // does not have decimals
14747                     (decimals ? ('.' + zero) : '');
14748             
14749             
14750             return whole + sub ;
14751         },
14752         
14753         /**
14754          * Parse a value into a formatted date using the specified format pattern.
14755          * @param {Mixed} value The value to format
14756          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14757          * @return {String} The formatted date string
14758          */
14759         date : function(v, format){
14760             if(!v){
14761                 return "";
14762             }
14763             if(!(v instanceof Date)){
14764                 v = new Date(Date.parse(v));
14765             }
14766             return v.dateFormat(format || Roo.util.Format.defaults.date);
14767         },
14768
14769         /**
14770          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14771          * @param {String} format Any valid date format string
14772          * @return {Function} The date formatting function
14773          */
14774         dateRenderer : function(format){
14775             return function(v){
14776                 return Roo.util.Format.date(v, format);  
14777             };
14778         },
14779
14780         // private
14781         stripTagsRE : /<\/?[^>]+>/gi,
14782         
14783         /**
14784          * Strips all HTML tags
14785          * @param {Mixed} value The text from which to strip tags
14786          * @return {String} The stripped text
14787          */
14788         stripTags : function(v){
14789             return !v ? v : String(v).replace(this.stripTagsRE, "");
14790         },
14791         
14792         /**
14793          * Size in Mb,Gb etc.
14794          * @param {Number} value The number to be formated
14795          * @param {number} decimals how many decimal places
14796          * @return {String} the formated string
14797          */
14798         size : function(value, decimals)
14799         {
14800             var sizes = ['b', 'k', 'M', 'G', 'T'];
14801             if (value == 0) {
14802                 return 0;
14803             }
14804             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14805             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
14806         }
14807         
14808         
14809         
14810     };
14811 }();
14812 Roo.util.Format.defaults = {
14813     date : 'd/M/Y'
14814 };/*
14815  * Based on:
14816  * Ext JS Library 1.1.1
14817  * Copyright(c) 2006-2007, Ext JS, LLC.
14818  *
14819  * Originally Released Under LGPL - original licence link has changed is not relivant.
14820  *
14821  * Fork - LGPL
14822  * <script type="text/javascript">
14823  */
14824
14825
14826  
14827
14828 /**
14829  * @class Roo.MasterTemplate
14830  * @extends Roo.Template
14831  * Provides a template that can have child templates. The syntax is:
14832 <pre><code>
14833 var t = new Roo.MasterTemplate(
14834         '&lt;select name="{name}"&gt;',
14835                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
14836         '&lt;/select&gt;'
14837 );
14838 t.add('options', {value: 'foo', text: 'bar'});
14839 // or you can add multiple child elements in one shot
14840 t.addAll('options', [
14841     {value: 'foo', text: 'bar'},
14842     {value: 'foo2', text: 'bar2'},
14843     {value: 'foo3', text: 'bar3'}
14844 ]);
14845 // then append, applying the master template values
14846 t.append('my-form', {name: 'my-select'});
14847 </code></pre>
14848 * A name attribute for the child template is not required if you have only one child
14849 * template or you want to refer to them by index.
14850  */
14851 Roo.MasterTemplate = function(){
14852     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14853     this.originalHtml = this.html;
14854     var st = {};
14855     var m, re = this.subTemplateRe;
14856     re.lastIndex = 0;
14857     var subIndex = 0;
14858     while(m = re.exec(this.html)){
14859         var name = m[1], content = m[2];
14860         st[subIndex] = {
14861             name: name,
14862             index: subIndex,
14863             buffer: [],
14864             tpl : new Roo.Template(content)
14865         };
14866         if(name){
14867             st[name] = st[subIndex];
14868         }
14869         st[subIndex].tpl.compile();
14870         st[subIndex].tpl.call = this.call.createDelegate(this);
14871         subIndex++;
14872     }
14873     this.subCount = subIndex;
14874     this.subs = st;
14875 };
14876 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14877     /**
14878     * The regular expression used to match sub templates
14879     * @type RegExp
14880     * @property
14881     */
14882     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14883
14884     /**
14885      * Applies the passed values to a child template.
14886      * @param {String/Number} name (optional) The name or index of the child template
14887      * @param {Array/Object} values The values to be applied to the template
14888      * @return {MasterTemplate} this
14889      */
14890      add : function(name, values){
14891         if(arguments.length == 1){
14892             values = arguments[0];
14893             name = 0;
14894         }
14895         var s = this.subs[name];
14896         s.buffer[s.buffer.length] = s.tpl.apply(values);
14897         return this;
14898     },
14899
14900     /**
14901      * Applies all the passed values to a child template.
14902      * @param {String/Number} name (optional) The name or index of the child template
14903      * @param {Array} values The values to be applied to the template, this should be an array of objects.
14904      * @param {Boolean} reset (optional) True to reset the template first
14905      * @return {MasterTemplate} this
14906      */
14907     fill : function(name, values, reset){
14908         var a = arguments;
14909         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14910             values = a[0];
14911             name = 0;
14912             reset = a[1];
14913         }
14914         if(reset){
14915             this.reset();
14916         }
14917         for(var i = 0, len = values.length; i < len; i++){
14918             this.add(name, values[i]);
14919         }
14920         return this;
14921     },
14922
14923     /**
14924      * Resets the template for reuse
14925      * @return {MasterTemplate} this
14926      */
14927      reset : function(){
14928         var s = this.subs;
14929         for(var i = 0; i < this.subCount; i++){
14930             s[i].buffer = [];
14931         }
14932         return this;
14933     },
14934
14935     applyTemplate : function(values){
14936         var s = this.subs;
14937         var replaceIndex = -1;
14938         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14939             return s[++replaceIndex].buffer.join("");
14940         });
14941         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14942     },
14943
14944     apply : function(){
14945         return this.applyTemplate.apply(this, arguments);
14946     },
14947
14948     compile : function(){return this;}
14949 });
14950
14951 /**
14952  * Alias for fill().
14953  * @method
14954  */
14955 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14956  /**
14957  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14958  * var tpl = Roo.MasterTemplate.from('element-id');
14959  * @param {String/HTMLElement} el
14960  * @param {Object} config
14961  * @static
14962  */
14963 Roo.MasterTemplate.from = function(el, config){
14964     el = Roo.getDom(el);
14965     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
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  
14978 /**
14979  * @class Roo.util.CSS
14980  * Utility class for manipulating CSS rules
14981  * @static
14982
14983  */
14984 Roo.util.CSS = function(){
14985         var rules = null;
14986         var doc = document;
14987
14988     var camelRe = /(-[a-z])/gi;
14989     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14990
14991    return {
14992    /**
14993     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14994     * tag and appended to the HEAD of the document.
14995     * @param {String|Object} cssText The text containing the css rules
14996     * @param {String} id An id to add to the stylesheet for later removal
14997     * @return {StyleSheet}
14998     */
14999     createStyleSheet : function(cssText, id){
15000         var ss;
15001         var head = doc.getElementsByTagName("head")[0];
15002         var nrules = doc.createElement("style");
15003         nrules.setAttribute("type", "text/css");
15004         if(id){
15005             nrules.setAttribute("id", id);
15006         }
15007         if (typeof(cssText) != 'string') {
15008             // support object maps..
15009             // not sure if this a good idea.. 
15010             // perhaps it should be merged with the general css handling
15011             // and handle js style props.
15012             var cssTextNew = [];
15013             for(var n in cssText) {
15014                 var citems = [];
15015                 for(var k in cssText[n]) {
15016                     citems.push( k + ' : ' +cssText[n][k] + ';' );
15017                 }
15018                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15019                 
15020             }
15021             cssText = cssTextNew.join("\n");
15022             
15023         }
15024        
15025        
15026        if(Roo.isIE){
15027            head.appendChild(nrules);
15028            ss = nrules.styleSheet;
15029            ss.cssText = cssText;
15030        }else{
15031            try{
15032                 nrules.appendChild(doc.createTextNode(cssText));
15033            }catch(e){
15034                nrules.cssText = cssText; 
15035            }
15036            head.appendChild(nrules);
15037            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15038        }
15039        this.cacheStyleSheet(ss);
15040        return ss;
15041    },
15042
15043    /**
15044     * Removes a style or link tag by id
15045     * @param {String} id The id of the tag
15046     */
15047    removeStyleSheet : function(id){
15048        var existing = doc.getElementById(id);
15049        if(existing){
15050            existing.parentNode.removeChild(existing);
15051        }
15052    },
15053
15054    /**
15055     * Dynamically swaps an existing stylesheet reference for a new one
15056     * @param {String} id The id of an existing link tag to remove
15057     * @param {String} url The href of the new stylesheet to include
15058     */
15059    swapStyleSheet : function(id, url){
15060        this.removeStyleSheet(id);
15061        var ss = doc.createElement("link");
15062        ss.setAttribute("rel", "stylesheet");
15063        ss.setAttribute("type", "text/css");
15064        ss.setAttribute("id", id);
15065        ss.setAttribute("href", url);
15066        doc.getElementsByTagName("head")[0].appendChild(ss);
15067    },
15068    
15069    /**
15070     * Refresh the rule cache if you have dynamically added stylesheets
15071     * @return {Object} An object (hash) of rules indexed by selector
15072     */
15073    refreshCache : function(){
15074        return this.getRules(true);
15075    },
15076
15077    // private
15078    cacheStyleSheet : function(stylesheet){
15079        if(!rules){
15080            rules = {};
15081        }
15082        try{// try catch for cross domain access issue
15083            var ssRules = stylesheet.cssRules || stylesheet.rules;
15084            for(var j = ssRules.length-1; j >= 0; --j){
15085                rules[ssRules[j].selectorText] = ssRules[j];
15086            }
15087        }catch(e){}
15088    },
15089    
15090    /**
15091     * Gets all css rules for the document
15092     * @param {Boolean} refreshCache true to refresh the internal cache
15093     * @return {Object} An object (hash) of rules indexed by selector
15094     */
15095    getRules : function(refreshCache){
15096                 if(rules == null || refreshCache){
15097                         rules = {};
15098                         var ds = doc.styleSheets;
15099                         for(var i =0, len = ds.length; i < len; i++){
15100                             try{
15101                         this.cacheStyleSheet(ds[i]);
15102                     }catch(e){} 
15103                 }
15104                 }
15105                 return rules;
15106         },
15107         
15108         /**
15109     * Gets an an individual CSS rule by selector(s)
15110     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15111     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15112     * @return {CSSRule} The CSS rule or null if one is not found
15113     */
15114    getRule : function(selector, refreshCache){
15115                 var rs = this.getRules(refreshCache);
15116                 if(!(selector instanceof Array)){
15117                     return rs[selector];
15118                 }
15119                 for(var i = 0; i < selector.length; i++){
15120                         if(rs[selector[i]]){
15121                                 return rs[selector[i]];
15122                         }
15123                 }
15124                 return null;
15125         },
15126         
15127         
15128         /**
15129     * Updates a rule property
15130     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15131     * @param {String} property The css property
15132     * @param {String} value The new value for the property
15133     * @return {Boolean} true If a rule was found and updated
15134     */
15135    updateRule : function(selector, property, value){
15136                 if(!(selector instanceof Array)){
15137                         var rule = this.getRule(selector);
15138                         if(rule){
15139                                 rule.style[property.replace(camelRe, camelFn)] = value;
15140                                 return true;
15141                         }
15142                 }else{
15143                         for(var i = 0; i < selector.length; i++){
15144                                 if(this.updateRule(selector[i], property, value)){
15145                                         return true;
15146                                 }
15147                         }
15148                 }
15149                 return false;
15150         }
15151    };   
15152 }();/*
15153  * Based on:
15154  * Ext JS Library 1.1.1
15155  * Copyright(c) 2006-2007, Ext JS, LLC.
15156  *
15157  * Originally Released Under LGPL - original licence link has changed is not relivant.
15158  *
15159  * Fork - LGPL
15160  * <script type="text/javascript">
15161  */
15162
15163  
15164
15165 /**
15166  * @class Roo.util.ClickRepeater
15167  * @extends Roo.util.Observable
15168  * 
15169  * A wrapper class which can be applied to any element. Fires a "click" event while the
15170  * mouse is pressed. The interval between firings may be specified in the config but
15171  * defaults to 10 milliseconds.
15172  * 
15173  * Optionally, a CSS class may be applied to the element during the time it is pressed.
15174  * 
15175  * @cfg {String/HTMLElement/Element} el The element to act as a button.
15176  * @cfg {Number} delay The initial delay before the repeating event begins firing.
15177  * Similar to an autorepeat key delay.
15178  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15179  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15180  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15181  *           "interval" and "delay" are ignored. "immediate" is honored.
15182  * @cfg {Boolean} preventDefault True to prevent the default click event
15183  * @cfg {Boolean} stopDefault True to stop the default click event
15184  * 
15185  * @history
15186  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
15187  *     2007-02-02 jvs Renamed to ClickRepeater
15188  *   2007-02-03 jvs Modifications for FF Mac and Safari 
15189  *
15190  *  @constructor
15191  * @param {String/HTMLElement/Element} el The element to listen on
15192  * @param {Object} config
15193  **/
15194 Roo.util.ClickRepeater = function(el, config)
15195 {
15196     this.el = Roo.get(el);
15197     this.el.unselectable();
15198
15199     Roo.apply(this, config);
15200
15201     this.addEvents({
15202     /**
15203      * @event mousedown
15204      * Fires when the mouse button is depressed.
15205      * @param {Roo.util.ClickRepeater} this
15206      */
15207         "mousedown" : true,
15208     /**
15209      * @event click
15210      * Fires on a specified interval during the time the element is pressed.
15211      * @param {Roo.util.ClickRepeater} this
15212      */
15213         "click" : true,
15214     /**
15215      * @event mouseup
15216      * Fires when the mouse key is released.
15217      * @param {Roo.util.ClickRepeater} this
15218      */
15219         "mouseup" : true
15220     });
15221
15222     this.el.on("mousedown", this.handleMouseDown, this);
15223     if(this.preventDefault || this.stopDefault){
15224         this.el.on("click", function(e){
15225             if(this.preventDefault){
15226                 e.preventDefault();
15227             }
15228             if(this.stopDefault){
15229                 e.stopEvent();
15230             }
15231         }, this);
15232     }
15233
15234     // allow inline handler
15235     if(this.handler){
15236         this.on("click", this.handler,  this.scope || this);
15237     }
15238
15239     Roo.util.ClickRepeater.superclass.constructor.call(this);
15240 };
15241
15242 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15243     interval : 20,
15244     delay: 250,
15245     preventDefault : true,
15246     stopDefault : false,
15247     timer : 0,
15248
15249     // private
15250     handleMouseDown : function(){
15251         clearTimeout(this.timer);
15252         this.el.blur();
15253         if(this.pressClass){
15254             this.el.addClass(this.pressClass);
15255         }
15256         this.mousedownTime = new Date();
15257
15258         Roo.get(document).on("mouseup", this.handleMouseUp, this);
15259         this.el.on("mouseout", this.handleMouseOut, this);
15260
15261         this.fireEvent("mousedown", this);
15262         this.fireEvent("click", this);
15263         
15264         this.timer = this.click.defer(this.delay || this.interval, this);
15265     },
15266
15267     // private
15268     click : function(){
15269         this.fireEvent("click", this);
15270         this.timer = this.click.defer(this.getInterval(), this);
15271     },
15272
15273     // private
15274     getInterval: function(){
15275         if(!this.accelerate){
15276             return this.interval;
15277         }
15278         var pressTime = this.mousedownTime.getElapsed();
15279         if(pressTime < 500){
15280             return 400;
15281         }else if(pressTime < 1700){
15282             return 320;
15283         }else if(pressTime < 2600){
15284             return 250;
15285         }else if(pressTime < 3500){
15286             return 180;
15287         }else if(pressTime < 4400){
15288             return 140;
15289         }else if(pressTime < 5300){
15290             return 80;
15291         }else if(pressTime < 6200){
15292             return 50;
15293         }else{
15294             return 10;
15295         }
15296     },
15297
15298     // private
15299     handleMouseOut : function(){
15300         clearTimeout(this.timer);
15301         if(this.pressClass){
15302             this.el.removeClass(this.pressClass);
15303         }
15304         this.el.on("mouseover", this.handleMouseReturn, this);
15305     },
15306
15307     // private
15308     handleMouseReturn : function(){
15309         this.el.un("mouseover", this.handleMouseReturn);
15310         if(this.pressClass){
15311             this.el.addClass(this.pressClass);
15312         }
15313         this.click();
15314     },
15315
15316     // private
15317     handleMouseUp : function(){
15318         clearTimeout(this.timer);
15319         this.el.un("mouseover", this.handleMouseReturn);
15320         this.el.un("mouseout", this.handleMouseOut);
15321         Roo.get(document).un("mouseup", this.handleMouseUp);
15322         this.el.removeClass(this.pressClass);
15323         this.fireEvent("mouseup", this);
15324     }
15325 });/**
15326  * @class Roo.util.Clipboard
15327  * @static
15328  * 
15329  * Clipboard UTILS
15330  * 
15331  **/
15332 Roo.util.Clipboard = {
15333     /**
15334      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15335      * @param {String} text to copy to clipboard
15336      */
15337     write : function(text) {
15338         // navigator clipboard api needs a secure context (https)
15339         if (navigator.clipboard && window.isSecureContext) {
15340             // navigator clipboard api method'
15341             navigator.clipboard.writeText(text);
15342             return ;
15343         } 
15344         // text area method
15345         var ta = document.createElement("textarea");
15346         ta.value = text;
15347         // make the textarea out of viewport
15348         ta.style.position = "fixed";
15349         ta.style.left = "-999999px";
15350         ta.style.top = "-999999px";
15351         document.body.appendChild(ta);
15352         ta.focus();
15353         ta.select();
15354         document.execCommand('copy');
15355         (function() {
15356             ta.remove();
15357         }).defer(100);
15358         
15359     }
15360         
15361 }
15362     /*
15363  * Based on:
15364  * Ext JS Library 1.1.1
15365  * Copyright(c) 2006-2007, Ext JS, LLC.
15366  *
15367  * Originally Released Under LGPL - original licence link has changed is not relivant.
15368  *
15369  * Fork - LGPL
15370  * <script type="text/javascript">
15371  */
15372
15373  
15374 /**
15375  * @class Roo.KeyNav
15376  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
15377  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15378  * way to implement custom navigation schemes for any UI component.</p>
15379  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15380  * pageUp, pageDown, del, home, end.  Usage:</p>
15381  <pre><code>
15382 var nav = new Roo.KeyNav("my-element", {
15383     "left" : function(e){
15384         this.moveLeft(e.ctrlKey);
15385     },
15386     "right" : function(e){
15387         this.moveRight(e.ctrlKey);
15388     },
15389     "enter" : function(e){
15390         this.save();
15391     },
15392     scope : this
15393 });
15394 </code></pre>
15395  * @constructor
15396  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15397  * @param {Object} config The config
15398  */
15399 Roo.KeyNav = function(el, config){
15400     this.el = Roo.get(el);
15401     Roo.apply(this, config);
15402     if(!this.disabled){
15403         this.disabled = true;
15404         this.enable();
15405     }
15406 };
15407
15408 Roo.KeyNav.prototype = {
15409     /**
15410      * @cfg {Boolean} disabled
15411      * True to disable this KeyNav instance (defaults to false)
15412      */
15413     disabled : false,
15414     /**
15415      * @cfg {String} defaultEventAction
15416      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
15417      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15418      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15419      */
15420     defaultEventAction: "stopEvent",
15421     /**
15422      * @cfg {Boolean} forceKeyDown
15423      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
15424      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15425      * handle keydown instead of keypress.
15426      */
15427     forceKeyDown : false,
15428
15429     // private
15430     prepareEvent : function(e){
15431         var k = e.getKey();
15432         var h = this.keyToHandler[k];
15433         //if(h && this[h]){
15434         //    e.stopPropagation();
15435         //}
15436         if(Roo.isSafari && h && k >= 37 && k <= 40){
15437             e.stopEvent();
15438         }
15439     },
15440
15441     // private
15442     relay : function(e){
15443         var k = e.getKey();
15444         var h = this.keyToHandler[k];
15445         if(h && this[h]){
15446             if(this.doRelay(e, this[h], h) !== true){
15447                 e[this.defaultEventAction]();
15448             }
15449         }
15450     },
15451
15452     // private
15453     doRelay : function(e, h, hname){
15454         return h.call(this.scope || this, e);
15455     },
15456
15457     // possible handlers
15458     enter : false,
15459     left : false,
15460     right : false,
15461     up : false,
15462     down : false,
15463     tab : false,
15464     esc : false,
15465     pageUp : false,
15466     pageDown : false,
15467     del : false,
15468     home : false,
15469     end : false,
15470
15471     // quick lookup hash
15472     keyToHandler : {
15473         37 : "left",
15474         39 : "right",
15475         38 : "up",
15476         40 : "down",
15477         33 : "pageUp",
15478         34 : "pageDown",
15479         46 : "del",
15480         36 : "home",
15481         35 : "end",
15482         13 : "enter",
15483         27 : "esc",
15484         9  : "tab"
15485     },
15486
15487         /**
15488          * Enable this KeyNav
15489          */
15490         enable: function(){
15491                 if(this.disabled){
15492             // ie won't do special keys on keypress, no one else will repeat keys with keydown
15493             // the EventObject will normalize Safari automatically
15494             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15495                 this.el.on("keydown", this.relay,  this);
15496             }else{
15497                 this.el.on("keydown", this.prepareEvent,  this);
15498                 this.el.on("keypress", this.relay,  this);
15499             }
15500                     this.disabled = false;
15501                 }
15502         },
15503
15504         /**
15505          * Disable this KeyNav
15506          */
15507         disable: function(){
15508                 if(!this.disabled){
15509                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15510                 this.el.un("keydown", this.relay);
15511             }else{
15512                 this.el.un("keydown", this.prepareEvent);
15513                 this.el.un("keypress", this.relay);
15514             }
15515                     this.disabled = true;
15516                 }
15517         }
15518 };/*
15519  * Based on:
15520  * Ext JS Library 1.1.1
15521  * Copyright(c) 2006-2007, Ext JS, LLC.
15522  *
15523  * Originally Released Under LGPL - original licence link has changed is not relivant.
15524  *
15525  * Fork - LGPL
15526  * <script type="text/javascript">
15527  */
15528
15529  
15530 /**
15531  * @class Roo.KeyMap
15532  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15533  * The constructor accepts the same config object as defined by {@link #addBinding}.
15534  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15535  * combination it will call the function with this signature (if the match is a multi-key
15536  * combination the callback will still be called only once): (String key, Roo.EventObject e)
15537  * A KeyMap can also handle a string representation of keys.<br />
15538  * Usage:
15539  <pre><code>
15540 // map one key by key code
15541 var map = new Roo.KeyMap("my-element", {
15542     key: 13, // or Roo.EventObject.ENTER
15543     fn: myHandler,
15544     scope: myObject
15545 });
15546
15547 // map multiple keys to one action by string
15548 var map = new Roo.KeyMap("my-element", {
15549     key: "a\r\n\t",
15550     fn: myHandler,
15551     scope: myObject
15552 });
15553
15554 // map multiple keys to multiple actions by strings and array of codes
15555 var map = new Roo.KeyMap("my-element", [
15556     {
15557         key: [10,13],
15558         fn: function(){ alert("Return was pressed"); }
15559     }, {
15560         key: "abc",
15561         fn: function(){ alert('a, b or c was pressed'); }
15562     }, {
15563         key: "\t",
15564         ctrl:true,
15565         shift:true,
15566         fn: function(){ alert('Control + shift + tab was pressed.'); }
15567     }
15568 ]);
15569 </code></pre>
15570  * <b>Note: A KeyMap starts enabled</b>
15571  * @constructor
15572  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15573  * @param {Object} config The config (see {@link #addBinding})
15574  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15575  */
15576 Roo.KeyMap = function(el, config, eventName){
15577     this.el  = Roo.get(el);
15578     this.eventName = eventName || "keydown";
15579     this.bindings = [];
15580     if(config){
15581         this.addBinding(config);
15582     }
15583     this.enable();
15584 };
15585
15586 Roo.KeyMap.prototype = {
15587     /**
15588      * True to stop the event from bubbling and prevent the default browser action if the
15589      * key was handled by the KeyMap (defaults to false)
15590      * @type Boolean
15591      */
15592     stopEvent : false,
15593
15594     /**
15595      * Add a new binding to this KeyMap. The following config object properties are supported:
15596      * <pre>
15597 Property    Type             Description
15598 ----------  ---------------  ----------------------------------------------------------------------
15599 key         String/Array     A single keycode or an array of keycodes to handle
15600 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
15601 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
15602 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
15603 fn          Function         The function to call when KeyMap finds the expected key combination
15604 scope       Object           The scope of the callback function
15605 </pre>
15606      *
15607      * Usage:
15608      * <pre><code>
15609 // Create a KeyMap
15610 var map = new Roo.KeyMap(document, {
15611     key: Roo.EventObject.ENTER,
15612     fn: handleKey,
15613     scope: this
15614 });
15615
15616 //Add a new binding to the existing KeyMap later
15617 map.addBinding({
15618     key: 'abc',
15619     shift: true,
15620     fn: handleKey,
15621     scope: this
15622 });
15623 </code></pre>
15624      * @param {Object/Array} config A single KeyMap config or an array of configs
15625      */
15626         addBinding : function(config){
15627         if(config instanceof Array){
15628             for(var i = 0, len = config.length; i < len; i++){
15629                 this.addBinding(config[i]);
15630             }
15631             return;
15632         }
15633         var keyCode = config.key,
15634             shift = config.shift, 
15635             ctrl = config.ctrl, 
15636             alt = config.alt,
15637             fn = config.fn,
15638             scope = config.scope;
15639         if(typeof keyCode == "string"){
15640             var ks = [];
15641             var keyString = keyCode.toUpperCase();
15642             for(var j = 0, len = keyString.length; j < len; j++){
15643                 ks.push(keyString.charCodeAt(j));
15644             }
15645             keyCode = ks;
15646         }
15647         var keyArray = keyCode instanceof Array;
15648         var handler = function(e){
15649             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
15650                 var k = e.getKey();
15651                 if(keyArray){
15652                     for(var i = 0, len = keyCode.length; i < len; i++){
15653                         if(keyCode[i] == k){
15654                           if(this.stopEvent){
15655                               e.stopEvent();
15656                           }
15657                           fn.call(scope || window, k, e);
15658                           return;
15659                         }
15660                     }
15661                 }else{
15662                     if(k == keyCode){
15663                         if(this.stopEvent){
15664                            e.stopEvent();
15665                         }
15666                         fn.call(scope || window, k, e);
15667                     }
15668                 }
15669             }
15670         };
15671         this.bindings.push(handler);  
15672         },
15673
15674     /**
15675      * Shorthand for adding a single key listener
15676      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
15677      * following options:
15678      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
15679      * @param {Function} fn The function to call
15680      * @param {Object} scope (optional) The scope of the function
15681      */
15682     on : function(key, fn, scope){
15683         var keyCode, shift, ctrl, alt;
15684         if(typeof key == "object" && !(key instanceof Array)){
15685             keyCode = key.key;
15686             shift = key.shift;
15687             ctrl = key.ctrl;
15688             alt = key.alt;
15689         }else{
15690             keyCode = key;
15691         }
15692         this.addBinding({
15693             key: keyCode,
15694             shift: shift,
15695             ctrl: ctrl,
15696             alt: alt,
15697             fn: fn,
15698             scope: scope
15699         })
15700     },
15701
15702     // private
15703     handleKeyDown : function(e){
15704             if(this.enabled){ //just in case
15705             var b = this.bindings;
15706             for(var i = 0, len = b.length; i < len; i++){
15707                 b[i].call(this, e);
15708             }
15709             }
15710         },
15711         
15712         /**
15713          * Returns true if this KeyMap is enabled
15714          * @return {Boolean} 
15715          */
15716         isEnabled : function(){
15717             return this.enabled;  
15718         },
15719         
15720         /**
15721          * Enables this KeyMap
15722          */
15723         enable: function(){
15724                 if(!this.enabled){
15725                     this.el.on(this.eventName, this.handleKeyDown, this);
15726                     this.enabled = true;
15727                 }
15728         },
15729
15730         /**
15731          * Disable this KeyMap
15732          */
15733         disable: function(){
15734                 if(this.enabled){
15735                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
15736                     this.enabled = false;
15737                 }
15738         }
15739 };/*
15740  * Based on:
15741  * Ext JS Library 1.1.1
15742  * Copyright(c) 2006-2007, Ext JS, LLC.
15743  *
15744  * Originally Released Under LGPL - original licence link has changed is not relivant.
15745  *
15746  * Fork - LGPL
15747  * <script type="text/javascript">
15748  */
15749
15750  
15751 /**
15752  * @class Roo.util.TextMetrics
15753  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15754  * wide, in pixels, a given block of text will be.
15755  * @static
15756  */
15757 Roo.util.TextMetrics = function(){
15758     var shared;
15759     return {
15760         /**
15761          * Measures the size of the specified text
15762          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15763          * that can affect the size of the rendered text
15764          * @param {String} text The text to measure
15765          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15766          * in order to accurately measure the text height
15767          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15768          */
15769         measure : function(el, text, fixedWidth){
15770             if(!shared){
15771                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15772             }
15773             shared.bind(el);
15774             shared.setFixedWidth(fixedWidth || 'auto');
15775             return shared.getSize(text);
15776         },
15777
15778         /**
15779          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
15780          * the overhead of multiple calls to initialize the style properties on each measurement.
15781          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15782          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15783          * in order to accurately measure the text height
15784          * @return {Roo.util.TextMetrics.Instance} instance The new instance
15785          */
15786         createInstance : function(el, fixedWidth){
15787             return Roo.util.TextMetrics.Instance(el, fixedWidth);
15788         }
15789     };
15790 }();
15791
15792 /**
15793  * @class Roo.util.TextMetrics.Instance
15794  * Instance of  TextMetrics Calcuation
15795  * @constructor
15796  * Create a new TextMetrics Instance
15797  * @param {Object} bindto
15798  * @param {Boolean} fixedWidth
15799  */
15800
15801 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
15802 {
15803     var ml = new Roo.Element(document.createElement('div'));
15804     document.body.appendChild(ml.dom);
15805     ml.position('absolute');
15806     ml.setLeftTop(-1000, -1000);
15807     ml.hide();
15808
15809     if(fixedWidth){
15810         ml.setWidth(fixedWidth);
15811     }
15812      
15813     var instance = {
15814         /**
15815          * Returns the size of the specified text based on the internal element's style and width properties
15816          * @param {String} text The text to measure
15817          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15818          */
15819         getSize : function(text){
15820             ml.update(text);
15821             var s = ml.getSize();
15822             ml.update('');
15823             return s;
15824         },
15825
15826         /**
15827          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15828          * that can affect the size of the rendered text
15829          * @param {String/HTMLElement} el The element, dom node or id
15830          */
15831         bind : function(el){
15832             ml.setStyle(
15833                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15834             );
15835         },
15836
15837         /**
15838          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
15839          * to set a fixed width in order to accurately measure the text height.
15840          * @param {Number} width The width to set on the element
15841          */
15842         setFixedWidth : function(width){
15843             ml.setWidth(width);
15844         },
15845
15846         /**
15847          * Returns the measured width of the specified text
15848          * @param {String} text The text to measure
15849          * @return {Number} width The width in pixels
15850          */
15851         getWidth : function(text){
15852             ml.dom.style.width = 'auto';
15853             return this.getSize(text).width;
15854         },
15855
15856         /**
15857          * Returns the measured height of the specified text.  For multiline text, be sure to call
15858          * {@link #setFixedWidth} if necessary.
15859          * @param {String} text The text to measure
15860          * @return {Number} height The height in pixels
15861          */
15862         getHeight : function(text){
15863             return this.getSize(text).height;
15864         }
15865     };
15866
15867     instance.bind(bindTo);
15868
15869     return instance;
15870 };
15871
15872 // backwards compat
15873 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15874  * Based on:
15875  * Ext JS Library 1.1.1
15876  * Copyright(c) 2006-2007, Ext JS, LLC.
15877  *
15878  * Originally Released Under LGPL - original licence link has changed is not relivant.
15879  *
15880  * Fork - LGPL
15881  * <script type="text/javascript">
15882  */
15883
15884 /**
15885  * @class Roo.state.Provider
15886  * Abstract base class for state provider implementations. This class provides methods
15887  * for encoding and decoding <b>typed</b> variables including dates and defines the 
15888  * Provider interface.
15889  */
15890 Roo.state.Provider = function(){
15891     /**
15892      * @event statechange
15893      * Fires when a state change occurs.
15894      * @param {Provider} this This state provider
15895      * @param {String} key The state key which was changed
15896      * @param {String} value The encoded value for the state
15897      */
15898     this.addEvents({
15899         "statechange": true
15900     });
15901     this.state = {};
15902     Roo.state.Provider.superclass.constructor.call(this);
15903 };
15904 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15905     /**
15906      * Returns the current value for a key
15907      * @param {String} name The key name
15908      * @param {Mixed} defaultValue A default value to return if the key's value is not found
15909      * @return {Mixed} The state data
15910      */
15911     get : function(name, defaultValue){
15912         return typeof this.state[name] == "undefined" ?
15913             defaultValue : this.state[name];
15914     },
15915     
15916     /**
15917      * Clears a value from the state
15918      * @param {String} name The key name
15919      */
15920     clear : function(name){
15921         delete this.state[name];
15922         this.fireEvent("statechange", this, name, null);
15923     },
15924     
15925     /**
15926      * Sets the value for a key
15927      * @param {String} name The key name
15928      * @param {Mixed} value The value to set
15929      */
15930     set : function(name, value){
15931         this.state[name] = value;
15932         this.fireEvent("statechange", this, name, value);
15933     },
15934     
15935     /**
15936      * Decodes a string previously encoded with {@link #encodeValue}.
15937      * @param {String} value The value to decode
15938      * @return {Mixed} The decoded value
15939      */
15940     decodeValue : function(cookie){
15941         var re = /^(a|n|d|b|s|o)\:(.*)$/;
15942         var matches = re.exec(unescape(cookie));
15943         if(!matches || !matches[1]) {
15944             return; // non state cookie
15945         }
15946         var type = matches[1];
15947         var v = matches[2];
15948         switch(type){
15949             case "n":
15950                 return parseFloat(v);
15951             case "d":
15952                 return new Date(Date.parse(v));
15953             case "b":
15954                 return (v == "1");
15955             case "a":
15956                 var all = [];
15957                 var values = v.split("^");
15958                 for(var i = 0, len = values.length; i < len; i++){
15959                     all.push(this.decodeValue(values[i]));
15960                 }
15961                 return all;
15962            case "o":
15963                 var all = {};
15964                 var values = v.split("^");
15965                 for(var i = 0, len = values.length; i < len; i++){
15966                     var kv = values[i].split("=");
15967                     all[kv[0]] = this.decodeValue(kv[1]);
15968                 }
15969                 return all;
15970            default:
15971                 return v;
15972         }
15973     },
15974     
15975     /**
15976      * Encodes a value including type information.  Decode with {@link #decodeValue}.
15977      * @param {Mixed} value The value to encode
15978      * @return {String} The encoded value
15979      */
15980     encodeValue : function(v){
15981         var enc;
15982         if(typeof v == "number"){
15983             enc = "n:" + v;
15984         }else if(typeof v == "boolean"){
15985             enc = "b:" + (v ? "1" : "0");
15986         }else if(v instanceof Date){
15987             enc = "d:" + v.toGMTString();
15988         }else if(v instanceof Array){
15989             var flat = "";
15990             for(var i = 0, len = v.length; i < len; i++){
15991                 flat += this.encodeValue(v[i]);
15992                 if(i != len-1) {
15993                     flat += "^";
15994                 }
15995             }
15996             enc = "a:" + flat;
15997         }else if(typeof v == "object"){
15998             var flat = "";
15999             for(var key in v){
16000                 if(typeof v[key] != "function"){
16001                     flat += key + "=" + this.encodeValue(v[key]) + "^";
16002                 }
16003             }
16004             enc = "o:" + flat.substring(0, flat.length-1);
16005         }else{
16006             enc = "s:" + v;
16007         }
16008         return escape(enc);        
16009     }
16010 });
16011
16012 /*
16013  * Based on:
16014  * Ext JS Library 1.1.1
16015  * Copyright(c) 2006-2007, Ext JS, LLC.
16016  *
16017  * Originally Released Under LGPL - original licence link has changed is not relivant.
16018  *
16019  * Fork - LGPL
16020  * <script type="text/javascript">
16021  */
16022 /**
16023  * @class Roo.state.Manager
16024  * This is the global state manager. By default all components that are "state aware" check this class
16025  * for state information if you don't pass them a custom state provider. In order for this class
16026  * to be useful, it must be initialized with a provider when your application initializes.
16027  <pre><code>
16028 // in your initialization function
16029 init : function(){
16030    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16031    ...
16032    // supposed you have a {@link Roo.BorderLayout}
16033    var layout = new Roo.BorderLayout(...);
16034    layout.restoreState();
16035    // or a {Roo.BasicDialog}
16036    var dialog = new Roo.BasicDialog(...);
16037    dialog.restoreState();
16038  </code></pre>
16039  * @static
16040  */
16041 Roo.state.Manager = function(){
16042     var provider = new Roo.state.Provider();
16043     
16044     return {
16045         /**
16046          * Configures the default state provider for your application
16047          * @param {Provider} stateProvider The state provider to set
16048          */
16049         setProvider : function(stateProvider){
16050             provider = stateProvider;
16051         },
16052         
16053         /**
16054          * Returns the current value for a key
16055          * @param {String} name The key name
16056          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16057          * @return {Mixed} The state data
16058          */
16059         get : function(key, defaultValue){
16060             return provider.get(key, defaultValue);
16061         },
16062         
16063         /**
16064          * Sets the value for a key
16065          * @param {String} name The key name
16066          * @param {Mixed} value The state data
16067          */
16068          set : function(key, value){
16069             provider.set(key, value);
16070         },
16071         
16072         /**
16073          * Clears a value from the state
16074          * @param {String} name The key name
16075          */
16076         clear : function(key){
16077             provider.clear(key);
16078         },
16079         
16080         /**
16081          * Gets the currently configured state provider
16082          * @return {Provider} The state provider
16083          */
16084         getProvider : function(){
16085             return provider;
16086         }
16087     };
16088 }();
16089 /*
16090  * Based on:
16091  * Ext JS Library 1.1.1
16092  * Copyright(c) 2006-2007, Ext JS, LLC.
16093  *
16094  * Originally Released Under LGPL - original licence link has changed is not relivant.
16095  *
16096  * Fork - LGPL
16097  * <script type="text/javascript">
16098  */
16099 /**
16100  * @class Roo.state.CookieProvider
16101  * @extends Roo.state.Provider
16102  * The default Provider implementation which saves state via cookies.
16103  * <br />Usage:
16104  <pre><code>
16105    var cp = new Roo.state.CookieProvider({
16106        path: "/cgi-bin/",
16107        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16108        domain: "roojs.com"
16109    })
16110    Roo.state.Manager.setProvider(cp);
16111  </code></pre>
16112  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16113  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16114  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
16115  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16116  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16117  * domain the page is running on including the 'www' like 'www.roojs.com')
16118  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16119  * @constructor
16120  * Create a new CookieProvider
16121  * @param {Object} config The configuration object
16122  */
16123 Roo.state.CookieProvider = function(config){
16124     Roo.state.CookieProvider.superclass.constructor.call(this);
16125     this.path = "/";
16126     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16127     this.domain = null;
16128     this.secure = false;
16129     Roo.apply(this, config);
16130     this.state = this.readCookies();
16131 };
16132
16133 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16134     // private
16135     set : function(name, value){
16136         if(typeof value == "undefined" || value === null){
16137             this.clear(name);
16138             return;
16139         }
16140         this.setCookie(name, value);
16141         Roo.state.CookieProvider.superclass.set.call(this, name, value);
16142     },
16143
16144     // private
16145     clear : function(name){
16146         this.clearCookie(name);
16147         Roo.state.CookieProvider.superclass.clear.call(this, name);
16148     },
16149
16150     // private
16151     readCookies : function(){
16152         var cookies = {};
16153         var c = document.cookie + ";";
16154         var re = /\s?(.*?)=(.*?);/g;
16155         var matches;
16156         while((matches = re.exec(c)) != null){
16157             var name = matches[1];
16158             var value = matches[2];
16159             if(name && name.substring(0,3) == "ys-"){
16160                 cookies[name.substr(3)] = this.decodeValue(value);
16161             }
16162         }
16163         return cookies;
16164     },
16165
16166     // private
16167     setCookie : function(name, value){
16168         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16169            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16170            ((this.path == null) ? "" : ("; path=" + this.path)) +
16171            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16172            ((this.secure == true) ? "; secure" : "");
16173     },
16174
16175     // private
16176     clearCookie : function(name){
16177         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16178            ((this.path == null) ? "" : ("; path=" + this.path)) +
16179            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16180            ((this.secure == true) ? "; secure" : "");
16181     }
16182 });/*
16183  * Based on:
16184  * Ext JS Library 1.1.1
16185  * Copyright(c) 2006-2007, Ext JS, LLC.
16186  *
16187  * Originally Released Under LGPL - original licence link has changed is not relivant.
16188  *
16189  * Fork - LGPL
16190  * <script type="text/javascript">
16191  */
16192  
16193
16194 /**
16195  * @class Roo.ComponentMgr
16196  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16197  * @static
16198  */
16199 Roo.ComponentMgr = function(){
16200     var all = new Roo.util.MixedCollection();
16201
16202     return {
16203         /**
16204          * Registers a component.
16205          * @param {Roo.Component} c The component
16206          */
16207         register : function(c){
16208             all.add(c);
16209         },
16210
16211         /**
16212          * Unregisters a component.
16213          * @param {Roo.Component} c The component
16214          */
16215         unregister : function(c){
16216             all.remove(c);
16217         },
16218
16219         /**
16220          * Returns a component by id
16221          * @param {String} id The component id
16222          */
16223         get : function(id){
16224             return all.get(id);
16225         },
16226
16227         /**
16228          * Registers a function that will be called when a specified component is added to ComponentMgr
16229          * @param {String} id The component id
16230          * @param {Funtction} fn The callback function
16231          * @param {Object} scope The scope of the callback
16232          */
16233         onAvailable : function(id, fn, scope){
16234             all.on("add", function(index, o){
16235                 if(o.id == id){
16236                     fn.call(scope || o, o);
16237                     all.un("add", fn, scope);
16238                 }
16239             });
16240         }
16241     };
16242 }();/*
16243  * Based on:
16244  * Ext JS Library 1.1.1
16245  * Copyright(c) 2006-2007, Ext JS, LLC.
16246  *
16247  * Originally Released Under LGPL - original licence link has changed is not relivant.
16248  *
16249  * Fork - LGPL
16250  * <script type="text/javascript">
16251  */
16252  
16253 /**
16254  * @class Roo.Component
16255  * @extends Roo.util.Observable
16256  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16257  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
16258  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16259  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16260  * All visual components (widgets) that require rendering into a layout should subclass Component.
16261  * @constructor
16262  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
16263  * 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
16264  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
16265  */
16266 Roo.Component = function(config){
16267     config = config || {};
16268     if(config.tagName || config.dom || typeof config == "string"){ // element object
16269         config = {el: config, id: config.id || config};
16270     }
16271     this.initialConfig = config;
16272
16273     Roo.apply(this, config);
16274     this.addEvents({
16275         /**
16276          * @event disable
16277          * Fires after the component is disabled.
16278              * @param {Roo.Component} this
16279              */
16280         disable : true,
16281         /**
16282          * @event enable
16283          * Fires after the component is enabled.
16284              * @param {Roo.Component} this
16285              */
16286         enable : true,
16287         /**
16288          * @event beforeshow
16289          * Fires before the component is shown.  Return false to stop the show.
16290              * @param {Roo.Component} this
16291              */
16292         beforeshow : true,
16293         /**
16294          * @event show
16295          * Fires after the component is shown.
16296              * @param {Roo.Component} this
16297              */
16298         show : true,
16299         /**
16300          * @event beforehide
16301          * Fires before the component is hidden. Return false to stop the hide.
16302              * @param {Roo.Component} this
16303              */
16304         beforehide : true,
16305         /**
16306          * @event hide
16307          * Fires after the component is hidden.
16308              * @param {Roo.Component} this
16309              */
16310         hide : true,
16311         /**
16312          * @event beforerender
16313          * Fires before the component is rendered. Return false to stop the render.
16314              * @param {Roo.Component} this
16315              */
16316         beforerender : true,
16317         /**
16318          * @event render
16319          * Fires after the component is rendered.
16320              * @param {Roo.Component} this
16321              */
16322         render : true,
16323         /**
16324          * @event beforedestroy
16325          * Fires before the component is destroyed. Return false to stop the destroy.
16326              * @param {Roo.Component} this
16327              */
16328         beforedestroy : true,
16329         /**
16330          * @event destroy
16331          * Fires after the component is destroyed.
16332              * @param {Roo.Component} this
16333              */
16334         destroy : true
16335     });
16336     if(!this.id){
16337         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16338     }
16339     Roo.ComponentMgr.register(this);
16340     Roo.Component.superclass.constructor.call(this);
16341     this.initComponent();
16342     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16343         this.render(this.renderTo);
16344         delete this.renderTo;
16345     }
16346 };
16347
16348 /** @private */
16349 Roo.Component.AUTO_ID = 1000;
16350
16351 Roo.extend(Roo.Component, Roo.util.Observable, {
16352     /**
16353      * @scope Roo.Component.prototype
16354      * @type {Boolean}
16355      * true if this component is hidden. Read-only.
16356      */
16357     hidden : false,
16358     /**
16359      * @type {Boolean}
16360      * true if this component is disabled. Read-only.
16361      */
16362     disabled : false,
16363     /**
16364      * @type {Boolean}
16365      * true if this component has been rendered. Read-only.
16366      */
16367     rendered : false,
16368     
16369     /** @cfg {String} disableClass
16370      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16371      */
16372     disabledClass : "x-item-disabled",
16373         /** @cfg {Boolean} allowDomMove
16374          * Whether the component can move the Dom node when rendering (defaults to true).
16375          */
16376     allowDomMove : true,
16377     /** @cfg {String} hideMode (display|visibility)
16378      * How this component should hidden. Supported values are
16379      * "visibility" (css visibility), "offsets" (negative offset position) and
16380      * "display" (css display) - defaults to "display".
16381      */
16382     hideMode: 'display',
16383
16384     /** @private */
16385     ctype : "Roo.Component",
16386
16387     /**
16388      * @cfg {String} actionMode 
16389      * which property holds the element that used for  hide() / show() / disable() / enable()
16390      * default is 'el' for forms you probably want to set this to fieldEl 
16391      */
16392     actionMode : "el",
16393
16394     /** @private */
16395     getActionEl : function(){
16396         return this[this.actionMode];
16397     },
16398
16399     initComponent : Roo.emptyFn,
16400     /**
16401      * If this is a lazy rendering component, render it to its container element.
16402      * @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.
16403      */
16404     render : function(container, position){
16405         
16406         if(this.rendered){
16407             return this;
16408         }
16409         
16410         if(this.fireEvent("beforerender", this) === false){
16411             return false;
16412         }
16413         
16414         if(!container && this.el){
16415             this.el = Roo.get(this.el);
16416             container = this.el.dom.parentNode;
16417             this.allowDomMove = false;
16418         }
16419         this.container = Roo.get(container);
16420         this.rendered = true;
16421         if(position !== undefined){
16422             if(typeof position == 'number'){
16423                 position = this.container.dom.childNodes[position];
16424             }else{
16425                 position = Roo.getDom(position);
16426             }
16427         }
16428         this.onRender(this.container, position || null);
16429         if(this.cls){
16430             this.el.addClass(this.cls);
16431             delete this.cls;
16432         }
16433         if(this.style){
16434             this.el.applyStyles(this.style);
16435             delete this.style;
16436         }
16437         this.fireEvent("render", this);
16438         this.afterRender(this.container);
16439         if(this.hidden){
16440             this.hide();
16441         }
16442         if(this.disabled){
16443             this.disable();
16444         }
16445
16446         return this;
16447         
16448     },
16449
16450     /** @private */
16451     // default function is not really useful
16452     onRender : function(ct, position){
16453         if(this.el){
16454             this.el = Roo.get(this.el);
16455             if(this.allowDomMove !== false){
16456                 ct.dom.insertBefore(this.el.dom, position);
16457             }
16458         }
16459     },
16460
16461     /** @private */
16462     getAutoCreate : function(){
16463         var cfg = typeof this.autoCreate == "object" ?
16464                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16465         if(this.id && !cfg.id){
16466             cfg.id = this.id;
16467         }
16468         return cfg;
16469     },
16470
16471     /** @private */
16472     afterRender : Roo.emptyFn,
16473
16474     /**
16475      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16476      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16477      */
16478     destroy : function(){
16479         if(this.fireEvent("beforedestroy", this) !== false){
16480             this.purgeListeners();
16481             this.beforeDestroy();
16482             if(this.rendered){
16483                 this.el.removeAllListeners();
16484                 this.el.remove();
16485                 if(this.actionMode == "container"){
16486                     this.container.remove();
16487                 }
16488             }
16489             this.onDestroy();
16490             Roo.ComponentMgr.unregister(this);
16491             this.fireEvent("destroy", this);
16492         }
16493     },
16494
16495         /** @private */
16496     beforeDestroy : function(){
16497
16498     },
16499
16500         /** @private */
16501         onDestroy : function(){
16502
16503     },
16504
16505     /**
16506      * Returns the underlying {@link Roo.Element}.
16507      * @return {Roo.Element} The element
16508      */
16509     getEl : function(){
16510         return this.el;
16511     },
16512
16513     /**
16514      * Returns the id of this component.
16515      * @return {String}
16516      */
16517     getId : function(){
16518         return this.id;
16519     },
16520
16521     /**
16522      * Try to focus this component.
16523      * @param {Boolean} selectText True to also select the text in this component (if applicable)
16524      * @return {Roo.Component} this
16525      */
16526     focus : function(selectText){
16527         if(this.rendered){
16528             this.el.focus();
16529             if(selectText === true){
16530                 this.el.dom.select();
16531             }
16532         }
16533         return this;
16534     },
16535
16536     /** @private */
16537     blur : function(){
16538         if(this.rendered){
16539             this.el.blur();
16540         }
16541         return this;
16542     },
16543
16544     /**
16545      * Disable this component.
16546      * @return {Roo.Component} this
16547      */
16548     disable : function(){
16549         if(this.rendered){
16550             this.onDisable();
16551         }
16552         this.disabled = true;
16553         this.fireEvent("disable", this);
16554         return this;
16555     },
16556
16557         // private
16558     onDisable : function(){
16559         this.getActionEl().addClass(this.disabledClass);
16560         this.el.dom.disabled = true;
16561     },
16562
16563     /**
16564      * Enable this component.
16565      * @return {Roo.Component} this
16566      */
16567     enable : function(){
16568         if(this.rendered){
16569             this.onEnable();
16570         }
16571         this.disabled = false;
16572         this.fireEvent("enable", this);
16573         return this;
16574     },
16575
16576         // private
16577     onEnable : function(){
16578         this.getActionEl().removeClass(this.disabledClass);
16579         this.el.dom.disabled = false;
16580     },
16581
16582     /**
16583      * Convenience function for setting disabled/enabled by boolean.
16584      * @param {Boolean} disabled
16585      */
16586     setDisabled : function(disabled){
16587         this[disabled ? "disable" : "enable"]();
16588     },
16589
16590     /**
16591      * Show this component.
16592      * @return {Roo.Component} this
16593      */
16594     show: function(){
16595         if(this.fireEvent("beforeshow", this) !== false){
16596             this.hidden = false;
16597             if(this.rendered){
16598                 this.onShow();
16599             }
16600             this.fireEvent("show", this);
16601         }
16602         return this;
16603     },
16604
16605     // private
16606     onShow : function(){
16607         var ae = this.getActionEl();
16608         if(this.hideMode == 'visibility'){
16609             ae.dom.style.visibility = "visible";
16610         }else if(this.hideMode == 'offsets'){
16611             ae.removeClass('x-hidden');
16612         }else{
16613             ae.dom.style.display = "";
16614         }
16615     },
16616
16617     /**
16618      * Hide this component.
16619      * @return {Roo.Component} this
16620      */
16621     hide: function(){
16622         if(this.fireEvent("beforehide", this) !== false){
16623             this.hidden = true;
16624             if(this.rendered){
16625                 this.onHide();
16626             }
16627             this.fireEvent("hide", this);
16628         }
16629         return this;
16630     },
16631
16632     // private
16633     onHide : function(){
16634         var ae = this.getActionEl();
16635         if(this.hideMode == 'visibility'){
16636             ae.dom.style.visibility = "hidden";
16637         }else if(this.hideMode == 'offsets'){
16638             ae.addClass('x-hidden');
16639         }else{
16640             ae.dom.style.display = "none";
16641         }
16642     },
16643
16644     /**
16645      * Convenience function to hide or show this component by boolean.
16646      * @param {Boolean} visible True to show, false to hide
16647      * @return {Roo.Component} this
16648      */
16649     setVisible: function(visible){
16650         if(visible) {
16651             this.show();
16652         }else{
16653             this.hide();
16654         }
16655         return this;
16656     },
16657
16658     /**
16659      * Returns true if this component is visible.
16660      */
16661     isVisible : function(){
16662         return this.getActionEl().isVisible();
16663     },
16664
16665     cloneConfig : function(overrides){
16666         overrides = overrides || {};
16667         var id = overrides.id || Roo.id();
16668         var cfg = Roo.applyIf(overrides, this.initialConfig);
16669         cfg.id = id; // prevent dup id
16670         return new this.constructor(cfg);
16671     }
16672 });/*
16673  * Based on:
16674  * Ext JS Library 1.1.1
16675  * Copyright(c) 2006-2007, Ext JS, LLC.
16676  *
16677  * Originally Released Under LGPL - original licence link has changed is not relivant.
16678  *
16679  * Fork - LGPL
16680  * <script type="text/javascript">
16681  */
16682
16683 /**
16684  * @class Roo.BoxComponent
16685  * @extends Roo.Component
16686  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
16687  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
16688  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
16689  * layout containers.
16690  * @constructor
16691  * @param {Roo.Element/String/Object} config The configuration options.
16692  */
16693 Roo.BoxComponent = function(config){
16694     Roo.Component.call(this, config);
16695     this.addEvents({
16696         /**
16697          * @event resize
16698          * Fires after the component is resized.
16699              * @param {Roo.Component} this
16700              * @param {Number} adjWidth The box-adjusted width that was set
16701              * @param {Number} adjHeight The box-adjusted height that was set
16702              * @param {Number} rawWidth The width that was originally specified
16703              * @param {Number} rawHeight The height that was originally specified
16704              */
16705         resize : true,
16706         /**
16707          * @event move
16708          * Fires after the component is moved.
16709              * @param {Roo.Component} this
16710              * @param {Number} x The new x position
16711              * @param {Number} y The new y position
16712              */
16713         move : true
16714     });
16715 };
16716
16717 Roo.extend(Roo.BoxComponent, Roo.Component, {
16718     // private, set in afterRender to signify that the component has been rendered
16719     boxReady : false,
16720     // private, used to defer height settings to subclasses
16721     deferHeight: false,
16722     /** @cfg {Number} width
16723      * width (optional) size of component
16724      */
16725      /** @cfg {Number} height
16726      * height (optional) size of component
16727      */
16728      
16729     /**
16730      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
16731      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
16732      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
16733      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
16734      * @return {Roo.BoxComponent} this
16735      */
16736     setSize : function(w, h){
16737         // support for standard size objects
16738         if(typeof w == 'object'){
16739             h = w.height;
16740             w = w.width;
16741         }
16742         // not rendered
16743         if(!this.boxReady){
16744             this.width = w;
16745             this.height = h;
16746             return this;
16747         }
16748
16749         // prevent recalcs when not needed
16750         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16751             return this;
16752         }
16753         this.lastSize = {width: w, height: h};
16754
16755         var adj = this.adjustSize(w, h);
16756         var aw = adj.width, ah = adj.height;
16757         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16758             var rz = this.getResizeEl();
16759             if(!this.deferHeight && aw !== undefined && ah !== undefined){
16760                 rz.setSize(aw, ah);
16761             }else if(!this.deferHeight && ah !== undefined){
16762                 rz.setHeight(ah);
16763             }else if(aw !== undefined){
16764                 rz.setWidth(aw);
16765             }
16766             this.onResize(aw, ah, w, h);
16767             this.fireEvent('resize', this, aw, ah, w, h);
16768         }
16769         return this;
16770     },
16771
16772     /**
16773      * Gets the current size of the component's underlying element.
16774      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16775      */
16776     getSize : function(){
16777         return this.el.getSize();
16778     },
16779
16780     /**
16781      * Gets the current XY position of the component's underlying element.
16782      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16783      * @return {Array} The XY position of the element (e.g., [100, 200])
16784      */
16785     getPosition : function(local){
16786         if(local === true){
16787             return [this.el.getLeft(true), this.el.getTop(true)];
16788         }
16789         return this.xy || this.el.getXY();
16790     },
16791
16792     /**
16793      * Gets the current box measurements of the component's underlying element.
16794      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16795      * @returns {Object} box An object in the format {x, y, width, height}
16796      */
16797     getBox : function(local){
16798         var s = this.el.getSize();
16799         if(local){
16800             s.x = this.el.getLeft(true);
16801             s.y = this.el.getTop(true);
16802         }else{
16803             var xy = this.xy || this.el.getXY();
16804             s.x = xy[0];
16805             s.y = xy[1];
16806         }
16807         return s;
16808     },
16809
16810     /**
16811      * Sets the current box measurements of the component's underlying element.
16812      * @param {Object} box An object in the format {x, y, width, height}
16813      * @returns {Roo.BoxComponent} this
16814      */
16815     updateBox : function(box){
16816         this.setSize(box.width, box.height);
16817         this.setPagePosition(box.x, box.y);
16818         return this;
16819     },
16820
16821     // protected
16822     getResizeEl : function(){
16823         return this.resizeEl || this.el;
16824     },
16825
16826     // protected
16827     getPositionEl : function(){
16828         return this.positionEl || this.el;
16829     },
16830
16831     /**
16832      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
16833      * This method fires the move event.
16834      * @param {Number} left The new left
16835      * @param {Number} top The new top
16836      * @returns {Roo.BoxComponent} this
16837      */
16838     setPosition : function(x, y){
16839         this.x = x;
16840         this.y = y;
16841         if(!this.boxReady){
16842             return this;
16843         }
16844         var adj = this.adjustPosition(x, y);
16845         var ax = adj.x, ay = adj.y;
16846
16847         var el = this.getPositionEl();
16848         if(ax !== undefined || ay !== undefined){
16849             if(ax !== undefined && ay !== undefined){
16850                 el.setLeftTop(ax, ay);
16851             }else if(ax !== undefined){
16852                 el.setLeft(ax);
16853             }else if(ay !== undefined){
16854                 el.setTop(ay);
16855             }
16856             this.onPosition(ax, ay);
16857             this.fireEvent('move', this, ax, ay);
16858         }
16859         return this;
16860     },
16861
16862     /**
16863      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
16864      * This method fires the move event.
16865      * @param {Number} x The new x position
16866      * @param {Number} y The new y position
16867      * @returns {Roo.BoxComponent} this
16868      */
16869     setPagePosition : function(x, y){
16870         this.pageX = x;
16871         this.pageY = y;
16872         if(!this.boxReady){
16873             return;
16874         }
16875         if(x === undefined || y === undefined){ // cannot translate undefined points
16876             return;
16877         }
16878         var p = this.el.translatePoints(x, y);
16879         this.setPosition(p.left, p.top);
16880         return this;
16881     },
16882
16883     // private
16884     onRender : function(ct, position){
16885         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16886         if(this.resizeEl){
16887             this.resizeEl = Roo.get(this.resizeEl);
16888         }
16889         if(this.positionEl){
16890             this.positionEl = Roo.get(this.positionEl);
16891         }
16892     },
16893
16894     // private
16895     afterRender : function(){
16896         Roo.BoxComponent.superclass.afterRender.call(this);
16897         this.boxReady = true;
16898         this.setSize(this.width, this.height);
16899         if(this.x || this.y){
16900             this.setPosition(this.x, this.y);
16901         }
16902         if(this.pageX || this.pageY){
16903             this.setPagePosition(this.pageX, this.pageY);
16904         }
16905     },
16906
16907     /**
16908      * Force the component's size to recalculate based on the underlying element's current height and width.
16909      * @returns {Roo.BoxComponent} this
16910      */
16911     syncSize : function(){
16912         delete this.lastSize;
16913         this.setSize(this.el.getWidth(), this.el.getHeight());
16914         return this;
16915     },
16916
16917     /**
16918      * Called after the component is resized, this method is empty by default but can be implemented by any
16919      * subclass that needs to perform custom logic after a resize occurs.
16920      * @param {Number} adjWidth The box-adjusted width that was set
16921      * @param {Number} adjHeight The box-adjusted height that was set
16922      * @param {Number} rawWidth The width that was originally specified
16923      * @param {Number} rawHeight The height that was originally specified
16924      */
16925     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16926
16927     },
16928
16929     /**
16930      * Called after the component is moved, this method is empty by default but can be implemented by any
16931      * subclass that needs to perform custom logic after a move occurs.
16932      * @param {Number} x The new x position
16933      * @param {Number} y The new y position
16934      */
16935     onPosition : function(x, y){
16936
16937     },
16938
16939     // private
16940     adjustSize : function(w, h){
16941         if(this.autoWidth){
16942             w = 'auto';
16943         }
16944         if(this.autoHeight){
16945             h = 'auto';
16946         }
16947         return {width : w, height: h};
16948     },
16949
16950     // private
16951     adjustPosition : function(x, y){
16952         return {x : x, y: y};
16953     }
16954 });/*
16955  * Based on:
16956  * Ext JS Library 1.1.1
16957  * Copyright(c) 2006-2007, Ext JS, LLC.
16958  *
16959  * Originally Released Under LGPL - original licence link has changed is not relivant.
16960  *
16961  * Fork - LGPL
16962  * <script type="text/javascript">
16963  */
16964  (function(){ 
16965 /**
16966  * @class Roo.Layer
16967  * @extends Roo.Element
16968  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16969  * automatic maintaining of shadow/shim positions.
16970  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16971  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16972  * you can pass a string with a CSS class name. False turns off the shadow.
16973  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16974  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16975  * @cfg {String} cls CSS class to add to the element
16976  * @cfg {Number} zindex Starting z-index (defaults to 11000)
16977  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16978  * @constructor
16979  * @param {Object} config An object with config options.
16980  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16981  */
16982
16983 Roo.Layer = function(config, existingEl){
16984     config = config || {};
16985     var dh = Roo.DomHelper;
16986     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16987     if(existingEl){
16988         this.dom = Roo.getDom(existingEl);
16989     }
16990     if(!this.dom){
16991         var o = config.dh || {tag: "div", cls: "x-layer"};
16992         this.dom = dh.append(pel, o);
16993     }
16994     if(config.cls){
16995         this.addClass(config.cls);
16996     }
16997     this.constrain = config.constrain !== false;
16998     this.visibilityMode = Roo.Element.VISIBILITY;
16999     if(config.id){
17000         this.id = this.dom.id = config.id;
17001     }else{
17002         this.id = Roo.id(this.dom);
17003     }
17004     this.zindex = config.zindex || this.getZIndex();
17005     this.position("absolute", this.zindex);
17006     if(config.shadow){
17007         this.shadowOffset = config.shadowOffset || 4;
17008         this.shadow = new Roo.Shadow({
17009             offset : this.shadowOffset,
17010             mode : config.shadow
17011         });
17012     }else{
17013         this.shadowOffset = 0;
17014     }
17015     this.useShim = config.shim !== false && Roo.useShims;
17016     this.useDisplay = config.useDisplay;
17017     this.hide();
17018 };
17019
17020 var supr = Roo.Element.prototype;
17021
17022 // shims are shared among layer to keep from having 100 iframes
17023 var shims = [];
17024
17025 Roo.extend(Roo.Layer, Roo.Element, {
17026
17027     getZIndex : function(){
17028         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17029     },
17030
17031     getShim : function(){
17032         if(!this.useShim){
17033             return null;
17034         }
17035         if(this.shim){
17036             return this.shim;
17037         }
17038         var shim = shims.shift();
17039         if(!shim){
17040             shim = this.createShim();
17041             shim.enableDisplayMode('block');
17042             shim.dom.style.display = 'none';
17043             shim.dom.style.visibility = 'visible';
17044         }
17045         var pn = this.dom.parentNode;
17046         if(shim.dom.parentNode != pn){
17047             pn.insertBefore(shim.dom, this.dom);
17048         }
17049         shim.setStyle('z-index', this.getZIndex()-2);
17050         this.shim = shim;
17051         return shim;
17052     },
17053
17054     hideShim : function(){
17055         if(this.shim){
17056             this.shim.setDisplayed(false);
17057             shims.push(this.shim);
17058             delete this.shim;
17059         }
17060     },
17061
17062     disableShadow : function(){
17063         if(this.shadow){
17064             this.shadowDisabled = true;
17065             this.shadow.hide();
17066             this.lastShadowOffset = this.shadowOffset;
17067             this.shadowOffset = 0;
17068         }
17069     },
17070
17071     enableShadow : function(show){
17072         if(this.shadow){
17073             this.shadowDisabled = false;
17074             this.shadowOffset = this.lastShadowOffset;
17075             delete this.lastShadowOffset;
17076             if(show){
17077                 this.sync(true);
17078             }
17079         }
17080     },
17081
17082     // private
17083     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17084     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17085     sync : function(doShow){
17086         var sw = this.shadow;
17087         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17088             var sh = this.getShim();
17089
17090             var w = this.getWidth(),
17091                 h = this.getHeight();
17092
17093             var l = this.getLeft(true),
17094                 t = this.getTop(true);
17095
17096             if(sw && !this.shadowDisabled){
17097                 if(doShow && !sw.isVisible()){
17098                     sw.show(this);
17099                 }else{
17100                     sw.realign(l, t, w, h);
17101                 }
17102                 if(sh){
17103                     if(doShow){
17104                        sh.show();
17105                     }
17106                     // fit the shim behind the shadow, so it is shimmed too
17107                     var a = sw.adjusts, s = sh.dom.style;
17108                     s.left = (Math.min(l, l+a.l))+"px";
17109                     s.top = (Math.min(t, t+a.t))+"px";
17110                     s.width = (w+a.w)+"px";
17111                     s.height = (h+a.h)+"px";
17112                 }
17113             }else if(sh){
17114                 if(doShow){
17115                    sh.show();
17116                 }
17117                 sh.setSize(w, h);
17118                 sh.setLeftTop(l, t);
17119             }
17120             
17121         }
17122     },
17123
17124     // private
17125     destroy : function(){
17126         this.hideShim();
17127         if(this.shadow){
17128             this.shadow.hide();
17129         }
17130         this.removeAllListeners();
17131         var pn = this.dom.parentNode;
17132         if(pn){
17133             pn.removeChild(this.dom);
17134         }
17135         Roo.Element.uncache(this.id);
17136     },
17137
17138     remove : function(){
17139         this.destroy();
17140     },
17141
17142     // private
17143     beginUpdate : function(){
17144         this.updating = true;
17145     },
17146
17147     // private
17148     endUpdate : function(){
17149         this.updating = false;
17150         this.sync(true);
17151     },
17152
17153     // private
17154     hideUnders : function(negOffset){
17155         if(this.shadow){
17156             this.shadow.hide();
17157         }
17158         this.hideShim();
17159     },
17160
17161     // private
17162     constrainXY : function(){
17163         if(this.constrain){
17164             var vw = Roo.lib.Dom.getViewWidth(),
17165                 vh = Roo.lib.Dom.getViewHeight();
17166             var s = Roo.get(document).getScroll();
17167
17168             var xy = this.getXY();
17169             var x = xy[0], y = xy[1];   
17170             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17171             // only move it if it needs it
17172             var moved = false;
17173             // first validate right/bottom
17174             if((x + w) > vw+s.left){
17175                 x = vw - w - this.shadowOffset;
17176                 moved = true;
17177             }
17178             if((y + h) > vh+s.top){
17179                 y = vh - h - this.shadowOffset;
17180                 moved = true;
17181             }
17182             // then make sure top/left isn't negative
17183             if(x < s.left){
17184                 x = s.left;
17185                 moved = true;
17186             }
17187             if(y < s.top){
17188                 y = s.top;
17189                 moved = true;
17190             }
17191             if(moved){
17192                 if(this.avoidY){
17193                     var ay = this.avoidY;
17194                     if(y <= ay && (y+h) >= ay){
17195                         y = ay-h-5;   
17196                     }
17197                 }
17198                 xy = [x, y];
17199                 this.storeXY(xy);
17200                 supr.setXY.call(this, xy);
17201                 this.sync();
17202             }
17203         }
17204     },
17205
17206     isVisible : function(){
17207         return this.visible;    
17208     },
17209
17210     // private
17211     showAction : function(){
17212         this.visible = true; // track visibility to prevent getStyle calls
17213         if(this.useDisplay === true){
17214             this.setDisplayed("");
17215         }else if(this.lastXY){
17216             supr.setXY.call(this, this.lastXY);
17217         }else if(this.lastLT){
17218             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17219         }
17220     },
17221
17222     // private
17223     hideAction : function(){
17224         this.visible = false;
17225         if(this.useDisplay === true){
17226             this.setDisplayed(false);
17227         }else{
17228             this.setLeftTop(-10000,-10000);
17229         }
17230     },
17231
17232     // overridden Element method
17233     setVisible : function(v, a, d, c, e){
17234         if(v){
17235             this.showAction();
17236         }
17237         if(a && v){
17238             var cb = function(){
17239                 this.sync(true);
17240                 if(c){
17241                     c();
17242                 }
17243             }.createDelegate(this);
17244             supr.setVisible.call(this, true, true, d, cb, e);
17245         }else{
17246             if(!v){
17247                 this.hideUnders(true);
17248             }
17249             var cb = c;
17250             if(a){
17251                 cb = function(){
17252                     this.hideAction();
17253                     if(c){
17254                         c();
17255                     }
17256                 }.createDelegate(this);
17257             }
17258             supr.setVisible.call(this, v, a, d, cb, e);
17259             if(v){
17260                 this.sync(true);
17261             }else if(!a){
17262                 this.hideAction();
17263             }
17264         }
17265     },
17266
17267     storeXY : function(xy){
17268         delete this.lastLT;
17269         this.lastXY = xy;
17270     },
17271
17272     storeLeftTop : function(left, top){
17273         delete this.lastXY;
17274         this.lastLT = [left, top];
17275     },
17276
17277     // private
17278     beforeFx : function(){
17279         this.beforeAction();
17280         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17281     },
17282
17283     // private
17284     afterFx : function(){
17285         Roo.Layer.superclass.afterFx.apply(this, arguments);
17286         this.sync(this.isVisible());
17287     },
17288
17289     // private
17290     beforeAction : function(){
17291         if(!this.updating && this.shadow){
17292             this.shadow.hide();
17293         }
17294     },
17295
17296     // overridden Element method
17297     setLeft : function(left){
17298         this.storeLeftTop(left, this.getTop(true));
17299         supr.setLeft.apply(this, arguments);
17300         this.sync();
17301     },
17302
17303     setTop : function(top){
17304         this.storeLeftTop(this.getLeft(true), top);
17305         supr.setTop.apply(this, arguments);
17306         this.sync();
17307     },
17308
17309     setLeftTop : function(left, top){
17310         this.storeLeftTop(left, top);
17311         supr.setLeftTop.apply(this, arguments);
17312         this.sync();
17313     },
17314
17315     setXY : function(xy, a, d, c, e){
17316         this.fixDisplay();
17317         this.beforeAction();
17318         this.storeXY(xy);
17319         var cb = this.createCB(c);
17320         supr.setXY.call(this, xy, a, d, cb, e);
17321         if(!a){
17322             cb();
17323         }
17324     },
17325
17326     // private
17327     createCB : function(c){
17328         var el = this;
17329         return function(){
17330             el.constrainXY();
17331             el.sync(true);
17332             if(c){
17333                 c();
17334             }
17335         };
17336     },
17337
17338     // overridden Element method
17339     setX : function(x, a, d, c, e){
17340         this.setXY([x, this.getY()], a, d, c, e);
17341     },
17342
17343     // overridden Element method
17344     setY : function(y, a, d, c, e){
17345         this.setXY([this.getX(), y], a, d, c, e);
17346     },
17347
17348     // overridden Element method
17349     setSize : function(w, h, a, d, c, e){
17350         this.beforeAction();
17351         var cb = this.createCB(c);
17352         supr.setSize.call(this, w, h, a, d, cb, e);
17353         if(!a){
17354             cb();
17355         }
17356     },
17357
17358     // overridden Element method
17359     setWidth : function(w, a, d, c, e){
17360         this.beforeAction();
17361         var cb = this.createCB(c);
17362         supr.setWidth.call(this, w, a, d, cb, e);
17363         if(!a){
17364             cb();
17365         }
17366     },
17367
17368     // overridden Element method
17369     setHeight : function(h, a, d, c, e){
17370         this.beforeAction();
17371         var cb = this.createCB(c);
17372         supr.setHeight.call(this, h, a, d, cb, e);
17373         if(!a){
17374             cb();
17375         }
17376     },
17377
17378     // overridden Element method
17379     setBounds : function(x, y, w, h, a, d, c, e){
17380         this.beforeAction();
17381         var cb = this.createCB(c);
17382         if(!a){
17383             this.storeXY([x, y]);
17384             supr.setXY.call(this, [x, y]);
17385             supr.setSize.call(this, w, h, a, d, cb, e);
17386             cb();
17387         }else{
17388             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17389         }
17390         return this;
17391     },
17392     
17393     /**
17394      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17395      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17396      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17397      * @param {Number} zindex The new z-index to set
17398      * @return {this} The Layer
17399      */
17400     setZIndex : function(zindex){
17401         this.zindex = zindex;
17402         this.setStyle("z-index", zindex + 2);
17403         if(this.shadow){
17404             this.shadow.setZIndex(zindex + 1);
17405         }
17406         if(this.shim){
17407             this.shim.setStyle("z-index", zindex);
17408         }
17409     }
17410 });
17411 })();/*
17412  * Original code for Roojs - LGPL
17413  * <script type="text/javascript">
17414  */
17415  
17416 /**
17417  * @class Roo.XComponent
17418  * A delayed Element creator...
17419  * Or a way to group chunks of interface together.
17420  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17421  *  used in conjunction with XComponent.build() it will create an instance of each element,
17422  *  then call addxtype() to build the User interface.
17423  * 
17424  * Mypart.xyx = new Roo.XComponent({
17425
17426     parent : 'Mypart.xyz', // empty == document.element.!!
17427     order : '001',
17428     name : 'xxxx'
17429     region : 'xxxx'
17430     disabled : function() {} 
17431      
17432     tree : function() { // return an tree of xtype declared components
17433         var MODULE = this;
17434         return 
17435         {
17436             xtype : 'NestedLayoutPanel',
17437             // technicall
17438         }
17439      ]
17440  *})
17441  *
17442  *
17443  * It can be used to build a big heiracy, with parent etc.
17444  * or you can just use this to render a single compoent to a dom element
17445  * MYPART.render(Roo.Element | String(id) | dom_element )
17446  *
17447  *
17448  * Usage patterns.
17449  *
17450  * Classic Roo
17451  *
17452  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17453  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17454  *
17455  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17456  *
17457  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17458  * - if mulitple topModules exist, the last one is defined as the top module.
17459  *
17460  * Embeded Roo
17461  * 
17462  * When the top level or multiple modules are to embedded into a existing HTML page,
17463  * the parent element can container '#id' of the element where the module will be drawn.
17464  *
17465  * Bootstrap Roo
17466  *
17467  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17468  * it relies more on a include mechanism, where sub modules are included into an outer page.
17469  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17470  * 
17471  * Bootstrap Roo Included elements
17472  *
17473  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17474  * hence confusing the component builder as it thinks there are multiple top level elements. 
17475  *
17476  * String Over-ride & Translations
17477  *
17478  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17479  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17480  * are needed. @see Roo.XComponent.overlayString  
17481  * 
17482  * 
17483  * 
17484  * @extends Roo.util.Observable
17485  * @constructor
17486  * @param cfg {Object} configuration of component
17487  * 
17488  */
17489 Roo.XComponent = function(cfg) {
17490     Roo.apply(this, cfg);
17491     this.addEvents({ 
17492         /**
17493              * @event built
17494              * Fires when this the componnt is built
17495              * @param {Roo.XComponent} c the component
17496              */
17497         'built' : true
17498         
17499     });
17500     this.region = this.region || 'center'; // default..
17501     Roo.XComponent.register(this);
17502     this.modules = false;
17503     this.el = false; // where the layout goes..
17504     
17505     
17506 }
17507 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17508     /**
17509      * @property el
17510      * The created element (with Roo.factory())
17511      * @type {Roo.Layout}
17512      */
17513     el  : false,
17514     
17515     /**
17516      * @property el
17517      * for BC  - use el in new code
17518      * @type {Roo.Layout}
17519      */
17520     panel : false,
17521     
17522     /**
17523      * @property layout
17524      * for BC  - use el in new code
17525      * @type {Roo.Layout}
17526      */
17527     layout : false,
17528     
17529      /**
17530      * @cfg {Function|boolean} disabled
17531      * If this module is disabled by some rule, return true from the funtion
17532      */
17533     disabled : false,
17534     
17535     /**
17536      * @cfg {String} parent 
17537      * Name of parent element which it get xtype added to..
17538      */
17539     parent: false,
17540     
17541     /**
17542      * @cfg {String} order
17543      * Used to set the order in which elements are created (usefull for multiple tabs)
17544      */
17545     
17546     order : false,
17547     /**
17548      * @cfg {String} name
17549      * String to display while loading.
17550      */
17551     name : false,
17552     /**
17553      * @cfg {String} region
17554      * Region to render component to (defaults to center)
17555      */
17556     region : 'center',
17557     
17558     /**
17559      * @cfg {Array} items
17560      * A single item array - the first element is the root of the tree..
17561      * It's done this way to stay compatible with the Xtype system...
17562      */
17563     items : false,
17564     
17565     /**
17566      * @property _tree
17567      * The method that retuns the tree of parts that make up this compoennt 
17568      * @type {function}
17569      */
17570     _tree  : false,
17571     
17572      /**
17573      * render
17574      * render element to dom or tree
17575      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17576      */
17577     
17578     render : function(el)
17579     {
17580         
17581         el = el || false;
17582         var hp = this.parent ? 1 : 0;
17583         Roo.debug &&  Roo.log(this);
17584         
17585         var tree = this._tree ? this._tree() : this.tree();
17586
17587         
17588         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17589             // if parent is a '#.....' string, then let's use that..
17590             var ename = this.parent.substr(1);
17591             this.parent = false;
17592             Roo.debug && Roo.log(ename);
17593             switch (ename) {
17594                 case 'bootstrap-body':
17595                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
17596                         // this is the BorderLayout standard?
17597                        this.parent = { el : true };
17598                        break;
17599                     }
17600                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
17601                         // need to insert stuff...
17602                         this.parent =  {
17603                              el : new Roo.bootstrap.layout.Border({
17604                                  el : document.body, 
17605                      
17606                                  center: {
17607                                     titlebar: false,
17608                                     autoScroll:false,
17609                                     closeOnTab: true,
17610                                     tabPosition: 'top',
17611                                       //resizeTabs: true,
17612                                     alwaysShowTabs: true,
17613                                     hideTabs: false
17614                                      //minTabWidth: 140
17615                                  }
17616                              })
17617                         
17618                          };
17619                          break;
17620                     }
17621                          
17622                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
17623                         this.parent = { el :  new  Roo.bootstrap.Body() };
17624                         Roo.debug && Roo.log("setting el to doc body");
17625                          
17626                     } else {
17627                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
17628                     }
17629                     break;
17630                 case 'bootstrap':
17631                     this.parent = { el : true};
17632                     // fall through
17633                 default:
17634                     el = Roo.get(ename);
17635                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
17636                         this.parent = { el : true};
17637                     }
17638                     
17639                     break;
17640             }
17641                 
17642             
17643             if (!el && !this.parent) {
17644                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
17645                 return;
17646             }
17647         }
17648         
17649         Roo.debug && Roo.log("EL:");
17650         Roo.debug && Roo.log(el);
17651         Roo.debug && Roo.log("this.parent.el:");
17652         Roo.debug && Roo.log(this.parent.el);
17653         
17654
17655         // altertive root elements ??? - we need a better way to indicate these.
17656         var is_alt = Roo.XComponent.is_alt ||
17657                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
17658                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
17659                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
17660         
17661         
17662         
17663         if (!this.parent && is_alt) {
17664             //el = Roo.get(document.body);
17665             this.parent = { el : true };
17666         }
17667             
17668             
17669         
17670         if (!this.parent) {
17671             
17672             Roo.debug && Roo.log("no parent - creating one");
17673             
17674             el = el ? Roo.get(el) : false;      
17675             
17676             if (typeof(Roo.BorderLayout) == 'undefined' ) {
17677                 
17678                 this.parent =  {
17679                     el : new Roo.bootstrap.layout.Border({
17680                         el: el || document.body,
17681                     
17682                         center: {
17683                             titlebar: false,
17684                             autoScroll:false,
17685                             closeOnTab: true,
17686                             tabPosition: 'top',
17687                              //resizeTabs: true,
17688                             alwaysShowTabs: false,
17689                             hideTabs: true,
17690                             minTabWidth: 140,
17691                             overflow: 'visible'
17692                          }
17693                      })
17694                 };
17695             } else {
17696             
17697                 // it's a top level one..
17698                 this.parent =  {
17699                     el : new Roo.BorderLayout(el || document.body, {
17700                         center: {
17701                             titlebar: false,
17702                             autoScroll:false,
17703                             closeOnTab: true,
17704                             tabPosition: 'top',
17705                              //resizeTabs: true,
17706                             alwaysShowTabs: el && hp? false :  true,
17707                             hideTabs: el || !hp ? true :  false,
17708                             minTabWidth: 140
17709                          }
17710                     })
17711                 };
17712             }
17713         }
17714         
17715         if (!this.parent.el) {
17716                 // probably an old style ctor, which has been disabled.
17717                 return;
17718
17719         }
17720                 // The 'tree' method is  '_tree now' 
17721             
17722         tree.region = tree.region || this.region;
17723         var is_body = false;
17724         if (this.parent.el === true) {
17725             // bootstrap... - body..
17726             if (el) {
17727                 tree.el = el;
17728             }
17729             this.parent.el = Roo.factory(tree);
17730             is_body = true;
17731         }
17732         
17733         this.el = this.parent.el.addxtype(tree, undefined, is_body);
17734         this.fireEvent('built', this);
17735         
17736         this.panel = this.el;
17737         this.layout = this.panel.layout;
17738         this.parentLayout = this.parent.layout  || false;  
17739          
17740     }
17741     
17742 });
17743
17744 Roo.apply(Roo.XComponent, {
17745     /**
17746      * @property  hideProgress
17747      * true to disable the building progress bar.. usefull on single page renders.
17748      * @type Boolean
17749      */
17750     hideProgress : false,
17751     /**
17752      * @property  buildCompleted
17753      * True when the builder has completed building the interface.
17754      * @type Boolean
17755      */
17756     buildCompleted : false,
17757      
17758     /**
17759      * @property  topModule
17760      * the upper most module - uses document.element as it's constructor.
17761      * @type Object
17762      */
17763      
17764     topModule  : false,
17765       
17766     /**
17767      * @property  modules
17768      * array of modules to be created by registration system.
17769      * @type {Array} of Roo.XComponent
17770      */
17771     
17772     modules : [],
17773     /**
17774      * @property  elmodules
17775      * array of modules to be created by which use #ID 
17776      * @type {Array} of Roo.XComponent
17777      */
17778      
17779     elmodules : [],
17780
17781      /**
17782      * @property  is_alt
17783      * Is an alternative Root - normally used by bootstrap or other systems,
17784      *    where the top element in the tree can wrap 'body' 
17785      * @type {boolean}  (default false)
17786      */
17787      
17788     is_alt : false,
17789     /**
17790      * @property  build_from_html
17791      * Build elements from html - used by bootstrap HTML stuff 
17792      *    - this is cleared after build is completed
17793      * @type {boolean}    (default false)
17794      */
17795      
17796     build_from_html : false,
17797     /**
17798      * Register components to be built later.
17799      *
17800      * This solves the following issues
17801      * - Building is not done on page load, but after an authentication process has occured.
17802      * - Interface elements are registered on page load
17803      * - Parent Interface elements may not be loaded before child, so this handles that..
17804      * 
17805      *
17806      * example:
17807      * 
17808      * MyApp.register({
17809           order : '000001',
17810           module : 'Pman.Tab.projectMgr',
17811           region : 'center',
17812           parent : 'Pman.layout',
17813           disabled : false,  // or use a function..
17814         })
17815      
17816      * * @param {Object} details about module
17817      */
17818     register : function(obj) {
17819                 
17820         Roo.XComponent.event.fireEvent('register', obj);
17821         switch(typeof(obj.disabled) ) {
17822                 
17823             case 'undefined':
17824                 break;
17825             
17826             case 'function':
17827                 if ( obj.disabled() ) {
17828                         return;
17829                 }
17830                 break;
17831             
17832             default:
17833                 if (obj.disabled || obj.region == '#disabled') {
17834                         return;
17835                 }
17836                 break;
17837         }
17838                 
17839         this.modules.push(obj);
17840          
17841     },
17842     /**
17843      * convert a string to an object..
17844      * eg. 'AAA.BBB' -> finds AAA.BBB
17845
17846      */
17847     
17848     toObject : function(str)
17849     {
17850         if (!str || typeof(str) == 'object') {
17851             return str;
17852         }
17853         if (str.substring(0,1) == '#') {
17854             return str;
17855         }
17856
17857         var ar = str.split('.');
17858         var rt, o;
17859         rt = ar.shift();
17860             /** eval:var:o */
17861         try {
17862             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17863         } catch (e) {
17864             throw "Module not found : " + str;
17865         }
17866         
17867         if (o === false) {
17868             throw "Module not found : " + str;
17869         }
17870         Roo.each(ar, function(e) {
17871             if (typeof(o[e]) == 'undefined') {
17872                 throw "Module not found : " + str;
17873             }
17874             o = o[e];
17875         });
17876         
17877         return o;
17878         
17879     },
17880     
17881     
17882     /**
17883      * move modules into their correct place in the tree..
17884      * 
17885      */
17886     preBuild : function ()
17887     {
17888         var _t = this;
17889         Roo.each(this.modules , function (obj)
17890         {
17891             Roo.XComponent.event.fireEvent('beforebuild', obj);
17892             
17893             var opar = obj.parent;
17894             try { 
17895                 obj.parent = this.toObject(opar);
17896             } catch(e) {
17897                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17898                 return;
17899             }
17900             
17901             if (!obj.parent) {
17902                 Roo.debug && Roo.log("GOT top level module");
17903                 Roo.debug && Roo.log(obj);
17904                 obj.modules = new Roo.util.MixedCollection(false, 
17905                     function(o) { return o.order + '' }
17906                 );
17907                 this.topModule = obj;
17908                 return;
17909             }
17910                         // parent is a string (usually a dom element name..)
17911             if (typeof(obj.parent) == 'string') {
17912                 this.elmodules.push(obj);
17913                 return;
17914             }
17915             if (obj.parent.constructor != Roo.XComponent) {
17916                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17917             }
17918             if (!obj.parent.modules) {
17919                 obj.parent.modules = new Roo.util.MixedCollection(false, 
17920                     function(o) { return o.order + '' }
17921                 );
17922             }
17923             if (obj.parent.disabled) {
17924                 obj.disabled = true;
17925             }
17926             obj.parent.modules.add(obj);
17927         }, this);
17928     },
17929     
17930      /**
17931      * make a list of modules to build.
17932      * @return {Array} list of modules. 
17933      */ 
17934     
17935     buildOrder : function()
17936     {
17937         var _this = this;
17938         var cmp = function(a,b) {   
17939             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17940         };
17941         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17942             throw "No top level modules to build";
17943         }
17944         
17945         // make a flat list in order of modules to build.
17946         var mods = this.topModule ? [ this.topModule ] : [];
17947                 
17948         
17949         // elmodules (is a list of DOM based modules )
17950         Roo.each(this.elmodules, function(e) {
17951             mods.push(e);
17952             if (!this.topModule &&
17953                 typeof(e.parent) == 'string' &&
17954                 e.parent.substring(0,1) == '#' &&
17955                 Roo.get(e.parent.substr(1))
17956                ) {
17957                 
17958                 _this.topModule = e;
17959             }
17960             
17961         });
17962
17963         
17964         // add modules to their parents..
17965         var addMod = function(m) {
17966             Roo.debug && Roo.log("build Order: add: " + m.name);
17967                 
17968             mods.push(m);
17969             if (m.modules && !m.disabled) {
17970                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17971                 m.modules.keySort('ASC',  cmp );
17972                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17973     
17974                 m.modules.each(addMod);
17975             } else {
17976                 Roo.debug && Roo.log("build Order: no child modules");
17977             }
17978             // not sure if this is used any more..
17979             if (m.finalize) {
17980                 m.finalize.name = m.name + " (clean up) ";
17981                 mods.push(m.finalize);
17982             }
17983             
17984         }
17985         if (this.topModule && this.topModule.modules) { 
17986             this.topModule.modules.keySort('ASC',  cmp );
17987             this.topModule.modules.each(addMod);
17988         } 
17989         return mods;
17990     },
17991     
17992      /**
17993      * Build the registered modules.
17994      * @param {Object} parent element.
17995      * @param {Function} optional method to call after module has been added.
17996      * 
17997      */ 
17998    
17999     build : function(opts) 
18000     {
18001         
18002         if (typeof(opts) != 'undefined') {
18003             Roo.apply(this,opts);
18004         }
18005         
18006         this.preBuild();
18007         var mods = this.buildOrder();
18008       
18009         //this.allmods = mods;
18010         //Roo.debug && Roo.log(mods);
18011         //return;
18012         if (!mods.length) { // should not happen
18013             throw "NO modules!!!";
18014         }
18015         
18016         
18017         var msg = "Building Interface...";
18018         // flash it up as modal - so we store the mask!?
18019         if (!this.hideProgress && Roo.MessageBox) {
18020             Roo.MessageBox.show({ title: 'loading' });
18021             Roo.MessageBox.show({
18022                title: "Please wait...",
18023                msg: msg,
18024                width:450,
18025                progress:true,
18026                buttons : false,
18027                closable:false,
18028                modal: false
18029               
18030             });
18031         }
18032         var total = mods.length;
18033         
18034         var _this = this;
18035         var progressRun = function() {
18036             if (!mods.length) {
18037                 Roo.debug && Roo.log('hide?');
18038                 if (!this.hideProgress && Roo.MessageBox) {
18039                     Roo.MessageBox.hide();
18040                 }
18041                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18042                 
18043                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18044                 
18045                 // THE END...
18046                 return false;   
18047             }
18048             
18049             var m = mods.shift();
18050             
18051             
18052             Roo.debug && Roo.log(m);
18053             // not sure if this is supported any more.. - modules that are are just function
18054             if (typeof(m) == 'function') { 
18055                 m.call(this);
18056                 return progressRun.defer(10, _this);
18057             } 
18058             
18059             
18060             msg = "Building Interface " + (total  - mods.length) + 
18061                     " of " + total + 
18062                     (m.name ? (' - ' + m.name) : '');
18063                         Roo.debug && Roo.log(msg);
18064             if (!_this.hideProgress &&  Roo.MessageBox) { 
18065                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18066             }
18067             
18068          
18069             // is the module disabled?
18070             var disabled = (typeof(m.disabled) == 'function') ?
18071                 m.disabled.call(m.module.disabled) : m.disabled;    
18072             
18073             
18074             if (disabled) {
18075                 return progressRun(); // we do not update the display!
18076             }
18077             
18078             // now build 
18079             
18080                         
18081                         
18082             m.render();
18083             // it's 10 on top level, and 1 on others??? why...
18084             return progressRun.defer(10, _this);
18085              
18086         }
18087         progressRun.defer(1, _this);
18088      
18089         
18090         
18091     },
18092     /**
18093      * Overlay a set of modified strings onto a component
18094      * This is dependant on our builder exporting the strings and 'named strings' elements.
18095      * 
18096      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18097      * @param {Object} associative array of 'named' string and it's new value.
18098      * 
18099      */
18100         overlayStrings : function( component, strings )
18101     {
18102         if (typeof(component['_named_strings']) == 'undefined') {
18103             throw "ERROR: component does not have _named_strings";
18104         }
18105         for ( var k in strings ) {
18106             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18107             if (md !== false) {
18108                 component['_strings'][md] = strings[k];
18109             } else {
18110                 Roo.log('could not find named string: ' + k + ' in');
18111                 Roo.log(component);
18112             }
18113             
18114         }
18115         
18116     },
18117     
18118         
18119         /**
18120          * Event Object.
18121          *
18122          *
18123          */
18124         event: false, 
18125     /**
18126          * wrapper for event.on - aliased later..  
18127          * Typically use to register a event handler for register:
18128          *
18129          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18130          *
18131          */
18132     on : false
18133    
18134     
18135     
18136 });
18137
18138 Roo.XComponent.event = new Roo.util.Observable({
18139                 events : { 
18140                         /**
18141                          * @event register
18142                          * Fires when an Component is registered,
18143                          * set the disable property on the Component to stop registration.
18144                          * @param {Roo.XComponent} c the component being registerd.
18145                          * 
18146                          */
18147                         'register' : true,
18148             /**
18149                          * @event beforebuild
18150                          * Fires before each Component is built
18151                          * can be used to apply permissions.
18152                          * @param {Roo.XComponent} c the component being registerd.
18153                          * 
18154                          */
18155                         'beforebuild' : true,
18156                         /**
18157                          * @event buildcomplete
18158                          * Fires on the top level element when all elements have been built
18159                          * @param {Roo.XComponent} the top level component.
18160                          */
18161                         'buildcomplete' : true
18162                         
18163                 }
18164 });
18165
18166 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18167  //
18168  /**
18169  * marked - a markdown parser
18170  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18171  * https://github.com/chjj/marked
18172  */
18173
18174
18175 /**
18176  *
18177  * Roo.Markdown - is a very crude wrapper around marked..
18178  *
18179  * usage:
18180  * 
18181  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18182  * 
18183  * Note: move the sample code to the bottom of this
18184  * file before uncommenting it.
18185  *
18186  */
18187
18188 Roo.Markdown = {};
18189 Roo.Markdown.toHtml = function(text) {
18190     
18191     var c = new Roo.Markdown.marked.setOptions({
18192             renderer: new Roo.Markdown.marked.Renderer(),
18193             gfm: true,
18194             tables: true,
18195             breaks: false,
18196             pedantic: false,
18197             sanitize: false,
18198             smartLists: true,
18199             smartypants: false
18200           });
18201     // A FEW HACKS!!?
18202     
18203     text = text.replace(/\\\n/g,' ');
18204     return Roo.Markdown.marked(text);
18205 };
18206 //
18207 // converter
18208 //
18209 // Wraps all "globals" so that the only thing
18210 // exposed is makeHtml().
18211 //
18212 (function() {
18213     
18214      /**
18215          * eval:var:escape
18216          * eval:var:unescape
18217          * eval:var:replace
18218          */
18219       
18220     /**
18221      * Helpers
18222      */
18223     
18224     var escape = function (html, encode) {
18225       return html
18226         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18227         .replace(/</g, '&lt;')
18228         .replace(/>/g, '&gt;')
18229         .replace(/"/g, '&quot;')
18230         .replace(/'/g, '&#39;');
18231     }
18232     
18233     var unescape = function (html) {
18234         // explicitly match decimal, hex, and named HTML entities 
18235       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18236         n = n.toLowerCase();
18237         if (n === 'colon') { return ':'; }
18238         if (n.charAt(0) === '#') {
18239           return n.charAt(1) === 'x'
18240             ? String.fromCharCode(parseInt(n.substring(2), 16))
18241             : String.fromCharCode(+n.substring(1));
18242         }
18243         return '';
18244       });
18245     }
18246     
18247     var replace = function (regex, opt) {
18248       regex = regex.source;
18249       opt = opt || '';
18250       return function self(name, val) {
18251         if (!name) { return new RegExp(regex, opt); }
18252         val = val.source || val;
18253         val = val.replace(/(^|[^\[])\^/g, '$1');
18254         regex = regex.replace(name, val);
18255         return self;
18256       };
18257     }
18258
18259
18260          /**
18261          * eval:var:noop
18262     */
18263     var noop = function () {}
18264     noop.exec = noop;
18265     
18266          /**
18267          * eval:var:merge
18268     */
18269     var merge = function (obj) {
18270       var i = 1
18271         , target
18272         , key;
18273     
18274       for (; i < arguments.length; i++) {
18275         target = arguments[i];
18276         for (key in target) {
18277           if (Object.prototype.hasOwnProperty.call(target, key)) {
18278             obj[key] = target[key];
18279           }
18280         }
18281       }
18282     
18283       return obj;
18284     }
18285     
18286     
18287     /**
18288      * Block-Level Grammar
18289      */
18290     
18291     
18292     
18293     
18294     var block = {
18295       newline: /^\n+/,
18296       code: /^( {4}[^\n]+\n*)+/,
18297       fences: noop,
18298       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18299       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18300       nptable: noop,
18301       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18302       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18303       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18304       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18305       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18306       table: noop,
18307       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18308       text: /^[^\n]+/
18309     };
18310     
18311     block.bullet = /(?:[*+-]|\d+\.)/;
18312     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18313     block.item = replace(block.item, 'gm')
18314       (/bull/g, block.bullet)
18315       ();
18316     
18317     block.list = replace(block.list)
18318       (/bull/g, block.bullet)
18319       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18320       ('def', '\\n+(?=' + block.def.source + ')')
18321       ();
18322     
18323     block.blockquote = replace(block.blockquote)
18324       ('def', block.def)
18325       ();
18326     
18327     block._tag = '(?!(?:'
18328       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18329       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18330       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18331     
18332     block.html = replace(block.html)
18333       ('comment', /<!--[\s\S]*?-->/)
18334       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18335       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18336       (/tag/g, block._tag)
18337       ();
18338     
18339     block.paragraph = replace(block.paragraph)
18340       ('hr', block.hr)
18341       ('heading', block.heading)
18342       ('lheading', block.lheading)
18343       ('blockquote', block.blockquote)
18344       ('tag', '<' + block._tag)
18345       ('def', block.def)
18346       ();
18347     
18348     /**
18349      * Normal Block Grammar
18350      */
18351     
18352     block.normal = merge({}, block);
18353     
18354     /**
18355      * GFM Block Grammar
18356      */
18357     
18358     block.gfm = merge({}, block.normal, {
18359       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18360       paragraph: /^/,
18361       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18362     });
18363     
18364     block.gfm.paragraph = replace(block.paragraph)
18365       ('(?!', '(?!'
18366         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18367         + block.list.source.replace('\\1', '\\3') + '|')
18368       ();
18369     
18370     /**
18371      * GFM + Tables Block Grammar
18372      */
18373     
18374     block.tables = merge({}, block.gfm, {
18375       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18376       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18377     });
18378     
18379     /**
18380      * Block Lexer
18381      */
18382     
18383     var Lexer = function (options) {
18384       this.tokens = [];
18385       this.tokens.links = {};
18386       this.options = options || marked.defaults;
18387       this.rules = block.normal;
18388     
18389       if (this.options.gfm) {
18390         if (this.options.tables) {
18391           this.rules = block.tables;
18392         } else {
18393           this.rules = block.gfm;
18394         }
18395       }
18396     }
18397     
18398     /**
18399      * Expose Block Rules
18400      */
18401     
18402     Lexer.rules = block;
18403     
18404     /**
18405      * Static Lex Method
18406      */
18407     
18408     Lexer.lex = function(src, options) {
18409       var lexer = new Lexer(options);
18410       return lexer.lex(src);
18411     };
18412     
18413     /**
18414      * Preprocessing
18415      */
18416     
18417     Lexer.prototype.lex = function(src) {
18418       src = src
18419         .replace(/\r\n|\r/g, '\n')
18420         .replace(/\t/g, '    ')
18421         .replace(/\u00a0/g, ' ')
18422         .replace(/\u2424/g, '\n');
18423     
18424       return this.token(src, true);
18425     };
18426     
18427     /**
18428      * Lexing
18429      */
18430     
18431     Lexer.prototype.token = function(src, top, bq) {
18432       var src = src.replace(/^ +$/gm, '')
18433         , next
18434         , loose
18435         , cap
18436         , bull
18437         , b
18438         , item
18439         , space
18440         , i
18441         , l;
18442     
18443       while (src) {
18444         // newline
18445         if (cap = this.rules.newline.exec(src)) {
18446           src = src.substring(cap[0].length);
18447           if (cap[0].length > 1) {
18448             this.tokens.push({
18449               type: 'space'
18450             });
18451           }
18452         }
18453     
18454         // code
18455         if (cap = this.rules.code.exec(src)) {
18456           src = src.substring(cap[0].length);
18457           cap = cap[0].replace(/^ {4}/gm, '');
18458           this.tokens.push({
18459             type: 'code',
18460             text: !this.options.pedantic
18461               ? cap.replace(/\n+$/, '')
18462               : cap
18463           });
18464           continue;
18465         }
18466     
18467         // fences (gfm)
18468         if (cap = this.rules.fences.exec(src)) {
18469           src = src.substring(cap[0].length);
18470           this.tokens.push({
18471             type: 'code',
18472             lang: cap[2],
18473             text: cap[3] || ''
18474           });
18475           continue;
18476         }
18477     
18478         // heading
18479         if (cap = this.rules.heading.exec(src)) {
18480           src = src.substring(cap[0].length);
18481           this.tokens.push({
18482             type: 'heading',
18483             depth: cap[1].length,
18484             text: cap[2]
18485           });
18486           continue;
18487         }
18488     
18489         // table no leading pipe (gfm)
18490         if (top && (cap = this.rules.nptable.exec(src))) {
18491           src = src.substring(cap[0].length);
18492     
18493           item = {
18494             type: 'table',
18495             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18496             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18497             cells: cap[3].replace(/\n$/, '').split('\n')
18498           };
18499     
18500           for (i = 0; i < item.align.length; i++) {
18501             if (/^ *-+: *$/.test(item.align[i])) {
18502               item.align[i] = 'right';
18503             } else if (/^ *:-+: *$/.test(item.align[i])) {
18504               item.align[i] = 'center';
18505             } else if (/^ *:-+ *$/.test(item.align[i])) {
18506               item.align[i] = 'left';
18507             } else {
18508               item.align[i] = null;
18509             }
18510           }
18511     
18512           for (i = 0; i < item.cells.length; i++) {
18513             item.cells[i] = item.cells[i].split(/ *\| */);
18514           }
18515     
18516           this.tokens.push(item);
18517     
18518           continue;
18519         }
18520     
18521         // lheading
18522         if (cap = this.rules.lheading.exec(src)) {
18523           src = src.substring(cap[0].length);
18524           this.tokens.push({
18525             type: 'heading',
18526             depth: cap[2] === '=' ? 1 : 2,
18527             text: cap[1]
18528           });
18529           continue;
18530         }
18531     
18532         // hr
18533         if (cap = this.rules.hr.exec(src)) {
18534           src = src.substring(cap[0].length);
18535           this.tokens.push({
18536             type: 'hr'
18537           });
18538           continue;
18539         }
18540     
18541         // blockquote
18542         if (cap = this.rules.blockquote.exec(src)) {
18543           src = src.substring(cap[0].length);
18544     
18545           this.tokens.push({
18546             type: 'blockquote_start'
18547           });
18548     
18549           cap = cap[0].replace(/^ *> ?/gm, '');
18550     
18551           // Pass `top` to keep the current
18552           // "toplevel" state. This is exactly
18553           // how markdown.pl works.
18554           this.token(cap, top, true);
18555     
18556           this.tokens.push({
18557             type: 'blockquote_end'
18558           });
18559     
18560           continue;
18561         }
18562     
18563         // list
18564         if (cap = this.rules.list.exec(src)) {
18565           src = src.substring(cap[0].length);
18566           bull = cap[2];
18567     
18568           this.tokens.push({
18569             type: 'list_start',
18570             ordered: bull.length > 1
18571           });
18572     
18573           // Get each top-level item.
18574           cap = cap[0].match(this.rules.item);
18575     
18576           next = false;
18577           l = cap.length;
18578           i = 0;
18579     
18580           for (; i < l; i++) {
18581             item = cap[i];
18582     
18583             // Remove the list item's bullet
18584             // so it is seen as the next token.
18585             space = item.length;
18586             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18587     
18588             // Outdent whatever the
18589             // list item contains. Hacky.
18590             if (~item.indexOf('\n ')) {
18591               space -= item.length;
18592               item = !this.options.pedantic
18593                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18594                 : item.replace(/^ {1,4}/gm, '');
18595             }
18596     
18597             // Determine whether the next list item belongs here.
18598             // Backpedal if it does not belong in this list.
18599             if (this.options.smartLists && i !== l - 1) {
18600               b = block.bullet.exec(cap[i + 1])[0];
18601               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
18602                 src = cap.slice(i + 1).join('\n') + src;
18603                 i = l - 1;
18604               }
18605             }
18606     
18607             // Determine whether item is loose or not.
18608             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
18609             // for discount behavior.
18610             loose = next || /\n\n(?!\s*$)/.test(item);
18611             if (i !== l - 1) {
18612               next = item.charAt(item.length - 1) === '\n';
18613               if (!loose) { loose = next; }
18614             }
18615     
18616             this.tokens.push({
18617               type: loose
18618                 ? 'loose_item_start'
18619                 : 'list_item_start'
18620             });
18621     
18622             // Recurse.
18623             this.token(item, false, bq);
18624     
18625             this.tokens.push({
18626               type: 'list_item_end'
18627             });
18628           }
18629     
18630           this.tokens.push({
18631             type: 'list_end'
18632           });
18633     
18634           continue;
18635         }
18636     
18637         // html
18638         if (cap = this.rules.html.exec(src)) {
18639           src = src.substring(cap[0].length);
18640           this.tokens.push({
18641             type: this.options.sanitize
18642               ? 'paragraph'
18643               : 'html',
18644             pre: !this.options.sanitizer
18645               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
18646             text: cap[0]
18647           });
18648           continue;
18649         }
18650     
18651         // def
18652         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
18653           src = src.substring(cap[0].length);
18654           this.tokens.links[cap[1].toLowerCase()] = {
18655             href: cap[2],
18656             title: cap[3]
18657           };
18658           continue;
18659         }
18660     
18661         // table (gfm)
18662         if (top && (cap = this.rules.table.exec(src))) {
18663           src = src.substring(cap[0].length);
18664     
18665           item = {
18666             type: 'table',
18667             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18668             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18669             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
18670           };
18671     
18672           for (i = 0; i < item.align.length; i++) {
18673             if (/^ *-+: *$/.test(item.align[i])) {
18674               item.align[i] = 'right';
18675             } else if (/^ *:-+: *$/.test(item.align[i])) {
18676               item.align[i] = 'center';
18677             } else if (/^ *:-+ *$/.test(item.align[i])) {
18678               item.align[i] = 'left';
18679             } else {
18680               item.align[i] = null;
18681             }
18682           }
18683     
18684           for (i = 0; i < item.cells.length; i++) {
18685             item.cells[i] = item.cells[i]
18686               .replace(/^ *\| *| *\| *$/g, '')
18687               .split(/ *\| */);
18688           }
18689     
18690           this.tokens.push(item);
18691     
18692           continue;
18693         }
18694     
18695         // top-level paragraph
18696         if (top && (cap = this.rules.paragraph.exec(src))) {
18697           src = src.substring(cap[0].length);
18698           this.tokens.push({
18699             type: 'paragraph',
18700             text: cap[1].charAt(cap[1].length - 1) === '\n'
18701               ? cap[1].slice(0, -1)
18702               : cap[1]
18703           });
18704           continue;
18705         }
18706     
18707         // text
18708         if (cap = this.rules.text.exec(src)) {
18709           // Top-level should never reach here.
18710           src = src.substring(cap[0].length);
18711           this.tokens.push({
18712             type: 'text',
18713             text: cap[0]
18714           });
18715           continue;
18716         }
18717     
18718         if (src) {
18719           throw new
18720             Error('Infinite loop on byte: ' + src.charCodeAt(0));
18721         }
18722       }
18723     
18724       return this.tokens;
18725     };
18726     
18727     /**
18728      * Inline-Level Grammar
18729      */
18730     
18731     var inline = {
18732       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18733       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18734       url: noop,
18735       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18736       link: /^!?\[(inside)\]\(href\)/,
18737       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18738       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18739       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18740       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18741       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18742       br: /^ {2,}\n(?!\s*$)/,
18743       del: noop,
18744       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18745     };
18746     
18747     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18748     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18749     
18750     inline.link = replace(inline.link)
18751       ('inside', inline._inside)
18752       ('href', inline._href)
18753       ();
18754     
18755     inline.reflink = replace(inline.reflink)
18756       ('inside', inline._inside)
18757       ();
18758     
18759     /**
18760      * Normal Inline Grammar
18761      */
18762     
18763     inline.normal = merge({}, inline);
18764     
18765     /**
18766      * Pedantic Inline Grammar
18767      */
18768     
18769     inline.pedantic = merge({}, inline.normal, {
18770       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18771       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18772     });
18773     
18774     /**
18775      * GFM Inline Grammar
18776      */
18777     
18778     inline.gfm = merge({}, inline.normal, {
18779       escape: replace(inline.escape)('])', '~|])')(),
18780       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18781       del: /^~~(?=\S)([\s\S]*?\S)~~/,
18782       text: replace(inline.text)
18783         (']|', '~]|')
18784         ('|', '|https?://|')
18785         ()
18786     });
18787     
18788     /**
18789      * GFM + Line Breaks Inline Grammar
18790      */
18791     
18792     inline.breaks = merge({}, inline.gfm, {
18793       br: replace(inline.br)('{2,}', '*')(),
18794       text: replace(inline.gfm.text)('{2,}', '*')()
18795     });
18796     
18797     /**
18798      * Inline Lexer & Compiler
18799      */
18800     
18801     var InlineLexer  = function (links, options) {
18802       this.options = options || marked.defaults;
18803       this.links = links;
18804       this.rules = inline.normal;
18805       this.renderer = this.options.renderer || new Renderer;
18806       this.renderer.options = this.options;
18807     
18808       if (!this.links) {
18809         throw new
18810           Error('Tokens array requires a `links` property.');
18811       }
18812     
18813       if (this.options.gfm) {
18814         if (this.options.breaks) {
18815           this.rules = inline.breaks;
18816         } else {
18817           this.rules = inline.gfm;
18818         }
18819       } else if (this.options.pedantic) {
18820         this.rules = inline.pedantic;
18821       }
18822     }
18823     
18824     /**
18825      * Expose Inline Rules
18826      */
18827     
18828     InlineLexer.rules = inline;
18829     
18830     /**
18831      * Static Lexing/Compiling Method
18832      */
18833     
18834     InlineLexer.output = function(src, links, options) {
18835       var inline = new InlineLexer(links, options);
18836       return inline.output(src);
18837     };
18838     
18839     /**
18840      * Lexing/Compiling
18841      */
18842     
18843     InlineLexer.prototype.output = function(src) {
18844       var out = ''
18845         , link
18846         , text
18847         , href
18848         , cap;
18849     
18850       while (src) {
18851         // escape
18852         if (cap = this.rules.escape.exec(src)) {
18853           src = src.substring(cap[0].length);
18854           out += cap[1];
18855           continue;
18856         }
18857     
18858         // autolink
18859         if (cap = this.rules.autolink.exec(src)) {
18860           src = src.substring(cap[0].length);
18861           if (cap[2] === '@') {
18862             text = cap[1].charAt(6) === ':'
18863               ? this.mangle(cap[1].substring(7))
18864               : this.mangle(cap[1]);
18865             href = this.mangle('mailto:') + text;
18866           } else {
18867             text = escape(cap[1]);
18868             href = text;
18869           }
18870           out += this.renderer.link(href, null, text);
18871           continue;
18872         }
18873     
18874         // url (gfm)
18875         if (!this.inLink && (cap = this.rules.url.exec(src))) {
18876           src = src.substring(cap[0].length);
18877           text = escape(cap[1]);
18878           href = text;
18879           out += this.renderer.link(href, null, text);
18880           continue;
18881         }
18882     
18883         // tag
18884         if (cap = this.rules.tag.exec(src)) {
18885           if (!this.inLink && /^<a /i.test(cap[0])) {
18886             this.inLink = true;
18887           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18888             this.inLink = false;
18889           }
18890           src = src.substring(cap[0].length);
18891           out += this.options.sanitize
18892             ? this.options.sanitizer
18893               ? this.options.sanitizer(cap[0])
18894               : escape(cap[0])
18895             : cap[0];
18896           continue;
18897         }
18898     
18899         // link
18900         if (cap = this.rules.link.exec(src)) {
18901           src = src.substring(cap[0].length);
18902           this.inLink = true;
18903           out += this.outputLink(cap, {
18904             href: cap[2],
18905             title: cap[3]
18906           });
18907           this.inLink = false;
18908           continue;
18909         }
18910     
18911         // reflink, nolink
18912         if ((cap = this.rules.reflink.exec(src))
18913             || (cap = this.rules.nolink.exec(src))) {
18914           src = src.substring(cap[0].length);
18915           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18916           link = this.links[link.toLowerCase()];
18917           if (!link || !link.href) {
18918             out += cap[0].charAt(0);
18919             src = cap[0].substring(1) + src;
18920             continue;
18921           }
18922           this.inLink = true;
18923           out += this.outputLink(cap, link);
18924           this.inLink = false;
18925           continue;
18926         }
18927     
18928         // strong
18929         if (cap = this.rules.strong.exec(src)) {
18930           src = src.substring(cap[0].length);
18931           out += this.renderer.strong(this.output(cap[2] || cap[1]));
18932           continue;
18933         }
18934     
18935         // em
18936         if (cap = this.rules.em.exec(src)) {
18937           src = src.substring(cap[0].length);
18938           out += this.renderer.em(this.output(cap[2] || cap[1]));
18939           continue;
18940         }
18941     
18942         // code
18943         if (cap = this.rules.code.exec(src)) {
18944           src = src.substring(cap[0].length);
18945           out += this.renderer.codespan(escape(cap[2], true));
18946           continue;
18947         }
18948     
18949         // br
18950         if (cap = this.rules.br.exec(src)) {
18951           src = src.substring(cap[0].length);
18952           out += this.renderer.br();
18953           continue;
18954         }
18955     
18956         // del (gfm)
18957         if (cap = this.rules.del.exec(src)) {
18958           src = src.substring(cap[0].length);
18959           out += this.renderer.del(this.output(cap[1]));
18960           continue;
18961         }
18962     
18963         // text
18964         if (cap = this.rules.text.exec(src)) {
18965           src = src.substring(cap[0].length);
18966           out += this.renderer.text(escape(this.smartypants(cap[0])));
18967           continue;
18968         }
18969     
18970         if (src) {
18971           throw new
18972             Error('Infinite loop on byte: ' + src.charCodeAt(0));
18973         }
18974       }
18975     
18976       return out;
18977     };
18978     
18979     /**
18980      * Compile Link
18981      */
18982     
18983     InlineLexer.prototype.outputLink = function(cap, link) {
18984       var href = escape(link.href)
18985         , title = link.title ? escape(link.title) : null;
18986     
18987       return cap[0].charAt(0) !== '!'
18988         ? this.renderer.link(href, title, this.output(cap[1]))
18989         : this.renderer.image(href, title, escape(cap[1]));
18990     };
18991     
18992     /**
18993      * Smartypants Transformations
18994      */
18995     
18996     InlineLexer.prototype.smartypants = function(text) {
18997       if (!this.options.smartypants)  { return text; }
18998       return text
18999         // em-dashes
19000         .replace(/---/g, '\u2014')
19001         // en-dashes
19002         .replace(/--/g, '\u2013')
19003         // opening singles
19004         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19005         // closing singles & apostrophes
19006         .replace(/'/g, '\u2019')
19007         // opening doubles
19008         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19009         // closing doubles
19010         .replace(/"/g, '\u201d')
19011         // ellipses
19012         .replace(/\.{3}/g, '\u2026');
19013     };
19014     
19015     /**
19016      * Mangle Links
19017      */
19018     
19019     InlineLexer.prototype.mangle = function(text) {
19020       if (!this.options.mangle) { return text; }
19021       var out = ''
19022         , l = text.length
19023         , i = 0
19024         , ch;
19025     
19026       for (; i < l; i++) {
19027         ch = text.charCodeAt(i);
19028         if (Math.random() > 0.5) {
19029           ch = 'x' + ch.toString(16);
19030         }
19031         out += '&#' + ch + ';';
19032       }
19033     
19034       return out;
19035     };
19036     
19037     /**
19038      * Renderer
19039      */
19040     
19041      /**
19042          * eval:var:Renderer
19043     */
19044     
19045     var Renderer   = function (options) {
19046       this.options = options || {};
19047     }
19048     
19049     Renderer.prototype.code = function(code, lang, escaped) {
19050       if (this.options.highlight) {
19051         var out = this.options.highlight(code, lang);
19052         if (out != null && out !== code) {
19053           escaped = true;
19054           code = out;
19055         }
19056       } else {
19057             // hack!!! - it's already escapeD?
19058             escaped = true;
19059       }
19060     
19061       if (!lang) {
19062         return '<pre><code>'
19063           + (escaped ? code : escape(code, true))
19064           + '\n</code></pre>';
19065       }
19066     
19067       return '<pre><code class="'
19068         + this.options.langPrefix
19069         + escape(lang, true)
19070         + '">'
19071         + (escaped ? code : escape(code, true))
19072         + '\n</code></pre>\n';
19073     };
19074     
19075     Renderer.prototype.blockquote = function(quote) {
19076       return '<blockquote>\n' + quote + '</blockquote>\n';
19077     };
19078     
19079     Renderer.prototype.html = function(html) {
19080       return html;
19081     };
19082     
19083     Renderer.prototype.heading = function(text, level, raw) {
19084       return '<h'
19085         + level
19086         + ' id="'
19087         + this.options.headerPrefix
19088         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19089         + '">'
19090         + text
19091         + '</h'
19092         + level
19093         + '>\n';
19094     };
19095     
19096     Renderer.prototype.hr = function() {
19097       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19098     };
19099     
19100     Renderer.prototype.list = function(body, ordered) {
19101       var type = ordered ? 'ol' : 'ul';
19102       return '<' + type + '>\n' + body + '</' + type + '>\n';
19103     };
19104     
19105     Renderer.prototype.listitem = function(text) {
19106       return '<li>' + text + '</li>\n';
19107     };
19108     
19109     Renderer.prototype.paragraph = function(text) {
19110       return '<p>' + text + '</p>\n';
19111     };
19112     
19113     Renderer.prototype.table = function(header, body) {
19114       return '<table class="table table-striped">\n'
19115         + '<thead>\n'
19116         + header
19117         + '</thead>\n'
19118         + '<tbody>\n'
19119         + body
19120         + '</tbody>\n'
19121         + '</table>\n';
19122     };
19123     
19124     Renderer.prototype.tablerow = function(content) {
19125       return '<tr>\n' + content + '</tr>\n';
19126     };
19127     
19128     Renderer.prototype.tablecell = function(content, flags) {
19129       var type = flags.header ? 'th' : 'td';
19130       var tag = flags.align
19131         ? '<' + type + ' style="text-align:' + flags.align + '">'
19132         : '<' + type + '>';
19133       return tag + content + '</' + type + '>\n';
19134     };
19135     
19136     // span level renderer
19137     Renderer.prototype.strong = function(text) {
19138       return '<strong>' + text + '</strong>';
19139     };
19140     
19141     Renderer.prototype.em = function(text) {
19142       return '<em>' + text + '</em>';
19143     };
19144     
19145     Renderer.prototype.codespan = function(text) {
19146       return '<code>' + text + '</code>';
19147     };
19148     
19149     Renderer.prototype.br = function() {
19150       return this.options.xhtml ? '<br/>' : '<br>';
19151     };
19152     
19153     Renderer.prototype.del = function(text) {
19154       return '<del>' + text + '</del>';
19155     };
19156     
19157     Renderer.prototype.link = function(href, title, text) {
19158       if (this.options.sanitize) {
19159         try {
19160           var prot = decodeURIComponent(unescape(href))
19161             .replace(/[^\w:]/g, '')
19162             .toLowerCase();
19163         } catch (e) {
19164           return '';
19165         }
19166         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19167           return '';
19168         }
19169       }
19170       var out = '<a href="' + href + '"';
19171       if (title) {
19172         out += ' title="' + title + '"';
19173       }
19174       out += '>' + text + '</a>';
19175       return out;
19176     };
19177     
19178     Renderer.prototype.image = function(href, title, text) {
19179       var out = '<img src="' + href + '" alt="' + text + '"';
19180       if (title) {
19181         out += ' title="' + title + '"';
19182       }
19183       out += this.options.xhtml ? '/>' : '>';
19184       return out;
19185     };
19186     
19187     Renderer.prototype.text = function(text) {
19188       return text;
19189     };
19190     
19191     /**
19192      * Parsing & Compiling
19193      */
19194          /**
19195          * eval:var:Parser
19196     */
19197     
19198     var Parser= function (options) {
19199       this.tokens = [];
19200       this.token = null;
19201       this.options = options || marked.defaults;
19202       this.options.renderer = this.options.renderer || new Renderer;
19203       this.renderer = this.options.renderer;
19204       this.renderer.options = this.options;
19205     }
19206     
19207     /**
19208      * Static Parse Method
19209      */
19210     
19211     Parser.parse = function(src, options, renderer) {
19212       var parser = new Parser(options, renderer);
19213       return parser.parse(src);
19214     };
19215     
19216     /**
19217      * Parse Loop
19218      */
19219     
19220     Parser.prototype.parse = function(src) {
19221       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19222       this.tokens = src.reverse();
19223     
19224       var out = '';
19225       while (this.next()) {
19226         out += this.tok();
19227       }
19228     
19229       return out;
19230     };
19231     
19232     /**
19233      * Next Token
19234      */
19235     
19236     Parser.prototype.next = function() {
19237       return this.token = this.tokens.pop();
19238     };
19239     
19240     /**
19241      * Preview Next Token
19242      */
19243     
19244     Parser.prototype.peek = function() {
19245       return this.tokens[this.tokens.length - 1] || 0;
19246     };
19247     
19248     /**
19249      * Parse Text Tokens
19250      */
19251     
19252     Parser.prototype.parseText = function() {
19253       var body = this.token.text;
19254     
19255       while (this.peek().type === 'text') {
19256         body += '\n' + this.next().text;
19257       }
19258     
19259       return this.inline.output(body);
19260     };
19261     
19262     /**
19263      * Parse Current Token
19264      */
19265     
19266     Parser.prototype.tok = function() {
19267       switch (this.token.type) {
19268         case 'space': {
19269           return '';
19270         }
19271         case 'hr': {
19272           return this.renderer.hr();
19273         }
19274         case 'heading': {
19275           return this.renderer.heading(
19276             this.inline.output(this.token.text),
19277             this.token.depth,
19278             this.token.text);
19279         }
19280         case 'code': {
19281           return this.renderer.code(this.token.text,
19282             this.token.lang,
19283             this.token.escaped);
19284         }
19285         case 'table': {
19286           var header = ''
19287             , body = ''
19288             , i
19289             , row
19290             , cell
19291             , flags
19292             , j;
19293     
19294           // header
19295           cell = '';
19296           for (i = 0; i < this.token.header.length; i++) {
19297             flags = { header: true, align: this.token.align[i] };
19298             cell += this.renderer.tablecell(
19299               this.inline.output(this.token.header[i]),
19300               { header: true, align: this.token.align[i] }
19301             );
19302           }
19303           header += this.renderer.tablerow(cell);
19304     
19305           for (i = 0; i < this.token.cells.length; i++) {
19306             row = this.token.cells[i];
19307     
19308             cell = '';
19309             for (j = 0; j < row.length; j++) {
19310               cell += this.renderer.tablecell(
19311                 this.inline.output(row[j]),
19312                 { header: false, align: this.token.align[j] }
19313               );
19314             }
19315     
19316             body += this.renderer.tablerow(cell);
19317           }
19318           return this.renderer.table(header, body);
19319         }
19320         case 'blockquote_start': {
19321           var body = '';
19322     
19323           while (this.next().type !== 'blockquote_end') {
19324             body += this.tok();
19325           }
19326     
19327           return this.renderer.blockquote(body);
19328         }
19329         case 'list_start': {
19330           var body = ''
19331             , ordered = this.token.ordered;
19332     
19333           while (this.next().type !== 'list_end') {
19334             body += this.tok();
19335           }
19336     
19337           return this.renderer.list(body, ordered);
19338         }
19339         case 'list_item_start': {
19340           var body = '';
19341     
19342           while (this.next().type !== 'list_item_end') {
19343             body += this.token.type === 'text'
19344               ? this.parseText()
19345               : this.tok();
19346           }
19347     
19348           return this.renderer.listitem(body);
19349         }
19350         case 'loose_item_start': {
19351           var body = '';
19352     
19353           while (this.next().type !== 'list_item_end') {
19354             body += this.tok();
19355           }
19356     
19357           return this.renderer.listitem(body);
19358         }
19359         case 'html': {
19360           var html = !this.token.pre && !this.options.pedantic
19361             ? this.inline.output(this.token.text)
19362             : this.token.text;
19363           return this.renderer.html(html);
19364         }
19365         case 'paragraph': {
19366           return this.renderer.paragraph(this.inline.output(this.token.text));
19367         }
19368         case 'text': {
19369           return this.renderer.paragraph(this.parseText());
19370         }
19371       }
19372     };
19373   
19374     
19375     /**
19376      * Marked
19377      */
19378          /**
19379          * eval:var:marked
19380     */
19381     var marked = function (src, opt, callback) {
19382       if (callback || typeof opt === 'function') {
19383         if (!callback) {
19384           callback = opt;
19385           opt = null;
19386         }
19387     
19388         opt = merge({}, marked.defaults, opt || {});
19389     
19390         var highlight = opt.highlight
19391           , tokens
19392           , pending
19393           , i = 0;
19394     
19395         try {
19396           tokens = Lexer.lex(src, opt)
19397         } catch (e) {
19398           return callback(e);
19399         }
19400     
19401         pending = tokens.length;
19402          /**
19403          * eval:var:done
19404     */
19405         var done = function(err) {
19406           if (err) {
19407             opt.highlight = highlight;
19408             return callback(err);
19409           }
19410     
19411           var out;
19412     
19413           try {
19414             out = Parser.parse(tokens, opt);
19415           } catch (e) {
19416             err = e;
19417           }
19418     
19419           opt.highlight = highlight;
19420     
19421           return err
19422             ? callback(err)
19423             : callback(null, out);
19424         };
19425     
19426         if (!highlight || highlight.length < 3) {
19427           return done();
19428         }
19429     
19430         delete opt.highlight;
19431     
19432         if (!pending) { return done(); }
19433     
19434         for (; i < tokens.length; i++) {
19435           (function(token) {
19436             if (token.type !== 'code') {
19437               return --pending || done();
19438             }
19439             return highlight(token.text, token.lang, function(err, code) {
19440               if (err) { return done(err); }
19441               if (code == null || code === token.text) {
19442                 return --pending || done();
19443               }
19444               token.text = code;
19445               token.escaped = true;
19446               --pending || done();
19447             });
19448           })(tokens[i]);
19449         }
19450     
19451         return;
19452       }
19453       try {
19454         if (opt) { opt = merge({}, marked.defaults, opt); }
19455         return Parser.parse(Lexer.lex(src, opt), opt);
19456       } catch (e) {
19457         e.message += '\nPlease report this to https://github.com/chjj/marked.';
19458         if ((opt || marked.defaults).silent) {
19459           return '<p>An error occured:</p><pre>'
19460             + escape(e.message + '', true)
19461             + '</pre>';
19462         }
19463         throw e;
19464       }
19465     }
19466     
19467     /**
19468      * Options
19469      */
19470     
19471     marked.options =
19472     marked.setOptions = function(opt) {
19473       merge(marked.defaults, opt);
19474       return marked;
19475     };
19476     
19477     marked.defaults = {
19478       gfm: true,
19479       tables: true,
19480       breaks: false,
19481       pedantic: false,
19482       sanitize: false,
19483       sanitizer: null,
19484       mangle: true,
19485       smartLists: false,
19486       silent: false,
19487       highlight: null,
19488       langPrefix: 'lang-',
19489       smartypants: false,
19490       headerPrefix: '',
19491       renderer: new Renderer,
19492       xhtml: false
19493     };
19494     
19495     /**
19496      * Expose
19497      */
19498     
19499     marked.Parser = Parser;
19500     marked.parser = Parser.parse;
19501     
19502     marked.Renderer = Renderer;
19503     
19504     marked.Lexer = Lexer;
19505     marked.lexer = Lexer.lex;
19506     
19507     marked.InlineLexer = InlineLexer;
19508     marked.inlineLexer = InlineLexer.output;
19509     
19510     marked.parse = marked;
19511     
19512     Roo.Markdown.marked = marked;
19513
19514 })();/*
19515  * Based on:
19516  * Ext JS Library 1.1.1
19517  * Copyright(c) 2006-2007, Ext JS, LLC.
19518  *
19519  * Originally Released Under LGPL - original licence link has changed is not relivant.
19520  *
19521  * Fork - LGPL
19522  * <script type="text/javascript">
19523  */
19524
19525
19526
19527 /*
19528  * These classes are derivatives of the similarly named classes in the YUI Library.
19529  * The original license:
19530  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19531  * Code licensed under the BSD License:
19532  * http://developer.yahoo.net/yui/license.txt
19533  */
19534
19535 (function() {
19536
19537 var Event=Roo.EventManager;
19538 var Dom=Roo.lib.Dom;
19539
19540 /**
19541  * @class Roo.dd.DragDrop
19542  * @extends Roo.util.Observable
19543  * Defines the interface and base operation of items that that can be
19544  * dragged or can be drop targets.  It was designed to be extended, overriding
19545  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19546  * Up to three html elements can be associated with a DragDrop instance:
19547  * <ul>
19548  * <li>linked element: the element that is passed into the constructor.
19549  * This is the element which defines the boundaries for interaction with
19550  * other DragDrop objects.</li>
19551  * <li>handle element(s): The drag operation only occurs if the element that
19552  * was clicked matches a handle element.  By default this is the linked
19553  * element, but there are times that you will want only a portion of the
19554  * linked element to initiate the drag operation, and the setHandleElId()
19555  * method provides a way to define this.</li>
19556  * <li>drag element: this represents the element that would be moved along
19557  * with the cursor during a drag operation.  By default, this is the linked
19558  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
19559  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19560  * </li>
19561  * </ul>
19562  * This class should not be instantiated until the onload event to ensure that
19563  * the associated elements are available.
19564  * The following would define a DragDrop obj that would interact with any
19565  * other DragDrop obj in the "group1" group:
19566  * <pre>
19567  *  dd = new Roo.dd.DragDrop("div1", "group1");
19568  * </pre>
19569  * Since none of the event handlers have been implemented, nothing would
19570  * actually happen if you were to run the code above.  Normally you would
19571  * override this class or one of the default implementations, but you can
19572  * also override the methods you want on an instance of the class...
19573  * <pre>
19574  *  dd.onDragDrop = function(e, id) {
19575  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
19576  *  }
19577  * </pre>
19578  * @constructor
19579  * @param {String} id of the element that is linked to this instance
19580  * @param {String} sGroup the group of related DragDrop objects
19581  * @param {object} config an object containing configurable attributes
19582  *                Valid properties for DragDrop:
19583  *                    padding, isTarget, maintainOffset, primaryButtonOnly
19584  */
19585 Roo.dd.DragDrop = function(id, sGroup, config) {
19586     if (id) {
19587         this.init(id, sGroup, config);
19588     }
19589     
19590 };
19591
19592 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19593
19594     /**
19595      * The id of the element associated with this object.  This is what we
19596      * refer to as the "linked element" because the size and position of
19597      * this element is used to determine when the drag and drop objects have
19598      * interacted.
19599      * @property id
19600      * @type String
19601      */
19602     id: null,
19603
19604     /**
19605      * Configuration attributes passed into the constructor
19606      * @property config
19607      * @type object
19608      */
19609     config: null,
19610
19611     /**
19612      * The id of the element that will be dragged.  By default this is same
19613      * as the linked element , but could be changed to another element. Ex:
19614      * Roo.dd.DDProxy
19615      * @property dragElId
19616      * @type String
19617      * @private
19618      */
19619     dragElId: null,
19620
19621     /**
19622      * the id of the element that initiates the drag operation.  By default
19623      * this is the linked element, but could be changed to be a child of this
19624      * element.  This lets us do things like only starting the drag when the
19625      * header element within the linked html element is clicked.
19626      * @property handleElId
19627      * @type String
19628      * @private
19629      */
19630     handleElId: null,
19631
19632     /**
19633      * An associative array of HTML tags that will be ignored if clicked.
19634      * @property invalidHandleTypes
19635      * @type {string: string}
19636      */
19637     invalidHandleTypes: null,
19638
19639     /**
19640      * An associative array of ids for elements that will be ignored if clicked
19641      * @property invalidHandleIds
19642      * @type {string: string}
19643      */
19644     invalidHandleIds: null,
19645
19646     /**
19647      * An indexted array of css class names for elements that will be ignored
19648      * if clicked.
19649      * @property invalidHandleClasses
19650      * @type string[]
19651      */
19652     invalidHandleClasses: null,
19653
19654     /**
19655      * The linked element's absolute X position at the time the drag was
19656      * started
19657      * @property startPageX
19658      * @type int
19659      * @private
19660      */
19661     startPageX: 0,
19662
19663     /**
19664      * The linked element's absolute X position at the time the drag was
19665      * started
19666      * @property startPageY
19667      * @type int
19668      * @private
19669      */
19670     startPageY: 0,
19671
19672     /**
19673      * The group defines a logical collection of DragDrop objects that are
19674      * related.  Instances only get events when interacting with other
19675      * DragDrop object in the same group.  This lets us define multiple
19676      * groups using a single DragDrop subclass if we want.
19677      * @property groups
19678      * @type {string: string}
19679      */
19680     groups: null,
19681
19682     /**
19683      * Individual drag/drop instances can be locked.  This will prevent
19684      * onmousedown start drag.
19685      * @property locked
19686      * @type boolean
19687      * @private
19688      */
19689     locked: false,
19690
19691     /**
19692      * Lock this instance
19693      * @method lock
19694      */
19695     lock: function() { this.locked = true; },
19696
19697     /**
19698      * Unlock this instace
19699      * @method unlock
19700      */
19701     unlock: function() { this.locked = false; },
19702
19703     /**
19704      * By default, all insances can be a drop target.  This can be disabled by
19705      * setting isTarget to false.
19706      * @method isTarget
19707      * @type boolean
19708      */
19709     isTarget: true,
19710
19711     /**
19712      * The padding configured for this drag and drop object for calculating
19713      * the drop zone intersection with this object.
19714      * @method padding
19715      * @type int[]
19716      */
19717     padding: null,
19718
19719     /**
19720      * Cached reference to the linked element
19721      * @property _domRef
19722      * @private
19723      */
19724     _domRef: null,
19725
19726     /**
19727      * Internal typeof flag
19728      * @property __ygDragDrop
19729      * @private
19730      */
19731     __ygDragDrop: true,
19732
19733     /**
19734      * Set to true when horizontal contraints are applied
19735      * @property constrainX
19736      * @type boolean
19737      * @private
19738      */
19739     constrainX: false,
19740
19741     /**
19742      * Set to true when vertical contraints are applied
19743      * @property constrainY
19744      * @type boolean
19745      * @private
19746      */
19747     constrainY: false,
19748
19749     /**
19750      * The left constraint
19751      * @property minX
19752      * @type int
19753      * @private
19754      */
19755     minX: 0,
19756
19757     /**
19758      * The right constraint
19759      * @property maxX
19760      * @type int
19761      * @private
19762      */
19763     maxX: 0,
19764
19765     /**
19766      * The up constraint
19767      * @property minY
19768      * @type int
19769      * @type int
19770      * @private
19771      */
19772     minY: 0,
19773
19774     /**
19775      * The down constraint
19776      * @property maxY
19777      * @type int
19778      * @private
19779      */
19780     maxY: 0,
19781
19782     /**
19783      * Maintain offsets when we resetconstraints.  Set to true when you want
19784      * the position of the element relative to its parent to stay the same
19785      * when the page changes
19786      *
19787      * @property maintainOffset
19788      * @type boolean
19789      */
19790     maintainOffset: false,
19791
19792     /**
19793      * Array of pixel locations the element will snap to if we specified a
19794      * horizontal graduation/interval.  This array is generated automatically
19795      * when you define a tick interval.
19796      * @property xTicks
19797      * @type int[]
19798      */
19799     xTicks: null,
19800
19801     /**
19802      * Array of pixel locations the element will snap to if we specified a
19803      * vertical graduation/interval.  This array is generated automatically
19804      * when you define a tick interval.
19805      * @property yTicks
19806      * @type int[]
19807      */
19808     yTicks: null,
19809
19810     /**
19811      * By default the drag and drop instance will only respond to the primary
19812      * button click (left button for a right-handed mouse).  Set to true to
19813      * allow drag and drop to start with any mouse click that is propogated
19814      * by the browser
19815      * @property primaryButtonOnly
19816      * @type boolean
19817      */
19818     primaryButtonOnly: true,
19819
19820     /**
19821      * The availabe property is false until the linked dom element is accessible.
19822      * @property available
19823      * @type boolean
19824      */
19825     available: false,
19826
19827     /**
19828      * By default, drags can only be initiated if the mousedown occurs in the
19829      * region the linked element is.  This is done in part to work around a
19830      * bug in some browsers that mis-report the mousedown if the previous
19831      * mouseup happened outside of the window.  This property is set to true
19832      * if outer handles are defined.
19833      *
19834      * @property hasOuterHandles
19835      * @type boolean
19836      * @default false
19837      */
19838     hasOuterHandles: false,
19839
19840     /**
19841      * Code that executes immediately before the startDrag event
19842      * @method b4StartDrag
19843      * @private
19844      */
19845     b4StartDrag: function(x, y) { },
19846
19847     /**
19848      * Abstract method called after a drag/drop object is clicked
19849      * and the drag or mousedown time thresholds have beeen met.
19850      * @method startDrag
19851      * @param {int} X click location
19852      * @param {int} Y click location
19853      */
19854     startDrag: function(x, y) { /* override this */ },
19855
19856     /**
19857      * Code that executes immediately before the onDrag event
19858      * @method b4Drag
19859      * @private
19860      */
19861     b4Drag: function(e) { },
19862
19863     /**
19864      * Abstract method called during the onMouseMove event while dragging an
19865      * object.
19866      * @method onDrag
19867      * @param {Event} e the mousemove event
19868      */
19869     onDrag: function(e) { /* override this */ },
19870
19871     /**
19872      * Abstract method called when this element fist begins hovering over
19873      * another DragDrop obj
19874      * @method onDragEnter
19875      * @param {Event} e the mousemove event
19876      * @param {String|DragDrop[]} id In POINT mode, the element
19877      * id this is hovering over.  In INTERSECT mode, an array of one or more
19878      * dragdrop items being hovered over.
19879      */
19880     onDragEnter: function(e, id) { /* override this */ },
19881
19882     /**
19883      * Code that executes immediately before the onDragOver event
19884      * @method b4DragOver
19885      * @private
19886      */
19887     b4DragOver: function(e) { },
19888
19889     /**
19890      * Abstract method called when this element is hovering over another
19891      * DragDrop obj
19892      * @method onDragOver
19893      * @param {Event} e the mousemove event
19894      * @param {String|DragDrop[]} id In POINT mode, the element
19895      * id this is hovering over.  In INTERSECT mode, an array of dd items
19896      * being hovered over.
19897      */
19898     onDragOver: function(e, id) { /* override this */ },
19899
19900     /**
19901      * Code that executes immediately before the onDragOut event
19902      * @method b4DragOut
19903      * @private
19904      */
19905     b4DragOut: function(e) { },
19906
19907     /**
19908      * Abstract method called when we are no longer hovering over an element
19909      * @method onDragOut
19910      * @param {Event} e the mousemove event
19911      * @param {String|DragDrop[]} id In POINT mode, the element
19912      * id this was hovering over.  In INTERSECT mode, an array of dd items
19913      * that the mouse is no longer over.
19914      */
19915     onDragOut: function(e, id) { /* override this */ },
19916
19917     /**
19918      * Code that executes immediately before the onDragDrop event
19919      * @method b4DragDrop
19920      * @private
19921      */
19922     b4DragDrop: function(e) { },
19923
19924     /**
19925      * Abstract method called when this item is dropped on another DragDrop
19926      * obj
19927      * @method onDragDrop
19928      * @param {Event} e the mouseup event
19929      * @param {String|DragDrop[]} id In POINT mode, the element
19930      * id this was dropped on.  In INTERSECT mode, an array of dd items this
19931      * was dropped on.
19932      */
19933     onDragDrop: function(e, id) { /* override this */ },
19934
19935     /**
19936      * Abstract method called when this item is dropped on an area with no
19937      * drop target
19938      * @method onInvalidDrop
19939      * @param {Event} e the mouseup event
19940      */
19941     onInvalidDrop: function(e) { /* override this */ },
19942
19943     /**
19944      * Code that executes immediately before the endDrag event
19945      * @method b4EndDrag
19946      * @private
19947      */
19948     b4EndDrag: function(e) { },
19949
19950     /**
19951      * Fired when we are done dragging the object
19952      * @method endDrag
19953      * @param {Event} e the mouseup event
19954      */
19955     endDrag: function(e) { /* override this */ },
19956
19957     /**
19958      * Code executed immediately before the onMouseDown event
19959      * @method b4MouseDown
19960      * @param {Event} e the mousedown event
19961      * @private
19962      */
19963     b4MouseDown: function(e) {  },
19964
19965     /**
19966      * Event handler that fires when a drag/drop obj gets a mousedown
19967      * @method onMouseDown
19968      * @param {Event} e the mousedown event
19969      */
19970     onMouseDown: function(e) { /* override this */ },
19971
19972     /**
19973      * Event handler that fires when a drag/drop obj gets a mouseup
19974      * @method onMouseUp
19975      * @param {Event} e the mouseup event
19976      */
19977     onMouseUp: function(e) { /* override this */ },
19978
19979     /**
19980      * Override the onAvailable method to do what is needed after the initial
19981      * position was determined.
19982      * @method onAvailable
19983      */
19984     onAvailable: function () {
19985     },
19986
19987     /*
19988      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19989      * @type Object
19990      */
19991     defaultPadding : {left:0, right:0, top:0, bottom:0},
19992
19993     /*
19994      * Initializes the drag drop object's constraints to restrict movement to a certain element.
19995  *
19996  * Usage:
19997  <pre><code>
19998  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19999                 { dragElId: "existingProxyDiv" });
20000  dd.startDrag = function(){
20001      this.constrainTo("parent-id");
20002  };
20003  </code></pre>
20004  * Or you can initalize it using the {@link Roo.Element} object:
20005  <pre><code>
20006  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20007      startDrag : function(){
20008          this.constrainTo("parent-id");
20009      }
20010  });
20011  </code></pre>
20012      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20013      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20014      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20015      * an object containing the sides to pad. For example: {right:10, bottom:10}
20016      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20017      */
20018     constrainTo : function(constrainTo, pad, inContent){
20019         if(typeof pad == "number"){
20020             pad = {left: pad, right:pad, top:pad, bottom:pad};
20021         }
20022         pad = pad || this.defaultPadding;
20023         var b = Roo.get(this.getEl()).getBox();
20024         var ce = Roo.get(constrainTo);
20025         var s = ce.getScroll();
20026         var c, cd = ce.dom;
20027         if(cd == document.body){
20028             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20029         }else{
20030             xy = ce.getXY();
20031             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20032         }
20033
20034
20035         var topSpace = b.y - c.y;
20036         var leftSpace = b.x - c.x;
20037
20038         this.resetConstraints();
20039         this.setXConstraint(leftSpace - (pad.left||0), // left
20040                 c.width - leftSpace - b.width - (pad.right||0) //right
20041         );
20042         this.setYConstraint(topSpace - (pad.top||0), //top
20043                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20044         );
20045     },
20046
20047     /**
20048      * Returns a reference to the linked element
20049      * @method getEl
20050      * @return {HTMLElement} the html element
20051      */
20052     getEl: function() {
20053         if (!this._domRef) {
20054             this._domRef = Roo.getDom(this.id);
20055         }
20056
20057         return this._domRef;
20058     },
20059
20060     /**
20061      * Returns a reference to the actual element to drag.  By default this is
20062      * the same as the html element, but it can be assigned to another
20063      * element. An example of this can be found in Roo.dd.DDProxy
20064      * @method getDragEl
20065      * @return {HTMLElement} the html element
20066      */
20067     getDragEl: function() {
20068         return Roo.getDom(this.dragElId);
20069     },
20070
20071     /**
20072      * Sets up the DragDrop object.  Must be called in the constructor of any
20073      * Roo.dd.DragDrop subclass
20074      * @method init
20075      * @param id the id of the linked element
20076      * @param {String} sGroup the group of related items
20077      * @param {object} config configuration attributes
20078      */
20079     init: function(id, sGroup, config) {
20080         this.initTarget(id, sGroup, config);
20081         if (!Roo.isTouch) {
20082             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20083         }
20084         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20085         // Event.on(this.id, "selectstart", Event.preventDefault);
20086     },
20087
20088     /**
20089      * Initializes Targeting functionality only... the object does not
20090      * get a mousedown handler.
20091      * @method initTarget
20092      * @param id the id of the linked element
20093      * @param {String} sGroup the group of related items
20094      * @param {object} config configuration attributes
20095      */
20096     initTarget: function(id, sGroup, config) {
20097
20098         // configuration attributes
20099         this.config = config || {};
20100
20101         // create a local reference to the drag and drop manager
20102         this.DDM = Roo.dd.DDM;
20103         // initialize the groups array
20104         this.groups = {};
20105
20106         // assume that we have an element reference instead of an id if the
20107         // parameter is not a string
20108         if (typeof id !== "string") {
20109             id = Roo.id(id);
20110         }
20111
20112         // set the id
20113         this.id = id;
20114
20115         // add to an interaction group
20116         this.addToGroup((sGroup) ? sGroup : "default");
20117
20118         // We don't want to register this as the handle with the manager
20119         // so we just set the id rather than calling the setter.
20120         this.handleElId = id;
20121
20122         // the linked element is the element that gets dragged by default
20123         this.setDragElId(id);
20124
20125         // by default, clicked anchors will not start drag operations.
20126         this.invalidHandleTypes = { A: "A" };
20127         this.invalidHandleIds = {};
20128         this.invalidHandleClasses = [];
20129
20130         this.applyConfig();
20131
20132         this.handleOnAvailable();
20133     },
20134
20135     /**
20136      * Applies the configuration parameters that were passed into the constructor.
20137      * This is supposed to happen at each level through the inheritance chain.  So
20138      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20139      * DragDrop in order to get all of the parameters that are available in
20140      * each object.
20141      * @method applyConfig
20142      */
20143     applyConfig: function() {
20144
20145         // configurable properties:
20146         //    padding, isTarget, maintainOffset, primaryButtonOnly
20147         this.padding           = this.config.padding || [0, 0, 0, 0];
20148         this.isTarget          = (this.config.isTarget !== false);
20149         this.maintainOffset    = (this.config.maintainOffset);
20150         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20151
20152     },
20153
20154     /**
20155      * Executed when the linked element is available
20156      * @method handleOnAvailable
20157      * @private
20158      */
20159     handleOnAvailable: function() {
20160         this.available = true;
20161         this.resetConstraints();
20162         this.onAvailable();
20163     },
20164
20165      /**
20166      * Configures the padding for the target zone in px.  Effectively expands
20167      * (or reduces) the virtual object size for targeting calculations.
20168      * Supports css-style shorthand; if only one parameter is passed, all sides
20169      * will have that padding, and if only two are passed, the top and bottom
20170      * will have the first param, the left and right the second.
20171      * @method setPadding
20172      * @param {int} iTop    Top pad
20173      * @param {int} iRight  Right pad
20174      * @param {int} iBot    Bot pad
20175      * @param {int} iLeft   Left pad
20176      */
20177     setPadding: function(iTop, iRight, iBot, iLeft) {
20178         // this.padding = [iLeft, iRight, iTop, iBot];
20179         if (!iRight && 0 !== iRight) {
20180             this.padding = [iTop, iTop, iTop, iTop];
20181         } else if (!iBot && 0 !== iBot) {
20182             this.padding = [iTop, iRight, iTop, iRight];
20183         } else {
20184             this.padding = [iTop, iRight, iBot, iLeft];
20185         }
20186     },
20187
20188     /**
20189      * Stores the initial placement of the linked element.
20190      * @method setInitialPosition
20191      * @param {int} diffX   the X offset, default 0
20192      * @param {int} diffY   the Y offset, default 0
20193      */
20194     setInitPosition: function(diffX, diffY) {
20195         var el = this.getEl();
20196
20197         if (!this.DDM.verifyEl(el)) {
20198             return;
20199         }
20200
20201         var dx = diffX || 0;
20202         var dy = diffY || 0;
20203
20204         var p = Dom.getXY( el );
20205
20206         this.initPageX = p[0] - dx;
20207         this.initPageY = p[1] - dy;
20208
20209         this.lastPageX = p[0];
20210         this.lastPageY = p[1];
20211
20212
20213         this.setStartPosition(p);
20214     },
20215
20216     /**
20217      * Sets the start position of the element.  This is set when the obj
20218      * is initialized, the reset when a drag is started.
20219      * @method setStartPosition
20220      * @param pos current position (from previous lookup)
20221      * @private
20222      */
20223     setStartPosition: function(pos) {
20224         var p = pos || Dom.getXY( this.getEl() );
20225         this.deltaSetXY = null;
20226
20227         this.startPageX = p[0];
20228         this.startPageY = p[1];
20229     },
20230
20231     /**
20232      * Add this instance to a group of related drag/drop objects.  All
20233      * instances belong to at least one group, and can belong to as many
20234      * groups as needed.
20235      * @method addToGroup
20236      * @param sGroup {string} the name of the group
20237      */
20238     addToGroup: function(sGroup) {
20239         this.groups[sGroup] = true;
20240         this.DDM.regDragDrop(this, sGroup);
20241     },
20242
20243     /**
20244      * Remove's this instance from the supplied interaction group
20245      * @method removeFromGroup
20246      * @param {string}  sGroup  The group to drop
20247      */
20248     removeFromGroup: function(sGroup) {
20249         if (this.groups[sGroup]) {
20250             delete this.groups[sGroup];
20251         }
20252
20253         this.DDM.removeDDFromGroup(this, sGroup);
20254     },
20255
20256     /**
20257      * Allows you to specify that an element other than the linked element
20258      * will be moved with the cursor during a drag
20259      * @method setDragElId
20260      * @param id {string} the id of the element that will be used to initiate the drag
20261      */
20262     setDragElId: function(id) {
20263         this.dragElId = id;
20264     },
20265
20266     /**
20267      * Allows you to specify a child of the linked element that should be
20268      * used to initiate the drag operation.  An example of this would be if
20269      * you have a content div with text and links.  Clicking anywhere in the
20270      * content area would normally start the drag operation.  Use this method
20271      * to specify that an element inside of the content div is the element
20272      * that starts the drag operation.
20273      * @method setHandleElId
20274      * @param id {string} the id of the element that will be used to
20275      * initiate the drag.
20276      */
20277     setHandleElId: function(id) {
20278         if (typeof id !== "string") {
20279             id = Roo.id(id);
20280         }
20281         this.handleElId = id;
20282         this.DDM.regHandle(this.id, id);
20283     },
20284
20285     /**
20286      * Allows you to set an element outside of the linked element as a drag
20287      * handle
20288      * @method setOuterHandleElId
20289      * @param id the id of the element that will be used to initiate the drag
20290      */
20291     setOuterHandleElId: function(id) {
20292         if (typeof id !== "string") {
20293             id = Roo.id(id);
20294         }
20295         Event.on(id, "mousedown",
20296                 this.handleMouseDown, this);
20297         this.setHandleElId(id);
20298
20299         this.hasOuterHandles = true;
20300     },
20301
20302     /**
20303      * Remove all drag and drop hooks for this element
20304      * @method unreg
20305      */
20306     unreg: function() {
20307         Event.un(this.id, "mousedown",
20308                 this.handleMouseDown);
20309         Event.un(this.id, "touchstart",
20310                 this.handleMouseDown);
20311         this._domRef = null;
20312         this.DDM._remove(this);
20313     },
20314
20315     destroy : function(){
20316         this.unreg();
20317     },
20318
20319     /**
20320      * Returns true if this instance is locked, or the drag drop mgr is locked
20321      * (meaning that all drag/drop is disabled on the page.)
20322      * @method isLocked
20323      * @return {boolean} true if this obj or all drag/drop is locked, else
20324      * false
20325      */
20326     isLocked: function() {
20327         return (this.DDM.isLocked() || this.locked);
20328     },
20329
20330     /**
20331      * Fired when this object is clicked
20332      * @method handleMouseDown
20333      * @param {Event} e
20334      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20335      * @private
20336      */
20337     handleMouseDown: function(e, oDD){
20338      
20339         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20340             //Roo.log('not touch/ button !=0');
20341             return;
20342         }
20343         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20344             return; // double touch..
20345         }
20346         
20347
20348         if (this.isLocked()) {
20349             //Roo.log('locked');
20350             return;
20351         }
20352
20353         this.DDM.refreshCache(this.groups);
20354 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20355         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20356         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20357             //Roo.log('no outer handes or not over target');
20358                 // do nothing.
20359         } else {
20360 //            Roo.log('check validator');
20361             if (this.clickValidator(e)) {
20362 //                Roo.log('validate success');
20363                 // set the initial element position
20364                 this.setStartPosition();
20365
20366
20367                 this.b4MouseDown(e);
20368                 this.onMouseDown(e);
20369
20370                 this.DDM.handleMouseDown(e, this);
20371
20372                 this.DDM.stopEvent(e);
20373             } else {
20374
20375
20376             }
20377         }
20378     },
20379
20380     clickValidator: function(e) {
20381         var target = e.getTarget();
20382         return ( this.isValidHandleChild(target) &&
20383                     (this.id == this.handleElId ||
20384                         this.DDM.handleWasClicked(target, this.id)) );
20385     },
20386
20387     /**
20388      * Allows you to specify a tag name that should not start a drag operation
20389      * when clicked.  This is designed to facilitate embedding links within a
20390      * drag handle that do something other than start the drag.
20391      * @method addInvalidHandleType
20392      * @param {string} tagName the type of element to exclude
20393      */
20394     addInvalidHandleType: function(tagName) {
20395         var type = tagName.toUpperCase();
20396         this.invalidHandleTypes[type] = type;
20397     },
20398
20399     /**
20400      * Lets you to specify an element id for a child of a drag handle
20401      * that should not initiate a drag
20402      * @method addInvalidHandleId
20403      * @param {string} id the element id of the element you wish to ignore
20404      */
20405     addInvalidHandleId: function(id) {
20406         if (typeof id !== "string") {
20407             id = Roo.id(id);
20408         }
20409         this.invalidHandleIds[id] = id;
20410     },
20411
20412     /**
20413      * Lets you specify a css class of elements that will not initiate a drag
20414      * @method addInvalidHandleClass
20415      * @param {string} cssClass the class of the elements you wish to ignore
20416      */
20417     addInvalidHandleClass: function(cssClass) {
20418         this.invalidHandleClasses.push(cssClass);
20419     },
20420
20421     /**
20422      * Unsets an excluded tag name set by addInvalidHandleType
20423      * @method removeInvalidHandleType
20424      * @param {string} tagName the type of element to unexclude
20425      */
20426     removeInvalidHandleType: function(tagName) {
20427         var type = tagName.toUpperCase();
20428         // this.invalidHandleTypes[type] = null;
20429         delete this.invalidHandleTypes[type];
20430     },
20431
20432     /**
20433      * Unsets an invalid handle id
20434      * @method removeInvalidHandleId
20435      * @param {string} id the id of the element to re-enable
20436      */
20437     removeInvalidHandleId: function(id) {
20438         if (typeof id !== "string") {
20439             id = Roo.id(id);
20440         }
20441         delete this.invalidHandleIds[id];
20442     },
20443
20444     /**
20445      * Unsets an invalid css class
20446      * @method removeInvalidHandleClass
20447      * @param {string} cssClass the class of the element(s) you wish to
20448      * re-enable
20449      */
20450     removeInvalidHandleClass: function(cssClass) {
20451         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20452             if (this.invalidHandleClasses[i] == cssClass) {
20453                 delete this.invalidHandleClasses[i];
20454             }
20455         }
20456     },
20457
20458     /**
20459      * Checks the tag exclusion list to see if this click should be ignored
20460      * @method isValidHandleChild
20461      * @param {HTMLElement} node the HTMLElement to evaluate
20462      * @return {boolean} true if this is a valid tag type, false if not
20463      */
20464     isValidHandleChild: function(node) {
20465
20466         var valid = true;
20467         // var n = (node.nodeName == "#text") ? node.parentNode : node;
20468         var nodeName;
20469         try {
20470             nodeName = node.nodeName.toUpperCase();
20471         } catch(e) {
20472             nodeName = node.nodeName;
20473         }
20474         valid = valid && !this.invalidHandleTypes[nodeName];
20475         valid = valid && !this.invalidHandleIds[node.id];
20476
20477         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20478             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20479         }
20480
20481
20482         return valid;
20483
20484     },
20485
20486     /**
20487      * Create the array of horizontal tick marks if an interval was specified
20488      * in setXConstraint().
20489      * @method setXTicks
20490      * @private
20491      */
20492     setXTicks: function(iStartX, iTickSize) {
20493         this.xTicks = [];
20494         this.xTickSize = iTickSize;
20495
20496         var tickMap = {};
20497
20498         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20499             if (!tickMap[i]) {
20500                 this.xTicks[this.xTicks.length] = i;
20501                 tickMap[i] = true;
20502             }
20503         }
20504
20505         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20506             if (!tickMap[i]) {
20507                 this.xTicks[this.xTicks.length] = i;
20508                 tickMap[i] = true;
20509             }
20510         }
20511
20512         this.xTicks.sort(this.DDM.numericSort) ;
20513     },
20514
20515     /**
20516      * Create the array of vertical tick marks if an interval was specified in
20517      * setYConstraint().
20518      * @method setYTicks
20519      * @private
20520      */
20521     setYTicks: function(iStartY, iTickSize) {
20522         this.yTicks = [];
20523         this.yTickSize = iTickSize;
20524
20525         var tickMap = {};
20526
20527         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20528             if (!tickMap[i]) {
20529                 this.yTicks[this.yTicks.length] = i;
20530                 tickMap[i] = true;
20531             }
20532         }
20533
20534         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20535             if (!tickMap[i]) {
20536                 this.yTicks[this.yTicks.length] = i;
20537                 tickMap[i] = true;
20538             }
20539         }
20540
20541         this.yTicks.sort(this.DDM.numericSort) ;
20542     },
20543
20544     /**
20545      * By default, the element can be dragged any place on the screen.  Use
20546      * this method to limit the horizontal travel of the element.  Pass in
20547      * 0,0 for the parameters if you want to lock the drag to the y axis.
20548      * @method setXConstraint
20549      * @param {int} iLeft the number of pixels the element can move to the left
20550      * @param {int} iRight the number of pixels the element can move to the
20551      * right
20552      * @param {int} iTickSize optional parameter for specifying that the
20553      * element
20554      * should move iTickSize pixels at a time.
20555      */
20556     setXConstraint: function(iLeft, iRight, iTickSize) {
20557         this.leftConstraint = iLeft;
20558         this.rightConstraint = iRight;
20559
20560         this.minX = this.initPageX - iLeft;
20561         this.maxX = this.initPageX + iRight;
20562         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20563
20564         this.constrainX = true;
20565     },
20566
20567     /**
20568      * Clears any constraints applied to this instance.  Also clears ticks
20569      * since they can't exist independent of a constraint at this time.
20570      * @method clearConstraints
20571      */
20572     clearConstraints: function() {
20573         this.constrainX = false;
20574         this.constrainY = false;
20575         this.clearTicks();
20576     },
20577
20578     /**
20579      * Clears any tick interval defined for this instance
20580      * @method clearTicks
20581      */
20582     clearTicks: function() {
20583         this.xTicks = null;
20584         this.yTicks = null;
20585         this.xTickSize = 0;
20586         this.yTickSize = 0;
20587     },
20588
20589     /**
20590      * By default, the element can be dragged any place on the screen.  Set
20591      * this to limit the vertical travel of the element.  Pass in 0,0 for the
20592      * parameters if you want to lock the drag to the x axis.
20593      * @method setYConstraint
20594      * @param {int} iUp the number of pixels the element can move up
20595      * @param {int} iDown the number of pixels the element can move down
20596      * @param {int} iTickSize optional parameter for specifying that the
20597      * element should move iTickSize pixels at a time.
20598      */
20599     setYConstraint: function(iUp, iDown, iTickSize) {
20600         this.topConstraint = iUp;
20601         this.bottomConstraint = iDown;
20602
20603         this.minY = this.initPageY - iUp;
20604         this.maxY = this.initPageY + iDown;
20605         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
20606
20607         this.constrainY = true;
20608
20609     },
20610
20611     /**
20612      * resetConstraints must be called if you manually reposition a dd element.
20613      * @method resetConstraints
20614      * @param {boolean} maintainOffset
20615      */
20616     resetConstraints: function() {
20617
20618
20619         // Maintain offsets if necessary
20620         if (this.initPageX || this.initPageX === 0) {
20621             // figure out how much this thing has moved
20622             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
20623             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
20624
20625             this.setInitPosition(dx, dy);
20626
20627         // This is the first time we have detected the element's position
20628         } else {
20629             this.setInitPosition();
20630         }
20631
20632         if (this.constrainX) {
20633             this.setXConstraint( this.leftConstraint,
20634                                  this.rightConstraint,
20635                                  this.xTickSize        );
20636         }
20637
20638         if (this.constrainY) {
20639             this.setYConstraint( this.topConstraint,
20640                                  this.bottomConstraint,
20641                                  this.yTickSize         );
20642         }
20643     },
20644
20645     /**
20646      * Normally the drag element is moved pixel by pixel, but we can specify
20647      * that it move a number of pixels at a time.  This method resolves the
20648      * location when we have it set up like this.
20649      * @method getTick
20650      * @param {int} val where we want to place the object
20651      * @param {int[]} tickArray sorted array of valid points
20652      * @return {int} the closest tick
20653      * @private
20654      */
20655     getTick: function(val, tickArray) {
20656
20657         if (!tickArray) {
20658             // If tick interval is not defined, it is effectively 1 pixel,
20659             // so we return the value passed to us.
20660             return val;
20661         } else if (tickArray[0] >= val) {
20662             // The value is lower than the first tick, so we return the first
20663             // tick.
20664             return tickArray[0];
20665         } else {
20666             for (var i=0, len=tickArray.length; i<len; ++i) {
20667                 var next = i + 1;
20668                 if (tickArray[next] && tickArray[next] >= val) {
20669                     var diff1 = val - tickArray[i];
20670                     var diff2 = tickArray[next] - val;
20671                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
20672                 }
20673             }
20674
20675             // The value is larger than the last tick, so we return the last
20676             // tick.
20677             return tickArray[tickArray.length - 1];
20678         }
20679     },
20680
20681     /**
20682      * toString method
20683      * @method toString
20684      * @return {string} string representation of the dd obj
20685      */
20686     toString: function() {
20687         return ("DragDrop " + this.id);
20688     }
20689
20690 });
20691
20692 })();
20693 /*
20694  * Based on:
20695  * Ext JS Library 1.1.1
20696  * Copyright(c) 2006-2007, Ext JS, LLC.
20697  *
20698  * Originally Released Under LGPL - original licence link has changed is not relivant.
20699  *
20700  * Fork - LGPL
20701  * <script type="text/javascript">
20702  */
20703
20704
20705 /**
20706  * The drag and drop utility provides a framework for building drag and drop
20707  * applications.  In addition to enabling drag and drop for specific elements,
20708  * the drag and drop elements are tracked by the manager class, and the
20709  * interactions between the various elements are tracked during the drag and
20710  * the implementing code is notified about these important moments.
20711  */
20712
20713 // Only load the library once.  Rewriting the manager class would orphan
20714 // existing drag and drop instances.
20715 if (!Roo.dd.DragDropMgr) {
20716
20717 /**
20718  * @class Roo.dd.DragDropMgr
20719  * DragDropMgr is a singleton that tracks the element interaction for
20720  * all DragDrop items in the window.  Generally, you will not call
20721  * this class directly, but it does have helper methods that could
20722  * be useful in your DragDrop implementations.
20723  * @static
20724  */
20725 Roo.dd.DragDropMgr = function() {
20726
20727     var Event = Roo.EventManager;
20728
20729     return {
20730
20731         /**
20732          * Two dimensional Array of registered DragDrop objects.  The first
20733          * dimension is the DragDrop item group, the second the DragDrop
20734          * object.
20735          * @property ids
20736          * @type {string: string}
20737          * @private
20738          * @static
20739          */
20740         ids: {},
20741
20742         /**
20743          * Array of element ids defined as drag handles.  Used to determine
20744          * if the element that generated the mousedown event is actually the
20745          * handle and not the html element itself.
20746          * @property handleIds
20747          * @type {string: string}
20748          * @private
20749          * @static
20750          */
20751         handleIds: {},
20752
20753         /**
20754          * the DragDrop object that is currently being dragged
20755          * @property dragCurrent
20756          * @type DragDrop
20757          * @private
20758          * @static
20759          **/
20760         dragCurrent: null,
20761
20762         /**
20763          * the DragDrop object(s) that are being hovered over
20764          * @property dragOvers
20765          * @type Array
20766          * @private
20767          * @static
20768          */
20769         dragOvers: {},
20770
20771         /**
20772          * the X distance between the cursor and the object being dragged
20773          * @property deltaX
20774          * @type int
20775          * @private
20776          * @static
20777          */
20778         deltaX: 0,
20779
20780         /**
20781          * the Y distance between the cursor and the object being dragged
20782          * @property deltaY
20783          * @type int
20784          * @private
20785          * @static
20786          */
20787         deltaY: 0,
20788
20789         /**
20790          * Flag to determine if we should prevent the default behavior of the
20791          * events we define. By default this is true, but this can be set to
20792          * false if you need the default behavior (not recommended)
20793          * @property preventDefault
20794          * @type boolean
20795          * @static
20796          */
20797         preventDefault: true,
20798
20799         /**
20800          * Flag to determine if we should stop the propagation of the events
20801          * we generate. This is true by default but you may want to set it to
20802          * false if the html element contains other features that require the
20803          * mouse click.
20804          * @property stopPropagation
20805          * @type boolean
20806          * @static
20807          */
20808         stopPropagation: true,
20809
20810         /**
20811          * Internal flag that is set to true when drag and drop has been
20812          * intialized
20813          * @property initialized
20814          * @private
20815          * @static
20816          */
20817         initalized: false,
20818
20819         /**
20820          * All drag and drop can be disabled.
20821          * @property locked
20822          * @private
20823          * @static
20824          */
20825         locked: false,
20826
20827         /**
20828          * Called the first time an element is registered.
20829          * @method init
20830          * @private
20831          * @static
20832          */
20833         init: function() {
20834             this.initialized = true;
20835         },
20836
20837         /**
20838          * In point mode, drag and drop interaction is defined by the
20839          * location of the cursor during the drag/drop
20840          * @property POINT
20841          * @type int
20842          * @static
20843          */
20844         POINT: 0,
20845
20846         /**
20847          * In intersect mode, drag and drop interactio nis defined by the
20848          * overlap of two or more drag and drop objects.
20849          * @property INTERSECT
20850          * @type int
20851          * @static
20852          */
20853         INTERSECT: 1,
20854
20855         /**
20856          * The current drag and drop mode.  Default: POINT
20857          * @property mode
20858          * @type int
20859          * @static
20860          */
20861         mode: 0,
20862
20863         /**
20864          * Runs method on all drag and drop objects
20865          * @method _execOnAll
20866          * @private
20867          * @static
20868          */
20869         _execOnAll: function(sMethod, args) {
20870             for (var i in this.ids) {
20871                 for (var j in this.ids[i]) {
20872                     var oDD = this.ids[i][j];
20873                     if (! this.isTypeOfDD(oDD)) {
20874                         continue;
20875                     }
20876                     oDD[sMethod].apply(oDD, args);
20877                 }
20878             }
20879         },
20880
20881         /**
20882          * Drag and drop initialization.  Sets up the global event handlers
20883          * @method _onLoad
20884          * @private
20885          * @static
20886          */
20887         _onLoad: function() {
20888
20889             this.init();
20890
20891             if (!Roo.isTouch) {
20892                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
20893                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20894             }
20895             Event.on(document, "touchend",   this.handleMouseUp, this, true);
20896             Event.on(document, "touchmove", this.handleMouseMove, this, true);
20897             
20898             Event.on(window,   "unload",    this._onUnload, this, true);
20899             Event.on(window,   "resize",    this._onResize, this, true);
20900             // Event.on(window,   "mouseout",    this._test);
20901
20902         },
20903
20904         /**
20905          * Reset constraints on all drag and drop objs
20906          * @method _onResize
20907          * @private
20908          * @static
20909          */
20910         _onResize: function(e) {
20911             this._execOnAll("resetConstraints", []);
20912         },
20913
20914         /**
20915          * Lock all drag and drop functionality
20916          * @method lock
20917          * @static
20918          */
20919         lock: function() { this.locked = true; },
20920
20921         /**
20922          * Unlock all drag and drop functionality
20923          * @method unlock
20924          * @static
20925          */
20926         unlock: function() { this.locked = false; },
20927
20928         /**
20929          * Is drag and drop locked?
20930          * @method isLocked
20931          * @return {boolean} True if drag and drop is locked, false otherwise.
20932          * @static
20933          */
20934         isLocked: function() { return this.locked; },
20935
20936         /**
20937          * Location cache that is set for all drag drop objects when a drag is
20938          * initiated, cleared when the drag is finished.
20939          * @property locationCache
20940          * @private
20941          * @static
20942          */
20943         locationCache: {},
20944
20945         /**
20946          * Set useCache to false if you want to force object the lookup of each
20947          * drag and drop linked element constantly during a drag.
20948          * @property useCache
20949          * @type boolean
20950          * @static
20951          */
20952         useCache: true,
20953
20954         /**
20955          * The number of pixels that the mouse needs to move after the
20956          * mousedown before the drag is initiated.  Default=3;
20957          * @property clickPixelThresh
20958          * @type int
20959          * @static
20960          */
20961         clickPixelThresh: 3,
20962
20963         /**
20964          * The number of milliseconds after the mousedown event to initiate the
20965          * drag if we don't get a mouseup event. Default=1000
20966          * @property clickTimeThresh
20967          * @type int
20968          * @static
20969          */
20970         clickTimeThresh: 350,
20971
20972         /**
20973          * Flag that indicates that either the drag pixel threshold or the
20974          * mousdown time threshold has been met
20975          * @property dragThreshMet
20976          * @type boolean
20977          * @private
20978          * @static
20979          */
20980         dragThreshMet: false,
20981
20982         /**
20983          * Timeout used for the click time threshold
20984          * @property clickTimeout
20985          * @type Object
20986          * @private
20987          * @static
20988          */
20989         clickTimeout: null,
20990
20991         /**
20992          * The X position of the mousedown event stored for later use when a
20993          * drag threshold is met.
20994          * @property startX
20995          * @type int
20996          * @private
20997          * @static
20998          */
20999         startX: 0,
21000
21001         /**
21002          * The Y position of the mousedown event stored for later use when a
21003          * drag threshold is met.
21004          * @property startY
21005          * @type int
21006          * @private
21007          * @static
21008          */
21009         startY: 0,
21010
21011         /**
21012          * Each DragDrop instance must be registered with the DragDropMgr.
21013          * This is executed in DragDrop.init()
21014          * @method regDragDrop
21015          * @param {DragDrop} oDD the DragDrop object to register
21016          * @param {String} sGroup the name of the group this element belongs to
21017          * @static
21018          */
21019         regDragDrop: function(oDD, sGroup) {
21020             if (!this.initialized) { this.init(); }
21021
21022             if (!this.ids[sGroup]) {
21023                 this.ids[sGroup] = {};
21024             }
21025             this.ids[sGroup][oDD.id] = oDD;
21026         },
21027
21028         /**
21029          * Removes the supplied dd instance from the supplied group. Executed
21030          * by DragDrop.removeFromGroup, so don't call this function directly.
21031          * @method removeDDFromGroup
21032          * @private
21033          * @static
21034          */
21035         removeDDFromGroup: function(oDD, sGroup) {
21036             if (!this.ids[sGroup]) {
21037                 this.ids[sGroup] = {};
21038             }
21039
21040             var obj = this.ids[sGroup];
21041             if (obj && obj[oDD.id]) {
21042                 delete obj[oDD.id];
21043             }
21044         },
21045
21046         /**
21047          * Unregisters a drag and drop item.  This is executed in
21048          * DragDrop.unreg, use that method instead of calling this directly.
21049          * @method _remove
21050          * @private
21051          * @static
21052          */
21053         _remove: function(oDD) {
21054             for (var g in oDD.groups) {
21055                 if (g && this.ids[g][oDD.id]) {
21056                     delete this.ids[g][oDD.id];
21057                 }
21058             }
21059             delete this.handleIds[oDD.id];
21060         },
21061
21062         /**
21063          * Each DragDrop handle element must be registered.  This is done
21064          * automatically when executing DragDrop.setHandleElId()
21065          * @method regHandle
21066          * @param {String} sDDId the DragDrop id this element is a handle for
21067          * @param {String} sHandleId the id of the element that is the drag
21068          * handle
21069          * @static
21070          */
21071         regHandle: function(sDDId, sHandleId) {
21072             if (!this.handleIds[sDDId]) {
21073                 this.handleIds[sDDId] = {};
21074             }
21075             this.handleIds[sDDId][sHandleId] = sHandleId;
21076         },
21077
21078         /**
21079          * Utility function to determine if a given element has been
21080          * registered as a drag drop item.
21081          * @method isDragDrop
21082          * @param {String} id the element id to check
21083          * @return {boolean} true if this element is a DragDrop item,
21084          * false otherwise
21085          * @static
21086          */
21087         isDragDrop: function(id) {
21088             return ( this.getDDById(id) ) ? true : false;
21089         },
21090
21091         /**
21092          * Returns the drag and drop instances that are in all groups the
21093          * passed in instance belongs to.
21094          * @method getRelated
21095          * @param {DragDrop} p_oDD the obj to get related data for
21096          * @param {boolean} bTargetsOnly if true, only return targetable objs
21097          * @return {DragDrop[]} the related instances
21098          * @static
21099          */
21100         getRelated: function(p_oDD, bTargetsOnly) {
21101             var oDDs = [];
21102             for (var i in p_oDD.groups) {
21103                 for (j in this.ids[i]) {
21104                     var dd = this.ids[i][j];
21105                     if (! this.isTypeOfDD(dd)) {
21106                         continue;
21107                     }
21108                     if (!bTargetsOnly || dd.isTarget) {
21109                         oDDs[oDDs.length] = dd;
21110                     }
21111                 }
21112             }
21113
21114             return oDDs;
21115         },
21116
21117         /**
21118          * Returns true if the specified dd target is a legal target for
21119          * the specifice drag obj
21120          * @method isLegalTarget
21121          * @param {DragDrop} the drag obj
21122          * @param {DragDrop} the target
21123          * @return {boolean} true if the target is a legal target for the
21124          * dd obj
21125          * @static
21126          */
21127         isLegalTarget: function (oDD, oTargetDD) {
21128             var targets = this.getRelated(oDD, true);
21129             for (var i=0, len=targets.length;i<len;++i) {
21130                 if (targets[i].id == oTargetDD.id) {
21131                     return true;
21132                 }
21133             }
21134
21135             return false;
21136         },
21137
21138         /**
21139          * My goal is to be able to transparently determine if an object is
21140          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21141          * returns "object", oDD.constructor.toString() always returns
21142          * "DragDrop" and not the name of the subclass.  So for now it just
21143          * evaluates a well-known variable in DragDrop.
21144          * @method isTypeOfDD
21145          * @param {Object} the object to evaluate
21146          * @return {boolean} true if typeof oDD = DragDrop
21147          * @static
21148          */
21149         isTypeOfDD: function (oDD) {
21150             return (oDD && oDD.__ygDragDrop);
21151         },
21152
21153         /**
21154          * Utility function to determine if a given element has been
21155          * registered as a drag drop handle for the given Drag Drop object.
21156          * @method isHandle
21157          * @param {String} id the element id to check
21158          * @return {boolean} true if this element is a DragDrop handle, false
21159          * otherwise
21160          * @static
21161          */
21162         isHandle: function(sDDId, sHandleId) {
21163             return ( this.handleIds[sDDId] &&
21164                             this.handleIds[sDDId][sHandleId] );
21165         },
21166
21167         /**
21168          * Returns the DragDrop instance for a given id
21169          * @method getDDById
21170          * @param {String} id the id of the DragDrop object
21171          * @return {DragDrop} the drag drop object, null if it is not found
21172          * @static
21173          */
21174         getDDById: function(id) {
21175             for (var i in this.ids) {
21176                 if (this.ids[i][id]) {
21177                     return this.ids[i][id];
21178                 }
21179             }
21180             return null;
21181         },
21182
21183         /**
21184          * Fired after a registered DragDrop object gets the mousedown event.
21185          * Sets up the events required to track the object being dragged
21186          * @method handleMouseDown
21187          * @param {Event} e the event
21188          * @param oDD the DragDrop object being dragged
21189          * @private
21190          * @static
21191          */
21192         handleMouseDown: function(e, oDD) {
21193             if(Roo.QuickTips){
21194                 Roo.QuickTips.disable();
21195             }
21196             this.currentTarget = e.getTarget();
21197
21198             this.dragCurrent = oDD;
21199
21200             var el = oDD.getEl();
21201
21202             // track start position
21203             this.startX = e.getPageX();
21204             this.startY = e.getPageY();
21205
21206             this.deltaX = this.startX - el.offsetLeft;
21207             this.deltaY = this.startY - el.offsetTop;
21208
21209             this.dragThreshMet = false;
21210
21211             this.clickTimeout = setTimeout(
21212                     function() {
21213                         var DDM = Roo.dd.DDM;
21214                         DDM.startDrag(DDM.startX, DDM.startY);
21215                     },
21216                     this.clickTimeThresh );
21217         },
21218
21219         /**
21220          * Fired when either the drag pixel threshol or the mousedown hold
21221          * time threshold has been met.
21222          * @method startDrag
21223          * @param x {int} the X position of the original mousedown
21224          * @param y {int} the Y position of the original mousedown
21225          * @static
21226          */
21227         startDrag: function(x, y) {
21228             clearTimeout(this.clickTimeout);
21229             if (this.dragCurrent) {
21230                 this.dragCurrent.b4StartDrag(x, y);
21231                 this.dragCurrent.startDrag(x, y);
21232             }
21233             this.dragThreshMet = true;
21234         },
21235
21236         /**
21237          * Internal function to handle the mouseup event.  Will be invoked
21238          * from the context of the document.
21239          * @method handleMouseUp
21240          * @param {Event} e the event
21241          * @private
21242          * @static
21243          */
21244         handleMouseUp: function(e) {
21245
21246             if(Roo.QuickTips){
21247                 Roo.QuickTips.enable();
21248             }
21249             if (! this.dragCurrent) {
21250                 return;
21251             }
21252
21253             clearTimeout(this.clickTimeout);
21254
21255             if (this.dragThreshMet) {
21256                 this.fireEvents(e, true);
21257             } else {
21258             }
21259
21260             this.stopDrag(e);
21261
21262             this.stopEvent(e);
21263         },
21264
21265         /**
21266          * Utility to stop event propagation and event default, if these
21267          * features are turned on.
21268          * @method stopEvent
21269          * @param {Event} e the event as returned by this.getEvent()
21270          * @static
21271          */
21272         stopEvent: function(e){
21273             if(this.stopPropagation) {
21274                 e.stopPropagation();
21275             }
21276
21277             if (this.preventDefault) {
21278                 e.preventDefault();
21279             }
21280         },
21281
21282         /**
21283          * Internal function to clean up event handlers after the drag
21284          * operation is complete
21285          * @method stopDrag
21286          * @param {Event} e the event
21287          * @private
21288          * @static
21289          */
21290         stopDrag: function(e) {
21291             // Fire the drag end event for the item that was dragged
21292             if (this.dragCurrent) {
21293                 if (this.dragThreshMet) {
21294                     this.dragCurrent.b4EndDrag(e);
21295                     this.dragCurrent.endDrag(e);
21296                 }
21297
21298                 this.dragCurrent.onMouseUp(e);
21299             }
21300
21301             this.dragCurrent = null;
21302             this.dragOvers = {};
21303         },
21304
21305         /**
21306          * Internal function to handle the mousemove event.  Will be invoked
21307          * from the context of the html element.
21308          *
21309          * @TODO figure out what we can do about mouse events lost when the
21310          * user drags objects beyond the window boundary.  Currently we can
21311          * detect this in internet explorer by verifying that the mouse is
21312          * down during the mousemove event.  Firefox doesn't give us the
21313          * button state on the mousemove event.
21314          * @method handleMouseMove
21315          * @param {Event} e the event
21316          * @private
21317          * @static
21318          */
21319         handleMouseMove: function(e) {
21320             if (! this.dragCurrent) {
21321                 return true;
21322             }
21323
21324             // var button = e.which || e.button;
21325
21326             // check for IE mouseup outside of page boundary
21327             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21328                 this.stopEvent(e);
21329                 return this.handleMouseUp(e);
21330             }
21331
21332             if (!this.dragThreshMet) {
21333                 var diffX = Math.abs(this.startX - e.getPageX());
21334                 var diffY = Math.abs(this.startY - e.getPageY());
21335                 if (diffX > this.clickPixelThresh ||
21336                             diffY > this.clickPixelThresh) {
21337                     this.startDrag(this.startX, this.startY);
21338                 }
21339             }
21340
21341             if (this.dragThreshMet) {
21342                 this.dragCurrent.b4Drag(e);
21343                 this.dragCurrent.onDrag(e);
21344                 if(!this.dragCurrent.moveOnly){
21345                     this.fireEvents(e, false);
21346                 }
21347             }
21348
21349             this.stopEvent(e);
21350
21351             return true;
21352         },
21353
21354         /**
21355          * Iterates over all of the DragDrop elements to find ones we are
21356          * hovering over or dropping on
21357          * @method fireEvents
21358          * @param {Event} e the event
21359          * @param {boolean} isDrop is this a drop op or a mouseover op?
21360          * @private
21361          * @static
21362          */
21363         fireEvents: function(e, isDrop) {
21364             var dc = this.dragCurrent;
21365
21366             // If the user did the mouse up outside of the window, we could
21367             // get here even though we have ended the drag.
21368             if (!dc || dc.isLocked()) {
21369                 return;
21370             }
21371
21372             var pt = e.getPoint();
21373
21374             // cache the previous dragOver array
21375             var oldOvers = [];
21376
21377             var outEvts   = [];
21378             var overEvts  = [];
21379             var dropEvts  = [];
21380             var enterEvts = [];
21381
21382             // Check to see if the object(s) we were hovering over is no longer
21383             // being hovered over so we can fire the onDragOut event
21384             for (var i in this.dragOvers) {
21385
21386                 var ddo = this.dragOvers[i];
21387
21388                 if (! this.isTypeOfDD(ddo)) {
21389                     continue;
21390                 }
21391
21392                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21393                     outEvts.push( ddo );
21394                 }
21395
21396                 oldOvers[i] = true;
21397                 delete this.dragOvers[i];
21398             }
21399
21400             for (var sGroup in dc.groups) {
21401
21402                 if ("string" != typeof sGroup) {
21403                     continue;
21404                 }
21405
21406                 for (i in this.ids[sGroup]) {
21407                     var oDD = this.ids[sGroup][i];
21408                     if (! this.isTypeOfDD(oDD)) {
21409                         continue;
21410                     }
21411
21412                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21413                         if (this.isOverTarget(pt, oDD, this.mode)) {
21414                             // look for drop interactions
21415                             if (isDrop) {
21416                                 dropEvts.push( oDD );
21417                             // look for drag enter and drag over interactions
21418                             } else {
21419
21420                                 // initial drag over: dragEnter fires
21421                                 if (!oldOvers[oDD.id]) {
21422                                     enterEvts.push( oDD );
21423                                 // subsequent drag overs: dragOver fires
21424                                 } else {
21425                                     overEvts.push( oDD );
21426                                 }
21427
21428                                 this.dragOvers[oDD.id] = oDD;
21429                             }
21430                         }
21431                     }
21432                 }
21433             }
21434
21435             if (this.mode) {
21436                 if (outEvts.length) {
21437                     dc.b4DragOut(e, outEvts);
21438                     dc.onDragOut(e, outEvts);
21439                 }
21440
21441                 if (enterEvts.length) {
21442                     dc.onDragEnter(e, enterEvts);
21443                 }
21444
21445                 if (overEvts.length) {
21446                     dc.b4DragOver(e, overEvts);
21447                     dc.onDragOver(e, overEvts);
21448                 }
21449
21450                 if (dropEvts.length) {
21451                     dc.b4DragDrop(e, dropEvts);
21452                     dc.onDragDrop(e, dropEvts);
21453                 }
21454
21455             } else {
21456                 // fire dragout events
21457                 var len = 0;
21458                 for (i=0, len=outEvts.length; i<len; ++i) {
21459                     dc.b4DragOut(e, outEvts[i].id);
21460                     dc.onDragOut(e, outEvts[i].id);
21461                 }
21462
21463                 // fire enter events
21464                 for (i=0,len=enterEvts.length; i<len; ++i) {
21465                     // dc.b4DragEnter(e, oDD.id);
21466                     dc.onDragEnter(e, enterEvts[i].id);
21467                 }
21468
21469                 // fire over events
21470                 for (i=0,len=overEvts.length; i<len; ++i) {
21471                     dc.b4DragOver(e, overEvts[i].id);
21472                     dc.onDragOver(e, overEvts[i].id);
21473                 }
21474
21475                 // fire drop events
21476                 for (i=0, len=dropEvts.length; i<len; ++i) {
21477                     dc.b4DragDrop(e, dropEvts[i].id);
21478                     dc.onDragDrop(e, dropEvts[i].id);
21479                 }
21480
21481             }
21482
21483             // notify about a drop that did not find a target
21484             if (isDrop && !dropEvts.length) {
21485                 dc.onInvalidDrop(e);
21486             }
21487
21488         },
21489
21490         /**
21491          * Helper function for getting the best match from the list of drag
21492          * and drop objects returned by the drag and drop events when we are
21493          * in INTERSECT mode.  It returns either the first object that the
21494          * cursor is over, or the object that has the greatest overlap with
21495          * the dragged element.
21496          * @method getBestMatch
21497          * @param  {DragDrop[]} dds The array of drag and drop objects
21498          * targeted
21499          * @return {DragDrop}       The best single match
21500          * @static
21501          */
21502         getBestMatch: function(dds) {
21503             var winner = null;
21504             // Return null if the input is not what we expect
21505             //if (!dds || !dds.length || dds.length == 0) {
21506                // winner = null;
21507             // If there is only one item, it wins
21508             //} else if (dds.length == 1) {
21509
21510             var len = dds.length;
21511
21512             if (len == 1) {
21513                 winner = dds[0];
21514             } else {
21515                 // Loop through the targeted items
21516                 for (var i=0; i<len; ++i) {
21517                     var dd = dds[i];
21518                     // If the cursor is over the object, it wins.  If the
21519                     // cursor is over multiple matches, the first one we come
21520                     // to wins.
21521                     if (dd.cursorIsOver) {
21522                         winner = dd;
21523                         break;
21524                     // Otherwise the object with the most overlap wins
21525                     } else {
21526                         if (!winner ||
21527                             winner.overlap.getArea() < dd.overlap.getArea()) {
21528                             winner = dd;
21529                         }
21530                     }
21531                 }
21532             }
21533
21534             return winner;
21535         },
21536
21537         /**
21538          * Refreshes the cache of the top-left and bottom-right points of the
21539          * drag and drop objects in the specified group(s).  This is in the
21540          * format that is stored in the drag and drop instance, so typical
21541          * usage is:
21542          * <code>
21543          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21544          * </code>
21545          * Alternatively:
21546          * <code>
21547          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21548          * </code>
21549          * @TODO this really should be an indexed array.  Alternatively this
21550          * method could accept both.
21551          * @method refreshCache
21552          * @param {Object} groups an associative array of groups to refresh
21553          * @static
21554          */
21555         refreshCache: function(groups) {
21556             for (var sGroup in groups) {
21557                 if ("string" != typeof sGroup) {
21558                     continue;
21559                 }
21560                 for (var i in this.ids[sGroup]) {
21561                     var oDD = this.ids[sGroup][i];
21562
21563                     if (this.isTypeOfDD(oDD)) {
21564                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21565                         var loc = this.getLocation(oDD);
21566                         if (loc) {
21567                             this.locationCache[oDD.id] = loc;
21568                         } else {
21569                             delete this.locationCache[oDD.id];
21570                             // this will unregister the drag and drop object if
21571                             // the element is not in a usable state
21572                             // oDD.unreg();
21573                         }
21574                     }
21575                 }
21576             }
21577         },
21578
21579         /**
21580          * This checks to make sure an element exists and is in the DOM.  The
21581          * main purpose is to handle cases where innerHTML is used to remove
21582          * drag and drop objects from the DOM.  IE provides an 'unspecified
21583          * error' when trying to access the offsetParent of such an element
21584          * @method verifyEl
21585          * @param {HTMLElement} el the element to check
21586          * @return {boolean} true if the element looks usable
21587          * @static
21588          */
21589         verifyEl: function(el) {
21590             if (el) {
21591                 var parent;
21592                 if(Roo.isIE){
21593                     try{
21594                         parent = el.offsetParent;
21595                     }catch(e){}
21596                 }else{
21597                     parent = el.offsetParent;
21598                 }
21599                 if (parent) {
21600                     return true;
21601                 }
21602             }
21603
21604             return false;
21605         },
21606
21607         /**
21608          * Returns a Region object containing the drag and drop element's position
21609          * and size, including the padding configured for it
21610          * @method getLocation
21611          * @param {DragDrop} oDD the drag and drop object to get the
21612          *                       location for
21613          * @return {Roo.lib.Region} a Region object representing the total area
21614          *                             the element occupies, including any padding
21615          *                             the instance is configured for.
21616          * @static
21617          */
21618         getLocation: function(oDD) {
21619             if (! this.isTypeOfDD(oDD)) {
21620                 return null;
21621             }
21622
21623             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
21624
21625             try {
21626                 pos= Roo.lib.Dom.getXY(el);
21627             } catch (e) { }
21628
21629             if (!pos) {
21630                 return null;
21631             }
21632
21633             x1 = pos[0];
21634             x2 = x1 + el.offsetWidth;
21635             y1 = pos[1];
21636             y2 = y1 + el.offsetHeight;
21637
21638             t = y1 - oDD.padding[0];
21639             r = x2 + oDD.padding[1];
21640             b = y2 + oDD.padding[2];
21641             l = x1 - oDD.padding[3];
21642
21643             return new Roo.lib.Region( t, r, b, l );
21644         },
21645
21646         /**
21647          * Checks the cursor location to see if it over the target
21648          * @method isOverTarget
21649          * @param {Roo.lib.Point} pt The point to evaluate
21650          * @param {DragDrop} oTarget the DragDrop object we are inspecting
21651          * @return {boolean} true if the mouse is over the target
21652          * @private
21653          * @static
21654          */
21655         isOverTarget: function(pt, oTarget, intersect) {
21656             // use cache if available
21657             var loc = this.locationCache[oTarget.id];
21658             if (!loc || !this.useCache) {
21659                 loc = this.getLocation(oTarget);
21660                 this.locationCache[oTarget.id] = loc;
21661
21662             }
21663
21664             if (!loc) {
21665                 return false;
21666             }
21667
21668             oTarget.cursorIsOver = loc.contains( pt );
21669
21670             // DragDrop is using this as a sanity check for the initial mousedown
21671             // in this case we are done.  In POINT mode, if the drag obj has no
21672             // contraints, we are also done. Otherwise we need to evaluate the
21673             // location of the target as related to the actual location of the
21674             // dragged element.
21675             var dc = this.dragCurrent;
21676             if (!dc || !dc.getTargetCoord ||
21677                     (!intersect && !dc.constrainX && !dc.constrainY)) {
21678                 return oTarget.cursorIsOver;
21679             }
21680
21681             oTarget.overlap = null;
21682
21683             // Get the current location of the drag element, this is the
21684             // location of the mouse event less the delta that represents
21685             // where the original mousedown happened on the element.  We
21686             // need to consider constraints and ticks as well.
21687             var pos = dc.getTargetCoord(pt.x, pt.y);
21688
21689             var el = dc.getDragEl();
21690             var curRegion = new Roo.lib.Region( pos.y,
21691                                                    pos.x + el.offsetWidth,
21692                                                    pos.y + el.offsetHeight,
21693                                                    pos.x );
21694
21695             var overlap = curRegion.intersect(loc);
21696
21697             if (overlap) {
21698                 oTarget.overlap = overlap;
21699                 return (intersect) ? true : oTarget.cursorIsOver;
21700             } else {
21701                 return false;
21702             }
21703         },
21704
21705         /**
21706          * unload event handler
21707          * @method _onUnload
21708          * @private
21709          * @static
21710          */
21711         _onUnload: function(e, me) {
21712             Roo.dd.DragDropMgr.unregAll();
21713         },
21714
21715         /**
21716          * Cleans up the drag and drop events and objects.
21717          * @method unregAll
21718          * @private
21719          * @static
21720          */
21721         unregAll: function() {
21722
21723             if (this.dragCurrent) {
21724                 this.stopDrag();
21725                 this.dragCurrent = null;
21726             }
21727
21728             this._execOnAll("unreg", []);
21729
21730             for (i in this.elementCache) {
21731                 delete this.elementCache[i];
21732             }
21733
21734             this.elementCache = {};
21735             this.ids = {};
21736         },
21737
21738         /**
21739          * A cache of DOM elements
21740          * @property elementCache
21741          * @private
21742          * @static
21743          */
21744         elementCache: {},
21745
21746         /**
21747          * Get the wrapper for the DOM element specified
21748          * @method getElWrapper
21749          * @param {String} id the id of the element to get
21750          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21751          * @private
21752          * @deprecated This wrapper isn't that useful
21753          * @static
21754          */
21755         getElWrapper: function(id) {
21756             var oWrapper = this.elementCache[id];
21757             if (!oWrapper || !oWrapper.el) {
21758                 oWrapper = this.elementCache[id] =
21759                     new this.ElementWrapper(Roo.getDom(id));
21760             }
21761             return oWrapper;
21762         },
21763
21764         /**
21765          * Returns the actual DOM element
21766          * @method getElement
21767          * @param {String} id the id of the elment to get
21768          * @return {Object} The element
21769          * @deprecated use Roo.getDom instead
21770          * @static
21771          */
21772         getElement: function(id) {
21773             return Roo.getDom(id);
21774         },
21775
21776         /**
21777          * Returns the style property for the DOM element (i.e.,
21778          * document.getElById(id).style)
21779          * @method getCss
21780          * @param {String} id the id of the elment to get
21781          * @return {Object} The style property of the element
21782          * @deprecated use Roo.getDom instead
21783          * @static
21784          */
21785         getCss: function(id) {
21786             var el = Roo.getDom(id);
21787             return (el) ? el.style : null;
21788         },
21789
21790         /**
21791          * Inner class for cached elements
21792          * @class DragDropMgr.ElementWrapper
21793          * @for DragDropMgr
21794          * @private
21795          * @deprecated
21796          */
21797         ElementWrapper: function(el) {
21798                 /**
21799                  * The element
21800                  * @property el
21801                  */
21802                 this.el = el || null;
21803                 /**
21804                  * The element id
21805                  * @property id
21806                  */
21807                 this.id = this.el && el.id;
21808                 /**
21809                  * A reference to the style property
21810                  * @property css
21811                  */
21812                 this.css = this.el && el.style;
21813             },
21814
21815         /**
21816          * Returns the X position of an html element
21817          * @method getPosX
21818          * @param el the element for which to get the position
21819          * @return {int} the X coordinate
21820          * @for DragDropMgr
21821          * @deprecated use Roo.lib.Dom.getX instead
21822          * @static
21823          */
21824         getPosX: function(el) {
21825             return Roo.lib.Dom.getX(el);
21826         },
21827
21828         /**
21829          * Returns the Y position of an html element
21830          * @method getPosY
21831          * @param el the element for which to get the position
21832          * @return {int} the Y coordinate
21833          * @deprecated use Roo.lib.Dom.getY instead
21834          * @static
21835          */
21836         getPosY: function(el) {
21837             return Roo.lib.Dom.getY(el);
21838         },
21839
21840         /**
21841          * Swap two nodes.  In IE, we use the native method, for others we
21842          * emulate the IE behavior
21843          * @method swapNode
21844          * @param n1 the first node to swap
21845          * @param n2 the other node to swap
21846          * @static
21847          */
21848         swapNode: function(n1, n2) {
21849             if (n1.swapNode) {
21850                 n1.swapNode(n2);
21851             } else {
21852                 var p = n2.parentNode;
21853                 var s = n2.nextSibling;
21854
21855                 if (s == n1) {
21856                     p.insertBefore(n1, n2);
21857                 } else if (n2 == n1.nextSibling) {
21858                     p.insertBefore(n2, n1);
21859                 } else {
21860                     n1.parentNode.replaceChild(n2, n1);
21861                     p.insertBefore(n1, s);
21862                 }
21863             }
21864         },
21865
21866         /**
21867          * Returns the current scroll position
21868          * @method getScroll
21869          * @private
21870          * @static
21871          */
21872         getScroll: function () {
21873             var t, l, dde=document.documentElement, db=document.body;
21874             if (dde && (dde.scrollTop || dde.scrollLeft)) {
21875                 t = dde.scrollTop;
21876                 l = dde.scrollLeft;
21877             } else if (db) {
21878                 t = db.scrollTop;
21879                 l = db.scrollLeft;
21880             } else {
21881
21882             }
21883             return { top: t, left: l };
21884         },
21885
21886         /**
21887          * Returns the specified element style property
21888          * @method getStyle
21889          * @param {HTMLElement} el          the element
21890          * @param {string}      styleProp   the style property
21891          * @return {string} The value of the style property
21892          * @deprecated use Roo.lib.Dom.getStyle
21893          * @static
21894          */
21895         getStyle: function(el, styleProp) {
21896             return Roo.fly(el).getStyle(styleProp);
21897         },
21898
21899         /**
21900          * Gets the scrollTop
21901          * @method getScrollTop
21902          * @return {int} the document's scrollTop
21903          * @static
21904          */
21905         getScrollTop: function () { return this.getScroll().top; },
21906
21907         /**
21908          * Gets the scrollLeft
21909          * @method getScrollLeft
21910          * @return {int} the document's scrollTop
21911          * @static
21912          */
21913         getScrollLeft: function () { return this.getScroll().left; },
21914
21915         /**
21916          * Sets the x/y position of an element to the location of the
21917          * target element.
21918          * @method moveToEl
21919          * @param {HTMLElement} moveEl      The element to move
21920          * @param {HTMLElement} targetEl    The position reference element
21921          * @static
21922          */
21923         moveToEl: function (moveEl, targetEl) {
21924             var aCoord = Roo.lib.Dom.getXY(targetEl);
21925             Roo.lib.Dom.setXY(moveEl, aCoord);
21926         },
21927
21928         /**
21929          * Numeric array sort function
21930          * @method numericSort
21931          * @static
21932          */
21933         numericSort: function(a, b) { return (a - b); },
21934
21935         /**
21936          * Internal counter
21937          * @property _timeoutCount
21938          * @private
21939          * @static
21940          */
21941         _timeoutCount: 0,
21942
21943         /**
21944          * Trying to make the load order less important.  Without this we get
21945          * an error if this file is loaded before the Event Utility.
21946          * @method _addListeners
21947          * @private
21948          * @static
21949          */
21950         _addListeners: function() {
21951             var DDM = Roo.dd.DDM;
21952             if ( Roo.lib.Event && document ) {
21953                 DDM._onLoad();
21954             } else {
21955                 if (DDM._timeoutCount > 2000) {
21956                 } else {
21957                     setTimeout(DDM._addListeners, 10);
21958                     if (document && document.body) {
21959                         DDM._timeoutCount += 1;
21960                     }
21961                 }
21962             }
21963         },
21964
21965         /**
21966          * Recursively searches the immediate parent and all child nodes for
21967          * the handle element in order to determine wheter or not it was
21968          * clicked.
21969          * @method handleWasClicked
21970          * @param node the html element to inspect
21971          * @static
21972          */
21973         handleWasClicked: function(node, id) {
21974             if (this.isHandle(id, node.id)) {
21975                 return true;
21976             } else {
21977                 // check to see if this is a text node child of the one we want
21978                 var p = node.parentNode;
21979
21980                 while (p) {
21981                     if (this.isHandle(id, p.id)) {
21982                         return true;
21983                     } else {
21984                         p = p.parentNode;
21985                     }
21986                 }
21987             }
21988
21989             return false;
21990         }
21991
21992     };
21993
21994 }();
21995
21996 // shorter alias, save a few bytes
21997 Roo.dd.DDM = Roo.dd.DragDropMgr;
21998 Roo.dd.DDM._addListeners();
21999
22000 }/*
22001  * Based on:
22002  * Ext JS Library 1.1.1
22003  * Copyright(c) 2006-2007, Ext JS, LLC.
22004  *
22005  * Originally Released Under LGPL - original licence link has changed is not relivant.
22006  *
22007  * Fork - LGPL
22008  * <script type="text/javascript">
22009  */
22010
22011 /**
22012  * @class Roo.dd.DD
22013  * A DragDrop implementation where the linked element follows the
22014  * mouse cursor during a drag.
22015  * @extends Roo.dd.DragDrop
22016  * @constructor
22017  * @param {String} id the id of the linked element
22018  * @param {String} sGroup the group of related DragDrop items
22019  * @param {object} config an object containing configurable attributes
22020  *                Valid properties for DD:
22021  *                    scroll
22022  */
22023 Roo.dd.DD = function(id, sGroup, config) {
22024     if (id) {
22025         this.init(id, sGroup, config);
22026     }
22027 };
22028
22029 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22030
22031     /**
22032      * When set to true, the utility automatically tries to scroll the browser
22033      * window wehn a drag and drop element is dragged near the viewport boundary.
22034      * Defaults to true.
22035      * @property scroll
22036      * @type boolean
22037      */
22038     scroll: true,
22039
22040     /**
22041      * Sets the pointer offset to the distance between the linked element's top
22042      * left corner and the location the element was clicked
22043      * @method autoOffset
22044      * @param {int} iPageX the X coordinate of the click
22045      * @param {int} iPageY the Y coordinate of the click
22046      */
22047     autoOffset: function(iPageX, iPageY) {
22048         var x = iPageX - this.startPageX;
22049         var y = iPageY - this.startPageY;
22050         this.setDelta(x, y);
22051     },
22052
22053     /**
22054      * Sets the pointer offset.  You can call this directly to force the
22055      * offset to be in a particular location (e.g., pass in 0,0 to set it
22056      * to the center of the object)
22057      * @method setDelta
22058      * @param {int} iDeltaX the distance from the left
22059      * @param {int} iDeltaY the distance from the top
22060      */
22061     setDelta: function(iDeltaX, iDeltaY) {
22062         this.deltaX = iDeltaX;
22063         this.deltaY = iDeltaY;
22064     },
22065
22066     /**
22067      * Sets the drag element to the location of the mousedown or click event,
22068      * maintaining the cursor location relative to the location on the element
22069      * that was clicked.  Override this if you want to place the element in a
22070      * location other than where the cursor is.
22071      * @method setDragElPos
22072      * @param {int} iPageX the X coordinate of the mousedown or drag event
22073      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22074      */
22075     setDragElPos: function(iPageX, iPageY) {
22076         // the first time we do this, we are going to check to make sure
22077         // the element has css positioning
22078
22079         var el = this.getDragEl();
22080         this.alignElWithMouse(el, iPageX, iPageY);
22081     },
22082
22083     /**
22084      * Sets the element to the location of the mousedown or click event,
22085      * maintaining the cursor location relative to the location on the element
22086      * that was clicked.  Override this if you want to place the element in a
22087      * location other than where the cursor is.
22088      * @method alignElWithMouse
22089      * @param {HTMLElement} el the element to move
22090      * @param {int} iPageX the X coordinate of the mousedown or drag event
22091      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22092      */
22093     alignElWithMouse: function(el, iPageX, iPageY) {
22094         var oCoord = this.getTargetCoord(iPageX, iPageY);
22095         var fly = el.dom ? el : Roo.fly(el);
22096         if (!this.deltaSetXY) {
22097             var aCoord = [oCoord.x, oCoord.y];
22098             fly.setXY(aCoord);
22099             var newLeft = fly.getLeft(true);
22100             var newTop  = fly.getTop(true);
22101             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22102         } else {
22103             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22104         }
22105
22106         this.cachePosition(oCoord.x, oCoord.y);
22107         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22108         return oCoord;
22109     },
22110
22111     /**
22112      * Saves the most recent position so that we can reset the constraints and
22113      * tick marks on-demand.  We need to know this so that we can calculate the
22114      * number of pixels the element is offset from its original position.
22115      * @method cachePosition
22116      * @param iPageX the current x position (optional, this just makes it so we
22117      * don't have to look it up again)
22118      * @param iPageY the current y position (optional, this just makes it so we
22119      * don't have to look it up again)
22120      */
22121     cachePosition: function(iPageX, iPageY) {
22122         if (iPageX) {
22123             this.lastPageX = iPageX;
22124             this.lastPageY = iPageY;
22125         } else {
22126             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22127             this.lastPageX = aCoord[0];
22128             this.lastPageY = aCoord[1];
22129         }
22130     },
22131
22132     /**
22133      * Auto-scroll the window if the dragged object has been moved beyond the
22134      * visible window boundary.
22135      * @method autoScroll
22136      * @param {int} x the drag element's x position
22137      * @param {int} y the drag element's y position
22138      * @param {int} h the height of the drag element
22139      * @param {int} w the width of the drag element
22140      * @private
22141      */
22142     autoScroll: function(x, y, h, w) {
22143
22144         if (this.scroll) {
22145             // The client height
22146             var clientH = Roo.lib.Dom.getViewWidth();
22147
22148             // The client width
22149             var clientW = Roo.lib.Dom.getViewHeight();
22150
22151             // The amt scrolled down
22152             var st = this.DDM.getScrollTop();
22153
22154             // The amt scrolled right
22155             var sl = this.DDM.getScrollLeft();
22156
22157             // Location of the bottom of the element
22158             var bot = h + y;
22159
22160             // Location of the right of the element
22161             var right = w + x;
22162
22163             // The distance from the cursor to the bottom of the visible area,
22164             // adjusted so that we don't scroll if the cursor is beyond the
22165             // element drag constraints
22166             var toBot = (clientH + st - y - this.deltaY);
22167
22168             // The distance from the cursor to the right of the visible area
22169             var toRight = (clientW + sl - x - this.deltaX);
22170
22171
22172             // How close to the edge the cursor must be before we scroll
22173             // var thresh = (document.all) ? 100 : 40;
22174             var thresh = 40;
22175
22176             // How many pixels to scroll per autoscroll op.  This helps to reduce
22177             // clunky scrolling. IE is more sensitive about this ... it needs this
22178             // value to be higher.
22179             var scrAmt = (document.all) ? 80 : 30;
22180
22181             // Scroll down if we are near the bottom of the visible page and the
22182             // obj extends below the crease
22183             if ( bot > clientH && toBot < thresh ) {
22184                 window.scrollTo(sl, st + scrAmt);
22185             }
22186
22187             // Scroll up if the window is scrolled down and the top of the object
22188             // goes above the top border
22189             if ( y < st && st > 0 && y - st < thresh ) {
22190                 window.scrollTo(sl, st - scrAmt);
22191             }
22192
22193             // Scroll right if the obj is beyond the right border and the cursor is
22194             // near the border.
22195             if ( right > clientW && toRight < thresh ) {
22196                 window.scrollTo(sl + scrAmt, st);
22197             }
22198
22199             // Scroll left if the window has been scrolled to the right and the obj
22200             // extends past the left border
22201             if ( x < sl && sl > 0 && x - sl < thresh ) {
22202                 window.scrollTo(sl - scrAmt, st);
22203             }
22204         }
22205     },
22206
22207     /**
22208      * Finds the location the element should be placed if we want to move
22209      * it to where the mouse location less the click offset would place us.
22210      * @method getTargetCoord
22211      * @param {int} iPageX the X coordinate of the click
22212      * @param {int} iPageY the Y coordinate of the click
22213      * @return an object that contains the coordinates (Object.x and Object.y)
22214      * @private
22215      */
22216     getTargetCoord: function(iPageX, iPageY) {
22217
22218
22219         var x = iPageX - this.deltaX;
22220         var y = iPageY - this.deltaY;
22221
22222         if (this.constrainX) {
22223             if (x < this.minX) { x = this.minX; }
22224             if (x > this.maxX) { x = this.maxX; }
22225         }
22226
22227         if (this.constrainY) {
22228             if (y < this.minY) { y = this.minY; }
22229             if (y > this.maxY) { y = this.maxY; }
22230         }
22231
22232         x = this.getTick(x, this.xTicks);
22233         y = this.getTick(y, this.yTicks);
22234
22235
22236         return {x:x, y:y};
22237     },
22238
22239     /*
22240      * Sets up config options specific to this class. Overrides
22241      * Roo.dd.DragDrop, but all versions of this method through the
22242      * inheritance chain are called
22243      */
22244     applyConfig: function() {
22245         Roo.dd.DD.superclass.applyConfig.call(this);
22246         this.scroll = (this.config.scroll !== false);
22247     },
22248
22249     /*
22250      * Event that fires prior to the onMouseDown event.  Overrides
22251      * Roo.dd.DragDrop.
22252      */
22253     b4MouseDown: function(e) {
22254         // this.resetConstraints();
22255         this.autoOffset(e.getPageX(),
22256                             e.getPageY());
22257     },
22258
22259     /*
22260      * Event that fires prior to the onDrag event.  Overrides
22261      * Roo.dd.DragDrop.
22262      */
22263     b4Drag: function(e) {
22264         this.setDragElPos(e.getPageX(),
22265                             e.getPageY());
22266     },
22267
22268     toString: function() {
22269         return ("DD " + this.id);
22270     }
22271
22272     //////////////////////////////////////////////////////////////////////////
22273     // Debugging ygDragDrop events that can be overridden
22274     //////////////////////////////////////////////////////////////////////////
22275     /*
22276     startDrag: function(x, y) {
22277     },
22278
22279     onDrag: function(e) {
22280     },
22281
22282     onDragEnter: function(e, id) {
22283     },
22284
22285     onDragOver: function(e, id) {
22286     },
22287
22288     onDragOut: function(e, id) {
22289     },
22290
22291     onDragDrop: function(e, id) {
22292     },
22293
22294     endDrag: function(e) {
22295     }
22296
22297     */
22298
22299 });/*
22300  * Based on:
22301  * Ext JS Library 1.1.1
22302  * Copyright(c) 2006-2007, Ext JS, LLC.
22303  *
22304  * Originally Released Under LGPL - original licence link has changed is not relivant.
22305  *
22306  * Fork - LGPL
22307  * <script type="text/javascript">
22308  */
22309
22310 /**
22311  * @class Roo.dd.DDProxy
22312  * A DragDrop implementation that inserts an empty, bordered div into
22313  * the document that follows the cursor during drag operations.  At the time of
22314  * the click, the frame div is resized to the dimensions of the linked html
22315  * element, and moved to the exact location of the linked element.
22316  *
22317  * References to the "frame" element refer to the single proxy element that
22318  * was created to be dragged in place of all DDProxy elements on the
22319  * page.
22320  *
22321  * @extends Roo.dd.DD
22322  * @constructor
22323  * @param {String} id the id of the linked html element
22324  * @param {String} sGroup the group of related DragDrop objects
22325  * @param {object} config an object containing configurable attributes
22326  *                Valid properties for DDProxy in addition to those in DragDrop:
22327  *                   resizeFrame, centerFrame, dragElId
22328  */
22329 Roo.dd.DDProxy = function(id, sGroup, config) {
22330     if (id) {
22331         this.init(id, sGroup, config);
22332         this.initFrame();
22333     }
22334 };
22335
22336 /**
22337  * The default drag frame div id
22338  * @property Roo.dd.DDProxy.dragElId
22339  * @type String
22340  * @static
22341  */
22342 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22343
22344 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22345
22346     /**
22347      * By default we resize the drag frame to be the same size as the element
22348      * we want to drag (this is to get the frame effect).  We can turn it off
22349      * if we want a different behavior.
22350      * @property resizeFrame
22351      * @type boolean
22352      */
22353     resizeFrame: true,
22354
22355     /**
22356      * By default the frame is positioned exactly where the drag element is, so
22357      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22358      * you do not have constraints on the obj is to have the drag frame centered
22359      * around the cursor.  Set centerFrame to true for this effect.
22360      * @property centerFrame
22361      * @type boolean
22362      */
22363     centerFrame: false,
22364
22365     /**
22366      * Creates the proxy element if it does not yet exist
22367      * @method createFrame
22368      */
22369     createFrame: function() {
22370         var self = this;
22371         var body = document.body;
22372
22373         if (!body || !body.firstChild) {
22374             setTimeout( function() { self.createFrame(); }, 50 );
22375             return;
22376         }
22377
22378         var div = this.getDragEl();
22379
22380         if (!div) {
22381             div    = document.createElement("div");
22382             div.id = this.dragElId;
22383             var s  = div.style;
22384
22385             s.position   = "absolute";
22386             s.visibility = "hidden";
22387             s.cursor     = "move";
22388             s.border     = "2px solid #aaa";
22389             s.zIndex     = 999;
22390
22391             // appendChild can blow up IE if invoked prior to the window load event
22392             // while rendering a table.  It is possible there are other scenarios
22393             // that would cause this to happen as well.
22394             body.insertBefore(div, body.firstChild);
22395         }
22396     },
22397
22398     /**
22399      * Initialization for the drag frame element.  Must be called in the
22400      * constructor of all subclasses
22401      * @method initFrame
22402      */
22403     initFrame: function() {
22404         this.createFrame();
22405     },
22406
22407     applyConfig: function() {
22408         Roo.dd.DDProxy.superclass.applyConfig.call(this);
22409
22410         this.resizeFrame = (this.config.resizeFrame !== false);
22411         this.centerFrame = (this.config.centerFrame);
22412         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22413     },
22414
22415     /**
22416      * Resizes the drag frame to the dimensions of the clicked object, positions
22417      * it over the object, and finally displays it
22418      * @method showFrame
22419      * @param {int} iPageX X click position
22420      * @param {int} iPageY Y click position
22421      * @private
22422      */
22423     showFrame: function(iPageX, iPageY) {
22424         var el = this.getEl();
22425         var dragEl = this.getDragEl();
22426         var s = dragEl.style;
22427
22428         this._resizeProxy();
22429
22430         if (this.centerFrame) {
22431             this.setDelta( Math.round(parseInt(s.width,  10)/2),
22432                            Math.round(parseInt(s.height, 10)/2) );
22433         }
22434
22435         this.setDragElPos(iPageX, iPageY);
22436
22437         Roo.fly(dragEl).show();
22438     },
22439
22440     /**
22441      * The proxy is automatically resized to the dimensions of the linked
22442      * element when a drag is initiated, unless resizeFrame is set to false
22443      * @method _resizeProxy
22444      * @private
22445      */
22446     _resizeProxy: function() {
22447         if (this.resizeFrame) {
22448             var el = this.getEl();
22449             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22450         }
22451     },
22452
22453     // overrides Roo.dd.DragDrop
22454     b4MouseDown: function(e) {
22455         var x = e.getPageX();
22456         var y = e.getPageY();
22457         this.autoOffset(x, y);
22458         this.setDragElPos(x, y);
22459     },
22460
22461     // overrides Roo.dd.DragDrop
22462     b4StartDrag: function(x, y) {
22463         // show the drag frame
22464         this.showFrame(x, y);
22465     },
22466
22467     // overrides Roo.dd.DragDrop
22468     b4EndDrag: function(e) {
22469         Roo.fly(this.getDragEl()).hide();
22470     },
22471
22472     // overrides Roo.dd.DragDrop
22473     // By default we try to move the element to the last location of the frame.
22474     // This is so that the default behavior mirrors that of Roo.dd.DD.
22475     endDrag: function(e) {
22476
22477         var lel = this.getEl();
22478         var del = this.getDragEl();
22479
22480         // Show the drag frame briefly so we can get its position
22481         del.style.visibility = "";
22482
22483         this.beforeMove();
22484         // Hide the linked element before the move to get around a Safari
22485         // rendering bug.
22486         lel.style.visibility = "hidden";
22487         Roo.dd.DDM.moveToEl(lel, del);
22488         del.style.visibility = "hidden";
22489         lel.style.visibility = "";
22490
22491         this.afterDrag();
22492     },
22493
22494     beforeMove : function(){
22495
22496     },
22497
22498     afterDrag : function(){
22499
22500     },
22501
22502     toString: function() {
22503         return ("DDProxy " + this.id);
22504     }
22505
22506 });
22507 /*
22508  * Based on:
22509  * Ext JS Library 1.1.1
22510  * Copyright(c) 2006-2007, Ext JS, LLC.
22511  *
22512  * Originally Released Under LGPL - original licence link has changed is not relivant.
22513  *
22514  * Fork - LGPL
22515  * <script type="text/javascript">
22516  */
22517
22518  /**
22519  * @class Roo.dd.DDTarget
22520  * A DragDrop implementation that does not move, but can be a drop
22521  * target.  You would get the same result by simply omitting implementation
22522  * for the event callbacks, but this way we reduce the processing cost of the
22523  * event listener and the callbacks.
22524  * @extends Roo.dd.DragDrop
22525  * @constructor
22526  * @param {String} id the id of the element that is a drop target
22527  * @param {String} sGroup the group of related DragDrop objects
22528  * @param {object} config an object containing configurable attributes
22529  *                 Valid properties for DDTarget in addition to those in
22530  *                 DragDrop:
22531  *                    none
22532  */
22533 Roo.dd.DDTarget = function(id, sGroup, config) {
22534     if (id) {
22535         this.initTarget(id, sGroup, config);
22536     }
22537     if (config && (config.listeners || config.events)) { 
22538         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
22539             listeners : config.listeners || {}, 
22540             events : config.events || {} 
22541         });    
22542     }
22543 };
22544
22545 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22546 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22547     toString: function() {
22548         return ("DDTarget " + this.id);
22549     }
22550 });
22551 /*
22552  * Based on:
22553  * Ext JS Library 1.1.1
22554  * Copyright(c) 2006-2007, Ext JS, LLC.
22555  *
22556  * Originally Released Under LGPL - original licence link has changed is not relivant.
22557  *
22558  * Fork - LGPL
22559  * <script type="text/javascript">
22560  */
22561  
22562
22563 /**
22564  * @class Roo.dd.ScrollManager
22565  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22566  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22567  * @static
22568  */
22569 Roo.dd.ScrollManager = function(){
22570     var ddm = Roo.dd.DragDropMgr;
22571     var els = {};
22572     var dragEl = null;
22573     var proc = {};
22574     
22575     
22576     
22577     var onStop = function(e){
22578         dragEl = null;
22579         clearProc();
22580     };
22581     
22582     var triggerRefresh = function(){
22583         if(ddm.dragCurrent){
22584              ddm.refreshCache(ddm.dragCurrent.groups);
22585         }
22586     };
22587     
22588     var doScroll = function(){
22589         if(ddm.dragCurrent){
22590             var dds = Roo.dd.ScrollManager;
22591             if(!dds.animate){
22592                 if(proc.el.scroll(proc.dir, dds.increment)){
22593                     triggerRefresh();
22594                 }
22595             }else{
22596                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
22597             }
22598         }
22599     };
22600     
22601     var clearProc = function(){
22602         if(proc.id){
22603             clearInterval(proc.id);
22604         }
22605         proc.id = 0;
22606         proc.el = null;
22607         proc.dir = "";
22608     };
22609     
22610     var startProc = function(el, dir){
22611          Roo.log('scroll startproc');
22612         clearProc();
22613         proc.el = el;
22614         proc.dir = dir;
22615         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
22616     };
22617     
22618     var onFire = function(e, isDrop){
22619        
22620         if(isDrop || !ddm.dragCurrent){ return; }
22621         var dds = Roo.dd.ScrollManager;
22622         if(!dragEl || dragEl != ddm.dragCurrent){
22623             dragEl = ddm.dragCurrent;
22624             // refresh regions on drag start
22625             dds.refreshCache();
22626         }
22627         
22628         var xy = Roo.lib.Event.getXY(e);
22629         var pt = new Roo.lib.Point(xy[0], xy[1]);
22630         for(var id in els){
22631             var el = els[id], r = el._region;
22632             if(r && r.contains(pt) && el.isScrollable()){
22633                 if(r.bottom - pt.y <= dds.thresh){
22634                     if(proc.el != el){
22635                         startProc(el, "down");
22636                     }
22637                     return;
22638                 }else if(r.right - pt.x <= dds.thresh){
22639                     if(proc.el != el){
22640                         startProc(el, "left");
22641                     }
22642                     return;
22643                 }else if(pt.y - r.top <= dds.thresh){
22644                     if(proc.el != el){
22645                         startProc(el, "up");
22646                     }
22647                     return;
22648                 }else if(pt.x - r.left <= dds.thresh){
22649                     if(proc.el != el){
22650                         startProc(el, "right");
22651                     }
22652                     return;
22653                 }
22654             }
22655         }
22656         clearProc();
22657     };
22658     
22659     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
22660     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
22661     
22662     return {
22663         /**
22664          * Registers new overflow element(s) to auto scroll
22665          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
22666          */
22667         register : function(el){
22668             if(el instanceof Array){
22669                 for(var i = 0, len = el.length; i < len; i++) {
22670                         this.register(el[i]);
22671                 }
22672             }else{
22673                 el = Roo.get(el);
22674                 els[el.id] = el;
22675             }
22676             Roo.dd.ScrollManager.els = els;
22677         },
22678         
22679         /**
22680          * Unregisters overflow element(s) so they are no longer scrolled
22681          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
22682          */
22683         unregister : function(el){
22684             if(el instanceof Array){
22685                 for(var i = 0, len = el.length; i < len; i++) {
22686                         this.unregister(el[i]);
22687                 }
22688             }else{
22689                 el = Roo.get(el);
22690                 delete els[el.id];
22691             }
22692         },
22693         
22694         /**
22695          * The number of pixels from the edge of a container the pointer needs to be to 
22696          * trigger scrolling (defaults to 25)
22697          * @type Number
22698          */
22699         thresh : 25,
22700         
22701         /**
22702          * The number of pixels to scroll in each scroll increment (defaults to 50)
22703          * @type Number
22704          */
22705         increment : 100,
22706         
22707         /**
22708          * The frequency of scrolls in milliseconds (defaults to 500)
22709          * @type Number
22710          */
22711         frequency : 500,
22712         
22713         /**
22714          * True to animate the scroll (defaults to true)
22715          * @type Boolean
22716          */
22717         animate: true,
22718         
22719         /**
22720          * The animation duration in seconds - 
22721          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
22722          * @type Number
22723          */
22724         animDuration: .4,
22725         
22726         /**
22727          * Manually trigger a cache refresh.
22728          */
22729         refreshCache : function(){
22730             for(var id in els){
22731                 if(typeof els[id] == 'object'){ // for people extending the object prototype
22732                     els[id]._region = els[id].getRegion();
22733                 }
22734             }
22735         }
22736     };
22737 }();/*
22738  * Based on:
22739  * Ext JS Library 1.1.1
22740  * Copyright(c) 2006-2007, Ext JS, LLC.
22741  *
22742  * Originally Released Under LGPL - original licence link has changed is not relivant.
22743  *
22744  * Fork - LGPL
22745  * <script type="text/javascript">
22746  */
22747  
22748
22749 /**
22750  * @class Roo.dd.Registry
22751  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
22752  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22753  * @static
22754  */
22755 Roo.dd.Registry = function(){
22756     var elements = {}; 
22757     var handles = {}; 
22758     var autoIdSeed = 0;
22759
22760     var getId = function(el, autogen){
22761         if(typeof el == "string"){
22762             return el;
22763         }
22764         var id = el.id;
22765         if(!id && autogen !== false){
22766             id = "roodd-" + (++autoIdSeed);
22767             el.id = id;
22768         }
22769         return id;
22770     };
22771     
22772     return {
22773     /**
22774      * Register a drag drop element
22775      * @param {String|HTMLElement} element The id or DOM node to register
22776      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22777      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
22778      * knows how to interpret, plus there are some specific properties known to the Registry that should be
22779      * populated in the data object (if applicable):
22780      * <pre>
22781 Value      Description<br />
22782 ---------  ------------------------------------------<br />
22783 handles    Array of DOM nodes that trigger dragging<br />
22784            for the element being registered<br />
22785 isHandle   True if the element passed in triggers<br />
22786            dragging itself, else false
22787 </pre>
22788      */
22789         register : function(el, data){
22790             data = data || {};
22791             if(typeof el == "string"){
22792                 el = document.getElementById(el);
22793             }
22794             data.ddel = el;
22795             elements[getId(el)] = data;
22796             if(data.isHandle !== false){
22797                 handles[data.ddel.id] = data;
22798             }
22799             if(data.handles){
22800                 var hs = data.handles;
22801                 for(var i = 0, len = hs.length; i < len; i++){
22802                         handles[getId(hs[i])] = data;
22803                 }
22804             }
22805         },
22806
22807     /**
22808      * Unregister a drag drop element
22809      * @param {String|HTMLElement}  element The id or DOM node to unregister
22810      */
22811         unregister : function(el){
22812             var id = getId(el, false);
22813             var data = elements[id];
22814             if(data){
22815                 delete elements[id];
22816                 if(data.handles){
22817                     var hs = data.handles;
22818                     for(var i = 0, len = hs.length; i < len; i++){
22819                         delete handles[getId(hs[i], false)];
22820                     }
22821                 }
22822             }
22823         },
22824
22825     /**
22826      * Returns the handle registered for a DOM Node by id
22827      * @param {String|HTMLElement} id The DOM node or id to look up
22828      * @return {Object} handle The custom handle data
22829      */
22830         getHandle : function(id){
22831             if(typeof id != "string"){ // must be element?
22832                 id = id.id;
22833             }
22834             return handles[id];
22835         },
22836
22837     /**
22838      * Returns the handle that is registered for the DOM node that is the target of the event
22839      * @param {Event} e The event
22840      * @return {Object} handle The custom handle data
22841      */
22842         getHandleFromEvent : function(e){
22843             var t = Roo.lib.Event.getTarget(e);
22844             return t ? handles[t.id] : null;
22845         },
22846
22847     /**
22848      * Returns a custom data object that is registered for a DOM node by id
22849      * @param {String|HTMLElement} id The DOM node or id to look up
22850      * @return {Object} data The custom data
22851      */
22852         getTarget : function(id){
22853             if(typeof id != "string"){ // must be element?
22854                 id = id.id;
22855             }
22856             return elements[id];
22857         },
22858
22859     /**
22860      * Returns a custom data object that is registered for the DOM node that is the target of the event
22861      * @param {Event} e The event
22862      * @return {Object} data The custom data
22863      */
22864         getTargetFromEvent : function(e){
22865             var t = Roo.lib.Event.getTarget(e);
22866             return t ? elements[t.id] || handles[t.id] : null;
22867         }
22868     };
22869 }();/*
22870  * Based on:
22871  * Ext JS Library 1.1.1
22872  * Copyright(c) 2006-2007, Ext JS, LLC.
22873  *
22874  * Originally Released Under LGPL - original licence link has changed is not relivant.
22875  *
22876  * Fork - LGPL
22877  * <script type="text/javascript">
22878  */
22879  
22880
22881 /**
22882  * @class Roo.dd.StatusProxy
22883  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
22884  * default drag proxy used by all Roo.dd components.
22885  * @constructor
22886  * @param {Object} config
22887  */
22888 Roo.dd.StatusProxy = function(config){
22889     Roo.apply(this, config);
22890     this.id = this.id || Roo.id();
22891     this.el = new Roo.Layer({
22892         dh: {
22893             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22894                 {tag: "div", cls: "x-dd-drop-icon"},
22895                 {tag: "div", cls: "x-dd-drag-ghost"}
22896             ]
22897         }, 
22898         shadow: !config || config.shadow !== false
22899     });
22900     this.ghost = Roo.get(this.el.dom.childNodes[1]);
22901     this.dropStatus = this.dropNotAllowed;
22902 };
22903
22904 Roo.dd.StatusProxy.prototype = {
22905     /**
22906      * @cfg {String} dropAllowed
22907      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22908      */
22909     dropAllowed : "x-dd-drop-ok",
22910     /**
22911      * @cfg {String} dropNotAllowed
22912      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22913      */
22914     dropNotAllowed : "x-dd-drop-nodrop",
22915
22916     /**
22917      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22918      * over the current target element.
22919      * @param {String} cssClass The css class for the new drop status indicator image
22920      */
22921     setStatus : function(cssClass){
22922         cssClass = cssClass || this.dropNotAllowed;
22923         if(this.dropStatus != cssClass){
22924             this.el.replaceClass(this.dropStatus, cssClass);
22925             this.dropStatus = cssClass;
22926         }
22927     },
22928
22929     /**
22930      * Resets the status indicator to the default dropNotAllowed value
22931      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22932      */
22933     reset : function(clearGhost){
22934         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22935         this.dropStatus = this.dropNotAllowed;
22936         if(clearGhost){
22937             this.ghost.update("");
22938         }
22939     },
22940
22941     /**
22942      * Updates the contents of the ghost element
22943      * @param {String} html The html that will replace the current innerHTML of the ghost element
22944      */
22945     update : function(html){
22946         if(typeof html == "string"){
22947             this.ghost.update(html);
22948         }else{
22949             this.ghost.update("");
22950             html.style.margin = "0";
22951             this.ghost.dom.appendChild(html);
22952         }
22953         // ensure float = none set?? cant remember why though.
22954         var el = this.ghost.dom.firstChild;
22955                 if(el){
22956                         Roo.fly(el).setStyle('float', 'none');
22957                 }
22958     },
22959     
22960     /**
22961      * Returns the underlying proxy {@link Roo.Layer}
22962      * @return {Roo.Layer} el
22963     */
22964     getEl : function(){
22965         return this.el;
22966     },
22967
22968     /**
22969      * Returns the ghost element
22970      * @return {Roo.Element} el
22971      */
22972     getGhost : function(){
22973         return this.ghost;
22974     },
22975
22976     /**
22977      * Hides the proxy
22978      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22979      */
22980     hide : function(clear){
22981         this.el.hide();
22982         if(clear){
22983             this.reset(true);
22984         }
22985     },
22986
22987     /**
22988      * Stops the repair animation if it's currently running
22989      */
22990     stop : function(){
22991         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22992             this.anim.stop();
22993         }
22994     },
22995
22996     /**
22997      * Displays this proxy
22998      */
22999     show : function(){
23000         this.el.show();
23001     },
23002
23003     /**
23004      * Force the Layer to sync its shadow and shim positions to the element
23005      */
23006     sync : function(){
23007         this.el.sync();
23008     },
23009
23010     /**
23011      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23012      * invalid drop operation by the item being dragged.
23013      * @param {Array} xy The XY position of the element ([x, y])
23014      * @param {Function} callback The function to call after the repair is complete
23015      * @param {Object} scope The scope in which to execute the callback
23016      */
23017     repair : function(xy, callback, scope){
23018         this.callback = callback;
23019         this.scope = scope;
23020         if(xy && this.animRepair !== false){
23021             this.el.addClass("x-dd-drag-repair");
23022             this.el.hideUnders(true);
23023             this.anim = this.el.shift({
23024                 duration: this.repairDuration || .5,
23025                 easing: 'easeOut',
23026                 xy: xy,
23027                 stopFx: true,
23028                 callback: this.afterRepair,
23029                 scope: this
23030             });
23031         }else{
23032             this.afterRepair();
23033         }
23034     },
23035
23036     // private
23037     afterRepair : function(){
23038         this.hide(true);
23039         if(typeof this.callback == "function"){
23040             this.callback.call(this.scope || this);
23041         }
23042         this.callback = null;
23043         this.scope = null;
23044     }
23045 };/*
23046  * Based on:
23047  * Ext JS Library 1.1.1
23048  * Copyright(c) 2006-2007, Ext JS, LLC.
23049  *
23050  * Originally Released Under LGPL - original licence link has changed is not relivant.
23051  *
23052  * Fork - LGPL
23053  * <script type="text/javascript">
23054  */
23055
23056 /**
23057  * @class Roo.dd.DragSource
23058  * @extends Roo.dd.DDProxy
23059  * A simple class that provides the basic implementation needed to make any element draggable.
23060  * @constructor
23061  * @param {String/HTMLElement/Element} el The container element
23062  * @param {Object} config
23063  */
23064 Roo.dd.DragSource = function(el, config){
23065     this.el = Roo.get(el);
23066     this.dragData = {};
23067     
23068     Roo.apply(this, config);
23069     
23070     if(!this.proxy){
23071         this.proxy = new Roo.dd.StatusProxy();
23072     }
23073
23074     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23075           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23076     
23077     this.dragging = false;
23078 };
23079
23080 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23081     /**
23082      * @cfg {String} dropAllowed
23083      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23084      */
23085     dropAllowed : "x-dd-drop-ok",
23086     /**
23087      * @cfg {String} dropNotAllowed
23088      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23089      */
23090     dropNotAllowed : "x-dd-drop-nodrop",
23091
23092     /**
23093      * Returns the data object associated with this drag source
23094      * @return {Object} data An object containing arbitrary data
23095      */
23096     getDragData : function(e){
23097         return this.dragData;
23098     },
23099
23100     // private
23101     onDragEnter : function(e, id){
23102         var target = Roo.dd.DragDropMgr.getDDById(id);
23103         this.cachedTarget = target;
23104         if(this.beforeDragEnter(target, e, id) !== false){
23105             if(target.isNotifyTarget){
23106                 var status = target.notifyEnter(this, e, this.dragData);
23107                 this.proxy.setStatus(status);
23108             }else{
23109                 this.proxy.setStatus(this.dropAllowed);
23110             }
23111             
23112             if(this.afterDragEnter){
23113                 /**
23114                  * An empty function by default, but provided so that you can perform a custom action
23115                  * when the dragged item enters the drop target by providing an implementation.
23116                  * @param {Roo.dd.DragDrop} target The drop target
23117                  * @param {Event} e The event object
23118                  * @param {String} id The id of the dragged element
23119                  * @method afterDragEnter
23120                  */
23121                 this.afterDragEnter(target, e, id);
23122             }
23123         }
23124     },
23125
23126     /**
23127      * An empty function by default, but provided so that you can perform a custom action
23128      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23129      * @param {Roo.dd.DragDrop} target The drop target
23130      * @param {Event} e The event object
23131      * @param {String} id The id of the dragged element
23132      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23133      */
23134     beforeDragEnter : function(target, e, id){
23135         return true;
23136     },
23137
23138     // private
23139     alignElWithMouse: function() {
23140         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23141         this.proxy.sync();
23142     },
23143
23144     // private
23145     onDragOver : function(e, id){
23146         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23147         if(this.beforeDragOver(target, e, id) !== false){
23148             if(target.isNotifyTarget){
23149                 var status = target.notifyOver(this, e, this.dragData);
23150                 this.proxy.setStatus(status);
23151             }
23152
23153             if(this.afterDragOver){
23154                 /**
23155                  * An empty function by default, but provided so that you can perform a custom action
23156                  * while the dragged item is over the drop target by providing an implementation.
23157                  * @param {Roo.dd.DragDrop} target The drop target
23158                  * @param {Event} e The event object
23159                  * @param {String} id The id of the dragged element
23160                  * @method afterDragOver
23161                  */
23162                 this.afterDragOver(target, e, id);
23163             }
23164         }
23165     },
23166
23167     /**
23168      * An empty function by default, but provided so that you can perform a custom action
23169      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23170      * @param {Roo.dd.DragDrop} target The drop target
23171      * @param {Event} e The event object
23172      * @param {String} id The id of the dragged element
23173      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23174      */
23175     beforeDragOver : function(target, e, id){
23176         return true;
23177     },
23178
23179     // private
23180     onDragOut : function(e, id){
23181         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23182         if(this.beforeDragOut(target, e, id) !== false){
23183             if(target.isNotifyTarget){
23184                 target.notifyOut(this, e, this.dragData);
23185             }
23186             this.proxy.reset();
23187             if(this.afterDragOut){
23188                 /**
23189                  * An empty function by default, but provided so that you can perform a custom action
23190                  * after the dragged item is dragged out of the target without dropping.
23191                  * @param {Roo.dd.DragDrop} target The drop target
23192                  * @param {Event} e The event object
23193                  * @param {String} id The id of the dragged element
23194                  * @method afterDragOut
23195                  */
23196                 this.afterDragOut(target, e, id);
23197             }
23198         }
23199         this.cachedTarget = null;
23200     },
23201
23202     /**
23203      * An empty function by default, but provided so that you can perform a custom action before the dragged
23204      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23205      * @param {Roo.dd.DragDrop} target The drop target
23206      * @param {Event} e The event object
23207      * @param {String} id The id of the dragged element
23208      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23209      */
23210     beforeDragOut : function(target, e, id){
23211         return true;
23212     },
23213     
23214     // private
23215     onDragDrop : function(e, id){
23216         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23217         if(this.beforeDragDrop(target, e, id) !== false){
23218             if(target.isNotifyTarget){
23219                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23220                     this.onValidDrop(target, e, id);
23221                 }else{
23222                     this.onInvalidDrop(target, e, id);
23223                 }
23224             }else{
23225                 this.onValidDrop(target, e, id);
23226             }
23227             
23228             if(this.afterDragDrop){
23229                 /**
23230                  * An empty function by default, but provided so that you can perform a custom action
23231                  * after a valid drag drop has occurred by providing an implementation.
23232                  * @param {Roo.dd.DragDrop} target The drop target
23233                  * @param {Event} e The event object
23234                  * @param {String} id The id of the dropped element
23235                  * @method afterDragDrop
23236                  */
23237                 this.afterDragDrop(target, e, id);
23238             }
23239         }
23240         delete this.cachedTarget;
23241     },
23242
23243     /**
23244      * An empty function by default, but provided so that you can perform a custom action before the dragged
23245      * item is dropped onto the target and optionally cancel the onDragDrop.
23246      * @param {Roo.dd.DragDrop} target The drop target
23247      * @param {Event} e The event object
23248      * @param {String} id The id of the dragged element
23249      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23250      */
23251     beforeDragDrop : function(target, e, id){
23252         return true;
23253     },
23254
23255     // private
23256     onValidDrop : function(target, e, id){
23257         this.hideProxy();
23258         if(this.afterValidDrop){
23259             /**
23260              * An empty function by default, but provided so that you can perform a custom action
23261              * after a valid drop has occurred by providing an implementation.
23262              * @param {Object} target The target DD 
23263              * @param {Event} e The event object
23264              * @param {String} id The id of the dropped element
23265              * @method afterInvalidDrop
23266              */
23267             this.afterValidDrop(target, e, id);
23268         }
23269     },
23270
23271     // private
23272     getRepairXY : function(e, data){
23273         return this.el.getXY();  
23274     },
23275
23276     // private
23277     onInvalidDrop : function(target, e, id){
23278         this.beforeInvalidDrop(target, e, id);
23279         if(this.cachedTarget){
23280             if(this.cachedTarget.isNotifyTarget){
23281                 this.cachedTarget.notifyOut(this, e, this.dragData);
23282             }
23283             this.cacheTarget = null;
23284         }
23285         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23286
23287         if(this.afterInvalidDrop){
23288             /**
23289              * An empty function by default, but provided so that you can perform a custom action
23290              * after an invalid drop has occurred by providing an implementation.
23291              * @param {Event} e The event object
23292              * @param {String} id The id of the dropped element
23293              * @method afterInvalidDrop
23294              */
23295             this.afterInvalidDrop(e, id);
23296         }
23297     },
23298
23299     // private
23300     afterRepair : function(){
23301         if(Roo.enableFx){
23302             this.el.highlight(this.hlColor || "c3daf9");
23303         }
23304         this.dragging = false;
23305     },
23306
23307     /**
23308      * An empty function by default, but provided so that you can perform a custom action after an invalid
23309      * drop has occurred.
23310      * @param {Roo.dd.DragDrop} target The drop target
23311      * @param {Event} e The event object
23312      * @param {String} id The id of the dragged element
23313      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23314      */
23315     beforeInvalidDrop : function(target, e, id){
23316         return true;
23317     },
23318
23319     // private
23320     handleMouseDown : function(e){
23321         if(this.dragging) {
23322             return;
23323         }
23324         var data = this.getDragData(e);
23325         if(data && this.onBeforeDrag(data, e) !== false){
23326             this.dragData = data;
23327             this.proxy.stop();
23328             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23329         } 
23330     },
23331
23332     /**
23333      * An empty function by default, but provided so that you can perform a custom action before the initial
23334      * drag event begins and optionally cancel it.
23335      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23336      * @param {Event} e The event object
23337      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23338      */
23339     onBeforeDrag : function(data, e){
23340         return true;
23341     },
23342
23343     /**
23344      * An empty function by default, but provided so that you can perform a custom action once the initial
23345      * drag event has begun.  The drag cannot be canceled from this function.
23346      * @param {Number} x The x position of the click on the dragged object
23347      * @param {Number} y The y position of the click on the dragged object
23348      */
23349     onStartDrag : Roo.emptyFn,
23350
23351     // private - YUI override
23352     startDrag : function(x, y){
23353         this.proxy.reset();
23354         this.dragging = true;
23355         this.proxy.update("");
23356         this.onInitDrag(x, y);
23357         this.proxy.show();
23358     },
23359
23360     // private
23361     onInitDrag : function(x, y){
23362         var clone = this.el.dom.cloneNode(true);
23363         clone.id = Roo.id(); // prevent duplicate ids
23364         this.proxy.update(clone);
23365         this.onStartDrag(x, y);
23366         return true;
23367     },
23368
23369     /**
23370      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23371      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23372      */
23373     getProxy : function(){
23374         return this.proxy;  
23375     },
23376
23377     /**
23378      * Hides the drag source's {@link Roo.dd.StatusProxy}
23379      */
23380     hideProxy : function(){
23381         this.proxy.hide();  
23382         this.proxy.reset(true);
23383         this.dragging = false;
23384     },
23385
23386     // private
23387     triggerCacheRefresh : function(){
23388         Roo.dd.DDM.refreshCache(this.groups);
23389     },
23390
23391     // private - override to prevent hiding
23392     b4EndDrag: function(e) {
23393     },
23394
23395     // private - override to prevent moving
23396     endDrag : function(e){
23397         this.onEndDrag(this.dragData, e);
23398     },
23399
23400     // private
23401     onEndDrag : function(data, e){
23402     },
23403     
23404     // private - pin to cursor
23405     autoOffset : function(x, y) {
23406         this.setDelta(-12, -20);
23407     }    
23408 });/*
23409  * Based on:
23410  * Ext JS Library 1.1.1
23411  * Copyright(c) 2006-2007, Ext JS, LLC.
23412  *
23413  * Originally Released Under LGPL - original licence link has changed is not relivant.
23414  *
23415  * Fork - LGPL
23416  * <script type="text/javascript">
23417  */
23418
23419
23420 /**
23421  * @class Roo.dd.DropTarget
23422  * @extends Roo.dd.DDTarget
23423  * A simple class that provides the basic implementation needed to make any element a drop target that can have
23424  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
23425  * @constructor
23426  * @param {String/HTMLElement/Element} el The container element
23427  * @param {Object} config
23428  */
23429 Roo.dd.DropTarget = function(el, config){
23430     this.el = Roo.get(el);
23431     
23432     var listeners = false; ;
23433     if (config && config.listeners) {
23434         listeners= config.listeners;
23435         delete config.listeners;
23436     }
23437     Roo.apply(this, config);
23438     
23439     if(this.containerScroll){
23440         Roo.dd.ScrollManager.register(this.el);
23441     }
23442     this.addEvents( {
23443          /**
23444          * @scope Roo.dd.DropTarget
23445          */
23446          
23447          /**
23448          * @event enter
23449          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23450          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
23451          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
23452          * 
23453          * IMPORTANT : it should set  this.valid to true|false
23454          * 
23455          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23456          * @param {Event} e The event
23457          * @param {Object} data An object containing arbitrary data supplied by the drag source
23458          */
23459         "enter" : true,
23460         
23461          /**
23462          * @event over
23463          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23464          * This method will be called on every mouse movement while the drag source is over the drop target.
23465          * This default implementation simply returns the dropAllowed config value.
23466          * 
23467          * IMPORTANT : it should set  this.valid to true|false
23468          * 
23469          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23470          * @param {Event} e The event
23471          * @param {Object} data An object containing arbitrary data supplied by the drag source
23472          
23473          */
23474         "over" : true,
23475         /**
23476          * @event out
23477          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23478          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
23479          * overClass (if any) from the drop element.
23480          * 
23481          * 
23482          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23483          * @param {Event} e The event
23484          * @param {Object} data An object containing arbitrary data supplied by the drag source
23485          */
23486          "out" : true,
23487          
23488         /**
23489          * @event drop
23490          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23491          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
23492          * implementation that does something to process the drop event and returns true so that the drag source's
23493          * repair action does not run.
23494          * 
23495          * IMPORTANT : it should set this.success
23496          * 
23497          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23498          * @param {Event} e The event
23499          * @param {Object} data An object containing arbitrary data supplied by the drag source
23500         */
23501          "drop" : true
23502     });
23503             
23504      
23505     Roo.dd.DropTarget.superclass.constructor.call(  this, 
23506         this.el.dom, 
23507         this.ddGroup || this.group,
23508         {
23509             isTarget: true,
23510             listeners : listeners || {} 
23511            
23512         
23513         }
23514     );
23515
23516 };
23517
23518 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23519     /**
23520      * @cfg {String} overClass
23521      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23522      */
23523      /**
23524      * @cfg {String} ddGroup
23525      * The drag drop group to handle drop events for
23526      */
23527      
23528     /**
23529      * @cfg {String} dropAllowed
23530      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23531      */
23532     dropAllowed : "x-dd-drop-ok",
23533     /**
23534      * @cfg {String} dropNotAllowed
23535      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23536      */
23537     dropNotAllowed : "x-dd-drop-nodrop",
23538     /**
23539      * @cfg {boolean} success
23540      * set this after drop listener.. 
23541      */
23542     success : false,
23543     /**
23544      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23545      * if the drop point is valid for over/enter..
23546      */
23547     valid : false,
23548     // private
23549     isTarget : true,
23550
23551     // private
23552     isNotifyTarget : true,
23553     
23554     /**
23555      * @hide
23556      */
23557     notifyEnter : function(dd, e, data)
23558     {
23559         this.valid = true;
23560         this.fireEvent('enter', dd, e, data);
23561         if(this.overClass){
23562             this.el.addClass(this.overClass);
23563         }
23564         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23565             this.valid ? this.dropAllowed : this.dropNotAllowed
23566         );
23567     },
23568
23569     /**
23570      * @hide
23571      */
23572     notifyOver : function(dd, e, data)
23573     {
23574         this.valid = true;
23575         this.fireEvent('over', dd, e, data);
23576         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23577             this.valid ? this.dropAllowed : this.dropNotAllowed
23578         );
23579     },
23580
23581     /**
23582      * @hide
23583      */
23584     notifyOut : function(dd, e, data)
23585     {
23586         this.fireEvent('out', dd, e, data);
23587         if(this.overClass){
23588             this.el.removeClass(this.overClass);
23589         }
23590     },
23591
23592     /**
23593      * @hide
23594      */
23595     notifyDrop : function(dd, e, data)
23596     {
23597         this.success = false;
23598         this.fireEvent('drop', dd, e, data);
23599         return this.success;
23600     }
23601 });/*
23602  * Based on:
23603  * Ext JS Library 1.1.1
23604  * Copyright(c) 2006-2007, Ext JS, LLC.
23605  *
23606  * Originally Released Under LGPL - original licence link has changed is not relivant.
23607  *
23608  * Fork - LGPL
23609  * <script type="text/javascript">
23610  */
23611
23612
23613 /**
23614  * @class Roo.dd.DragZone
23615  * @extends Roo.dd.DragSource
23616  * This class provides a container DD instance that proxies for multiple child node sources.<br />
23617  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
23618  * @constructor
23619  * @param {String/HTMLElement/Element} el The container element
23620  * @param {Object} config
23621  */
23622 Roo.dd.DragZone = function(el, config){
23623     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
23624     if(this.containerScroll){
23625         Roo.dd.ScrollManager.register(this.el);
23626     }
23627 };
23628
23629 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
23630     /**
23631      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
23632      * for auto scrolling during drag operations.
23633      */
23634     /**
23635      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
23636      * method after a failed drop (defaults to "c3daf9" - light blue)
23637      */
23638
23639     /**
23640      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
23641      * for a valid target to drag based on the mouse down. Override this method
23642      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
23643      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
23644      * @param {EventObject} e The mouse down event
23645      * @return {Object} The dragData
23646      */
23647     getDragData : function(e){
23648         return Roo.dd.Registry.getHandleFromEvent(e);
23649     },
23650     
23651     /**
23652      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
23653      * this.dragData.ddel
23654      * @param {Number} x The x position of the click on the dragged object
23655      * @param {Number} y The y position of the click on the dragged object
23656      * @return {Boolean} true to continue the drag, false to cancel
23657      */
23658     onInitDrag : function(x, y){
23659         this.proxy.update(this.dragData.ddel.cloneNode(true));
23660         this.onStartDrag(x, y);
23661         return true;
23662     },
23663     
23664     /**
23665      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
23666      */
23667     afterRepair : function(){
23668         if(Roo.enableFx){
23669             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
23670         }
23671         this.dragging = false;
23672     },
23673
23674     /**
23675      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
23676      * the XY of this.dragData.ddel
23677      * @param {EventObject} e The mouse up event
23678      * @return {Array} The xy location (e.g. [100, 200])
23679      */
23680     getRepairXY : function(e){
23681         return Roo.Element.fly(this.dragData.ddel).getXY();  
23682     }
23683 });/*
23684  * Based on:
23685  * Ext JS Library 1.1.1
23686  * Copyright(c) 2006-2007, Ext JS, LLC.
23687  *
23688  * Originally Released Under LGPL - original licence link has changed is not relivant.
23689  *
23690  * Fork - LGPL
23691  * <script type="text/javascript">
23692  */
23693 /**
23694  * @class Roo.dd.DropZone
23695  * @extends Roo.dd.DropTarget
23696  * This class provides a container DD instance that proxies for multiple child node targets.<br />
23697  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
23698  * @constructor
23699  * @param {String/HTMLElement/Element} el The container element
23700  * @param {Object} config
23701  */
23702 Roo.dd.DropZone = function(el, config){
23703     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
23704 };
23705
23706 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
23707     /**
23708      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
23709      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
23710      * provide your own custom lookup.
23711      * @param {Event} e The event
23712      * @return {Object} data The custom data
23713      */
23714     getTargetFromEvent : function(e){
23715         return Roo.dd.Registry.getTargetFromEvent(e);
23716     },
23717
23718     /**
23719      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
23720      * that it has registered.  This method has no default implementation and should be overridden to provide
23721      * node-specific processing if necessary.
23722      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
23723      * {@link #getTargetFromEvent} for this node)
23724      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23725      * @param {Event} e The event
23726      * @param {Object} data An object containing arbitrary data supplied by the drag source
23727      */
23728     onNodeEnter : function(n, dd, e, data){
23729         
23730     },
23731
23732     /**
23733      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
23734      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
23735      * overridden to provide the proper feedback.
23736      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23737      * {@link #getTargetFromEvent} for this node)
23738      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23739      * @param {Event} e The event
23740      * @param {Object} data An object containing arbitrary data supplied by the drag source
23741      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23742      * underlying {@link Roo.dd.StatusProxy} can be updated
23743      */
23744     onNodeOver : function(n, dd, e, data){
23745         return this.dropAllowed;
23746     },
23747
23748     /**
23749      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23750      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
23751      * node-specific processing if necessary.
23752      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23753      * {@link #getTargetFromEvent} for this node)
23754      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23755      * @param {Event} e The event
23756      * @param {Object} data An object containing arbitrary data supplied by the drag source
23757      */
23758     onNodeOut : function(n, dd, e, data){
23759         
23760     },
23761
23762     /**
23763      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23764      * the drop node.  The default implementation returns false, so it should be overridden to provide the
23765      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23766      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23767      * {@link #getTargetFromEvent} for this node)
23768      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23769      * @param {Event} e The event
23770      * @param {Object} data An object containing arbitrary data supplied by the drag source
23771      * @return {Boolean} True if the drop was valid, else false
23772      */
23773     onNodeDrop : function(n, dd, e, data){
23774         return false;
23775     },
23776
23777     /**
23778      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23779      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
23780      * it should be overridden to provide the proper feedback if necessary.
23781      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23782      * @param {Event} e The event
23783      * @param {Object} data An object containing arbitrary data supplied by the drag source
23784      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23785      * underlying {@link Roo.dd.StatusProxy} can be updated
23786      */
23787     onContainerOver : function(dd, e, data){
23788         return this.dropNotAllowed;
23789     },
23790
23791     /**
23792      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23793      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
23794      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23795      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
23796      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23797      * @param {Event} e The event
23798      * @param {Object} data An object containing arbitrary data supplied by the drag source
23799      * @return {Boolean} True if the drop was valid, else false
23800      */
23801     onContainerDrop : function(dd, e, data){
23802         return false;
23803     },
23804
23805     /**
23806      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23807      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
23808      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23809      * you should override this method and provide a custom implementation.
23810      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23811      * @param {Event} e The event
23812      * @param {Object} data An object containing arbitrary data supplied by the drag source
23813      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23814      * underlying {@link Roo.dd.StatusProxy} can be updated
23815      */
23816     notifyEnter : function(dd, e, data){
23817         return this.dropNotAllowed;
23818     },
23819
23820     /**
23821      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23822      * This method will be called on every mouse movement while the drag source is over the drop zone.
23823      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23824      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23825      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23826      * registered node, it will call {@link #onContainerOver}.
23827      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23828      * @param {Event} e The event
23829      * @param {Object} data An object containing arbitrary data supplied by the drag source
23830      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23831      * underlying {@link Roo.dd.StatusProxy} can be updated
23832      */
23833     notifyOver : function(dd, e, data){
23834         var n = this.getTargetFromEvent(e);
23835         if(!n){ // not over valid drop target
23836             if(this.lastOverNode){
23837                 this.onNodeOut(this.lastOverNode, dd, e, data);
23838                 this.lastOverNode = null;
23839             }
23840             return this.onContainerOver(dd, e, data);
23841         }
23842         if(this.lastOverNode != n){
23843             if(this.lastOverNode){
23844                 this.onNodeOut(this.lastOverNode, dd, e, data);
23845             }
23846             this.onNodeEnter(n, dd, e, data);
23847             this.lastOverNode = n;
23848         }
23849         return this.onNodeOver(n, dd, e, data);
23850     },
23851
23852     /**
23853      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23854      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
23855      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23856      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23857      * @param {Event} e The event
23858      * @param {Object} data An object containing arbitrary data supplied by the drag zone
23859      */
23860     notifyOut : function(dd, e, data){
23861         if(this.lastOverNode){
23862             this.onNodeOut(this.lastOverNode, dd, e, data);
23863             this.lastOverNode = null;
23864         }
23865     },
23866
23867     /**
23868      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23869      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
23870      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23871      * otherwise it will call {@link #onContainerDrop}.
23872      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23873      * @param {Event} e The event
23874      * @param {Object} data An object containing arbitrary data supplied by the drag source
23875      * @return {Boolean} True if the drop was valid, else false
23876      */
23877     notifyDrop : function(dd, e, data){
23878         if(this.lastOverNode){
23879             this.onNodeOut(this.lastOverNode, dd, e, data);
23880             this.lastOverNode = null;
23881         }
23882         var n = this.getTargetFromEvent(e);
23883         return n ?
23884             this.onNodeDrop(n, dd, e, data) :
23885             this.onContainerDrop(dd, e, data);
23886     },
23887
23888     // private
23889     triggerCacheRefresh : function(){
23890         Roo.dd.DDM.refreshCache(this.groups);
23891     }  
23892 });